diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fx.hpp b/sdk/lib/drivers/wdf/kmdf/inc/private/fx.hpp new file mode 100644 index 00000000000..d3eae97629e --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fx.hpp @@ -0,0 +1,208 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Fx.hpp + +Abstract: + + This is the main driver framework include file. + +Author: + WDF team + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FX_H +#define _FX_H + +extern "C" { +#include "mx.h" +} + +#include "FxMacros.hpp" + +extern "C" { +#include "wdf.h" +#include "wdmsec.h" +#include "wdmguid.h" + +#include "wdfdevicepri.h" +#include "wdfiotargetpri.h" +#include "wdfcx.h" +#include "wdfldr.h" + +#include + +#include "wdf10.h" +#include "wdf11.h" +#include "wdf15.h" +#include "wdf17.h" +#include "wdf19.h" +#include "wdf111.h" +#include "wdf113.h" +#include "wdf115.h" +} + +#define KMDF_ONLY_CODE_PATH_ASSERT() + +// Integer overflow functions +#include "ntintsafe.h" + +#include "FxForward.hpp" + +//KMDF defines for shared type names +#include "FxTypeDefsKm.hpp" + +#include "fxwmicompat.h" +#include "fxtrace.h" +#include "fxtypes.h" +#include "fxrequestcontexttypes.h" +#include "fxpool.h" +#include "FxGlobalsKM.h" +#include "FxPoolInlines.hpp" +#include "fxverifier.h" +#include "fxverifierkm.h" +#include "FxMdl.h" +#include "FxProbeAndLock.h" + +#include "FxPerfTraceKm.hpp" +#include "DriverFrameworks-KernelMode-KmEvents.h" + +#include + +#include "FxStump.hpp" + +#include "FxRequestBuffer.hpp" + +#include "FxTagTracker.hpp" + +// internal locks +#include "FxVerifierLock.hpp" +#include "FxLock.hpp" + +// base objects +#include "fxobject.hpp" +#include "FxPagedObject.hpp" +#include "FxNonPagedObject.hpp" + +#include "fxhandle.h" + +// external locks +#include "FxWaitLock.hpp" +#include "FxSpinLock.hpp" + +// utitilty classes and functions +#include "FxTransactionedList.hpp" +#include "FxRelatedDeviceList.hpp" +#include "FxDisposeList.hpp" +#include "FxCollection.hpp" +#include "StringUtil.hpp" + +// abstract classes +#include "IFxHasCallbacks.hpp" + +// callback delegation and locking +#include "FxSystemThread.hpp" +#include "FxSystemWorkItem.hpp" +#include "FxCallbackLock.hpp" +#include "FxCallbackSpinLock.hpp" +#include "FxCallbackMutexLock.hpp" +#include "FxCallback.hpp" +#include "FxSystemThread.hpp" + +#include "IFxMemory.hpp" +#include "FxLookasideList.hpp" +#include "FxNPagedLookasideList.hpp" +#include "FxPagedLookasideList.hpp" +#include "FxMemoryObject.hpp" +#include "FxMemoryBuffer.hpp" +#include "FxMemoryBufferFromPool.hpp" +#include "FxMemoryBufferPreallocated.hpp" +#include "FxMemoryBufferFromLookaside.hpp" +#include "FxRequestMemory.hpp" +#include "FxRegKey.hpp" +#include "FxAutoRegistry.hpp" +#include "FxAutoString.hpp" +#include "FxString.hpp" + +#include "FxValidateFunctions.hpp" +#include "FxRequestValidateFunctions.hpp" + +#include "FxResource.hpp" +#include "FxRelatedDevice.hpp" +#include "FxDeviceInterface.hpp" +#include "FxQueryInterface.hpp" +#include "FxDeviceText.hpp" + +#include "FxIrp.hpp" +#include "FxDriver.hpp" + +// generic package interface +#include "FxPackage.hpp" +#include "FxPkgGeneral.hpp" +#include "FxDefaultIrpHandler.hpp" +#include "FxPkgPnp.hpp" +#include "FxWatchDog.hpp" + +// Device support +#include "FxChildList.hpp" +#include "FxCxDeviceInfo.hpp" +#include "FxDevice.hpp" + +#include "FxPkgIo.hpp" + +#include "FxDeviceToMxInterface.hpp" + +#include "FxIrpQueue.hpp" +#include "FxRequestContext.hpp" +#include "FxRequestCallbacks.hpp" +#include "FxRequestBase.hpp" +#include "FxRequest.hpp" +#include "FxSyncRequest.hpp" + +// specialized irp handlers (ie packages) +#include "FxPkgFdo.hpp" +#include "FxPkgPdo.hpp" +#include "FxWmiIrpHandler.hpp" +#include "FxWmiProvider.hpp" +#include "FxWmiInstance.hpp" + +// queus for read, write, (internal) IOCTL +#include "FxIoQueue.hpp" +#include "FxFileObject.hpp" +#include "FxIrpPreprocessInfo.hpp" +#include "FxIrpDynamicDispatchInfo.hpp" + +#include "FxDpc.hpp" +#include "FxWorkItem.hpp" +#include "FxTimer.hpp" +#include "FxInterruptKm.hpp" + +// IO targets (device lower edge interface) +#include "FxIoTarget.hpp" +#include "FxIoTargetRemote.hpp" +#include "FxIoTargetSelf.hpp" + +#include "FxUsbDevice.hpp" +#include "FxUsbInterface.hpp" +#include "FxUsbPipe.hpp" + +// DMA support +#include "FxDmaEnabler.hpp" +#include "FxDmaTransaction.hpp" +#include "FxCommonBuffer.hpp" + +// Triage info. +#include "wdftriage.h" + +#include "FxTelemetry.hpp" +#endif // _FX_H diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxbugcheck.h b/sdk/lib/drivers/wdf/kmdf/inc/private/fxbugcheck.h new file mode 100644 index 00000000000..d7894530347 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxbugcheck.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxBugcheck.h + +Abstract: + This module contains private macros/defines for crashdumps. + +--*/ + +#ifndef __FXBUGCHECK_H__ +#define __FXBUGCHECK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Macro for doing pointer arithmetic. +// +#define Add2Ptr(P,I) ((PVOID)((PUCHAR)(P) + (I))) + +// +// This macro takes a length & rounds it up to a multiple of the alignment +// Alignment is given as a power of 2 +// +#define EXP_ALIGN_UP_PTR_ON_BOUNDARY(_length, _alignment) \ + (PVOID) ((((ULONG_PTR) (_length)) + ((_alignment)-1)) & \ + ~(ULONG_PTR)((_alignment) - 1)) + +// +// Checks if 1st argument is aligned on given power of 2 boundary specified +// by 2nd argument +// +#define EXP_IS_PTR_ALIGNED_ON_BOUNDARY(_pointer, _alignment) \ + ((((ULONG_PTR) (_pointer)) & ((_alignment) - 1)) == 0) + + +// +// This macro takes a size and rounds it down to a multiple of the alignemnt. +// Alignment doesn't need to be a power of 2. +// +#define EXP_ALIGN_DOWN_ON_BOUNDARY(_size, _alignment) \ + ((_size) - ((_size) % _alignment)) + +// +// Define the max data size the bugcheck callback can write. Per callback the +// total size is around 16K on 32bit OS (32K on 64bit OS). +// +#ifdef _WIN64 +#define FX_MAX_DUMP_SIZE (32*1024) +#else +#define FX_MAX_DUMP_SIZE (16*1024) +#endif + +// +// Maximum number of CPUs supported by the driver tracker. +// +#define FX_DRIVER_TRACKER_MAX_CPUS 256 // Max Win7 processors. + +// +// The initial/increment size of the array to hold driver info. +// +#define FX_DUMP_DRIVER_INFO_INCREMENT 10 // # entries. + +// +// The max size of the array to hold the driver info. This is the max data +// we can write into the minidump. +// +#define FX_MAX_DUMP_DRIVER_INFO_COUNT \ + (FX_MAX_DUMP_SIZE/sizeof(FX_DUMP_DRIVER_INFO_ENTRY)) + +// +// During run-time we store info about the loaded drivers in an array +// of FX_DUMP_DRIVER_INFO_ENTRY struct entries, on a crash we write the +// entire array in the minidump for postmortem analysis. +// +typedef struct _FX_DUMP_DRIVER_INFO_ENTRY { + PFX_DRIVER_GLOBALS FxDriverGlobals; + WDF_VERSION Version; + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; +} FX_DUMP_DRIVER_INFO_ENTRY, *PFX_DUMP_DRIVER_INFO_ENTRY; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __FXBUGCHECK_H__ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxcommonbuffer.hpp b/sdk/lib/drivers/wdf/kmdf/inc/private/fxcommonbuffer.hpp new file mode 100644 index 00000000000..329c07fa02a --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxcommonbuffer.hpp @@ -0,0 +1,161 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCommonBuffer.hpp + +Abstract: + + WDF CommonBuffer Object support + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#ifndef _FXCOMMONBUFFER_H_ +#define _FXCOMMONBUFFER_H_ + +// +// Calculate an "aligned" address (Logical or Virtual) per +// a specific alignment value. +// +FORCEINLINE +PVOID +FX_ALIGN_VIRTUAL_ADDRESS( + __in PVOID VA, + __in size_t AlignTo + ) +{ + return (PVOID)(((ULONG_PTR)VA + AlignTo) & ~AlignTo); +} + +FORCEINLINE +ULONGLONG +FX_ALIGN_LOGICAL_ADDRESS( + __in PHYSICAL_ADDRESS LA, + __in size_t AlignTo + ) +{ + return (LA.QuadPart + AlignTo) & ~((ULONGLONG)AlignTo); +} + +// +// Declare the FxCommonBuffer class +// +class FxCommonBuffer : public FxNonPagedObject { + +public: + + FxCommonBuffer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxDmaEnabler * pDmaEnabler + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + AllocateCommonBuffer( + __in size_t Length + ); + + VOID + FreeCommonBuffer( + VOID + ); + + __forceinline + PHYSICAL_ADDRESS + GetAlignedLogicalAddress( + VOID + ) + { + return m_BufferAlignedLA; + } + + __forceinline + PVOID + GetAlignedVirtualAddress( + VOID + ) + { + return m_BufferAlignedVA; + } + + __forceinline + size_t + GetLength( + VOID + ) + { + return m_Length; + } + + __forceinline + VOID + SetAlignment( + __in ULONG Alignment + ) + { + m_Alignment = Alignment; + } + +protected: + + // + // Unaligned virtual address + // + PVOID m_BufferRawVA; + + // + // Aligned virtual address + // + PVOID m_BufferAlignedVA; + + // + // Aligned logical address + // + PHYSICAL_ADDRESS m_BufferAlignedLA; + + // + // Unaligned logical address + // + PHYSICAL_ADDRESS m_BufferRawLA; + + // + // Pointer to the DMA enabler + // + FxDmaEnabler * m_DmaEnabler; + + // + // Length specified by the caller + // + size_t m_Length; + + // + // Actual length used to allocate buffer after adding the alignement + // value. + // + size_t m_RawLength; + + // + // Alignment of the allocated buffer. + // + size_t m_Alignment; + +}; + +#endif // _FXCOMMONBUFFER_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxdmatransaction.hpp b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdmatransaction.hpp new file mode 100644 index 00000000000..0e3535b669c --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdmatransaction.hpp @@ -0,0 +1,1559 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXDMATRANSACTION_HPP_ +#define _FXDMATRANSACTION_HPP_ + +extern "C" { +#include "FxDmaTransaction.hpp.tmh" +} + +#include "FxDmaTransactionCallbacks.hpp" + +// +// This type is used to allocate scatter-gather list of 1 element on the stack. +// +typedef __declspec(align(MEMORY_ALLOCATION_ALIGNMENT))UCHAR UCHAR_MEMORY_ALIGNED; + +// begin_wpp enum + +// +// FxDmaTransactionStateCreated when the object is created. +// FxDmaTransactionStateInitialized when object is initialized using with +// Mdl/VA/Length. +// FxDmaTransactionStateReserved when driver calls AllocateResources until +// the adapter control routine returns +// FxDmaTransactionStateTransfer is called when the driver call Execute +// to start the DMA transfer. +// FxDmaTransactionStateTransferCompleted is when transfer is completed or +// aborted +// FxDmaTransactionStateTransferFailed is set if the framework is not able +// to start the transfer due to error. +// FxDmaTransactionStateReleased is set when the object is reinitailized for reuse +// FxDmaTransactionStateDeleted is set in the Dipose due to WdfObjectDelete +// +enum FxDmaTransactionState { + FxDmaTransactionStateInvalid = 0, + FxDmaTransactionStateCreated, + FxDmaTransactionStateReserved, + FxDmaTransactionStateInitialized, + FxDmaTransactionStateTransfer, + FxDmaTransactionStateTransferCompleted, + FxDmaTransactionStateTransferFailed, + FxDmaTransactionStateReleased, + FxDmaTransactionStateDeleted, +}; + +// +// FxDmaCompletionTypeFull is used when the driver calls WdfDmaTransactionDmaComplete +// to indicate that last framgement has been transmitted fully and to initiate +// the transfer of next fragment. +// FxDmaCompletionTypePartial is used when the driver completes the transfer and +// specifies a amount of bytes it has transfered, and to initiate the next transfer +// from the untransmitted portion of the buffer. +// FxDmaCompletionTypeAbort i used when the driver calls DmaCompleteFinal to indicate +// that's the final transfer and not initiate anymore transfers for the remaining +// data. +// +enum FxDmaCompletionType { + FxDmaCompletionTypeFull = 1, + FxDmaCompletionTypePartial, + FxDmaCompletionTypeAbort, +}; + +// end_wpp + +// +// This tag is used to track whether the request pointer in the transaction +// has a reference taken on it. Since the pointer is guaranteed to be +// 4-byte aligned this can be set and cleared without destroying the pointer. +// +#define FX_STRONG_REF_TAG 0x1 + +// +// Simple set of macros to encode and decode tagged pointers. +// +#define FX_ENCODE_POINTER(T,p,tag) ((T*) ((ULONG_PTR) p | (ULONG_PTR) tag)) +#define FX_DECODE_POINTER(T,p,tag) ((T*) ((ULONG_PTR) p & ~(ULONG_PTR) tag)) +#define FX_IS_POINTER_ENCODED(p,tag) ((((ULONG_PTR) p & (ULONG_PTR) tag) == tag) ? TRUE : FALSE) + +// +// An uninitialized value for Dma completion status +// + +#define UNDEFINED_DMA_COMPLETION_STATUS ((DMA_COMPLETION_STATUS) -1) + +class FxDmaTransactionBase : public FxNonPagedObject { + + friend class FxDmaEnabler; + +public: + + FxDmaTransactionBase( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ); + + static + VOID + _ComputeNextTransferAddress( + __in PMDL CurrentMdl, + __in size_t CurrentOffset, + __in ULONG Transferred, + __deref_out PMDL *NextMdl, + __out size_t *NextOffset + ); + + _Must_inspect_result_ + static + NTSTATUS + _CalculateRequiredMapRegisters( + __in PMDL Mdl, + __in size_t CurrentOffset, + __in ULONG Length, + __in ULONG AvailableMapRegisters, + __out_opt PULONG PossibleTransferLength, + __out PULONG MapRegistersRequired + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PFN_WDF_PROGRAM_DMA ProgramDmaFunction, + __in WDF_DMA_DIRECTION DmaDirection, + __in PMDL Mdl, + __in size_t Offset, + __in ULONG Length + ); + + _Must_inspect_result_ + virtual + NTSTATUS + InitializeResources( + VOID + )=0; + + _Must_inspect_result_ + NTSTATUS + Execute( + __in PVOID Context + ); + + _Must_inspect_result_ + virtual + NTSTATUS + StartTransfer( + VOID + )=0; + + _Must_inspect_result_ + virtual + NTSTATUS + StageTransfer( + VOID + )=0; + + BOOLEAN + DmaCompleted( + __in size_t TransferredLength, + __out NTSTATUS * ReturnStatus, + __in FxDmaCompletionType CompletionType + ); + + _Must_inspect_result_ + virtual + NTSTATUS + TransferCompleted( + VOID + )=0; + + VOID + ReleaseForReuse( + __in BOOLEAN ForceRelease + ); + + virtual + VOID + ReleaseResources( + __in BOOLEAN ForceRelease + )=0; + + VOID + GetTransferInfo( + __out_opt ULONG *MapRegisterCount, + __out_opt ULONG *ScatterGatherElementCount + ); + + __forceinline + size_t + GetBytesTransferred( + VOID + ) + { + return m_Transferred; + } + + __forceinline + FxDmaEnabler * + GetDmaEnabler( + VOID + ) + { + return m_DmaEnabler; + } + + __forceinline + FxRequest * + GetRequest( + VOID + ) + { + // + // Strip out the strong reference tag if it's set + // + return FX_DECODE_POINTER(FxRequest, + m_EncodedRequest, + FX_STRONG_REF_TAG); + } + + __forceinline + BOOLEAN + IsRequestReferenced( + VOID + ) + { + return FX_IS_POINTER_ENCODED(m_EncodedRequest, FX_STRONG_REF_TAG); + } + + __forceinline + VOID + SetRequest( + __in FxRequest* Request + ) + { + ASSERT(m_EncodedRequest == NULL); + + // + // Make sure the pointer doesn't have the strong ref flag set already + // + ASSERT(FX_IS_POINTER_ENCODED(Request, FX_STRONG_REF_TAG) == FALSE); + + m_EncodedRequest = Request; + } + + __forceinline + VOID + ReferenceRequest( + VOID + ) + { + ASSERT(m_EncodedRequest != NULL); + ASSERT(IsRequestReferenced() == false); + + // + // Take a reference on the irp to catch completion of request + // when there is a pending DMA transaction. + // While there is no need to take a reference on request itself, + // I'm keeping it to avoid regression as we are so close to + // shipping this. + // + m_EncodedRequest->AddIrpReference(); + + // + // Increment reference to this Request. + // See complementary section in WdfDmaTransactionDelete + // and WdfDmaTransactionRelease. + // + m_EncodedRequest->ADDREF( this ); + + m_EncodedRequest = FX_ENCODE_POINTER(FxRequest, + m_EncodedRequest, + FX_STRONG_REF_TAG); + } + + __forceinline + VOID + ReleaseButRetainRequest( + VOID + ) + { + ASSERT(m_EncodedRequest != NULL); + ASSERT(IsRequestReferenced()); + + // + // Clear the referenced bit on the encoded request. + // + m_EncodedRequest = FX_DECODE_POINTER(FxRequest, + m_EncodedRequest, + FX_STRONG_REF_TAG); + + // + // Release this reference to the Irp and FxRequest. + // + m_EncodedRequest->ReleaseIrpReference(); + + m_EncodedRequest->RELEASE( this ); + } + + __forceinline + VOID + ClearRequest( + VOID + ) + { + if (IsRequestReferenced()) { + ReleaseButRetainRequest(); + } + m_EncodedRequest = NULL; + } + + __forceinline + size_t + GetMaximumFragmentLength( + VOID + ) + { + return m_MaxFragmentLength; + } + + __forceinline + VOID + SetMaximumFragmentLength( + size_t MaximumFragmentLength + ) + { + if (MaximumFragmentLength < m_AdapterInfo->MaximumFragmentLength) { + m_MaxFragmentLength = MaximumFragmentLength; + } + } + + __forceinline + size_t + GetCurrentFragmentLength( + VOID + ) + { + return m_CurrentFragmentLength; + } + + __forceinline + WDFDMATRANSACTION + GetHandle( + VOID + ) + { + return (WDFDMATRANSACTION) GetObjectHandle(); + } + + PVOID + GetTransferContext( + VOID + ) + { + return m_TransferContext; + } + + VOID + SetImmediateExecution( + __in BOOLEAN Value + ); + + BOOLEAN + CancelResourceAllocation( + VOID + ); + + FxDmaTransactionState + GetTransactionState( + VOID + ) + { + return m_State; + } + +protected: + + FxDmaTransactionState m_State; + + WDF_DMA_DIRECTION m_DmaDirection; + + FxDmaEnabler* m_DmaEnabler; + + // + // Depending on the direction of the transfer, this one + // points to either m_ReadAdapterInfo or m_WriteAdapterInfo + // structure of the DMA enabler. + // + FxDmaDescription* m_AdapterInfo; + + // + // Request associated with this transfer. Encoding uses the + // FX_[EN|DE]CODE_POINTER macros with the FX_STRONG_REF_TAG + // to indicate whether the reference has been taken or not + // + FxRequest* m_EncodedRequest; + + // + // Callback and context for ProgramDma function + // + // The callback is overloaded to also hold the callback for + // Packet & System transfer's Reserve callback (to save space.) + // This is possible because the driver may not call execute + // and reserve in parallel on the same transaction. Disambiguate + // using the state of the transaction. + // + FxDmaTransactionProgramOrReserveDma m_DmaAcquiredFunction; + PVOID m_DmaAcquiredContext; + + // + // The DMA transfer context (when using V3 DMA) + // + PVOID m_TransferContext; + + // + // This is the first MDL of the transaction. + // + PMDL m_StartMdl; + + // + // This is the MDL where the current transfer is being executed. + // If the data spans multiple MDL then this would be different + // from the startMDL when we stage large transfers and also + // if the driver performs partial transfers. + // + PMDL m_CurrentFragmentMdl; + + // + // Starting offset in the first m_StartMdl. This might be same as + // m_StartMdl->StartVA. + // + size_t m_StartOffset; + + // + // Points to address where the next transfer will begin. + // + size_t m_CurrentFragmentOffset; + + // + // This is maximum length of transfer that can be made. This is + // computed based on the available map registers and driver + // configuration. + // + size_t m_MaxFragmentLength; + + // + // Length of the whole transaction. + // + size_t m_TransactionLength; + + // + // Number of bytes pending to be transfered. + // + size_t m_Remaining; + + // + // Total number of bytes transfered. + // + size_t m_Transferred; + + // + // Number of bytes transfered in the last transaction. + // + size_t m_CurrentFragmentLength; + + // + // DMA flags for passing to GetScatterGatherListEx & + // AllocateAdapterChannelEx + // + + ULONG m_Flags; + + static + PVOID + GetStartVaFromOffset( + __in PMDL Mdl, + __in size_t Offset + ) + { + return ((PUCHAR) MmGetMdlVirtualAddress(Mdl)) + Offset; + } + + virtual + VOID + Reuse( + VOID + ) + { + return; + } + +}; + +class FxDmaScatterGatherTransaction : public FxDmaTransactionBase { + +public: + + FxDmaScatterGatherTransaction( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + InitializeResources( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + StartTransfer( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + TransferCompleted( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + StageTransfer( + VOID + ); + + virtual + VOID + ReleaseResources( + __in BOOLEAN ForceRelease + ); + + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDmaEnabler* DmaEnabler, + __out WDFDMATRANSACTION* Transaction + ); + +protected: + + // + // Scatter-Gather list provided by the system. + // + PSCATTER_GATHER_LIST m_SGList; + + // + // Preallocated memory from lookaside buffer for the + // scatter-gather list when running on XP and later OSes. + // + PVOID m_LookasideBuffer; + + +private: + + static + VOID + _AdapterListControl( + __in DEVICE_OBJECT * DeviceObject, + __in IRP * Irp, + __in SCATTER_GATHER_LIST * SgList, + __in VOID * Context + ); + + _Must_inspect_result_ + NTSTATUS + GetScatterGatherList ( + __in PMDL Mdl, + __in size_t CurrentOffset, + __in ULONG Length, + __in PDRIVER_LIST_CONTROL ExecutionRoutine, + __in PVOID Context + ) + { + NTSTATUS status; + KIRQL irql; + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + if (m_DmaEnabler->UsesDmaV3()) + { + PDMA_OPERATIONS dmaOperations = + m_AdapterInfo->AdapterObject->DmaOperations; + + status = dmaOperations->GetScatterGatherListEx( + m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + GetTransferContext(), + Mdl, + CurrentOffset, + Length, + m_Flags, + ExecutionRoutine, + Context, + (BOOLEAN) m_DmaDirection, + NULL, + NULL, + NULL + ); + } + else + { + status = m_AdapterInfo->AdapterObject->DmaOperations-> + GetScatterGatherList(m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + Mdl, + GetStartVaFromOffset(Mdl, CurrentOffset), + Length, + ExecutionRoutine, + Context, + (BOOLEAN) m_DmaDirection); + } + + KeLowerIrql(irql); + + return status; + } + + VOID + PutScatterGatherList( + __in PSCATTER_GATHER_LIST ScatterGather + ) + { + KIRQL irql; + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + m_AdapterInfo->AdapterObject->DmaOperations-> + PutScatterGatherList(m_AdapterInfo->AdapterObject, + ScatterGather, + (BOOLEAN) m_DmaDirection); + KeLowerIrql(irql); + + return; + } + + _Must_inspect_result_ + NTSTATUS + BuildScatterGatherList( + __in PMDL Mdl, + __in size_t CurrentOffset, + __in ULONG Length, + __in PDRIVER_LIST_CONTROL ExecutionRoutine, + __in PVOID Context, + __in PVOID ScatterGatherBuffer, + __in ULONG ScatterGatherBufferLength + ) + { + NTSTATUS status; + KIRQL irql; + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + if (m_DmaEnabler->UsesDmaV3()) { + + PDMA_OPERATIONS dmaOperations = + m_AdapterInfo->AdapterObject->DmaOperations; + ULONG flags = 0; + + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,15)) { + // + // Though the correct behavior is to pass the m_Flags to the + // BuildScatterGatherListEx function, the code was not doing it + // for versions <= 1.13. To reduce any chance of regression, + // the m_Flags is honored for drivers that are 1.15 + // or newer. + // + flags = m_Flags; + } + + status = dmaOperations->BuildScatterGatherListEx( + m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + GetTransferContext(), + Mdl, + CurrentOffset, + Length, + flags, + ExecutionRoutine, + Context, + (BOOLEAN) m_DmaDirection, + ScatterGatherBuffer, + ScatterGatherBufferLength, + NULL, + NULL, + NULL + ); + } + else { + + status = m_AdapterInfo->AdapterObject->DmaOperations-> + BuildScatterGatherList(m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + Mdl, + GetStartVaFromOffset(Mdl, CurrentOffset), + Length, + ExecutionRoutine, + Context, + (BOOLEAN) m_DmaDirection, + ScatterGatherBuffer, + ScatterGatherBufferLength); + } + + + KeLowerIrql(irql); + + return status; + } +}; + +class FxDmaPacketTransaction : public FxDmaTransactionBase { + +protected: + FxDmaPacketTransaction( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ); + +public: + + _Must_inspect_result_ + virtual + NTSTATUS + InitializeResources( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + ReserveAdapter( + __in ULONG NumberOfMapRegisters, + __in WDF_DMA_DIRECTION Direction, + __in PFN_WDF_RESERVE_DMA Callback, + __in_opt PVOID Context + ); + + VOID + ReleaseAdapter( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + StartTransfer( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + TransferCompleted( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + StageTransfer( + VOID + ); + + virtual + VOID + ReleaseResources( + __in BOOLEAN ForceRelease + ); + + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDmaEnabler* DmaEnabler, + __out WDFDMATRANSACTION* Transaction + ); + + VOID + SetDeviceAddressOffset( + __in ULONG Offset + ) + { + m_DeviceAddressOffset = Offset; + } + +protected: + + // + // Number of map registers to be used in this transfer. + // This value is the least of the number of map registers + // needed to satisfy the current transfer request, and the + // number of available map registers returned by IoGetDmaAdapter. + // + ULONG m_MapRegistersNeeded; + + // + // Opaque-value represents the map registers that the system has + // assigned for this transfer operation. We pass this value in + // FlushAdapterBuffers, FreeMapRegisters, and MapTransfer. + // + PVOID m_MapRegisterBase; + + // + // TRUE when the map register base above is valid. The HAL can give + // us a NULL map register base when double buffering isn't required, + // so we can't just do a NULL test on m_MapRegisterBase to know if + // the DMA channel is allocated. + // + BOOLEAN m_MapRegisterBaseSet; + + // + // For system-DMA this provides the offset from the original + // DeviceAddress used to compute the device register to or from which + // DMA should occur. + // + ULONG m_DeviceAddressOffset; + + // + // 0 if the transaction has not reserved the enabler. Otherwise + // this is the number of map registers requested for the reservation. + // This value persists across a reuse and reinitialization of the + // transaction, and is only cleared when the enabler is released. + // + ULONG m_MapRegistersReserved; + + // + // These fields are used to defer completion or staging while another + // thread/CPU is already staging. They are protected by the + // transfer state lock. + // + // These values are cleared when checked, not in InitializeResources. + // It's possible for a transaction being staged to complete on another + // CPU, get reused and reinitialized. Clearing these values in + // InitializeResources would destroy the state the prior call to + // StageTransfer depends on. + // + struct { + + // + // Non-null when a staging operation is in progress on some CPU. + // When set any attempt to call the DMA completion routine or + // stage the transfer again (due to a call to TransferComplete) + // will be deferred to this thread. + // + PKTHREAD CurrentStagingThread; + + // + // Indicates that a nested or concurrent attempt to stage + // the transaction was deferred. The CurrentStagingThread + // will restage the transaction. + // + BOOLEAN RerunStaging; + + // + // Indicates that a nested or concurrent attempt to call the + // DMA completion routine occurred. The CurrentStagingThread + // will call the DMA completion routine when it unwinds providing + // the saved CompletionStatus + // + BOOLEAN RerunCompletion; + DMA_COMPLETION_STATUS CompletionStatus; + + } m_TransferState; + + // + // Indicates that the DMA transfer has been cancelled. + // Set during StopTransfer and cleared during InitializeResources + // Checked during StageTransfer. Stop and Initialize should never + // race (it's not valid for the driver to stop an uninitialized + // transaction). Stop and Stage can race but in that case Stop + // will mark the transaction context such that MapTransfer fails + // (and that's protected by a HAL lock). + // + // So this field does not need to be volatile or interlocked, but + // it needs to be sized to allow atomic writes. + // + ULONG m_IsCancelled; + + + virtual + VOID + Reuse( + VOID + ) + { + return; + } + +protected: + + inline + SetMapRegisterBase( + __in PVOID Value + ) + { + NT_ASSERTMSG("Map register base is already set", + m_MapRegisterBaseSet == FALSE); + + m_MapRegisterBase = Value; + m_MapRegisterBaseSet = TRUE; + } + + inline + ClearMapRegisterBase( + VOID + ) + { + NT_ASSERTMSG("Map register base was not set", + m_MapRegisterBaseSet == TRUE); + m_MapRegisterBaseSet = FALSE; + } + + inline + IsMapRegisterBaseSet( + VOID + ) + { + return m_MapRegisterBaseSet; + } + + inline + PVOID + GetMapRegisterBase( + VOID + ) + { + NT_ASSERTMSG("Map register base is not set", + m_MapRegisterBaseSet == TRUE); + return m_MapRegisterBase; + } + + virtual + IO_ALLOCATION_ACTION + GetAdapterControlReturnValue( + VOID + ) + { + return DeallocateObjectKeepRegisters; + } + + virtual + BOOLEAN + PreMapTransfer( + VOID + ) + { + return TRUE; + } + + _Acquires_lock_(this) + VOID + __drv_raisesIRQL(DISPATCH_LEVEL) +#pragma prefast(suppress:__WARNING_FAILING_TO_ACQUIRE_MEDIUM_CONFIDENCE, "transferring lock name to 'this->TransferStateLock'") +#pragma prefast(suppress:__WARNING_FAILING_TO_RELEASE_MEDIUM_CONFIDENCE, "transferring lock name to 'this->TransferStateLock'") + LockTransferState( + __out __drv_deref(__drv_savesIRQL) KIRQL *OldIrql + ) + { + Lock(OldIrql); + } + + _Requires_lock_held_(this) + _Releases_lock_(this) + VOID +#pragma prefast(suppress:__WARNING_FAILING_TO_RELEASE_MEDIUM_CONFIDENCE, "transferring lock name from 'this->TransferStateLock'") + UnlockTransferState( + __in __drv_restoresIRQL KIRQL OldIrql + ) + { +#pragma prefast(suppress:__WARNING_CALLER_FAILING_TO_HOLD, "transferring lock name from 'this->TransferStateLock'") + Unlock(OldIrql); + } + + virtual + PDMA_COMPLETION_ROUTINE + GetTransferCompletionRoutine( + VOID + ) + { + return NULL; + } + + static + IO_ALLOCATION_ACTION + _AdapterControl( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp, + __in PVOID MapRegisterBase, + __in PVOID Context + ); + + _Must_inspect_result_ + NTSTATUS + AcquireDevice( + VOID + ) + { + if (m_DmaEnabler->UsesDmaV3() == FALSE) + { + return m_DmaEnabler->GetDevice()->AcquireDmaPacketTransaction(); + } + else + { + return STATUS_SUCCESS; + } + } + + FORCEINLINE + VOID + ReleaseDevice( + VOID + ) + { + if (m_DmaEnabler->UsesDmaV3() == FALSE) + { + m_DmaEnabler->GetDevice()->ReleaseDmaPacketTransaction(); + } + } + + _Must_inspect_result_ + NTSTATUS + AllocateAdapterChannel( + __in BOOLEAN MapRegistersReserved + ) + { + NTSTATUS status; + KIRQL irql; + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + if (GetDriverGlobals()->FxVerifierOn) { + + if (MapRegistersReserved == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Allocating %d map registers for " + "WDFDMATRANSACTION %p", + m_MapRegistersNeeded, + GetHandle() + ); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Using %d reserved map registers for " + "WDFDMATRANSACTION %p", + m_MapRegistersNeeded, + GetHandle() + ); + } + } + + if (m_DmaEnabler->UsesDmaV3()) { + PDMA_OPERATIONS dmaOperations = + m_AdapterInfo->AdapterObject->DmaOperations; + + if (MapRegistersReserved == FALSE) + { + status = dmaOperations->AllocateAdapterChannelEx( + m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + GetTransferContext(), + m_MapRegistersNeeded, + m_Flags, +#pragma prefast(suppress: __WARNING_CLASS_MISMATCH_NONE, "This warning requires a wrapper class for the DRIVER_CONTROL type.") + _AdapterControl, + this, + NULL + ); + } + else { +#pragma prefast(suppress:__WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "_AdapterControl does not actually use the IRP parameter."); + _AdapterControl(m_DmaEnabler->m_FDO, + NULL, + GetMapRegisterBase(), + this); + status = STATUS_SUCCESS; + } + } + else { + + ASSERTMSG("Prereserved map registers are not compatible with DMA V2", + MapRegistersReserved == FALSE); + + status = m_AdapterInfo->AdapterObject->DmaOperations-> + AllocateAdapterChannel(m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + m_MapRegistersNeeded, +#pragma prefast(suppress: __WARNING_CLASS_MISMATCH_NONE, "This warning requires a wrapper class for the DRIVER_CONTROL type.") + _AdapterControl, + this); + } + + KeLowerIrql(irql); + + if (!NT_SUCCESS(status)) + { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "Allocating DMA resources (%d map registers) for WDFDMATRANSACTION %p " + "returned %!STATUS!", + m_MapRegistersNeeded, + GetHandle(), + status + ); + } + + return status; + } + + FORCEINLINE + NTSTATUS + MapTransfer( + __out_bcount_opt(ScatterGatherListCb) + PSCATTER_GATHER_LIST ScatterGatherList, + __in ULONG ScatterGatherListCb, + __in_opt PDMA_COMPLETION_ROUTINE CompletionRoutine, + __in_opt PVOID CompletionContext, + __out ULONG *TransferLength + ) + { + // + // Cache globals & object handle since call to MapTransferEx could + // result in a DmaComplete callback before returning. + // + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMATRANSACTION handle = GetHandle(); +#if DBG + ULONG_PTR mapRegistersRequired; + + mapRegistersRequired = ADDRESS_AND_SIZE_TO_SPAN_PAGES( + GetStartVaFromOffset(m_CurrentFragmentMdl, + m_CurrentFragmentOffset), + m_CurrentFragmentLength + ); + NT_ASSERTMSG("Mapping requires too many map registers", + mapRegistersRequired <= m_MapRegistersNeeded); +#endif + + NTSTATUS status; + + // + // Assume we're going to transfer the entire current fragment. + // MapTransfer may say otherwise. + // + + *TransferLength = (ULONG) m_CurrentFragmentLength; + + // + // Map the transfer. + // + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Mapping transfer for WDFDMATRANSACTION %p. " + "MDL %p, Offset %I64x, Length %x, MapRegisterBase %p", + handle, + m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + *TransferLength, + GetMapRegisterBase()); + } + + if (m_DmaEnabler->UsesDmaV3()) { + + PDMA_OPERATIONS dmaOperations = + m_AdapterInfo->AdapterObject->DmaOperations; + + status = dmaOperations->MapTransferEx( + m_AdapterInfo->AdapterObject, + m_CurrentFragmentMdl, + GetMapRegisterBase(), + m_CurrentFragmentOffset, + m_DeviceAddressOffset, + TransferLength, + (BOOLEAN) m_DmaDirection, + ScatterGatherList, + ScatterGatherListCb, + CompletionRoutine, + CompletionContext + ); + + NT_ASSERTMSG( + "With these parameters, MapTransferEx should never fail", + NT_SUCCESS(status) || status == STATUS_CANCELLED + ); + } + else { + NT_ASSERTMSG("cannot use DMA completion routine with DMAv2", + CompletionRoutine == NULL); + + NT_ASSERTMSG( + "scatter gather list length must be large enough for at least one element", + (ScatterGatherListCb >= (sizeof(SCATTER_GATHER_LIST) + + sizeof(SCATTER_GATHER_ELEMENT))) + ); + + // + // This matches the assertion above. There's no way to explain to + // prefast that this code path requires the caller to provide a buffer + // of sufficient size to store the SGL. The only case which doesn't + // provide any buffer is system-mode DMA and that uses DMA v3 and so + // won't go through this path. + // + + __assume((ScatterGatherListCb >= (sizeof(SCATTER_GATHER_LIST) + + sizeof(SCATTER_GATHER_ELEMENT)))); + + ScatterGatherList->NumberOfElements = 1; + ScatterGatherList->Reserved = 0; + ScatterGatherList->Elements[0].Address = + m_AdapterInfo->AdapterObject->DmaOperations-> + MapTransfer(m_AdapterInfo->AdapterObject, + m_CurrentFragmentMdl, + GetMapRegisterBase(), + GetStartVaFromOffset(m_CurrentFragmentMdl, + m_CurrentFragmentOffset), + TransferLength, + (BOOLEAN) m_DmaDirection); + ScatterGatherList->Elements[0].Length = *TransferLength; + + status = STATUS_SUCCESS; + } + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "MapTransfer mapped next %d bytes of " + "WDFDMATRANSACTION %p - status %!STATUS!", + *TransferLength, + handle, + status); + } + + return status; + } + + FORCEINLINE + NTSTATUS + FlushAdapterBuffers( + VOID + ) + { + PDMA_OPERATIONS dmaOperations = + m_AdapterInfo->AdapterObject->DmaOperations; + + NTSTATUS status; + +#if DBG + ULONG_PTR mapRegistersRequired; + + mapRegistersRequired = ADDRESS_AND_SIZE_TO_SPAN_PAGES( + GetStartVaFromOffset(m_CurrentFragmentMdl, + m_CurrentFragmentOffset), + m_CurrentFragmentLength + ); + NT_ASSERTMSG("Mapping requires too many map registers", + mapRegistersRequired <= m_MapRegistersNeeded); +#endif + + if (GetDriverGlobals()->FxVerifierOn) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Flushing DMA buffers for WDFDMATRANSACTION %p. " + "MDL %p, Offset %I64x, Length %I64x", + GetHandle(), + m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + m_CurrentFragmentLength); + } + + if (m_DmaEnabler->UsesDmaV3()) { + status = dmaOperations->FlushAdapterBuffersEx( + m_AdapterInfo->AdapterObject, + m_CurrentFragmentMdl, + GetMapRegisterBase(), + m_CurrentFragmentOffset, + (ULONG) m_CurrentFragmentLength, + (BOOLEAN) m_DmaDirection + ); + } + else if (dmaOperations->FlushAdapterBuffers( + m_AdapterInfo->AdapterObject, + m_CurrentFragmentMdl, + GetMapRegisterBase(), + GetStartVaFromOffset(m_CurrentFragmentMdl, + m_CurrentFragmentOffset), + (ULONG) m_CurrentFragmentLength, + (BOOLEAN) m_DmaDirection) == FALSE) { + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "Flushing DMA buffers for WDFDMATRANSACTION %p (" + "MDL %p, Offset %I64x, Length %I64x)" + "completed with %!STATUS!", + GetHandle(), + m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + m_CurrentFragmentLength, + status); + } + + return status; + } + + virtual + VOID + FreeMapRegistersAndAdapter( + VOID + ) + { + KIRQL irql; + + PVOID mapRegisterBase = GetMapRegisterBase(); + + // + // It's illegal to free a NULL map register base, even if the HAL gave it + // to us. + // + if (mapRegisterBase == NULL) { + if (GetDriverGlobals()->FxVerifierOn) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Skipping free of %d map registers for WDFDMATRANSACTION %p " + "because base was NULL", + m_MapRegistersNeeded, + GetHandle()); + } + + return; + } + + // + // Free the map registers + // + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + if (GetDriverGlobals()->FxVerifierOn) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Freeing %d map registers for WDFDMATRANSACTION %p " + "(base %p)", + m_MapRegistersNeeded, + GetHandle(), + mapRegisterBase); + } + + // + // If we pre-reserved map registers then Reserved contains + // the number to free. Otherwise Needed is the number allocated + // for the last transaction, which is the number to free. + // + m_AdapterInfo->AdapterObject->DmaOperations-> + FreeMapRegisters(m_AdapterInfo->AdapterObject, + mapRegisterBase, + (m_MapRegistersReserved > 0 ? + m_MapRegistersReserved : + m_MapRegistersNeeded)); + KeLowerIrql(irql); + + return; + } + + virtual + VOID + CallEvtDmaCompleted( + __in DMA_COMPLETION_STATUS /* Status */ + ) + { + // + // Packet mode DMA doesn't support cancellation or + // completion routines. So this should never run. + // + ASSERTMSG("EvtDmaCompleted is not a valid callback for " + "a packet-mode transaction", + FALSE); + return; + } + +}; + +class FxDmaSystemTransaction: public FxDmaPacketTransaction { + + friend FxDmaPacketTransaction; + +public: + + FxDmaSystemTransaction( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ); + + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDmaEnabler* DmaEnabler, + __out WDFDMATRANSACTION* Transaction + ); + + VOID + SetConfigureChannelCallback( + __in_opt PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL Callback, + __in_opt PVOID Context + ) + { + m_ConfigureChannelFunction.Method = Callback; + m_ConfigureChannelContext = Context; + } + + VOID + SetTransferCompleteCallback( + __in_opt PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Callback, + __in_opt PVOID Context + ) + { + m_TransferCompleteFunction.Method = Callback; + m_TransferCompleteContext = Context; + } + + VOID + StopTransfer( + VOID + ); + +protected: + + // + // Callback and context for configure channel callback + // + FxDmaTransactionConfigureChannel m_ConfigureChannelFunction; + PVOID m_ConfigureChannelContext; + + // + // Callback and context for DMA completion callback + // + FxDmaTransactionTransferComplete m_TransferCompleteFunction; + PVOID m_TransferCompleteContext; + + IO_ALLOCATION_ACTION + GetAdapterControlReturnValue( + VOID + ) + { + return KeepObject; + } + + VOID + FreeMapRegistersAndAdapter( + VOID + ) + { + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + + KeRaiseIrql(DISPATCH_LEVEL, &irql); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Freeing adapter channel for WDFDMATRANSACTION %p", + GetHandle()); + } + + m_AdapterInfo->AdapterObject->DmaOperations-> + FreeAdapterChannel(m_AdapterInfo->AdapterObject); + KeLowerIrql(irql); + + return; + } + + BOOLEAN + CancelMappedTransfer( + VOID + ) + { + NTSTATUS status; + + ASSERT(m_DmaEnabler->UsesDmaV3()); + + // + // Cancel the transfer. if it's not yet mapped this will mark the + // TC so that mapping will fail. If it's running this will invoke the + // DMA completion routine. + // + status = + m_AdapterInfo->AdapterObject->DmaOperations->CancelMappedTransfer( + m_AdapterInfo->AdapterObject, + GetTransferContext() + ); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Stopping WDFDMATRANSACTION %p returned status %!STATUS!", + GetHandle(), + status); + + return NT_SUCCESS(status); + } + + VOID + Reuse( + VOID + ) + { + __super::Reuse(); + m_ConfigureChannelFunction.Method = NULL; + m_ConfigureChannelContext = NULL; + + m_TransferCompleteFunction.Method = NULL; + m_TransferCompleteContext = NULL; + } + + VOID + CallEvtDmaCompleted( + __in DMA_COMPLETION_STATUS Status + ); + + virtual + BOOLEAN + PreMapTransfer( + VOID + ); + + virtual + PDMA_COMPLETION_ROUTINE + GetTransferCompletionRoutine( + VOID + ); + + static DMA_COMPLETION_ROUTINE _SystemDmaCompletion; +}; + +#endif // _FXDMATRANSACTION_HPP_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxdmatransactioncallbacks.hpp b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdmatransactioncallbacks.hpp new file mode 100644 index 00000000000..189528c3d3d --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdmatransactioncallbacks.hpp @@ -0,0 +1,168 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaTransactionCallbacks.h + +Abstract: + + This module implements the FxDmaTransaction object callbacks + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXDMATRANSACTIONCALLBACKS_H +#define _FXDMATRANSACTIONCALLBACKS_H + +// +// FxDmaTransactionProgramDma or FxDmaTransactionReserveDma callback delegate +// These are mutually exclusive callbacks and are packed together in +// the callback structure (C++ won't allow two classes with constructors +// to be together in a union, so the containing class can't do the +// packing) +// +class FxDmaTransactionProgramOrReserveDma : public FxCallback { + +public: + union { + PFN_WDF_PROGRAM_DMA ProgramDma; + PFN_WDF_RESERVE_DMA ReserveDma; + } Method; + + FxDmaTransactionProgramOrReserveDma( + VOID + ) : + FxCallback() + { + Method.ProgramDma = NULL; + } + + BOOLEAN + InvokeProgramDma( + __in WDFDMATRANSACTION Transaction, + __in WDFDEVICE Device, + __in PVOID Context, + __in WDF_DMA_DIRECTION Direction, + __in PSCATTER_GATHER_LIST SgList + ) + { + if (Method.ProgramDma) { + BOOLEAN cc; + + CallbackStart(); + cc = Method.ProgramDma( Transaction, + Device, + Context, + Direction, + SgList ); + CallbackEnd(); + + return cc; + } + else { + return FALSE; + } + } + + VOID + InvokeReserveDma( + __in WDFDMATRANSACTION Transaction, + __in PVOID Context + ) + { + if (Method.ReserveDma) { + CallbackStart(); + Method.ReserveDma( Transaction, Context ); + CallbackEnd(); + } + } + + VOID + Clear( + VOID + ) + { + Method.ProgramDma = NULL; + } +}; + +// +// FxDmaTransactionConfigureChannel callback delegate +// + +class FxDmaTransactionConfigureChannel : public FxCallback { + +public: + PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL Method; + + FxDmaTransactionConfigureChannel( + VOID + ) : + FxCallback() + { + Method = NULL; + } + + _Must_inspect_result_ + BOOLEAN + Invoke( + __in WDFDMATRANSACTION DmaTransaction, + __in WDFDEVICE Device, + __in PVOID Context, + __in_opt PMDL Mdl, + __in size_t Offset, + __in size_t Length + ) + { + BOOLEAN b = TRUE; + if (Method) { + CallbackStart(); + b = Method( DmaTransaction, Device, Context, Mdl, Offset, Length ); + CallbackEnd(); + } + return b; + } +}; + +// +// FxDmaTransactionTransferComplete callback delegate +// + +class FxDmaTransactionTransferComplete : public FxCallback { + +public: + PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE Method; + + FxDmaTransactionTransferComplete( + VOID + ) : + FxCallback() + { + Method = NULL; + } + + VOID + Invoke( + __in WDFDMATRANSACTION Transaction, + __in WDFDEVICE Device, + __in WDFCONTEXT Context, + __in WDF_DMA_DIRECTION Direction, + __in DMA_COMPLETION_STATUS Status + ) + { + if (Method) { + CallbackStart(); + Method( Transaction, Device, Context, Direction, Status ); + CallbackEnd(); + } + } +}; + +#endif // _FXDMATRANSACTIONCALLBACKS_H diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxdpc.hpp b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdpc.hpp new file mode 100644 index 00000000000..97933d35447 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdpc.hpp @@ -0,0 +1,201 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDpc.hpp + +Abstract: + + This module implements a frameworks managed DPC that + can synchrononize with driver frameworks object locks. + +Author: + + + +Environment: + + kernel mode only + +Revision History: + + +--*/ + +#ifndef _FXDPC_H_ +#define _FXDPC_H_ + +// +// Driver Frameworks DPC Design: +// +// The driver frameworks provides an optional DPC wrapper object that allows +// the creation of a reference counted DPC object that can synchronize +// automatically with certain frameworks objects. +// +// This provides automatic synchronization between the DPC's execution, and the +// frameworks objects' event callbacks into the device driver. +// +// The WDFDPC object is designed to be re-useable, in which it can be re-linked +// into the DPC queue after firing. +// +// In many cases, the KDPC struct is embedded inside another structure that +// represents a device command block. These device command blocks are typically +// submitted to another device driver. So the calling driver, which is utilizing +// the driver frameworks would not likely have an opportunity to make +// changes to this. In order to support this, the caller can optionally supply +// a DPC object pointer to Initialize, and the WDFDPC object will use this +// embedded user supplied DPC object, and pass its address as the RawDpc +// parameter to the callback function. +// +// If the user does not supply a DPC pointer by passing NULL, then the +// internal DPC object is used, and RawDPC is NULL. +// +// Calling GetDpcPtr returns the DPC to be used, and could be +// the caller supplied DPC, or the embedded one depending on +// whether the caller supplied a user DPC pointer to Initialize. +// +// The GetDpcPtr allows linking of the WDFDPC object into various DPC +// lists by the driver. +// + +class FxDpc : public FxNonPagedObject { + +private: + + KDPC m_Dpc; + + // + // This is the Framework object who is associated with the DPC + // if supplied + // + FxObject* m_Object; + + // + // This is the callback lock for the object this DPC will + // synchronize with + // + FxCallbackLock* m_CallbackLock; + + // + // This is the object whose reference count actually controls + // the lifetime of the m_CallbackLock + // + FxObject* m_CallbackLockObject; + + // + // This is the user supplied callback function + // + PFN_WDF_DPC m_Callback; + + // Ensures only one of either Delete or Cleanup runs down the object + BOOLEAN m_RunningDown; + +public: + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_DPC_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObject* ParentObject, + __out WDFDPC* Dpc + ); + + FxDpc( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + ~FxDpc( + VOID + ); + + KDPC* + GetDpcPtr( + VOID + ) + { + return &m_Dpc; + } + + WDFOBJECT + GetObject( + VOID + ) + { + if (m_Object != NULL) { + return m_Object->GetObjectHandle(); + } + else { + return NULL; + } + } + +/*++ + +Routine Description: + + Initialize the DPC using either the caller supplied DPC + struct, or if NULL, our own internal one. + +Arguments: + +Returns: + + NTSTATUS + +--*/ + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_DPC_CONFIG Config, + __in FxObject* ParentObject, + __out WDFDPC* Dpc + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + BOOLEAN + Cancel( + __in BOOLEAN Wait + ); + + VOID + DpcHandler( + __in PKDPC Dpc, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ); + +private: + + // + // Called from Dispose, or cleanup list to perform final flushing of any + // outstanding DPC's and dereferencing of objects. + // + VOID + FlushAndRundown( + ); + + static + KDEFERRED_ROUTINE + FxDpcThunk; + + static + VOID + WorkItemThunk( + PDEVICE_OBJECT DeviceObject, + PVOID Context + ); +}; + +#endif // _FXDPC_H_ + diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxdynamics.h b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdynamics.h new file mode 100644 index 00000000000..35a3564dab3 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdynamics.h @@ -0,0 +1,6943 @@ +/*++ + +Module Name: FxDynamics.h + +Abstract: + Generated header for WDF APIs + +Environment: + kernel mode only + + Warning: manual changes to this file will be lost. +--*/ + +#ifndef _FXDYNAMICS_H_ +#define _FXDYNAMICS_H_ + + +typedef struct _WDFFUNCTIONS { + + PFN_WDFCHILDLISTCREATE pfnWdfChildListCreate; + PFN_WDFCHILDLISTGETDEVICE pfnWdfChildListGetDevice; + PFN_WDFCHILDLISTRETRIEVEPDO pfnWdfChildListRetrievePdo; + PFN_WDFCHILDLISTRETRIEVEADDRESSDESCRIPTION pfnWdfChildListRetrieveAddressDescription; + PFN_WDFCHILDLISTBEGINSCAN pfnWdfChildListBeginScan; + PFN_WDFCHILDLISTENDSCAN pfnWdfChildListEndScan; + PFN_WDFCHILDLISTBEGINITERATION pfnWdfChildListBeginIteration; + PFN_WDFCHILDLISTRETRIEVENEXTDEVICE pfnWdfChildListRetrieveNextDevice; + PFN_WDFCHILDLISTENDITERATION pfnWdfChildListEndIteration; + PFN_WDFCHILDLISTADDORUPDATECHILDDESCRIPTIONASPRESENT pfnWdfChildListAddOrUpdateChildDescriptionAsPresent; + PFN_WDFCHILDLISTUPDATECHILDDESCRIPTIONASMISSING pfnWdfChildListUpdateChildDescriptionAsMissing; + PFN_WDFCHILDLISTUPDATEALLCHILDDESCRIPTIONSASPRESENT pfnWdfChildListUpdateAllChildDescriptionsAsPresent; + PFN_WDFCHILDLISTREQUESTCHILDEJECT pfnWdfChildListRequestChildEject; + PFN_WDFCOLLECTIONCREATE pfnWdfCollectionCreate; + PFN_WDFCOLLECTIONGETCOUNT pfnWdfCollectionGetCount; + PFN_WDFCOLLECTIONADD pfnWdfCollectionAdd; + PFN_WDFCOLLECTIONREMOVE pfnWdfCollectionRemove; + PFN_WDFCOLLECTIONREMOVEITEM pfnWdfCollectionRemoveItem; + PFN_WDFCOLLECTIONGETITEM pfnWdfCollectionGetItem; + PFN_WDFCOLLECTIONGETFIRSTITEM pfnWdfCollectionGetFirstItem; + PFN_WDFCOLLECTIONGETLASTITEM pfnWdfCollectionGetLastItem; + PFN_WDFCOMMONBUFFERCREATE pfnWdfCommonBufferCreate; + PFN_WDFCOMMONBUFFERGETALIGNEDVIRTUALADDRESS pfnWdfCommonBufferGetAlignedVirtualAddress; + PFN_WDFCOMMONBUFFERGETALIGNEDLOGICALADDRESS pfnWdfCommonBufferGetAlignedLogicalAddress; + PFN_WDFCOMMONBUFFERGETLENGTH pfnWdfCommonBufferGetLength; + PFN_WDFCONTROLDEVICEINITALLOCATE pfnWdfControlDeviceInitAllocate; + PFN_WDFCONTROLDEVICEINITSETSHUTDOWNNOTIFICATION pfnWdfControlDeviceInitSetShutdownNotification; + PFN_WDFCONTROLFINISHINITIALIZING pfnWdfControlFinishInitializing; + PFN_WDFDEVICEGETDEVICESTATE pfnWdfDeviceGetDeviceState; + PFN_WDFDEVICESETDEVICESTATE pfnWdfDeviceSetDeviceState; + PFN_WDFWDMDEVICEGETWDFDEVICEHANDLE pfnWdfWdmDeviceGetWdfDeviceHandle; + PFN_WDFDEVICEWDMGETDEVICEOBJECT pfnWdfDeviceWdmGetDeviceObject; + PFN_WDFDEVICEWDMGETATTACHEDDEVICE pfnWdfDeviceWdmGetAttachedDevice; + PFN_WDFDEVICEWDMGETPHYSICALDEVICE pfnWdfDeviceWdmGetPhysicalDevice; + PFN_WDFDEVICEWDMDISPATCHPREPROCESSEDIRP pfnWdfDeviceWdmDispatchPreprocessedIrp; + PFN_WDFDEVICEADDDEPENDENTUSAGEDEVICEOBJECT pfnWdfDeviceAddDependentUsageDeviceObject; + PFN_WDFDEVICEADDREMOVALRELATIONSPHYSICALDEVICE pfnWdfDeviceAddRemovalRelationsPhysicalDevice; + PFN_WDFDEVICEREMOVEREMOVALRELATIONSPHYSICALDEVICE pfnWdfDeviceRemoveRemovalRelationsPhysicalDevice; + PFN_WDFDEVICECLEARREMOVALRELATIONSDEVICES pfnWdfDeviceClearRemovalRelationsDevices; + PFN_WDFDEVICEGETDRIVER pfnWdfDeviceGetDriver; + PFN_WDFDEVICERETRIEVEDEVICENAME pfnWdfDeviceRetrieveDeviceName; + PFN_WDFDEVICEASSIGNMOFRESOURCENAME pfnWdfDeviceAssignMofResourceName; + PFN_WDFDEVICEGETIOTARGET pfnWdfDeviceGetIoTarget; + PFN_WDFDEVICEGETDEVICEPNPSTATE pfnWdfDeviceGetDevicePnpState; + PFN_WDFDEVICEGETDEVICEPOWERSTATE pfnWdfDeviceGetDevicePowerState; + PFN_WDFDEVICEGETDEVICEPOWERPOLICYSTATE pfnWdfDeviceGetDevicePowerPolicyState; + PFN_WDFDEVICEASSIGNS0IDLESETTINGS pfnWdfDeviceAssignS0IdleSettings; + PFN_WDFDEVICEASSIGNSXWAKESETTINGS pfnWdfDeviceAssignSxWakeSettings; + PFN_WDFDEVICEOPENREGISTRYKEY pfnWdfDeviceOpenRegistryKey; + PFN_WDFDEVICESETSPECIALFILESUPPORT pfnWdfDeviceSetSpecialFileSupport; + PFN_WDFDEVICESETCHARACTERISTICS pfnWdfDeviceSetCharacteristics; + PFN_WDFDEVICEGETCHARACTERISTICS pfnWdfDeviceGetCharacteristics; + PFN_WDFDEVICEGETALIGNMENTREQUIREMENT pfnWdfDeviceGetAlignmentRequirement; + PFN_WDFDEVICESETALIGNMENTREQUIREMENT pfnWdfDeviceSetAlignmentRequirement; + PFN_WDFDEVICEINITFREE pfnWdfDeviceInitFree; + PFN_WDFDEVICEINITSETPNPPOWEREVENTCALLBACKS pfnWdfDeviceInitSetPnpPowerEventCallbacks; + PFN_WDFDEVICEINITSETPOWERPOLICYEVENTCALLBACKS pfnWdfDeviceInitSetPowerPolicyEventCallbacks; + PFN_WDFDEVICEINITSETPOWERPOLICYOWNERSHIP pfnWdfDeviceInitSetPowerPolicyOwnership; + PFN_WDFDEVICEINITREGISTERPNPSTATECHANGECALLBACK pfnWdfDeviceInitRegisterPnpStateChangeCallback; + PFN_WDFDEVICEINITREGISTERPOWERSTATECHANGECALLBACK pfnWdfDeviceInitRegisterPowerStateChangeCallback; + PFN_WDFDEVICEINITREGISTERPOWERPOLICYSTATECHANGECALLBACK pfnWdfDeviceInitRegisterPowerPolicyStateChangeCallback; + PFN_WDFDEVICEINITSETIOTYPE pfnWdfDeviceInitSetIoType; + PFN_WDFDEVICEINITSETEXCLUSIVE pfnWdfDeviceInitSetExclusive; + PFN_WDFDEVICEINITSETPOWERNOTPAGEABLE pfnWdfDeviceInitSetPowerNotPageable; + PFN_WDFDEVICEINITSETPOWERPAGEABLE pfnWdfDeviceInitSetPowerPageable; + PFN_WDFDEVICEINITSETPOWERINRUSH pfnWdfDeviceInitSetPowerInrush; + PFN_WDFDEVICEINITSETDEVICETYPE pfnWdfDeviceInitSetDeviceType; + PFN_WDFDEVICEINITASSIGNNAME pfnWdfDeviceInitAssignName; + PFN_WDFDEVICEINITASSIGNSDDLSTRING pfnWdfDeviceInitAssignSDDLString; + PFN_WDFDEVICEINITSETDEVICECLASS pfnWdfDeviceInitSetDeviceClass; + PFN_WDFDEVICEINITSETCHARACTERISTICS pfnWdfDeviceInitSetCharacteristics; + PFN_WDFDEVICEINITSETFILEOBJECTCONFIG pfnWdfDeviceInitSetFileObjectConfig; + PFN_WDFDEVICEINITSETREQUESTATTRIBUTES pfnWdfDeviceInitSetRequestAttributes; + PFN_WDFDEVICEINITASSIGNWDMIRPPREPROCESSCALLBACK pfnWdfDeviceInitAssignWdmIrpPreprocessCallback; + PFN_WDFDEVICEINITSETIOINCALLERCONTEXTCALLBACK pfnWdfDeviceInitSetIoInCallerContextCallback; + PFN_WDFDEVICECREATE pfnWdfDeviceCreate; + PFN_WDFDEVICESETSTATICSTOPREMOVE pfnWdfDeviceSetStaticStopRemove; + PFN_WDFDEVICECREATEDEVICEINTERFACE pfnWdfDeviceCreateDeviceInterface; + PFN_WDFDEVICESETDEVICEINTERFACESTATE pfnWdfDeviceSetDeviceInterfaceState; + PFN_WDFDEVICERETRIEVEDEVICEINTERFACESTRING pfnWdfDeviceRetrieveDeviceInterfaceString; + PFN_WDFDEVICECREATESYMBOLICLINK pfnWdfDeviceCreateSymbolicLink; + PFN_WDFDEVICEQUERYPROPERTY pfnWdfDeviceQueryProperty; + PFN_WDFDEVICEALLOCANDQUERYPROPERTY pfnWdfDeviceAllocAndQueryProperty; + PFN_WDFDEVICESETPNPCAPABILITIES pfnWdfDeviceSetPnpCapabilities; + PFN_WDFDEVICESETPOWERCAPABILITIES pfnWdfDeviceSetPowerCapabilities; + PFN_WDFDEVICESETBUSINFORMATIONFORCHILDREN pfnWdfDeviceSetBusInformationForChildren; + PFN_WDFDEVICEINDICATEWAKESTATUS pfnWdfDeviceIndicateWakeStatus; + PFN_WDFDEVICESETFAILED pfnWdfDeviceSetFailed; + PFN_WDFDEVICESTOPIDLENOTRACK pfnWdfDeviceStopIdleNoTrack; + PFN_WDFDEVICERESUMEIDLENOTRACK pfnWdfDeviceResumeIdleNoTrack; + PFN_WDFDEVICEGETFILEOBJECT pfnWdfDeviceGetFileObject; + PFN_WDFDEVICEENQUEUEREQUEST pfnWdfDeviceEnqueueRequest; + PFN_WDFDEVICEGETDEFAULTQUEUE pfnWdfDeviceGetDefaultQueue; + PFN_WDFDEVICECONFIGUREREQUESTDISPATCHING pfnWdfDeviceConfigureRequestDispatching; + PFN_WDFDMAENABLERCREATE pfnWdfDmaEnablerCreate; + PFN_WDFDMAENABLERGETMAXIMUMLENGTH pfnWdfDmaEnablerGetMaximumLength; + PFN_WDFDMAENABLERGETMAXIMUMSCATTERGATHERELEMENTS pfnWdfDmaEnablerGetMaximumScatterGatherElements; + PFN_WDFDMAENABLERSETMAXIMUMSCATTERGATHERELEMENTS pfnWdfDmaEnablerSetMaximumScatterGatherElements; + PFN_WDFDMATRANSACTIONCREATE pfnWdfDmaTransactionCreate; + PFN_WDFDMATRANSACTIONINITIALIZE pfnWdfDmaTransactionInitialize; + PFN_WDFDMATRANSACTIONINITIALIZEUSINGREQUEST pfnWdfDmaTransactionInitializeUsingRequest; + PFN_WDFDMATRANSACTIONEXECUTE pfnWdfDmaTransactionExecute; + PFN_WDFDMATRANSACTIONRELEASE pfnWdfDmaTransactionRelease; + PFN_WDFDMATRANSACTIONDMACOMPLETED pfnWdfDmaTransactionDmaCompleted; + PFN_WDFDMATRANSACTIONDMACOMPLETEDWITHLENGTH pfnWdfDmaTransactionDmaCompletedWithLength; + PFN_WDFDMATRANSACTIONDMACOMPLETEDFINAL pfnWdfDmaTransactionDmaCompletedFinal; + PFN_WDFDMATRANSACTIONGETBYTESTRANSFERRED pfnWdfDmaTransactionGetBytesTransferred; + PFN_WDFDMATRANSACTIONSETMAXIMUMLENGTH pfnWdfDmaTransactionSetMaximumLength; + PFN_WDFDMATRANSACTIONGETREQUEST pfnWdfDmaTransactionGetRequest; + PFN_WDFDMATRANSACTIONGETCURRENTDMATRANSFERLENGTH pfnWdfDmaTransactionGetCurrentDmaTransferLength; + PFN_WDFDMATRANSACTIONGETDEVICE pfnWdfDmaTransactionGetDevice; + PFN_WDFDPCCREATE pfnWdfDpcCreate; + PFN_WDFDPCENQUEUE pfnWdfDpcEnqueue; + PFN_WDFDPCCANCEL pfnWdfDpcCancel; + PFN_WDFDPCGETPARENTOBJECT pfnWdfDpcGetParentObject; + PFN_WDFDPCWDMGETDPC pfnWdfDpcWdmGetDpc; + PFN_WDFDRIVERCREATE pfnWdfDriverCreate; + PFN_WDFDRIVERGETREGISTRYPATH pfnWdfDriverGetRegistryPath; + PFN_WDFDRIVERWDMGETDRIVEROBJECT pfnWdfDriverWdmGetDriverObject; + PFN_WDFDRIVEROPENPARAMETERSREGISTRYKEY pfnWdfDriverOpenParametersRegistryKey; + PFN_WDFWDMDRIVERGETWDFDRIVERHANDLE pfnWdfWdmDriverGetWdfDriverHandle; + PFN_WDFDRIVERREGISTERTRACEINFO pfnWdfDriverRegisterTraceInfo; + PFN_WDFDRIVERRETRIEVEVERSIONSTRING pfnWdfDriverRetrieveVersionString; + PFN_WDFDRIVERISVERSIONAVAILABLE pfnWdfDriverIsVersionAvailable; + PFN_WDFFDOINITWDMGETPHYSICALDEVICE pfnWdfFdoInitWdmGetPhysicalDevice; + PFN_WDFFDOINITOPENREGISTRYKEY pfnWdfFdoInitOpenRegistryKey; + PFN_WDFFDOINITQUERYPROPERTY pfnWdfFdoInitQueryProperty; + PFN_WDFFDOINITALLOCANDQUERYPROPERTY pfnWdfFdoInitAllocAndQueryProperty; + PFN_WDFFDOINITSETEVENTCALLBACKS pfnWdfFdoInitSetEventCallbacks; + PFN_WDFFDOINITSETFILTER pfnWdfFdoInitSetFilter; + PFN_WDFFDOINITSETDEFAULTCHILDLISTCONFIG pfnWdfFdoInitSetDefaultChildListConfig; + PFN_WDFFDOQUERYFORINTERFACE pfnWdfFdoQueryForInterface; + PFN_WDFFDOGETDEFAULTCHILDLIST pfnWdfFdoGetDefaultChildList; + PFN_WDFFDOADDSTATICCHILD pfnWdfFdoAddStaticChild; + PFN_WDFFDOLOCKSTATICCHILDLISTFORITERATION pfnWdfFdoLockStaticChildListForIteration; + PFN_WDFFDORETRIEVENEXTSTATICCHILD pfnWdfFdoRetrieveNextStaticChild; + PFN_WDFFDOUNLOCKSTATICCHILDLISTFROMITERATION pfnWdfFdoUnlockStaticChildListFromIteration; + PFN_WDFFILEOBJECTGETFILENAME pfnWdfFileObjectGetFileName; + PFN_WDFFILEOBJECTGETFLAGS pfnWdfFileObjectGetFlags; + PFN_WDFFILEOBJECTGETDEVICE pfnWdfFileObjectGetDevice; + PFN_WDFFILEOBJECTWDMGETFILEOBJECT pfnWdfFileObjectWdmGetFileObject; + PFN_WDFINTERRUPTCREATE pfnWdfInterruptCreate; + PFN_WDFINTERRUPTQUEUEDPCFORISR pfnWdfInterruptQueueDpcForIsr; + PFN_WDFINTERRUPTSYNCHRONIZE pfnWdfInterruptSynchronize; + PFN_WDFINTERRUPTACQUIRELOCK pfnWdfInterruptAcquireLock; + PFN_WDFINTERRUPTRELEASELOCK pfnWdfInterruptReleaseLock; + PFN_WDFINTERRUPTENABLE pfnWdfInterruptEnable; + PFN_WDFINTERRUPTDISABLE pfnWdfInterruptDisable; + PFN_WDFINTERRUPTWDMGETINTERRUPT pfnWdfInterruptWdmGetInterrupt; + PFN_WDFINTERRUPTGETINFO pfnWdfInterruptGetInfo; + PFN_WDFINTERRUPTSETPOLICY pfnWdfInterruptSetPolicy; + PFN_WDFINTERRUPTGETDEVICE pfnWdfInterruptGetDevice; + PFN_WDFIOQUEUECREATE pfnWdfIoQueueCreate; + PFN_WDFIOQUEUEGETSTATE pfnWdfIoQueueGetState; + PFN_WDFIOQUEUESTART pfnWdfIoQueueStart; + PFN_WDFIOQUEUESTOP pfnWdfIoQueueStop; + PFN_WDFIOQUEUESTOPSYNCHRONOUSLY pfnWdfIoQueueStopSynchronously; + PFN_WDFIOQUEUEGETDEVICE pfnWdfIoQueueGetDevice; + PFN_WDFIOQUEUERETRIEVENEXTREQUEST pfnWdfIoQueueRetrieveNextRequest; + PFN_WDFIOQUEUERETRIEVEREQUESTBYFILEOBJECT pfnWdfIoQueueRetrieveRequestByFileObject; + PFN_WDFIOQUEUEFINDREQUEST pfnWdfIoQueueFindRequest; + PFN_WDFIOQUEUERETRIEVEFOUNDREQUEST pfnWdfIoQueueRetrieveFoundRequest; + PFN_WDFIOQUEUEDRAINSYNCHRONOUSLY pfnWdfIoQueueDrainSynchronously; + PFN_WDFIOQUEUEDRAIN pfnWdfIoQueueDrain; + PFN_WDFIOQUEUEPURGESYNCHRONOUSLY pfnWdfIoQueuePurgeSynchronously; + PFN_WDFIOQUEUEPURGE pfnWdfIoQueuePurge; + PFN_WDFIOQUEUEREADYNOTIFY pfnWdfIoQueueReadyNotify; + PFN_WDFIOTARGETCREATE pfnWdfIoTargetCreate; + PFN_WDFIOTARGETOPEN pfnWdfIoTargetOpen; + PFN_WDFIOTARGETCLOSEFORQUERYREMOVE pfnWdfIoTargetCloseForQueryRemove; + PFN_WDFIOTARGETCLOSE pfnWdfIoTargetClose; + PFN_WDFIOTARGETSTART pfnWdfIoTargetStart; + PFN_WDFIOTARGETSTOP pfnWdfIoTargetStop; + PFN_WDFIOTARGETGETSTATE pfnWdfIoTargetGetState; + PFN_WDFIOTARGETGETDEVICE pfnWdfIoTargetGetDevice; + PFN_WDFIOTARGETQUERYTARGETPROPERTY pfnWdfIoTargetQueryTargetProperty; + PFN_WDFIOTARGETALLOCANDQUERYTARGETPROPERTY pfnWdfIoTargetAllocAndQueryTargetProperty; + PFN_WDFIOTARGETQUERYFORINTERFACE pfnWdfIoTargetQueryForInterface; + PFN_WDFIOTARGETWDMGETTARGETDEVICEOBJECT pfnWdfIoTargetWdmGetTargetDeviceObject; + PFN_WDFIOTARGETWDMGETTARGETPHYSICALDEVICE pfnWdfIoTargetWdmGetTargetPhysicalDevice; + PFN_WDFIOTARGETWDMGETTARGETFILEOBJECT pfnWdfIoTargetWdmGetTargetFileObject; + PFN_WDFIOTARGETWDMGETTARGETFILEHANDLE pfnWdfIoTargetWdmGetTargetFileHandle; + PFN_WDFIOTARGETSENDREADSYNCHRONOUSLY pfnWdfIoTargetSendReadSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORREAD pfnWdfIoTargetFormatRequestForRead; + PFN_WDFIOTARGETSENDWRITESYNCHRONOUSLY pfnWdfIoTargetSendWriteSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORWRITE pfnWdfIoTargetFormatRequestForWrite; + PFN_WDFIOTARGETSENDIOCTLSYNCHRONOUSLY pfnWdfIoTargetSendIoctlSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORIOCTL pfnWdfIoTargetFormatRequestForIoctl; + PFN_WDFIOTARGETSENDINTERNALIOCTLSYNCHRONOUSLY pfnWdfIoTargetSendInternalIoctlSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORINTERNALIOCTL pfnWdfIoTargetFormatRequestForInternalIoctl; + PFN_WDFIOTARGETSENDINTERNALIOCTLOTHERSSYNCHRONOUSLY pfnWdfIoTargetSendInternalIoctlOthersSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORINTERNALIOCTLOTHERS pfnWdfIoTargetFormatRequestForInternalIoctlOthers; + PFN_WDFMEMORYCREATE pfnWdfMemoryCreate; + PFN_WDFMEMORYCREATEPREALLOCATED pfnWdfMemoryCreatePreallocated; + PFN_WDFMEMORYGETBUFFER pfnWdfMemoryGetBuffer; + PFN_WDFMEMORYASSIGNBUFFER pfnWdfMemoryAssignBuffer; + PFN_WDFMEMORYCOPYTOBUFFER pfnWdfMemoryCopyToBuffer; + PFN_WDFMEMORYCOPYFROMBUFFER pfnWdfMemoryCopyFromBuffer; + PFN_WDFLOOKASIDELISTCREATE pfnWdfLookasideListCreate; + PFN_WDFMEMORYCREATEFROMLOOKASIDE pfnWdfMemoryCreateFromLookaside; + PFN_WDFDEVICEMINIPORTCREATE pfnWdfDeviceMiniportCreate; + PFN_WDFDRIVERMINIPORTUNLOAD pfnWdfDriverMiniportUnload; + PFN_WDFOBJECTGETTYPEDCONTEXTWORKER pfnWdfObjectGetTypedContextWorker; + PFN_WDFOBJECTALLOCATECONTEXT pfnWdfObjectAllocateContext; + PFN_WDFOBJECTCONTEXTGETOBJECT pfnWdfObjectContextGetObject; + PFN_WDFOBJECTREFERENCEACTUAL pfnWdfObjectReferenceActual; + PFN_WDFOBJECTDEREFERENCEACTUAL pfnWdfObjectDereferenceActual; + PFN_WDFOBJECTCREATE pfnWdfObjectCreate; + PFN_WDFOBJECTDELETE pfnWdfObjectDelete; + PFN_WDFOBJECTQUERY pfnWdfObjectQuery; + PFN_WDFPDOINITALLOCATE pfnWdfPdoInitAllocate; + PFN_WDFPDOINITSETEVENTCALLBACKS pfnWdfPdoInitSetEventCallbacks; + PFN_WDFPDOINITASSIGNDEVICEID pfnWdfPdoInitAssignDeviceID; + PFN_WDFPDOINITASSIGNINSTANCEID pfnWdfPdoInitAssignInstanceID; + PFN_WDFPDOINITADDHARDWAREID pfnWdfPdoInitAddHardwareID; + PFN_WDFPDOINITADDCOMPATIBLEID pfnWdfPdoInitAddCompatibleID; + PFN_WDFPDOINITADDDEVICETEXT pfnWdfPdoInitAddDeviceText; + PFN_WDFPDOINITSETDEFAULTLOCALE pfnWdfPdoInitSetDefaultLocale; + PFN_WDFPDOINITASSIGNRAWDEVICE pfnWdfPdoInitAssignRawDevice; + PFN_WDFPDOMARKMISSING pfnWdfPdoMarkMissing; + PFN_WDFPDOREQUESTEJECT pfnWdfPdoRequestEject; + PFN_WDFPDOGETPARENT pfnWdfPdoGetParent; + PFN_WDFPDORETRIEVEIDENTIFICATIONDESCRIPTION pfnWdfPdoRetrieveIdentificationDescription; + PFN_WDFPDORETRIEVEADDRESSDESCRIPTION pfnWdfPdoRetrieveAddressDescription; + PFN_WDFPDOUPDATEADDRESSDESCRIPTION pfnWdfPdoUpdateAddressDescription; + PFN_WDFPDOADDEJECTIONRELATIONSPHYSICALDEVICE pfnWdfPdoAddEjectionRelationsPhysicalDevice; + PFN_WDFPDOREMOVEEJECTIONRELATIONSPHYSICALDEVICE pfnWdfPdoRemoveEjectionRelationsPhysicalDevice; + PFN_WDFPDOCLEAREJECTIONRELATIONSDEVICES pfnWdfPdoClearEjectionRelationsDevices; + PFN_WDFDEVICEADDQUERYINTERFACE pfnWdfDeviceAddQueryInterface; + PFN_WDFREGISTRYOPENKEY pfnWdfRegistryOpenKey; + PFN_WDFREGISTRYCREATEKEY pfnWdfRegistryCreateKey; + PFN_WDFREGISTRYCLOSE pfnWdfRegistryClose; + PFN_WDFREGISTRYWDMGETHANDLE pfnWdfRegistryWdmGetHandle; + PFN_WDFREGISTRYREMOVEKEY pfnWdfRegistryRemoveKey; + PFN_WDFREGISTRYREMOVEVALUE pfnWdfRegistryRemoveValue; + PFN_WDFREGISTRYQUERYVALUE pfnWdfRegistryQueryValue; + PFN_WDFREGISTRYQUERYMEMORY pfnWdfRegistryQueryMemory; + PFN_WDFREGISTRYQUERYMULTISTRING pfnWdfRegistryQueryMultiString; + PFN_WDFREGISTRYQUERYUNICODESTRING pfnWdfRegistryQueryUnicodeString; + PFN_WDFREGISTRYQUERYSTRING pfnWdfRegistryQueryString; + PFN_WDFREGISTRYQUERYULONG pfnWdfRegistryQueryULong; + PFN_WDFREGISTRYASSIGNVALUE pfnWdfRegistryAssignValue; + PFN_WDFREGISTRYASSIGNMEMORY pfnWdfRegistryAssignMemory; + PFN_WDFREGISTRYASSIGNMULTISTRING pfnWdfRegistryAssignMultiString; + PFN_WDFREGISTRYASSIGNUNICODESTRING pfnWdfRegistryAssignUnicodeString; + PFN_WDFREGISTRYASSIGNSTRING pfnWdfRegistryAssignString; + PFN_WDFREGISTRYASSIGNULONG pfnWdfRegistryAssignULong; + PFN_WDFREQUESTCREATE pfnWdfRequestCreate; + PFN_WDFREQUESTCREATEFROMIRP pfnWdfRequestCreateFromIrp; + PFN_WDFREQUESTREUSE pfnWdfRequestReuse; + PFN_WDFREQUESTCHANGETARGET pfnWdfRequestChangeTarget; + PFN_WDFREQUESTFORMATREQUESTUSINGCURRENTTYPE pfnWdfRequestFormatRequestUsingCurrentType; + PFN_WDFREQUESTWDMFORMATUSINGSTACKLOCATION pfnWdfRequestWdmFormatUsingStackLocation; + PFN_WDFREQUESTSEND pfnWdfRequestSend; + PFN_WDFREQUESTGETSTATUS pfnWdfRequestGetStatus; + PFN_WDFREQUESTMARKCANCELABLE pfnWdfRequestMarkCancelable; + PFN_WDFREQUESTUNMARKCANCELABLE pfnWdfRequestUnmarkCancelable; + PFN_WDFREQUESTISCANCELED pfnWdfRequestIsCanceled; + PFN_WDFREQUESTCANCELSENTREQUEST pfnWdfRequestCancelSentRequest; + PFN_WDFREQUESTISFROM32BITPROCESS pfnWdfRequestIsFrom32BitProcess; + PFN_WDFREQUESTSETCOMPLETIONROUTINE pfnWdfRequestSetCompletionRoutine; + PFN_WDFREQUESTGETCOMPLETIONPARAMS pfnWdfRequestGetCompletionParams; + PFN_WDFREQUESTALLOCATETIMER pfnWdfRequestAllocateTimer; + PFN_WDFREQUESTCOMPLETE pfnWdfRequestComplete; + PFN_WDFREQUESTCOMPLETEWITHPRIORITYBOOST pfnWdfRequestCompleteWithPriorityBoost; + PFN_WDFREQUESTCOMPLETEWITHINFORMATION pfnWdfRequestCompleteWithInformation; + PFN_WDFREQUESTGETPARAMETERS pfnWdfRequestGetParameters; + PFN_WDFREQUESTRETRIEVEINPUTMEMORY pfnWdfRequestRetrieveInputMemory; + PFN_WDFREQUESTRETRIEVEOUTPUTMEMORY pfnWdfRequestRetrieveOutputMemory; + PFN_WDFREQUESTRETRIEVEINPUTBUFFER pfnWdfRequestRetrieveInputBuffer; + PFN_WDFREQUESTRETRIEVEOUTPUTBUFFER pfnWdfRequestRetrieveOutputBuffer; + PFN_WDFREQUESTRETRIEVEINPUTWDMMDL pfnWdfRequestRetrieveInputWdmMdl; + PFN_WDFREQUESTRETRIEVEOUTPUTWDMMDL pfnWdfRequestRetrieveOutputWdmMdl; + PFN_WDFREQUESTRETRIEVEUNSAFEUSERINPUTBUFFER pfnWdfRequestRetrieveUnsafeUserInputBuffer; + PFN_WDFREQUESTRETRIEVEUNSAFEUSEROUTPUTBUFFER pfnWdfRequestRetrieveUnsafeUserOutputBuffer; + PFN_WDFREQUESTSETINFORMATION pfnWdfRequestSetInformation; + PFN_WDFREQUESTGETINFORMATION pfnWdfRequestGetInformation; + PFN_WDFREQUESTGETFILEOBJECT pfnWdfRequestGetFileObject; + PFN_WDFREQUESTPROBEANDLOCKUSERBUFFERFORREAD pfnWdfRequestProbeAndLockUserBufferForRead; + PFN_WDFREQUESTPROBEANDLOCKUSERBUFFERFORWRITE pfnWdfRequestProbeAndLockUserBufferForWrite; + PFN_WDFREQUESTGETREQUESTORMODE pfnWdfRequestGetRequestorMode; + PFN_WDFREQUESTFORWARDTOIOQUEUE pfnWdfRequestForwardToIoQueue; + PFN_WDFREQUESTGETIOQUEUE pfnWdfRequestGetIoQueue; + PFN_WDFREQUESTREQUEUE pfnWdfRequestRequeue; + PFN_WDFREQUESTSTOPACKNOWLEDGE pfnWdfRequestStopAcknowledge; + PFN_WDFREQUESTWDMGETIRP pfnWdfRequestWdmGetIrp; + PFN_WDFIORESOURCEREQUIREMENTSLISTSETSLOTNUMBER pfnWdfIoResourceRequirementsListSetSlotNumber; + PFN_WDFIORESOURCEREQUIREMENTSLISTSETINTERFACETYPE pfnWdfIoResourceRequirementsListSetInterfaceType; + PFN_WDFIORESOURCEREQUIREMENTSLISTAPPENDIORESLIST pfnWdfIoResourceRequirementsListAppendIoResList; + PFN_WDFIORESOURCEREQUIREMENTSLISTINSERTIORESLIST pfnWdfIoResourceRequirementsListInsertIoResList; + PFN_WDFIORESOURCEREQUIREMENTSLISTGETCOUNT pfnWdfIoResourceRequirementsListGetCount; + PFN_WDFIORESOURCEREQUIREMENTSLISTGETIORESLIST pfnWdfIoResourceRequirementsListGetIoResList; + PFN_WDFIORESOURCEREQUIREMENTSLISTREMOVE pfnWdfIoResourceRequirementsListRemove; + PFN_WDFIORESOURCEREQUIREMENTSLISTREMOVEBYIORESLIST pfnWdfIoResourceRequirementsListRemoveByIoResList; + PFN_WDFIORESOURCELISTCREATE pfnWdfIoResourceListCreate; + PFN_WDFIORESOURCELISTAPPENDDESCRIPTOR pfnWdfIoResourceListAppendDescriptor; + PFN_WDFIORESOURCELISTINSERTDESCRIPTOR pfnWdfIoResourceListInsertDescriptor; + PFN_WDFIORESOURCELISTUPDATEDESCRIPTOR pfnWdfIoResourceListUpdateDescriptor; + PFN_WDFIORESOURCELISTGETCOUNT pfnWdfIoResourceListGetCount; + PFN_WDFIORESOURCELISTGETDESCRIPTOR pfnWdfIoResourceListGetDescriptor; + PFN_WDFIORESOURCELISTREMOVE pfnWdfIoResourceListRemove; + PFN_WDFIORESOURCELISTREMOVEBYDESCRIPTOR pfnWdfIoResourceListRemoveByDescriptor; + PFN_WDFCMRESOURCELISTAPPENDDESCRIPTOR pfnWdfCmResourceListAppendDescriptor; + PFN_WDFCMRESOURCELISTINSERTDESCRIPTOR pfnWdfCmResourceListInsertDescriptor; + PFN_WDFCMRESOURCELISTGETCOUNT pfnWdfCmResourceListGetCount; + PFN_WDFCMRESOURCELISTGETDESCRIPTOR pfnWdfCmResourceListGetDescriptor; + PFN_WDFCMRESOURCELISTREMOVE pfnWdfCmResourceListRemove; + PFN_WDFCMRESOURCELISTREMOVEBYDESCRIPTOR pfnWdfCmResourceListRemoveByDescriptor; + PFN_WDFSTRINGCREATE pfnWdfStringCreate; + PFN_WDFSTRINGGETUNICODESTRING pfnWdfStringGetUnicodeString; + PFN_WDFOBJECTACQUIRELOCK pfnWdfObjectAcquireLock; + PFN_WDFOBJECTRELEASELOCK pfnWdfObjectReleaseLock; + PFN_WDFWAITLOCKCREATE pfnWdfWaitLockCreate; + PFN_WDFWAITLOCKACQUIRE pfnWdfWaitLockAcquire; + PFN_WDFWAITLOCKRELEASE pfnWdfWaitLockRelease; + PFN_WDFSPINLOCKCREATE pfnWdfSpinLockCreate; + PFN_WDFSPINLOCKACQUIRE pfnWdfSpinLockAcquire; + PFN_WDFSPINLOCKRELEASE pfnWdfSpinLockRelease; + PFN_WDFTIMERCREATE pfnWdfTimerCreate; + PFN_WDFTIMERSTART pfnWdfTimerStart; + PFN_WDFTIMERSTOP pfnWdfTimerStop; + PFN_WDFTIMERGETPARENTOBJECT pfnWdfTimerGetParentObject; + PFN_WDFUSBTARGETDEVICECREATE pfnWdfUsbTargetDeviceCreate; + PFN_WDFUSBTARGETDEVICERETRIEVEINFORMATION pfnWdfUsbTargetDeviceRetrieveInformation; + PFN_WDFUSBTARGETDEVICEGETDEVICEDESCRIPTOR pfnWdfUsbTargetDeviceGetDeviceDescriptor; + PFN_WDFUSBTARGETDEVICERETRIEVECONFIGDESCRIPTOR pfnWdfUsbTargetDeviceRetrieveConfigDescriptor; + PFN_WDFUSBTARGETDEVICEQUERYSTRING pfnWdfUsbTargetDeviceQueryString; + PFN_WDFUSBTARGETDEVICEALLOCANDQUERYSTRING pfnWdfUsbTargetDeviceAllocAndQueryString; + PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORSTRING pfnWdfUsbTargetDeviceFormatRequestForString; + PFN_WDFUSBTARGETDEVICEGETNUMINTERFACES pfnWdfUsbTargetDeviceGetNumInterfaces; + PFN_WDFUSBTARGETDEVICESELECTCONFIG pfnWdfUsbTargetDeviceSelectConfig; + PFN_WDFUSBTARGETDEVICEWDMGETCONFIGURATIONHANDLE pfnWdfUsbTargetDeviceWdmGetConfigurationHandle; + PFN_WDFUSBTARGETDEVICERETRIEVECURRENTFRAMENUMBER pfnWdfUsbTargetDeviceRetrieveCurrentFrameNumber; + PFN_WDFUSBTARGETDEVICESENDCONTROLTRANSFERSYNCHRONOUSLY pfnWdfUsbTargetDeviceSendControlTransferSynchronously; + PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORCONTROLTRANSFER pfnWdfUsbTargetDeviceFormatRequestForControlTransfer; + PFN_WDFUSBTARGETDEVICEISCONNECTEDSYNCHRONOUS pfnWdfUsbTargetDeviceIsConnectedSynchronous; + PFN_WDFUSBTARGETDEVICERESETPORTSYNCHRONOUSLY pfnWdfUsbTargetDeviceResetPortSynchronously; + PFN_WDFUSBTARGETDEVICECYCLEPORTSYNCHRONOUSLY pfnWdfUsbTargetDeviceCyclePortSynchronously; + PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORCYCLEPORT pfnWdfUsbTargetDeviceFormatRequestForCyclePort; + PFN_WDFUSBTARGETDEVICESENDURBSYNCHRONOUSLY pfnWdfUsbTargetDeviceSendUrbSynchronously; + PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORURB pfnWdfUsbTargetDeviceFormatRequestForUrb; + PFN_WDFUSBTARGETPIPEGETINFORMATION pfnWdfUsbTargetPipeGetInformation; + PFN_WDFUSBTARGETPIPEISINENDPOINT pfnWdfUsbTargetPipeIsInEndpoint; + PFN_WDFUSBTARGETPIPEISOUTENDPOINT pfnWdfUsbTargetPipeIsOutEndpoint; + PFN_WDFUSBTARGETPIPEGETTYPE pfnWdfUsbTargetPipeGetType; + PFN_WDFUSBTARGETPIPESETNOMAXIMUMPACKETSIZECHECK pfnWdfUsbTargetPipeSetNoMaximumPacketSizeCheck; + PFN_WDFUSBTARGETPIPEWRITESYNCHRONOUSLY pfnWdfUsbTargetPipeWriteSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORWRITE pfnWdfUsbTargetPipeFormatRequestForWrite; + PFN_WDFUSBTARGETPIPEREADSYNCHRONOUSLY pfnWdfUsbTargetPipeReadSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORREAD pfnWdfUsbTargetPipeFormatRequestForRead; + PFN_WDFUSBTARGETPIPECONFIGCONTINUOUSREADER pfnWdfUsbTargetPipeConfigContinuousReader; + PFN_WDFUSBTARGETPIPEABORTSYNCHRONOUSLY pfnWdfUsbTargetPipeAbortSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORABORT pfnWdfUsbTargetPipeFormatRequestForAbort; + PFN_WDFUSBTARGETPIPERESETSYNCHRONOUSLY pfnWdfUsbTargetPipeResetSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORRESET pfnWdfUsbTargetPipeFormatRequestForReset; + PFN_WDFUSBTARGETPIPESENDURBSYNCHRONOUSLY pfnWdfUsbTargetPipeSendUrbSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORURB pfnWdfUsbTargetPipeFormatRequestForUrb; + PFN_WDFUSBINTERFACEGETINTERFACENUMBER pfnWdfUsbInterfaceGetInterfaceNumber; + PFN_WDFUSBINTERFACEGETNUMENDPOINTS pfnWdfUsbInterfaceGetNumEndpoints; + PFN_WDFUSBINTERFACEGETDESCRIPTOR pfnWdfUsbInterfaceGetDescriptor; + PFN_WDFUSBINTERFACESELECTSETTING pfnWdfUsbInterfaceSelectSetting; + PFN_WDFUSBINTERFACEGETENDPOINTINFORMATION pfnWdfUsbInterfaceGetEndpointInformation; + PFN_WDFUSBTARGETDEVICEGETINTERFACE pfnWdfUsbTargetDeviceGetInterface; + PFN_WDFUSBINTERFACEGETCONFIGUREDSETTINGINDEX pfnWdfUsbInterfaceGetConfiguredSettingIndex; + PFN_WDFUSBINTERFACEGETNUMCONFIGUREDPIPES pfnWdfUsbInterfaceGetNumConfiguredPipes; + PFN_WDFUSBINTERFACEGETCONFIGUREDPIPE pfnWdfUsbInterfaceGetConfiguredPipe; + PFN_WDFUSBTARGETPIPEWDMGETPIPEHANDLE pfnWdfUsbTargetPipeWdmGetPipeHandle; + PFN_WDFVERIFIERDBGBREAKPOINT pfnWdfVerifierDbgBreakPoint; + PFN_WDFVERIFIERKEBUGCHECK pfnWdfVerifierKeBugCheck; + PFN_WDFWMIPROVIDERCREATE pfnWdfWmiProviderCreate; + PFN_WDFWMIPROVIDERGETDEVICE pfnWdfWmiProviderGetDevice; + PFN_WDFWMIPROVIDERISENABLED pfnWdfWmiProviderIsEnabled; + PFN_WDFWMIPROVIDERGETTRACINGHANDLE pfnWdfWmiProviderGetTracingHandle; + PFN_WDFWMIINSTANCECREATE pfnWdfWmiInstanceCreate; + PFN_WDFWMIINSTANCEREGISTER pfnWdfWmiInstanceRegister; + PFN_WDFWMIINSTANCEDEREGISTER pfnWdfWmiInstanceDeregister; + PFN_WDFWMIINSTANCEGETDEVICE pfnWdfWmiInstanceGetDevice; + PFN_WDFWMIINSTANCEGETPROVIDER pfnWdfWmiInstanceGetProvider; + PFN_WDFWMIINSTANCEFIREEVENT pfnWdfWmiInstanceFireEvent; + PFN_WDFWORKITEMCREATE pfnWdfWorkItemCreate; + PFN_WDFWORKITEMENQUEUE pfnWdfWorkItemEnqueue; + PFN_WDFWORKITEMGETPARENTOBJECT pfnWdfWorkItemGetParentObject; + PFN_WDFWORKITEMFLUSH pfnWdfWorkItemFlush; + PFN_WDFCOMMONBUFFERCREATEWITHCONFIG pfnWdfCommonBufferCreateWithConfig; + PFN_WDFDMAENABLERGETFRAGMENTLENGTH pfnWdfDmaEnablerGetFragmentLength; + PFN_WDFDMAENABLERWDMGETDMAADAPTER pfnWdfDmaEnablerWdmGetDmaAdapter; + PFN_WDFUSBINTERFACEGETNUMSETTINGS pfnWdfUsbInterfaceGetNumSettings; + PFN_WDFDEVICEREMOVEDEPENDENTUSAGEDEVICEOBJECT pfnWdfDeviceRemoveDependentUsageDeviceObject; + PFN_WDFDEVICEGETSYSTEMPOWERACTION pfnWdfDeviceGetSystemPowerAction; + PFN_WDFINTERRUPTSETEXTENDEDPOLICY pfnWdfInterruptSetExtendedPolicy; + PFN_WDFIOQUEUEASSIGNFORWARDPROGRESSPOLICY pfnWdfIoQueueAssignForwardProgressPolicy; + PFN_WDFPDOINITASSIGNCONTAINERID pfnWdfPdoInitAssignContainerID; + PFN_WDFPDOINITALLOWFORWARDINGREQUESTTOPARENT pfnWdfPdoInitAllowForwardingRequestToParent; + PFN_WDFREQUESTMARKCANCELABLEEX pfnWdfRequestMarkCancelableEx; + PFN_WDFREQUESTISRESERVED pfnWdfRequestIsReserved; + PFN_WDFREQUESTFORWARDTOPARENTDEVICEIOQUEUE pfnWdfRequestForwardToParentDeviceIoQueue; + PFN_WDFCXDEVICEINITALLOCATE pfnWdfCxDeviceInitAllocate; + PFN_WDFCXDEVICEINITASSIGNWDMIRPPREPROCESSCALLBACK pfnWdfCxDeviceInitAssignWdmIrpPreprocessCallback; + PFN_WDFCXDEVICEINITSETIOINCALLERCONTEXTCALLBACK pfnWdfCxDeviceInitSetIoInCallerContextCallback; + PFN_WDFCXDEVICEINITSETREQUESTATTRIBUTES pfnWdfCxDeviceInitSetRequestAttributes; + PFN_WDFCXDEVICEINITSETFILEOBJECTCONFIG pfnWdfCxDeviceInitSetFileObjectConfig; + PFN_WDFDEVICEWDMDISPATCHIRP pfnWdfDeviceWdmDispatchIrp; + PFN_WDFDEVICEWDMDISPATCHIRPTOIOQUEUE pfnWdfDeviceWdmDispatchIrpToIoQueue; + PFN_WDFDEVICEINITSETREMOVELOCKOPTIONS pfnWdfDeviceInitSetRemoveLockOptions; + PFN_WDFDEVICECONFIGUREWDMIRPDISPATCHCALLBACK pfnWdfDeviceConfigureWdmIrpDispatchCallback; + PFN_WDFDMAENABLERCONFIGURESYSTEMPROFILE pfnWdfDmaEnablerConfigureSystemProfile; + PFN_WDFDMATRANSACTIONINITIALIZEUSINGOFFSET pfnWdfDmaTransactionInitializeUsingOffset; + PFN_WDFDMATRANSACTIONGETTRANSFERINFO pfnWdfDmaTransactionGetTransferInfo; + PFN_WDFDMATRANSACTIONSETCHANNELCONFIGURATIONCALLBACK pfnWdfDmaTransactionSetChannelConfigurationCallback; + PFN_WDFDMATRANSACTIONSETTRANSFERCOMPLETECALLBACK pfnWdfDmaTransactionSetTransferCompleteCallback; + PFN_WDFDMATRANSACTIONSETIMMEDIATEEXECUTION pfnWdfDmaTransactionSetImmediateExecution; + PFN_WDFDMATRANSACTIONALLOCATERESOURCES pfnWdfDmaTransactionAllocateResources; + PFN_WDFDMATRANSACTIONSETDEVICEADDRESSOFFSET pfnWdfDmaTransactionSetDeviceAddressOffset; + PFN_WDFDMATRANSACTIONFREERESOURCES pfnWdfDmaTransactionFreeResources; + PFN_WDFDMATRANSACTIONCANCEL pfnWdfDmaTransactionCancel; + PFN_WDFDMATRANSACTIONWDMGETTRANSFERCONTEXT pfnWdfDmaTransactionWdmGetTransferContext; + PFN_WDFINTERRUPTQUEUEWORKITEMFORISR pfnWdfInterruptQueueWorkItemForIsr; + PFN_WDFINTERRUPTTRYTOACQUIRELOCK pfnWdfInterruptTryToAcquireLock; + PFN_WDFIOQUEUESTOPANDPURGE pfnWdfIoQueueStopAndPurge; + PFN_WDFIOQUEUESTOPANDPURGESYNCHRONOUSLY pfnWdfIoQueueStopAndPurgeSynchronously; + PFN_WDFIOTARGETPURGE pfnWdfIoTargetPurge; + PFN_WDFUSBTARGETDEVICECREATEWITHPARAMETERS pfnWdfUsbTargetDeviceCreateWithParameters; + PFN_WDFUSBTARGETDEVICEQUERYUSBCAPABILITY pfnWdfUsbTargetDeviceQueryUsbCapability; + PFN_WDFUSBTARGETDEVICECREATEURB pfnWdfUsbTargetDeviceCreateUrb; + PFN_WDFUSBTARGETDEVICECREATEISOCHURB pfnWdfUsbTargetDeviceCreateIsochUrb; + PFN_WDFDEVICEWDMASSIGNPOWERFRAMEWORKSETTINGS pfnWdfDeviceWdmAssignPowerFrameworkSettings; + PFN_WDFDMATRANSACTIONSTOPSYSTEMTRANSFER pfnWdfDmaTransactionStopSystemTransfer; + PFN_WDFCXVERIFIERKEBUGCHECK pfnWdfCxVerifierKeBugCheck; + PFN_WDFINTERRUPTREPORTACTIVE pfnWdfInterruptReportActive; + PFN_WDFINTERRUPTREPORTINACTIVE pfnWdfInterruptReportInactive; + PFN_WDFDEVICEINITSETRELEASEHARDWAREORDERONFAILURE pfnWdfDeviceInitSetReleaseHardwareOrderOnFailure; + PFN_WDFGETTRIAGEINFO pfnWdfGetTriageInfo; + PFN_WDFDEVICEINITSETIOTYPEEX pfnWdfDeviceInitSetIoTypeEx; + PFN_WDFDEVICEQUERYPROPERTYEX pfnWdfDeviceQueryPropertyEx; + PFN_WDFDEVICEALLOCANDQUERYPROPERTYEX pfnWdfDeviceAllocAndQueryPropertyEx; + PFN_WDFDEVICEASSIGNPROPERTY pfnWdfDeviceAssignProperty; + PFN_WDFFDOINITQUERYPROPERTYEX pfnWdfFdoInitQueryPropertyEx; + PFN_WDFFDOINITALLOCANDQUERYPROPERTYEX pfnWdfFdoInitAllocAndQueryPropertyEx; + PFN_WDFDEVICESTOPIDLEACTUAL pfnWdfDeviceStopIdleActual; + PFN_WDFDEVICERESUMEIDLEACTUAL pfnWdfDeviceResumeIdleActual; + PFN_WDFDEVICEGETSELFIOTARGET pfnWdfDeviceGetSelfIoTarget; + PFN_WDFDEVICEINITALLOWSELFIOTARGET pfnWdfDeviceInitAllowSelfIoTarget; + PFN_WDFIOTARGETSELFASSIGNDEFAULTIOQUEUE pfnWdfIoTargetSelfAssignDefaultIoQueue; + PFN_WDFDEVICEOPENDEVICEMAPKEY pfnWdfDeviceOpenDevicemapKey; + +} WDFFUNCTIONS, *PWDFFUNCTIONS; + + +typedef struct _WDFVERSION { + + ULONG Size; + ULONG FuncCount; + WDFFUNCTIONS Functions; + +} WDFVERSION, *PWDFVERSION; + + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfChildListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_CHILD_LIST_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES ChildListAttributes, + _Out_ + WDFCHILDLIST* ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfChildListGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfChildListRetrievePdo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _Inout_ + PWDF_CHILD_RETRIEVE_INFO RetrieveInfo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfChildListRetrieveAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfChildListBeginScan)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfChildListEndScan)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfChildListBeginIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfChildListRetrieveNextDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator, + _Out_ + WDFDEVICE* Device, + _Inout_opt_ + PWDF_CHILD_RETRIEVE_INFO Info + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfChildListEndIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + _In_opt_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfChildListRequestChildEject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCollectionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + _Out_ + WDFCOLLECTION* Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfCollectionGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCollectionAdd)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCollectionRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Item + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCollectionRemoveItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfCollectionGetItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfCollectionGetFirstItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfCollectionGetLastItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCommonBufferCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFCOMMONBUFFER* CommonBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCommonBufferCreateWithConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + _In_ + PWDF_COMMON_BUFFER_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFCOMMONBUFFER* CommonBuffer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +WDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PHYSICAL_ADDRESS +WDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +WDFEXPORT(WdfCommonBufferGetLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFDEVICE_INIT +WDFEXPORT(WdfControlDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + CONST UNICODE_STRING* SDDLString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfControlDeviceInitSetShutdownNotification)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDF_DEVICE_SHUTDOWN_NOTIFICATION Notification, + _In_ + UCHAR Flags + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfControlFinishInitializing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFCXDEVICE_INIT +WDFEXPORT(WdfCxDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess, + _In_ + UCHAR MajorFunction, + _When_(NumMinorFunctions > 0, _In_reads_bytes_(NumMinorFunctions)) + _When_(NumMinorFunctions == 0, _In_opt_) + PUCHAR MinorFunctions, + _In_ + ULONG NumMinorFunctions + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +WDFAPI +VOID +WDFEXPORT(WdfCxVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFOBJECT Object, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceGetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + PWDF_DEVICE_STATE DeviceState + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_STATE DeviceState + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDEVICE_OBJECT DeviceObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +WDFEXPORT(WdfDeviceWdmGetDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +WDFEXPORT(WdfDeviceWdmGetAttachedDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +WDFEXPORT(WdfDeviceWdmGetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFCONTEXT DispatchContext + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFQUEUE Queue, + _In_ + ULONG Flags + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAddDependentUsageDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT DependentDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT DependentDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceClearRemovalRelationsDevices)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +WDFEXPORT(WdfDeviceGetDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceRetrieveDeviceName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignMofResourceName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING MofResourceName + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +WDFEXPORT(WdfDeviceGetIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_PNP_STATE +WDFEXPORT(WdfDeviceGetDevicePnpState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_POWER_STATE +WDFEXPORT(WdfDeviceGetDevicePowerState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_POWER_POLICY_STATE +WDFEXPORT(WdfDeviceGetDevicePowerPolicyState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignS0IdleSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignSxWakeSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceOpenDevicemapKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetSpecialFileSupport)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_SPECIAL_FILE_TYPE FileType, + _In_ + BOOLEAN FileTypeIsSupported + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceCharacteristics + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfDeviceGetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfDeviceGetAlignmentRequirement)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetAlignmentRequirement)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG AlignmentRequirement + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitFree)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsPowerPolicyOwner + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_PNP_STATE PnpState, + _In_ + PFN_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION EvtDevicePnpStateChange, + _In_ + ULONG CallbackTypes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_POWER_STATE PowerState, + _In_ + PFN_WDF_DEVICE_POWER_STATE_CHANGE_NOTIFICATION EvtDevicePowerStateChange, + _In_ + ULONG CallbackTypes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState, + _In_ + PFN_WDF_DEVICE_POWER_POLICY_STATE_CHANGE_NOTIFICATION EvtDevicePowerPolicyStateChange, + _In_ + ULONG CallbackTypes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetExclusive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsExclusive + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_IO_TYPE IoType + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerNotPageable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerPageable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerInrush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetDeviceType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_TYPE DeviceType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitAssignName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_opt_ + PCUNICODE_STRING DeviceName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitAssignSDDLString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_opt_ + PCUNICODE_STRING SDDLString + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetDeviceClass)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + CONST GUID* DeviceClassGuid + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceCharacteristics, + _In_ + BOOLEAN OrInValues + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmIrpPreprocess, + _In_ + UCHAR MajorFunction, + _When_(NumMinorFunctions > 0, _In_reads_bytes_(NumMinorFunctions)) + _When_(NumMinorFunctions == 0, _In_opt_) + PUCHAR MinorFunctions, + _In_ + ULONG NumMinorFunctions + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetRemoveLockOptions)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_REMOVE_LOCK_OPTIONS Options + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT* DeviceInit, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + _Out_ + WDFDEVICE* Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetStaticStopRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN Stoppable + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceCreateDeviceInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + BOOLEAN IsInterfaceEnabled + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceCreateSymbolicLink)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING SymbolicLinkName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetPnpCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetPowerCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetBusInformationForChildren)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PPNP_BUS_INFORMATION BusInformation + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceIndicateWakeStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + NTSTATUS WaitWakeStatus + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetFailed)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_FAILED_ACTION FailedAction + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceStopIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceResumeIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceStopIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceResumeIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +WDFEXPORT(WdfDeviceGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PFILE_OBJECT FileObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceEnqueueRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +WDFEXPORT(WdfDeviceGetDefaultQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceConfigureRequestDispatching)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFQUEUE Queue, + _In_ + _Strict_type_match_ + WDF_REQUEST_TYPE RequestType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDisptach, + _In_opt_ + WDFCONTEXT DriverContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +POWER_ACTION +WDFEXPORT(WdfDeviceGetSystemPowerAction)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG Size, + _In_opt_ + PVOID Data + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +WDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaEnablerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DMA_ENABLER_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDMAENABLER* DmaEnablerHandle + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaEnablerConfigureSystemProfile)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig, + _In_ + WDF_DMA_DIRECTION ConfigDirection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +WDFEXPORT(WdfDmaEnablerGetMaximumLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +WDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(MaximumFragments == 0, __drv_reportError(MaximumFragments cannot be zero)) + size_t MaximumFragments + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +WDFEXPORT(WdfDmaEnablerGetFragmentLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + WDF_DMA_DIRECTION DmaDirection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDMA_ADAPTER +WDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + WDF_DMA_DIRECTION DmaDirection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaTransactionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDMATRANSACTION* DmaTransaction + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaTransactionInitialize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + PMDL Mdl, + _In_ + PVOID VirtualAddress, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaTransactionInitializeUsingOffset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + PMDL Mdl, + _In_ + size_t Offset, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +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 + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaTransactionExecute)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + WDFCONTEXT Context + ); + +_Success_(TRUE) +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaTransactionRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDmaTransactionDmaCompleted)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _Out_ + NTSTATUS* Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDmaTransactionDmaCompletedWithLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t TransferredLength, + _Out_ + NTSTATUS* Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDmaTransactionDmaCompletedFinal)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t FinalTransferredLength, + _Out_ + NTSTATUS* Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +WDFEXPORT(WdfDmaTransactionGetBytesTransferred)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionSetMaximumLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t MaximumLength + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFREQUEST +WDFEXPORT(WdfDmaTransactionGetRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +WDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfDmaTransactionGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionGetTransferInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _Out_opt_ + ULONG* MapRegisterCount, + _Out_opt_ + ULONG* ScatterGatherElementCount + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL ConfigureRoutine, + _In_opt_ + PVOID ConfigureContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE DmaCompletionRoutine, + _In_opt_ + PVOID DmaCompletionContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionSetImmediateExecution)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + BOOLEAN UseImmediateExecution + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDmaTransactionAllocateResources)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + ULONG RequiredMapRegisters, + _In_ + PFN_WDF_RESERVE_DMA EvtReserveDmaFunction, + _In_ + PVOID EvtReserveDmaContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + ULONG Offset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionFreeResources)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDmaTransactionCancel)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +WDFEXPORT(WdfDmaTransactionWdmGetTransferContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDmaTransactionStopSystemTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDpcCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_DPC_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDPC* Dpc + ); + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDpcEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ); + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(HIGH_LEVEL)) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDpcCancel)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc, + _In_ + BOOLEAN Wait + ); + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfDpcGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ); + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +PKDPC +WDFEXPORT(WdfDpcWdmGetDpc)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PCUNICODE_STRING RegistryPath, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + _In_ + PWDF_DRIVER_CONFIG DriverConfig, + _Out_opt_ + WDFDRIVER* Driver + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWSTR +WDFEXPORT(WdfDriverGetRegistryPath)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDRIVER_OBJECT +WDFEXPORT(WdfDriverWdmGetDriverObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverOpenParametersRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +WDFEXPORT(WdfWdmDriverGetWdfDriverHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverRegisterTraceInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PFN_WDF_TRACE_CALLBACK EvtTraceCallback, + _In_ + PVOID ControlBlock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverRetrieveVersionString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDriverIsVersionAvailable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +WDFEXPORT(WdfFdoInitWdmGetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFdoInitSetEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FDO_EVENT_CALLBACKS FdoEventCallbacks + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFdoInitSetFilter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFdoInitSetDefaultChildListConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_CHILD_LIST_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DefaultChildListAttributes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoQueryForInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_ + LPCGUID InterfaceType, + _Out_ + PINTERFACE Interface, + _In_ + USHORT Size, + _In_ + USHORT Version, + _In_opt_ + PVOID InterfaceSpecificData + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFCHILDLIST +WDFEXPORT(WdfFdoGetDefaultChildList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoAddStaticChild)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_ + WDFDEVICE Child + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFdoLockStaticChildListForIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfFdoRetrieveNextStaticChild)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_opt_ + WDFDEVICE PreviousChild, + _In_ + ULONG Flags + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFdoUnlockStaticChildListFromIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PUNICODE_STRING +WDFEXPORT(WdfFileObjectGetFileName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfFileObjectGetFlags)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfFileObjectGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PFILE_OBJECT +WDFEXPORT(WdfFileObjectWdmGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfInterruptCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_INTERRUPT_CONFIG Configuration, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFINTERRUPT* Interrupt + ); + +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptQueueDpcForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptSynchronize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + _In_ + WDFCONTEXT Context + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +WDFEXPORT(WdfInterruptAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +WDFEXPORT(WdfInterruptReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptEnable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptDisable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +WDFAPI +PKINTERRUPT +WDFEXPORT(WdfInterruptWdmGetInterrupt)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptGetInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _Out_ + PWDF_INTERRUPT_INFO Info + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptSetPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + WDF_INTERRUPT_POLICY Policy, + _In_ + WDF_INTERRUPT_PRIORITY Priority, + _In_ + KAFFINITY TargetProcessorSet + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptSetExtendedPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ); + +WDFAPI +WDFDEVICE +WDFEXPORT(WdfInterruptGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_Post_satisfies_(return == 1 || return == 0) +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptTryToAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptReportActive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptReportInactive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_IO_QUEUE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + _Out_opt_ + WDFQUEUE* Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_QUEUE_STATE +WDFEXPORT(WdfIoQueueGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_opt_ + PULONG QueueRequests, + _Out_opt_ + PULONG DriverRequests + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopComplete, + _When_(StopComplete != 0, _In_) + _When_(StopComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStopSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfIoQueueGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveNextRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFFILEOBJECT FileObject, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueFindRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + WDFREQUEST FoundRequest, + _In_opt_ + WDFFILEOBJECT FileObject, + _Inout_opt_ + PWDF_REQUEST_PARAMETERS Parameters, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFREQUEST FoundRequest, + _Out_ + WDFREQUEST* OutRequest + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueDrainSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueDrain)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + _When_(DrainComplete != 0, _In_) + _When_(DrainComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueuePurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueuePurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + _When_(PurgeComplete != 0, _In_) + _When_(PurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueReadyNotify)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + PFN_WDF_IO_QUEUE_STATE QueueReady, + _In_opt_ + WDFCONTEXT Context + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueAssignForwardProgressPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY ForwardProgressPolicy + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStopAndPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + _When_(StopAndPurgeComplete != 0, _In_) + _When_(StopAndPurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + _Out_ + WDFIOTARGET* IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetOpen)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetCloseForQueryRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_When_(Action == 3, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1 || Action == 2, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_SENT_IO_ACTION Action + ); + +_When_(Action == 2, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_PURGE_IO_ACTION Action + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_TARGET_STATE +WDFEXPORT(WdfIoTargetGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfIoTargetGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetQueryTargetProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _When_(BufferLength != 0, _Out_writes_bytes_to_opt_(BufferLength, *ResultLength)) + _When_(BufferLength == 0, _Out_opt_) + PVOID PropertyBuffer, + _Deref_out_range_(<=,BufferLength) + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetQueryForInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + LPCGUID InterfaceType, + _Out_ + PINTERFACE Interface, + _In_ + USHORT Size, + _In_ + USHORT Version, + _In_opt_ + PVOID InterfaceSpecificData + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +WDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +WDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PFILE_OBJECT +WDFEXPORT(WdfIoTargetWdmGetTargetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +HANDLE +WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg1, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg2, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg4, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY OtherArg1, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg1Offset, + _In_opt_ + WDFMEMORY OtherArg2, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg2Offset, + _In_opt_ + WDFMEMORY OtherArg4, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg4Offset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + ULONG PoolTag, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory, + _Outptr_opt_result_bytebuffer_(BufferSize) + PVOID* Buffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCreatePreallocated)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ __drv_aliasesMem + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +WDFEXPORT(WdfMemoryGetBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Out_opt_ + size_t* BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCopyToBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY SourceMemory, + _In_ + size_t SourceOffset, + _Out_writes_bytes_( NumBytesToCopyTo ) + PVOID Buffer, + _In_ + _When_(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCopyFromBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY DestinationMemory, + _In_ + size_t DestinationOffset, + _In_ + PVOID Buffer, + _In_ + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ); + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfLookasideListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LookasideAttributes, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _In_opt_ + ULONG PoolTag, + _Out_ + WDFLOOKASIDE* Lookaside + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCreateFromLookaside)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFLOOKASIDE Lookaside, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceMiniportCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + PDEVICE_OBJECT DeviceObject, + _In_opt_ + PDEVICE_OBJECT AttachedDeviceObject, + _In_opt_ + PDEVICE_OBJECT Pdo, + _Out_ + WDFDEVICE* Device + ); + +WDFAPI +VOID +WDFEXPORT(WdfDriverMiniportUnload)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +WDFAPI +PVOID +FASTCALL +WDFEXPORT(WdfObjectGetTypedContextWorker)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ); + +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectAllocateContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PWDF_OBJECT_ATTRIBUTES ContextAttributes, + _Outptr_opt_ + PVOID* Context + ); + +WDFAPI +WDFOBJECT +FASTCALL +WDFEXPORT(WdfObjectContextGetObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PVOID ContextPointer + ); + +WDFAPI +VOID +WDFEXPORT(WdfObjectReferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +WDFAPI +VOID +WDFEXPORT(WdfObjectDereferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFOBJECT* Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectDelete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectQuery)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object, + _In_ + CONST GUID* Guid, + _In_ + ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFDEVICE_INIT +WDFEXPORT(WdfPdoInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE ParentDevice + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoInitSetEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PDO_EVENT_CALLBACKS DispatchTable + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAssignDeviceID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING DeviceID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAssignInstanceID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING InstanceID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAddHardwareID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING HardwareID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAddCompatibleID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING CompatibleID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAssignContainerID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING ContainerID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAddDeviceText)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING DeviceDescription, + _In_ + PCUNICODE_STRING DeviceLocation, + _In_ + LCID LocaleId + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoInitSetDefaultLocale)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + LCID LocaleId + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoInitAssignRawDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + CONST GUID* DeviceClassGuid + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoInitAllowForwardingRequestToParent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoMarkMissing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoRequestEject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfPdoGetParent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoRetrieveIdentificationDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoRetrieveAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoUpdateAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoClearEjectionRelationsDevices)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAddQueryInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_QUERY_INTERFACE_CONFIG InterfaceConfig + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryOpenKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryCreateKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_ + ULONG CreateOptions, + _Out_opt_ + PULONG CreateDisposition, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRegistryClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +HANDLE +WDFEXPORT(WdfRegistryWdmGetHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryRemoveKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryRemoveValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueLength, + _Out_writes_bytes_opt_( ValueLength) + PVOID Value, + _Out_opt_ + PULONG ValueLengthQueried, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _Out_ + WDFMEMORY* Memory, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_opt_ + PUSHORT ValueByteLength, + _Inout_opt_ + PUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_ + PULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + ULONG ValueLength, + _In_reads_( ValueLength) + PVOID Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET MemoryOffsets + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFCOLLECTION StringsCollection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + PCUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_opt_ + WDFIOTARGET IoTarget, + _Out_ + WDFREQUEST* Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestCreateFromIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_ + PIRP Irp, + _In_ + BOOLEAN RequestFreesIrp, + _Out_ + WDFREQUEST* Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestReuse)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestChangeTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestWdmFormatUsingStackLocation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PIO_STACK_LOCATION Stack + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS == 0, _Must_inspect_result_) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestSend)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET Target, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS Options + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestGetStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestMarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestMarkCancelableEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestUnmarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsCanceled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestCancelSentRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsFrom32BitProcess)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetCompletionRoutine)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_opt_ + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ __drv_aliasesMem + WDFCONTEXT CompletionContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestGetCompletionParams)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_COMPLETION_PARAMS Params + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestAllocateTimer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestComplete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestCompleteWithPriorityBoost)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + CCHAR PriorityBoost + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestCompleteWithInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestGetParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_PARAMETERS Parameters + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveInputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveOutputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredSize, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveInputWdmMdl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Outptr_ + PMDL* Mdl + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveOutputWdmMdl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Outptr_ + PMDL* Mdl + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_maybenull_(*Length) + PVOID* InputBuffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_maybenull_(*Length) + PVOID* OutputBuffer, + _Out_opt_ + size_t* Length + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG_PTR +WDFEXPORT(WdfRequestGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +WDFEXPORT(WdfRequestGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestProbeAndLockUserBufferForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_reads_bytes_(Length) + PVOID Buffer, + _In_ + size_t Length, + _Out_ + WDFMEMORY* MemoryObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_reads_bytes_(Length) + PVOID Buffer, + _In_ + size_t Length, + _Out_ + WDFMEMORY* MemoryObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +KPROCESSOR_MODE +WDFEXPORT(WdfRequestGetRequestorMode)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestForwardToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE DestinationQueue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +WDFEXPORT(WdfRequestGetIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRequeue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestStopAcknowledge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN Requeue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PIRP +WDFEXPORT(WdfRequestWdmGetIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsReserved)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestForwardToParentDeviceIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE ParentDeviceQueue, + _In_ + PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG SlotNumber + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + _Strict_type_match_ + INTERFACE_TYPE InterfaceType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoResourceRequirementsListAppendIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoResourceRequirementsListInsertIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfIoResourceRequirementsListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIORESLIST +WDFEXPORT(WdfIoResourceRequirementsListGetIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceRequirementsListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoResourceListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFIORESLIST* ResourceList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoResourceListAppendDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoResourceListInsertDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceListUpdateDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfIoResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PIO_RESOURCE_DESCRIPTOR +WDFEXPORT(WdfIoResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoResourceListRemoveByDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCmResourceListAppendDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCmResourceListInsertDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfCmResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PCM_PARTIAL_RESOURCE_DESCRIPTOR +WDFEXPORT(WdfCmResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCmResourceListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCmResourceListRemoveByDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfStringCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PCUNICODE_STRING UnicodeString, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringAttributes, + _Out_ + WDFSTRING* String + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfStringGetUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFSTRING String, + _Out_ + PUNICODE_STRING UnicodeString + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWaitLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LockAttributes, + _Out_ + WDFWAITLOCK* Lock + ); + +_When_(Timeout == NULL, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Timeout != NULL && *Timeout == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Timeout != NULL && *Timeout != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +_Always_(_When_(Timeout == NULL, _Acquires_lock_(Lock))) +_When_(Timeout != NULL && return == STATUS_SUCCESS, _Acquires_lock_(Lock)) +_When_(Timeout != NULL, _Must_inspect_result_) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWaitLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + WDFWAITLOCK Lock, + _In_opt_ + PLONGLONG Timeout + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWaitLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFWAITLOCK Lock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfSpinLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + _Out_ + WDFSPINLOCK* SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfSpinLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + _IRQL_saves_ + WDFSPINLOCK SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_min_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfSpinLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + _IRQL_restores_ + WDFSPINLOCK SpinLock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfTimerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_TIMER_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFTIMER* Timer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfTimerStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + LONGLONG DueTime + ); + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +BOOLEAN +WDFEXPORT(WdfTimerStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + BOOLEAN Wait + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfTimerGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_USB_DEVICE_CREATE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PWDF_USB_DEVICE_INFORMATION Information + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_writes_bytes_to_opt_(*ConfigDescriptorLength,*ConfigDescriptorLength) + PVOID ConfigDescriptor, + _Inout_ + PUSHORT ConfigDescriptorLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_writes_opt_(*NumCharacters) + PUSHORT String, + _Inout_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + _Out_ + WDFMEMORY* StringMemory, + _Out_opt_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET Offset, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +UCHAR +WDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipeAttributes, + _Inout_ + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +USBD_CONFIGURATION_HANDLE +WDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PULONG CurrentFrameNumber + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesTransferred + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + WDFMEMORY TransferMemory, + _In_opt_ + PWDFMEMORY_OFFSET TransferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_reads_(_Inexpressible_("union bug in SAL")) + PURB Urb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY UrbMemory, + _In_opt_ + PWDFMEMORY_OFFSET UrbMemoryOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + CONST GUID* CapabilityType, + _In_ + ULONG CapabilityBufferLength, + _When_(CapabilityBufferLength == 0, _Out_opt_) + _When_(CapabilityBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(CapabilityBufferLength)) + _When_(CapabilityBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + _Out_opt_ + _When_(ResultLength != NULL,_Deref_out_range_(<=,CapabilityBufferLength)) + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCreateUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFMEMORY* UrbMemory, + _Outptr_opt_result_bytebuffer_(sizeof(URB)) + PURB* Urb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + ULONG NumberOfIsochPackets, + _Out_ + WDFMEMORY* UrbMemory, + _Outptr_opt_result_bytebuffer_(GET_ISO_URB_SIZE(NumberOfIsochPackets)) + PURB* Urb + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbTargetPipeGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _Out_ + PWDF_USB_PIPE_INFORMATION PipeInformation + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_USB_PIPE_TYPE +WDFEXPORT(WdfUsbTargetPipeGetType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY WriteMemory, + _In_opt_ + PWDFMEMORY_OFFSET WriteOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY ReadMemory, + _In_opt_ + PWDFMEMORY_OFFSET ReadOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_reads_(_Inexpressible_("union bug in SAL")) + PURB Urb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE PIPE, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY UrbMemory, + _In_opt_ + PWDFMEMORY_OFFSET UrbMemoryOffset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbInterfaceGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _Out_ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbInterfaceSelectSetting)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + _In_ + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _In_ + UCHAR EndpointIndex, + _Out_ + PWDF_USB_PIPE_INFORMATION EndpointInfo + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBINTERFACE +WDFEXPORT(WdfUsbTargetDeviceGetInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + UCHAR InterfaceIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE Interface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBPIPE +WDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR PipeIndex, + _Out_opt_ + PWDF_USB_PIPE_INFORMATION PipeInfo + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +USBD_PIPE_HANDLE +WDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE UsbPipe + ); + +WDFAPI +VOID +WDFEXPORT(WdfVerifierDbgBreakPoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +WDFAPI +VOID +WDFEXPORT(WdfVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +WDFAPI +PVOID +WDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWmiProviderCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + _Out_ + WDFWMIPROVIDER* WmiProvider + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfWmiProviderGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfWmiProviderIsEnabled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider, + _In_ + WDF_WMI_PROVIDER_CONTROL ProviderControl + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONGLONG +WDFEXPORT(WdfWmiProviderGetTracingHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWmiInstanceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_WMI_INSTANCE_CONFIG InstanceConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES InstanceAttributes, + _Out_opt_ + WDFWMIINSTANCE* Instance + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWmiInstanceRegister)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWmiInstanceDeregister)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfWmiInstanceGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFWMIPROVIDER +WDFEXPORT(WdfWmiInstanceGetProvider)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWmiInstanceFireEvent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance, + _In_opt_ + ULONG EventDataSize, + _In_reads_bytes_opt_(EventDataSize) + PVOID EventData + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWorkItemCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_WORKITEM_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFWORKITEM* WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWorkItemEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfWorkItemGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWorkItemFlush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + + +#ifdef FX_DYNAMICS_GENERATE_TABLE + +WDFVERSION WdfVersion = { + sizeof(WDFVERSION), + sizeof(WDFFUNCTIONS)/sizeof(PVOID), + { + WDFEXPORT(WdfChildListCreate), + WDFEXPORT(WdfChildListGetDevice), + WDFEXPORT(WdfChildListRetrievePdo), + WDFEXPORT(WdfChildListRetrieveAddressDescription), + WDFEXPORT(WdfChildListBeginScan), + WDFEXPORT(WdfChildListEndScan), + WDFEXPORT(WdfChildListBeginIteration), + WDFEXPORT(WdfChildListRetrieveNextDevice), + WDFEXPORT(WdfChildListEndIteration), + WDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent), + WDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing), + WDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent), + WDFEXPORT(WdfChildListRequestChildEject), + WDFEXPORT(WdfCollectionCreate), + WDFEXPORT(WdfCollectionGetCount), + WDFEXPORT(WdfCollectionAdd), + WDFEXPORT(WdfCollectionRemove), + WDFEXPORT(WdfCollectionRemoveItem), + WDFEXPORT(WdfCollectionGetItem), + WDFEXPORT(WdfCollectionGetFirstItem), + WDFEXPORT(WdfCollectionGetLastItem), + WDFEXPORT(WdfCommonBufferCreate), + WDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress), + WDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress), + WDFEXPORT(WdfCommonBufferGetLength), + WDFEXPORT(WdfControlDeviceInitAllocate), + WDFEXPORT(WdfControlDeviceInitSetShutdownNotification), + WDFEXPORT(WdfControlFinishInitializing), + WDFEXPORT(WdfDeviceGetDeviceState), + WDFEXPORT(WdfDeviceSetDeviceState), + WDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle), + WDFEXPORT(WdfDeviceWdmGetDeviceObject), + WDFEXPORT(WdfDeviceWdmGetAttachedDevice), + WDFEXPORT(WdfDeviceWdmGetPhysicalDevice), + WDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp), + WDFEXPORT(WdfDeviceAddDependentUsageDeviceObject), + WDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice), + WDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice), + WDFEXPORT(WdfDeviceClearRemovalRelationsDevices), + WDFEXPORT(WdfDeviceGetDriver), + WDFEXPORT(WdfDeviceRetrieveDeviceName), + WDFEXPORT(WdfDeviceAssignMofResourceName), + WDFEXPORT(WdfDeviceGetIoTarget), + WDFEXPORT(WdfDeviceGetDevicePnpState), + WDFEXPORT(WdfDeviceGetDevicePowerState), + WDFEXPORT(WdfDeviceGetDevicePowerPolicyState), + WDFEXPORT(WdfDeviceAssignS0IdleSettings), + WDFEXPORT(WdfDeviceAssignSxWakeSettings), + WDFEXPORT(WdfDeviceOpenRegistryKey), + WDFEXPORT(WdfDeviceSetSpecialFileSupport), + WDFEXPORT(WdfDeviceSetCharacteristics), + WDFEXPORT(WdfDeviceGetCharacteristics), + WDFEXPORT(WdfDeviceGetAlignmentRequirement), + WDFEXPORT(WdfDeviceSetAlignmentRequirement), + WDFEXPORT(WdfDeviceInitFree), + WDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks), + WDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks), + WDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership), + WDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback), + WDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback), + WDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback), + WDFEXPORT(WdfDeviceInitSetIoType), + WDFEXPORT(WdfDeviceInitSetExclusive), + WDFEXPORT(WdfDeviceInitSetPowerNotPageable), + WDFEXPORT(WdfDeviceInitSetPowerPageable), + WDFEXPORT(WdfDeviceInitSetPowerInrush), + WDFEXPORT(WdfDeviceInitSetDeviceType), + WDFEXPORT(WdfDeviceInitAssignName), + WDFEXPORT(WdfDeviceInitAssignSDDLString), + WDFEXPORT(WdfDeviceInitSetDeviceClass), + WDFEXPORT(WdfDeviceInitSetCharacteristics), + WDFEXPORT(WdfDeviceInitSetFileObjectConfig), + WDFEXPORT(WdfDeviceInitSetRequestAttributes), + WDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback), + WDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback), + WDFEXPORT(WdfDeviceCreate), + WDFEXPORT(WdfDeviceSetStaticStopRemove), + WDFEXPORT(WdfDeviceCreateDeviceInterface), + WDFEXPORT(WdfDeviceSetDeviceInterfaceState), + WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString), + WDFEXPORT(WdfDeviceCreateSymbolicLink), + WDFEXPORT(WdfDeviceQueryProperty), + WDFEXPORT(WdfDeviceAllocAndQueryProperty), + WDFEXPORT(WdfDeviceSetPnpCapabilities), + WDFEXPORT(WdfDeviceSetPowerCapabilities), + WDFEXPORT(WdfDeviceSetBusInformationForChildren), + WDFEXPORT(WdfDeviceIndicateWakeStatus), + WDFEXPORT(WdfDeviceSetFailed), + WDFEXPORT(WdfDeviceStopIdleNoTrack), + WDFEXPORT(WdfDeviceResumeIdleNoTrack), + WDFEXPORT(WdfDeviceGetFileObject), + WDFEXPORT(WdfDeviceEnqueueRequest), + WDFEXPORT(WdfDeviceGetDefaultQueue), + WDFEXPORT(WdfDeviceConfigureRequestDispatching), + WDFEXPORT(WdfDmaEnablerCreate), + WDFEXPORT(WdfDmaEnablerGetMaximumLength), + WDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements), + WDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements), + WDFEXPORT(WdfDmaTransactionCreate), + WDFEXPORT(WdfDmaTransactionInitialize), + WDFEXPORT(WdfDmaTransactionInitializeUsingRequest), + WDFEXPORT(WdfDmaTransactionExecute), + WDFEXPORT(WdfDmaTransactionRelease), + WDFEXPORT(WdfDmaTransactionDmaCompleted), + WDFEXPORT(WdfDmaTransactionDmaCompletedWithLength), + WDFEXPORT(WdfDmaTransactionDmaCompletedFinal), + WDFEXPORT(WdfDmaTransactionGetBytesTransferred), + WDFEXPORT(WdfDmaTransactionSetMaximumLength), + WDFEXPORT(WdfDmaTransactionGetRequest), + WDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength), + WDFEXPORT(WdfDmaTransactionGetDevice), + WDFEXPORT(WdfDpcCreate), + WDFEXPORT(WdfDpcEnqueue), + WDFEXPORT(WdfDpcCancel), + WDFEXPORT(WdfDpcGetParentObject), + WDFEXPORT(WdfDpcWdmGetDpc), + WDFEXPORT(WdfDriverCreate), + WDFEXPORT(WdfDriverGetRegistryPath), + WDFEXPORT(WdfDriverWdmGetDriverObject), + WDFEXPORT(WdfDriverOpenParametersRegistryKey), + WDFEXPORT(WdfWdmDriverGetWdfDriverHandle), + WDFEXPORT(WdfDriverRegisterTraceInfo), + WDFEXPORT(WdfDriverRetrieveVersionString), + WDFEXPORT(WdfDriverIsVersionAvailable), + WDFEXPORT(WdfFdoInitWdmGetPhysicalDevice), + WDFEXPORT(WdfFdoInitOpenRegistryKey), + WDFEXPORT(WdfFdoInitQueryProperty), + WDFEXPORT(WdfFdoInitAllocAndQueryProperty), + WDFEXPORT(WdfFdoInitSetEventCallbacks), + WDFEXPORT(WdfFdoInitSetFilter), + WDFEXPORT(WdfFdoInitSetDefaultChildListConfig), + WDFEXPORT(WdfFdoQueryForInterface), + WDFEXPORT(WdfFdoGetDefaultChildList), + WDFEXPORT(WdfFdoAddStaticChild), + WDFEXPORT(WdfFdoLockStaticChildListForIteration), + WDFEXPORT(WdfFdoRetrieveNextStaticChild), + WDFEXPORT(WdfFdoUnlockStaticChildListFromIteration), + WDFEXPORT(WdfFileObjectGetFileName), + WDFEXPORT(WdfFileObjectGetFlags), + WDFEXPORT(WdfFileObjectGetDevice), + WDFEXPORT(WdfFileObjectWdmGetFileObject), + WDFEXPORT(WdfInterruptCreate), + WDFEXPORT(WdfInterruptQueueDpcForIsr), + WDFEXPORT(WdfInterruptSynchronize), + WDFEXPORT(WdfInterruptAcquireLock), + WDFEXPORT(WdfInterruptReleaseLock), + WDFEXPORT(WdfInterruptEnable), + WDFEXPORT(WdfInterruptDisable), + WDFEXPORT(WdfInterruptWdmGetInterrupt), + WDFEXPORT(WdfInterruptGetInfo), + WDFEXPORT(WdfInterruptSetPolicy), + WDFEXPORT(WdfInterruptGetDevice), + WDFEXPORT(WdfIoQueueCreate), + WDFEXPORT(WdfIoQueueGetState), + WDFEXPORT(WdfIoQueueStart), + WDFEXPORT(WdfIoQueueStop), + WDFEXPORT(WdfIoQueueStopSynchronously), + WDFEXPORT(WdfIoQueueGetDevice), + WDFEXPORT(WdfIoQueueRetrieveNextRequest), + WDFEXPORT(WdfIoQueueRetrieveRequestByFileObject), + WDFEXPORT(WdfIoQueueFindRequest), + WDFEXPORT(WdfIoQueueRetrieveFoundRequest), + WDFEXPORT(WdfIoQueueDrainSynchronously), + WDFEXPORT(WdfIoQueueDrain), + WDFEXPORT(WdfIoQueuePurgeSynchronously), + WDFEXPORT(WdfIoQueuePurge), + WDFEXPORT(WdfIoQueueReadyNotify), + WDFEXPORT(WdfIoTargetCreate), + WDFEXPORT(WdfIoTargetOpen), + WDFEXPORT(WdfIoTargetCloseForQueryRemove), + WDFEXPORT(WdfIoTargetClose), + WDFEXPORT(WdfIoTargetStart), + WDFEXPORT(WdfIoTargetStop), + WDFEXPORT(WdfIoTargetGetState), + WDFEXPORT(WdfIoTargetGetDevice), + WDFEXPORT(WdfIoTargetQueryTargetProperty), + WDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty), + WDFEXPORT(WdfIoTargetQueryForInterface), + WDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject), + WDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice), + WDFEXPORT(WdfIoTargetWdmGetTargetFileObject), + WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle), + WDFEXPORT(WdfIoTargetSendReadSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForRead), + WDFEXPORT(WdfIoTargetSendWriteSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForWrite), + WDFEXPORT(WdfIoTargetSendIoctlSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForIoctl), + WDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl), + WDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers), + WDFEXPORT(WdfMemoryCreate), + WDFEXPORT(WdfMemoryCreatePreallocated), + WDFEXPORT(WdfMemoryGetBuffer), + WDFEXPORT(WdfMemoryAssignBuffer), + WDFEXPORT(WdfMemoryCopyToBuffer), + WDFEXPORT(WdfMemoryCopyFromBuffer), + WDFEXPORT(WdfLookasideListCreate), + WDFEXPORT(WdfMemoryCreateFromLookaside), + WDFEXPORT(WdfDeviceMiniportCreate), + WDFEXPORT(WdfDriverMiniportUnload), + WDFEXPORT(WdfObjectGetTypedContextWorker), + WDFEXPORT(WdfObjectAllocateContext), + WDFEXPORT(WdfObjectContextGetObject), + WDFEXPORT(WdfObjectReferenceActual), + WDFEXPORT(WdfObjectDereferenceActual), + WDFEXPORT(WdfObjectCreate), + WDFEXPORT(WdfObjectDelete), + WDFEXPORT(WdfObjectQuery), + WDFEXPORT(WdfPdoInitAllocate), + WDFEXPORT(WdfPdoInitSetEventCallbacks), + WDFEXPORT(WdfPdoInitAssignDeviceID), + WDFEXPORT(WdfPdoInitAssignInstanceID), + WDFEXPORT(WdfPdoInitAddHardwareID), + WDFEXPORT(WdfPdoInitAddCompatibleID), + WDFEXPORT(WdfPdoInitAddDeviceText), + WDFEXPORT(WdfPdoInitSetDefaultLocale), + WDFEXPORT(WdfPdoInitAssignRawDevice), + WDFEXPORT(WdfPdoMarkMissing), + WDFEXPORT(WdfPdoRequestEject), + WDFEXPORT(WdfPdoGetParent), + WDFEXPORT(WdfPdoRetrieveIdentificationDescription), + WDFEXPORT(WdfPdoRetrieveAddressDescription), + WDFEXPORT(WdfPdoUpdateAddressDescription), + WDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice), + WDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice), + WDFEXPORT(WdfPdoClearEjectionRelationsDevices), + WDFEXPORT(WdfDeviceAddQueryInterface), + WDFEXPORT(WdfRegistryOpenKey), + WDFEXPORT(WdfRegistryCreateKey), + WDFEXPORT(WdfRegistryClose), + WDFEXPORT(WdfRegistryWdmGetHandle), + WDFEXPORT(WdfRegistryRemoveKey), + WDFEXPORT(WdfRegistryRemoveValue), + WDFEXPORT(WdfRegistryQueryValue), + WDFEXPORT(WdfRegistryQueryMemory), + WDFEXPORT(WdfRegistryQueryMultiString), + WDFEXPORT(WdfRegistryQueryUnicodeString), + WDFEXPORT(WdfRegistryQueryString), + WDFEXPORT(WdfRegistryQueryULong), + WDFEXPORT(WdfRegistryAssignValue), + WDFEXPORT(WdfRegistryAssignMemory), + WDFEXPORT(WdfRegistryAssignMultiString), + WDFEXPORT(WdfRegistryAssignUnicodeString), + WDFEXPORT(WdfRegistryAssignString), + WDFEXPORT(WdfRegistryAssignULong), + WDFEXPORT(WdfRequestCreate), + WDFEXPORT(WdfRequestCreateFromIrp), + WDFEXPORT(WdfRequestReuse), + WDFEXPORT(WdfRequestChangeTarget), + WDFEXPORT(WdfRequestFormatRequestUsingCurrentType), + WDFEXPORT(WdfRequestWdmFormatUsingStackLocation), + WDFEXPORT(WdfRequestSend), + WDFEXPORT(WdfRequestGetStatus), + WDFEXPORT(WdfRequestMarkCancelable), + WDFEXPORT(WdfRequestUnmarkCancelable), + WDFEXPORT(WdfRequestIsCanceled), + WDFEXPORT(WdfRequestCancelSentRequest), + WDFEXPORT(WdfRequestIsFrom32BitProcess), + WDFEXPORT(WdfRequestSetCompletionRoutine), + WDFEXPORT(WdfRequestGetCompletionParams), + WDFEXPORT(WdfRequestAllocateTimer), + WDFEXPORT(WdfRequestComplete), + WDFEXPORT(WdfRequestCompleteWithPriorityBoost), + WDFEXPORT(WdfRequestCompleteWithInformation), + WDFEXPORT(WdfRequestGetParameters), + WDFEXPORT(WdfRequestRetrieveInputMemory), + WDFEXPORT(WdfRequestRetrieveOutputMemory), + WDFEXPORT(WdfRequestRetrieveInputBuffer), + WDFEXPORT(WdfRequestRetrieveOutputBuffer), + WDFEXPORT(WdfRequestRetrieveInputWdmMdl), + WDFEXPORT(WdfRequestRetrieveOutputWdmMdl), + WDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer), + WDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer), + WDFEXPORT(WdfRequestSetInformation), + WDFEXPORT(WdfRequestGetInformation), + WDFEXPORT(WdfRequestGetFileObject), + WDFEXPORT(WdfRequestProbeAndLockUserBufferForRead), + WDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite), + WDFEXPORT(WdfRequestGetRequestorMode), + WDFEXPORT(WdfRequestForwardToIoQueue), + WDFEXPORT(WdfRequestGetIoQueue), + WDFEXPORT(WdfRequestRequeue), + WDFEXPORT(WdfRequestStopAcknowledge), + WDFEXPORT(WdfRequestWdmGetIrp), + WDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber), + WDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType), + WDFEXPORT(WdfIoResourceRequirementsListAppendIoResList), + WDFEXPORT(WdfIoResourceRequirementsListInsertIoResList), + WDFEXPORT(WdfIoResourceRequirementsListGetCount), + WDFEXPORT(WdfIoResourceRequirementsListGetIoResList), + WDFEXPORT(WdfIoResourceRequirementsListRemove), + WDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList), + WDFEXPORT(WdfIoResourceListCreate), + WDFEXPORT(WdfIoResourceListAppendDescriptor), + WDFEXPORT(WdfIoResourceListInsertDescriptor), + WDFEXPORT(WdfIoResourceListUpdateDescriptor), + WDFEXPORT(WdfIoResourceListGetCount), + WDFEXPORT(WdfIoResourceListGetDescriptor), + WDFEXPORT(WdfIoResourceListRemove), + WDFEXPORT(WdfIoResourceListRemoveByDescriptor), + WDFEXPORT(WdfCmResourceListAppendDescriptor), + WDFEXPORT(WdfCmResourceListInsertDescriptor), + WDFEXPORT(WdfCmResourceListGetCount), + WDFEXPORT(WdfCmResourceListGetDescriptor), + WDFEXPORT(WdfCmResourceListRemove), + WDFEXPORT(WdfCmResourceListRemoveByDescriptor), + WDFEXPORT(WdfStringCreate), + WDFEXPORT(WdfStringGetUnicodeString), + WDFEXPORT(WdfObjectAcquireLock), + WDFEXPORT(WdfObjectReleaseLock), + WDFEXPORT(WdfWaitLockCreate), + WDFEXPORT(WdfWaitLockAcquire), + WDFEXPORT(WdfWaitLockRelease), + WDFEXPORT(WdfSpinLockCreate), + WDFEXPORT(WdfSpinLockAcquire), + WDFEXPORT(WdfSpinLockRelease), + WDFEXPORT(WdfTimerCreate), + WDFEXPORT(WdfTimerStart), + WDFEXPORT(WdfTimerStop), + WDFEXPORT(WdfTimerGetParentObject), + WDFEXPORT(WdfUsbTargetDeviceCreate), + WDFEXPORT(WdfUsbTargetDeviceRetrieveInformation), + WDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor), + WDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor), + WDFEXPORT(WdfUsbTargetDeviceQueryString), + WDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString), + WDFEXPORT(WdfUsbTargetDeviceFormatRequestForString), + WDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces), + WDFEXPORT(WdfUsbTargetDeviceSelectConfig), + WDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle), + WDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber), + WDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously), + WDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer), + WDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous), + WDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously), + WDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously), + WDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort), + WDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously), + WDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb), + WDFEXPORT(WdfUsbTargetPipeGetInformation), + WDFEXPORT(WdfUsbTargetPipeIsInEndpoint), + WDFEXPORT(WdfUsbTargetPipeIsOutEndpoint), + WDFEXPORT(WdfUsbTargetPipeGetType), + WDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck), + WDFEXPORT(WdfUsbTargetPipeWriteSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite), + WDFEXPORT(WdfUsbTargetPipeReadSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForRead), + WDFEXPORT(WdfUsbTargetPipeConfigContinuousReader), + WDFEXPORT(WdfUsbTargetPipeAbortSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort), + WDFEXPORT(WdfUsbTargetPipeResetSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForReset), + WDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb), + WDFEXPORT(WdfUsbInterfaceGetInterfaceNumber), + WDFEXPORT(WdfUsbInterfaceGetNumEndpoints), + WDFEXPORT(WdfUsbInterfaceGetDescriptor), + WDFEXPORT(WdfUsbInterfaceSelectSetting), + WDFEXPORT(WdfUsbInterfaceGetEndpointInformation), + WDFEXPORT(WdfUsbTargetDeviceGetInterface), + WDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex), + WDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes), + WDFEXPORT(WdfUsbInterfaceGetConfiguredPipe), + WDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle), + WDFEXPORT(WdfVerifierDbgBreakPoint), + WDFEXPORT(WdfVerifierKeBugCheck), + WDFEXPORT(WdfWmiProviderCreate), + WDFEXPORT(WdfWmiProviderGetDevice), + WDFEXPORT(WdfWmiProviderIsEnabled), + WDFEXPORT(WdfWmiProviderGetTracingHandle), + WDFEXPORT(WdfWmiInstanceCreate), + WDFEXPORT(WdfWmiInstanceRegister), + WDFEXPORT(WdfWmiInstanceDeregister), + WDFEXPORT(WdfWmiInstanceGetDevice), + WDFEXPORT(WdfWmiInstanceGetProvider), + WDFEXPORT(WdfWmiInstanceFireEvent), + WDFEXPORT(WdfWorkItemCreate), + WDFEXPORT(WdfWorkItemEnqueue), + WDFEXPORT(WdfWorkItemGetParentObject), + WDFEXPORT(WdfWorkItemFlush), + WDFEXPORT(WdfCommonBufferCreateWithConfig), + WDFEXPORT(WdfDmaEnablerGetFragmentLength), + WDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter), + WDFEXPORT(WdfUsbInterfaceGetNumSettings), + WDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject), + WDFEXPORT(WdfDeviceGetSystemPowerAction), + WDFEXPORT(WdfInterruptSetExtendedPolicy), + WDFEXPORT(WdfIoQueueAssignForwardProgressPolicy), + WDFEXPORT(WdfPdoInitAssignContainerID), + WDFEXPORT(WdfPdoInitAllowForwardingRequestToParent), + WDFEXPORT(WdfRequestMarkCancelableEx), + WDFEXPORT(WdfRequestIsReserved), + WDFEXPORT(WdfRequestForwardToParentDeviceIoQueue), + WDFEXPORT(WdfCxDeviceInitAllocate), + WDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback), + WDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback), + WDFEXPORT(WdfCxDeviceInitSetRequestAttributes), + WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig), + WDFEXPORT(WdfDeviceWdmDispatchIrp), + WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue), + WDFEXPORT(WdfDeviceInitSetRemoveLockOptions), + WDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback), + WDFEXPORT(WdfDmaEnablerConfigureSystemProfile), + WDFEXPORT(WdfDmaTransactionInitializeUsingOffset), + WDFEXPORT(WdfDmaTransactionGetTransferInfo), + WDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback), + WDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback), + WDFEXPORT(WdfDmaTransactionSetImmediateExecution), + WDFEXPORT(WdfDmaTransactionAllocateResources), + WDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset), + WDFEXPORT(WdfDmaTransactionFreeResources), + WDFEXPORT(WdfDmaTransactionCancel), + WDFEXPORT(WdfDmaTransactionWdmGetTransferContext), + WDFEXPORT(WdfInterruptQueueWorkItemForIsr), + WDFEXPORT(WdfInterruptTryToAcquireLock), + WDFEXPORT(WdfIoQueueStopAndPurge), + WDFEXPORT(WdfIoQueueStopAndPurgeSynchronously), + WDFEXPORT(WdfIoTargetPurge), + WDFEXPORT(WdfUsbTargetDeviceCreateWithParameters), + WDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability), + WDFEXPORT(WdfUsbTargetDeviceCreateUrb), + WDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb), + WDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings), + WDFEXPORT(WdfDmaTransactionStopSystemTransfer), + WDFEXPORT(WdfCxVerifierKeBugCheck), + WDFEXPORT(WdfInterruptReportActive), + WDFEXPORT(WdfInterruptReportInactive), + WDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure), + WDFEXPORT(WdfGetTriageInfo), + WDFEXPORT(WdfDeviceInitSetIoTypeEx), + WDFEXPORT(WdfDeviceQueryPropertyEx), + WDFEXPORT(WdfDeviceAllocAndQueryPropertyEx), + WDFEXPORT(WdfDeviceAssignProperty), + WDFEXPORT(WdfFdoInitQueryPropertyEx), + WDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx), + WDFEXPORT(WdfDeviceStopIdleActual), + WDFEXPORT(WdfDeviceResumeIdleActual), + WDFEXPORT(WdfDeviceGetSelfIoTarget), + WDFEXPORT(WdfDeviceInitAllowSelfIoTarget), + WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue), + WDFEXPORT(WdfDeviceOpenDevicemapKey), + } +}; + +#endif // FX_DYNAMICS_GENERATE_TABLE + +#endif // _FXDYNAMICS_H_ + diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxdynamicswrapper.h b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdynamicswrapper.h new file mode 100644 index 00000000000..c409d2d04e7 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxdynamicswrapper.h @@ -0,0 +1,18 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +// +// Since #include'ing FxDymamics.h requires a bunch of headers before it, we +// do this in one place because multiple spots in the code include this header. +// + +extern "C" { +#pragma warning(disable:4200) // zero-sized array in struct/union +#include +#pragma warning(default:4200) + +#include +#include +#include "FxDynamics.h" +#include "VfFxDynamics.h" +} diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxlibrarycommon.h b/sdk/lib/drivers/wdf/kmdf/inc/private/fxlibrarycommon.h new file mode 100644 index 00000000000..a23f0bf8754 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxlibrarycommon.h @@ -0,0 +1,87 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef __FX_LIBRARY_COMMON_H__ +#define __FX_LIBRARY_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern ULONG WdfLdrDbgPrintOn; +extern PCHAR WdfLdrType; + +extern WDFVERSION WdfVersion; + +extern RTL_OSVERSIONINFOW gOsVersion; + +#define _LIT_(a) # a +#define LITERAL(a) _LIT_(a) + +#define __PrintUnfiltered(...) \ + DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__); + +#define __Print(_x_) \ +{ \ + if (WdfLdrDbgPrintOn) { \ + DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, "%s: ", WdfLdrType); \ + __PrintUnfiltered _x_ \ + } \ +} + +#define WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME L"EnhancedVerifierOptions" + +typedef +NTSTATUS +(*PFN_RTL_GET_VERSION)( + __out PRTL_OSVERSIONINFOW VersionInformation + ); + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonCommission( + VOID + ); + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonDecommission( + VOID + ); + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonRegisterClient( + __inout PWDF_BIND_INFO Info, + __deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + __in_opt PCLIENT_INFO ClientInfo + ); + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonUnregisterClient( + __in PWDF_BIND_INFO Info, + __in PWDF_DRIVER_GLOBALS WdfDriverGlobals + ); + +VOID +GetEnhancedVerifierOptions( + __in PCLIENT_INFO ClientInfo, + __out PULONG Options + ); + +VOID +LibraryLogEvent( + __in PDRIVER_OBJECT DriverObject, + __in NTSTATUS ErrorCode, + __in NTSTATUS FinalStatus, + __in PWSTR ErrorInsertionString, + __in_bcount(RawDataLen) PVOID RawDataBuf, + __in USHORT RawDataLen +); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __FX_LIBRARY_COMMON_H__ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/fxprobeandlock.h b/sdk/lib/drivers/wdf/kmdf/inc/private/fxprobeandlock.h new file mode 100644 index 00000000000..4a612acba0c --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/fxprobeandlock.h @@ -0,0 +1,38 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef __FXPROBEANDLOCK_H__ +#define __FXPROBEANDLOCK_H__ + +extern "C" { + +// +// These are defined in a C file in src\support\ProbeAndLock.c +// to avoid C++ exception handling issues. +// +// They do not raise the exception beyond the C function, but +// translate it into an NTSTATUS before returning. +// + +NTSTATUS +FxProbeAndLockForRead( + __in PMDL Mdl, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS +FxProbeAndLockForWrite( + __in PMDL Mdl, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS +FxProbeAndLockWithAccess( + __in PMDL Mdl, + __in KPROCESSOR_MODE AccessMode, + __in LOCK_OPERATION Operation + ); + +} + +#endif __FXPROBEANDLOCK_H__ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/ifxmemory.hpp b/sdk/lib/drivers/wdf/kmdf/inc/private/ifxmemory.hpp new file mode 100644 index 00000000000..06d1bc8139b --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/ifxmemory.hpp @@ -0,0 +1,161 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +/*++ + +Module Name: + + IFxMemory.hpp + +Abstract: + + Abstract base class for a memory object. It is necessary to split the + memory interface away from an FxObject derived base class so that we can + hand out WDFMEMORY handles that are embedded within other FxObject derived + classes without having to embed another FxObject derived class within the + parent. + +Author: + + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef __IFX_MEMORY_HPP__ +#define __IFX_MEMORY_HPP__ + +// begin_wpp enum +enum IFxMemoryFlags { + IFxMemoryFlagReadOnly = 0x0001, +}; +// end_wpp + + +class IFxMemory { +public: + virtual + PVOID + GetBuffer( + VOID + ) =0; + + virtual + size_t + GetBufferSize( + VOID + ) =0; + + virtual + PMDL + GetMdl( + VOID + ) =0; + + virtual + WDFMEMORY + GetHandle( + VOID + ) =0; + + // + // Value returned is a bit field from the enum IFxMemoryFlags + // + virtual + USHORT + GetFlags( + VOID + ) =0; + + virtual + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ) =0; + + virtual + ULONG + AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) =0; + + virtual + ULONG + Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) =0; + + virtual + VOID + Delete( + VOID + ) =0; + + _Must_inspect_result_ + NTSTATUS + ValidateMemoryOffsets( + __in_opt PWDFMEMORY_OFFSET Offsets + ) + { + NTSTATUS status; + size_t total; + + if (Offsets == NULL) { + return STATUS_SUCCESS; + } + + status = RtlSizeTAdd(Offsets->BufferLength, Offsets->BufferOffset, &total); + + if (!NT_SUCCESS(status)) { + return status; + } + + if (total > GetBufferSize()) { + return STATUS_INTEGER_OVERFLOW; + } + + return STATUS_SUCCESS; + } + + _Must_inspect_result_ + NTSTATUS + CopyFromPtr( + __in_opt PWDFMEMORY_OFFSET DestinationOffsets, + __in_bcount(SourceBufferLength) PVOID SourceBuffer, + __in size_t SourceBufferLength, + __in_opt PWDFMEMORY_OFFSET SourceOffsets + ); + + _Must_inspect_result_ + NTSTATUS + CopyToPtr( + __in_opt PWDFMEMORY_OFFSET SourceOffsets, + __out_bcount(DestinationBufferLength) PVOID DestinationBuffer, + __in size_t DestinationBufferLength, + __in_opt PWDFMEMORY_OFFSET DestinationOffsets + ); + +protected: + static + _Must_inspect_result_ + NTSTATUS + _CopyPtrToPtr( + __in_bcount(SourceBufferLength) PVOID SourceBuffer, + __in size_t SourceBufferLength, + __in_opt PWDFMEMORY_OFFSET SourceOffsets, + __out_bcount(DestinationBufferLength) PVOID DestinationBuffer, + __in size_t DestinationBufferLength, + __in_opt PWDFMEMORY_OFFSET DestinationOffsets + ); +}; + +#endif // __IFX_MEMORY_HPP__ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/vffxdynamics.h b/sdk/lib/drivers/wdf/kmdf/inc/private/vffxdynamics.h new file mode 100644 index 00000000000..0c1c34a8ddd --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/vffxdynamics.h @@ -0,0 +1,6484 @@ +/*++ + +Module Name: VfFxDynamics.h + +Abstract: + Generated header for WDF API Verifier hooks + +Environment: + kernel mode only + + Warning: manual changes to this file will be lost. +--*/ + +#ifndef _VFFXDYNAMICS_H_ +#define _VFFXDYNAMICS_H_ + + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_CHILD_LIST_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES ChildListAttributes, + _Out_ + WDFCHILDLIST* ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfChildListGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfChildListRetrievePdo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _Inout_ + PWDF_CHILD_RETRIEVE_INFO RetrieveInfo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListRetrieveAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListBeginScan)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListEndScan)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListBeginIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListRetrieveNextDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator, + _Out_ + WDFDEVICE* Device, + _Inout_opt_ + PWDF_CHILD_RETRIEVE_INFO Info + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListEndIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + _In_opt_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfChildListRequestChildEject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + _Out_ + WDFCOLLECTION* Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCollectionGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionAdd)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Item + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemoveItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetFirstItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetLastItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCommonBufferCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFCOMMONBUFFER* CommonBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCommonBufferCreateWithConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + _In_ + PWDF_COMMON_BUFFER_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFCOMMONBUFFER* CommonBuffer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PHYSICAL_ADDRESS +VFWDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfCommonBufferGetLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFDEVICE_INIT +VFWDFEXPORT(WdfControlDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + CONST UNICODE_STRING* SDDLString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfControlDeviceInitSetShutdownNotification)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDF_DEVICE_SHUTDOWN_NOTIFICATION Notification, + _In_ + UCHAR Flags + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfControlFinishInitializing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFCXDEVICE_INIT +VFWDFEXPORT(WdfCxDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess, + _In_ + UCHAR MajorFunction, + _When_(NumMinorFunctions > 0, _In_reads_bytes_(NumMinorFunctions)) + _When_(NumMinorFunctions == 0, _In_opt_) + PUCHAR MinorFunctions, + _In_ + ULONG NumMinorFunctions + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfCxVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFOBJECT Object, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceGetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + PWDF_DEVICE_STATE DeviceState + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_STATE DeviceState + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDEVICE_OBJECT DeviceObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfDeviceWdmGetDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfDeviceWdmGetAttachedDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfDeviceWdmGetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFCONTEXT DispatchContext + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFQUEUE Queue, + _In_ + ULONG Flags + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAddDependentUsageDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT DependentDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT DependentDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceClearRemovalRelationsDevices)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +VFWDFEXPORT(WdfDeviceGetDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceRetrieveDeviceName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignMofResourceName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING MofResourceName + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_PNP_STATE +VFWDFEXPORT(WdfDeviceGetDevicePnpState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_POWER_STATE +VFWDFEXPORT(WdfDeviceGetDevicePowerState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_POWER_POLICY_STATE +VFWDFEXPORT(WdfDeviceGetDevicePowerPolicyState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignS0IdleSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignSxWakeSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenDevicemapKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetSpecialFileSupport)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_SPECIAL_FILE_TYPE FileType, + _In_ + BOOLEAN FileTypeIsSupported + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceCharacteristics + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfDeviceGetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfDeviceGetAlignmentRequirement)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetAlignmentRequirement)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG AlignmentRequirement + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitFree)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsPowerPolicyOwner + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_PNP_STATE PnpState, + _In_ + PFN_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION EvtDevicePnpStateChange, + _In_ + ULONG CallbackTypes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_POWER_STATE PowerState, + _In_ + PFN_WDF_DEVICE_POWER_STATE_CHANGE_NOTIFICATION EvtDevicePowerStateChange, + _In_ + ULONG CallbackTypes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState, + _In_ + PFN_WDF_DEVICE_POWER_POLICY_STATE_CHANGE_NOTIFICATION EvtDevicePowerPolicyStateChange, + _In_ + ULONG CallbackTypes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetExclusive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsExclusive + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_IO_TYPE IoType + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerNotPageable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPageable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerInrush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetDeviceType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_TYPE DeviceType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitAssignName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_opt_ + PCUNICODE_STRING DeviceName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitAssignSDDLString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_opt_ + PCUNICODE_STRING SDDLString + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetDeviceClass)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + CONST GUID* DeviceClassGuid + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceCharacteristics, + _In_ + BOOLEAN OrInValues + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmIrpPreprocess, + _In_ + UCHAR MajorFunction, + _When_(NumMinorFunctions > 0, _In_reads_bytes_(NumMinorFunctions)) + _When_(NumMinorFunctions == 0, _In_opt_) + PUCHAR MinorFunctions, + _In_ + ULONG NumMinorFunctions + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetRemoveLockOptions)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_REMOVE_LOCK_OPTIONS Options + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT* DeviceInit, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + _Out_ + WDFDEVICE* Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetStaticStopRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN Stoppable + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateDeviceInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + BOOLEAN IsInterfaceEnabled + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateSymbolicLink)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING SymbolicLinkName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPnpCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPowerCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetBusInformationForChildren)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PPNP_BUS_INFORMATION BusInformation + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceIndicateWakeStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + NTSTATUS WaitWakeStatus + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetFailed)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_FAILED_ACTION FailedAction + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfDeviceGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PFILE_OBJECT FileObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceEnqueueRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfDeviceGetDefaultQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureRequestDispatching)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFQUEUE Queue, + _In_ + _Strict_type_match_ + WDF_REQUEST_TYPE RequestType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDisptach, + _In_opt_ + WDFCONTEXT DriverContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +POWER_ACTION +VFWDFEXPORT(WdfDeviceGetSystemPowerAction)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG Size, + _In_opt_ + PVOID Data + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaEnablerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DMA_ENABLER_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDMAENABLER* DmaEnablerHandle + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaEnablerConfigureSystemProfile)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig, + _In_ + WDF_DMA_DIRECTION ConfigDirection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaEnablerGetMaximumLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(MaximumFragments == 0, __drv_reportError(MaximumFragments cannot be zero)) + size_t MaximumFragments + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaEnablerGetFragmentLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + WDF_DMA_DIRECTION DmaDirection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDMA_ADAPTER +VFWDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + WDF_DMA_DIRECTION DmaDirection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDMATRANSACTION* DmaTransaction + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionInitialize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + PMDL Mdl, + _In_ + PVOID VirtualAddress, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionInitializeUsingOffset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + PMDL Mdl, + _In_ + size_t Offset, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionInitializeUsingRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionExecute)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + WDFCONTEXT Context + ); + +_Success_(TRUE) +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionDmaCompleted)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _Out_ + NTSTATUS* Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionDmaCompletedWithLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t TransferredLength, + _Out_ + NTSTATUS* Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionDmaCompletedFinal)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t FinalTransferredLength, + _Out_ + NTSTATUS* Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaTransactionGetBytesTransferred)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetMaximumLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t MaximumLength + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFREQUEST +VFWDFEXPORT(WdfDmaTransactionGetRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfDmaTransactionGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionGetTransferInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _Out_opt_ + ULONG* MapRegisterCount, + _Out_opt_ + ULONG* ScatterGatherElementCount + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL ConfigureRoutine, + _In_opt_ + PVOID ConfigureContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE DmaCompletionRoutine, + _In_opt_ + PVOID DmaCompletionContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetImmediateExecution)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + BOOLEAN UseImmediateExecution + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionAllocateResources)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + ULONG RequiredMapRegisters, + _In_ + PFN_WDF_RESERVE_DMA EvtReserveDmaFunction, + _In_ + PVOID EvtReserveDmaContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + ULONG Offset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionFreeResources)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionCancel)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfDmaTransactionWdmGetTransferContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionStopSystemTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDpcCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_DPC_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDPC* Dpc + ); + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDpcEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ); + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(HIGH_LEVEL)) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDpcCancel)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc, + _In_ + BOOLEAN Wait + ); + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfDpcGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ); + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +PKDPC +VFWDFEXPORT(WdfDpcWdmGetDpc)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PCUNICODE_STRING RegistryPath, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + _In_ + PWDF_DRIVER_CONFIG DriverConfig, + _Out_opt_ + WDFDRIVER* Driver + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWSTR +VFWDFEXPORT(WdfDriverGetRegistryPath)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDRIVER_OBJECT +VFWDFEXPORT(WdfDriverWdmGetDriverObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverOpenParametersRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +VFWDFEXPORT(WdfWdmDriverGetWdfDriverHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverRegisterTraceInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PFN_WDF_TRACE_CALLBACK EvtTraceCallback, + _In_ + PVOID ControlBlock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverRetrieveVersionString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDriverIsVersionAvailable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfFdoInitWdmGetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FDO_EVENT_CALLBACKS FdoEventCallbacks + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetFilter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetDefaultChildListConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_CHILD_LIST_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DefaultChildListAttributes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoQueryForInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_ + LPCGUID InterfaceType, + _Out_ + PINTERFACE Interface, + _In_ + USHORT Size, + _In_ + USHORT Version, + _In_opt_ + PVOID InterfaceSpecificData + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFCHILDLIST +VFWDFEXPORT(WdfFdoGetDefaultChildList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoAddStaticChild)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_ + WDFDEVICE Child + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoLockStaticChildListForIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfFdoRetrieveNextStaticChild)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_opt_ + WDFDEVICE PreviousChild, + _In_ + ULONG Flags + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoUnlockStaticChildListFromIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PUNICODE_STRING +VFWDFEXPORT(WdfFileObjectGetFileName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfFileObjectGetFlags)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfFileObjectGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PFILE_OBJECT +VFWDFEXPORT(WdfFileObjectWdmGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfInterruptCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_INTERRUPT_CONFIG Configuration, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFINTERRUPT* Interrupt + ); + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueDpcForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptSynchronize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + _In_ + WDFCONTEXT Context + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptEnable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptDisable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +WDFAPI +PKINTERRUPT +VFWDFEXPORT(WdfInterruptWdmGetInterrupt)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptGetInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _Out_ + PWDF_INTERRUPT_INFO Info + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + WDF_INTERRUPT_POLICY Policy, + _In_ + WDF_INTERRUPT_PRIORITY Priority, + _In_ + KAFFINITY TargetProcessorSet + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetExtendedPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ); + +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfInterruptGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_Post_satisfies_(return == 1 || return == 0) +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptTryToAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReportActive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReportInactive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_IO_QUEUE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + _Out_opt_ + WDFQUEUE* Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_QUEUE_STATE +VFWDFEXPORT(WdfIoQueueGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_opt_ + PULONG QueueRequests, + _Out_opt_ + PULONG DriverRequests + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopComplete, + _When_(StopComplete != 0, _In_) + _When_(StopComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoQueueGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveNextRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFFILEOBJECT FileObject, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueFindRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + WDFREQUEST FoundRequest, + _In_opt_ + WDFFILEOBJECT FileObject, + _Inout_opt_ + PWDF_REQUEST_PARAMETERS Parameters, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFREQUEST FoundRequest, + _Out_ + WDFREQUEST* OutRequest + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrainSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrain)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + _When_(DrainComplete != 0, _In_) + _When_(DrainComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + _When_(PurgeComplete != 0, _In_) + _When_(PurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueReadyNotify)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + PFN_WDF_IO_QUEUE_STATE QueueReady, + _In_opt_ + WDFCONTEXT Context + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueAssignForwardProgressPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY ForwardProgressPolicy + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + _When_(StopAndPurgeComplete != 0, _In_) + _When_(StopAndPurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + _Out_ + WDFIOTARGET* IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetOpen)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetCloseForQueryRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_When_(Action == 3, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1 || Action == 2, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_SENT_IO_ACTION Action + ); + +_When_(Action == 2, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_PURGE_IO_ACTION Action + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_TARGET_STATE +VFWDFEXPORT(WdfIoTargetGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoTargetGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetQueryTargetProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _When_(BufferLength != 0, _Out_writes_bytes_to_opt_(BufferLength, *ResultLength)) + _When_(BufferLength == 0, _Out_opt_) + PVOID PropertyBuffer, + _Deref_out_range_(<=,BufferLength) + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetQueryForInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + LPCGUID InterfaceType, + _Out_ + PINTERFACE Interface, + _In_ + USHORT Size, + _In_ + USHORT Version, + _In_opt_ + PVOID InterfaceSpecificData + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PFILE_OBJECT +VFWDFEXPORT(WdfIoTargetWdmGetTargetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg1, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg2, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg4, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY OtherArg1, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg1Offset, + _In_opt_ + WDFMEMORY OtherArg2, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg2Offset, + _In_opt_ + WDFMEMORY OtherArg4, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg4Offset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + ULONG PoolTag, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory, + _Outptr_opt_result_bytebuffer_(BufferSize) + PVOID* Buffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreatePreallocated)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ __drv_aliasesMem + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfMemoryGetBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Out_opt_ + size_t* BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyToBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY SourceMemory, + _In_ + size_t SourceOffset, + _Out_writes_bytes_( NumBytesToCopyTo ) + PVOID Buffer, + _In_ + _When_(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyFromBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY DestinationMemory, + _In_ + size_t DestinationOffset, + _In_ + PVOID Buffer, + _In_ + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ); + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfLookasideListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LookasideAttributes, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _In_opt_ + ULONG PoolTag, + _Out_ + WDFLOOKASIDE* Lookaside + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreateFromLookaside)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFLOOKASIDE Lookaside, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceMiniportCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + PDEVICE_OBJECT DeviceObject, + _In_opt_ + PDEVICE_OBJECT AttachedDeviceObject, + _In_opt_ + PDEVICE_OBJECT Pdo, + _Out_ + WDFDEVICE* Device + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfDriverMiniportUnload)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +WDFAPI +PVOID +FASTCALL +VFWDFEXPORT(WdfObjectGetTypedContextWorker)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ); + +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectAllocateContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PWDF_OBJECT_ATTRIBUTES ContextAttributes, + _Outptr_opt_ + PVOID* Context + ); + +WDFAPI +WDFOBJECT +FASTCALL +VFWDFEXPORT(WdfObjectContextGetObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PVOID ContextPointer + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDereferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFOBJECT* Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDelete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectQuery)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object, + _In_ + CONST GUID* Guid, + _In_ + ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFDEVICE_INIT +VFWDFEXPORT(WdfPdoInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE ParentDevice + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoInitSetEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PDO_EVENT_CALLBACKS DispatchTable + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignDeviceID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING DeviceID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignInstanceID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING InstanceID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAddHardwareID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING HardwareID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAddCompatibleID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING CompatibleID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignContainerID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING ContainerID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAddDeviceText)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING DeviceDescription, + _In_ + PCUNICODE_STRING DeviceLocation, + _In_ + LCID LocaleId + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoInitSetDefaultLocale)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + LCID LocaleId + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignRawDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + CONST GUID* DeviceClassGuid + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoInitAllowForwardingRequestToParent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoMarkMissing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoRequestEject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfPdoGetParent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoRetrieveIdentificationDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoRetrieveAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoUpdateAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoClearEjectionRelationsDevices)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAddQueryInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_QUERY_INTERFACE_CONFIG InterfaceConfig + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryOpenKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryCreateKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_ + ULONG CreateOptions, + _Out_opt_ + PULONG CreateDisposition, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRegistryClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfRegistryWdmGetHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueLength, + _Out_writes_bytes_opt_( ValueLength) + PVOID Value, + _Out_opt_ + PULONG ValueLengthQueried, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _Out_ + WDFMEMORY* Memory, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_opt_ + PUSHORT ValueByteLength, + _Inout_opt_ + PUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_ + PULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + ULONG ValueLength, + _In_reads_( ValueLength) + PVOID Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET MemoryOffsets + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFCOLLECTION StringsCollection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + PCUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_opt_ + WDFIOTARGET IoTarget, + _Out_ + WDFREQUEST* Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestCreateFromIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_ + PIRP Irp, + _In_ + BOOLEAN RequestFreesIrp, + _Out_ + WDFREQUEST* Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestReuse)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestChangeTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestWdmFormatUsingStackLocation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PIO_STACK_LOCATION Stack + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS == 0, _Must_inspect_result_) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestSend)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET Target, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS Options + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestGetStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestMarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestMarkCancelableEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestUnmarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsCanceled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestCancelSentRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsFrom32BitProcess)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetCompletionRoutine)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_opt_ + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ __drv_aliasesMem + WDFCONTEXT CompletionContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetCompletionParams)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_COMPLETION_PARAMS Params + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestAllocateTimer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestComplete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestCompleteWithPriorityBoost)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + CCHAR PriorityBoost + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestCompleteWithInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_PARAMETERS Parameters + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredSize, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputWdmMdl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Outptr_ + PMDL* Mdl + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputWdmMdl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Outptr_ + PMDL* Mdl + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_maybenull_(*Length) + PVOID* InputBuffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_maybenull_(*Length) + PVOID* OutputBuffer, + _Out_opt_ + size_t* Length + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG_PTR +VFWDFEXPORT(WdfRequestGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfRequestGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_reads_bytes_(Length) + PVOID Buffer, + _In_ + size_t Length, + _Out_ + WDFMEMORY* MemoryObject + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_reads_bytes_(Length) + PVOID Buffer, + _In_ + size_t Length, + _Out_ + WDFMEMORY* MemoryObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +KPROCESSOR_MODE +VFWDFEXPORT(WdfRequestGetRequestorMode)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestForwardToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE DestinationQueue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfRequestGetIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRequeue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestStopAcknowledge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN Requeue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PIRP +VFWDFEXPORT(WdfRequestWdmGetIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsReserved)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestForwardToParentDeviceIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE ParentDeviceQueue, + _In_ + PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG SlotNumber + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + _Strict_type_match_ + INTERFACE_TYPE InterfaceType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceRequirementsListAppendIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceRequirementsListInsertIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfIoResourceRequirementsListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIORESLIST +VFWDFEXPORT(WdfIoResourceRequirementsListGetIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFIORESLIST* ResourceList + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceListAppendDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceListInsertDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceListUpdateDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfIoResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PIO_RESOURCE_DESCRIPTOR +VFWDFEXPORT(WdfIoResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceListRemoveByDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCmResourceListAppendDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCmResourceListInsertDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCmResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PCM_PARTIAL_RESOURCE_DESCRIPTOR +VFWDFEXPORT(WdfCmResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCmResourceListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCmResourceListRemoveByDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfStringCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PCUNICODE_STRING UnicodeString, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringAttributes, + _Out_ + WDFSTRING* String + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfStringGetUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFSTRING String, + _Out_ + PUNICODE_STRING UnicodeString + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LockAttributes, + _Out_ + WDFWAITLOCK* Lock + ); + +_When_(Timeout == NULL, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Timeout != NULL && *Timeout == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Timeout != NULL && *Timeout != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +_Always_(_When_(Timeout == NULL, _Acquires_lock_(Lock))) +_When_(Timeout != NULL && return == STATUS_SUCCESS, _Acquires_lock_(Lock)) +_When_(Timeout != NULL, _Must_inspect_result_) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + WDFWAITLOCK Lock, + _In_opt_ + PLONGLONG Timeout + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWaitLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFWAITLOCK Lock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfSpinLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + _Out_ + WDFSPINLOCK* SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + _IRQL_saves_ + WDFSPINLOCK SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_min_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + _IRQL_restores_ + WDFSPINLOCK SpinLock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfTimerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_TIMER_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFTIMER* Timer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + LONGLONG DueTime + ); + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + BOOLEAN Wait + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfTimerGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_USB_DEVICE_CREATE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PWDF_USB_DEVICE_INFORMATION Information + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_writes_bytes_to_opt_(*ConfigDescriptorLength,*ConfigDescriptorLength) + PVOID ConfigDescriptor, + _Inout_ + PUSHORT ConfigDescriptorLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_writes_opt_(*NumCharacters) + PUSHORT String, + _Inout_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + _Out_ + WDFMEMORY* StringMemory, + _Out_opt_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET Offset, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +UCHAR +VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipeAttributes, + _Inout_ + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +USBD_CONFIGURATION_HANDLE +VFWDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PULONG CurrentFrameNumber + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesTransferred + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + WDFMEMORY TransferMemory, + _In_opt_ + PWDFMEMORY_OFFSET TransferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_reads_(_Inexpressible_("union bug in SAL")) + PURB Urb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY UrbMemory, + _In_opt_ + PWDFMEMORY_OFFSET UrbMemoryOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + CONST GUID* CapabilityType, + _In_ + ULONG CapabilityBufferLength, + _When_(CapabilityBufferLength == 0, _Out_opt_) + _When_(CapabilityBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(CapabilityBufferLength)) + _When_(CapabilityBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + _Out_opt_ + _When_(ResultLength != NULL,_Deref_out_range_(<=,CapabilityBufferLength)) + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFMEMORY* UrbMemory, + _Outptr_opt_result_bytebuffer_(sizeof(URB)) + PURB* Urb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + ULONG NumberOfIsochPackets, + _Out_ + WDFMEMORY* UrbMemory, + _Outptr_opt_result_bytebuffer_(GET_ISO_URB_SIZE(NumberOfIsochPackets)) + PURB* Urb + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _Out_ + PWDF_USB_PIPE_INFORMATION PipeInformation + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_USB_PIPE_TYPE +VFWDFEXPORT(WdfUsbTargetPipeGetType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY WriteMemory, + _In_opt_ + PWDFMEMORY_OFFSET WriteOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY ReadMemory, + _In_opt_ + PWDFMEMORY_OFFSET ReadOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_reads_(_Inexpressible_("union bug in SAL")) + PURB Urb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE PIPE, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY UrbMemory, + _In_opt_ + PWDFMEMORY_OFFSET UrbMemoryOffset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _Out_ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbInterfaceSelectSetting)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + _In_ + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _In_ + UCHAR EndpointIndex, + _Out_ + PWDF_USB_PIPE_INFORMATION EndpointInfo + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBINTERFACE +VFWDFEXPORT(WdfUsbTargetDeviceGetInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + UCHAR InterfaceIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE Interface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBPIPE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR PipeIndex, + _Out_opt_ + PWDF_USB_PIPE_INFORMATION PipeInfo + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +USBD_PIPE_HANDLE +VFWDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE UsbPipe + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierDbgBreakPoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +WDFAPI +PVOID +VFWDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiProviderCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + _Out_ + WDFWMIPROVIDER* WmiProvider + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfWmiProviderGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfWmiProviderIsEnabled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider, + _In_ + WDF_WMI_PROVIDER_CONTROL ProviderControl + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONGLONG +VFWDFEXPORT(WdfWmiProviderGetTracingHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiInstanceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_WMI_INSTANCE_CONFIG InstanceConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES InstanceAttributes, + _Out_opt_ + WDFWMIINSTANCE* Instance + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiInstanceRegister)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWmiInstanceDeregister)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfWmiInstanceGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFWMIPROVIDER +VFWDFEXPORT(WdfWmiInstanceGetProvider)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiInstanceFireEvent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance, + _In_opt_ + ULONG EventDataSize, + _In_reads_bytes_opt_(EventDataSize) + PVOID EventData + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWorkItemCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_WORKITEM_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFWORKITEM* WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfWorkItemGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemFlush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + + +#ifdef VF_FX_DYNAMICS_GENERATE_TABLE + +WDFVERSION VfWdfVersion = { + sizeof(WDFVERSION), + sizeof(WDFFUNCTIONS)/sizeof(PVOID), + { + VFWDFEXPORT(WdfChildListCreate), + VFWDFEXPORT(WdfChildListGetDevice), + VFWDFEXPORT(WdfChildListRetrievePdo), + VFWDFEXPORT(WdfChildListRetrieveAddressDescription), + VFWDFEXPORT(WdfChildListBeginScan), + VFWDFEXPORT(WdfChildListEndScan), + VFWDFEXPORT(WdfChildListBeginIteration), + VFWDFEXPORT(WdfChildListRetrieveNextDevice), + VFWDFEXPORT(WdfChildListEndIteration), + VFWDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent), + VFWDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing), + VFWDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent), + VFWDFEXPORT(WdfChildListRequestChildEject), + VFWDFEXPORT(WdfCollectionCreate), + VFWDFEXPORT(WdfCollectionGetCount), + VFWDFEXPORT(WdfCollectionAdd), + VFWDFEXPORT(WdfCollectionRemove), + VFWDFEXPORT(WdfCollectionRemoveItem), + VFWDFEXPORT(WdfCollectionGetItem), + VFWDFEXPORT(WdfCollectionGetFirstItem), + VFWDFEXPORT(WdfCollectionGetLastItem), + VFWDFEXPORT(WdfCommonBufferCreate), + VFWDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress), + VFWDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress), + VFWDFEXPORT(WdfCommonBufferGetLength), + VFWDFEXPORT(WdfControlDeviceInitAllocate), + VFWDFEXPORT(WdfControlDeviceInitSetShutdownNotification), + VFWDFEXPORT(WdfControlFinishInitializing), + VFWDFEXPORT(WdfDeviceGetDeviceState), + VFWDFEXPORT(WdfDeviceSetDeviceState), + VFWDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle), + VFWDFEXPORT(WdfDeviceWdmGetDeviceObject), + VFWDFEXPORT(WdfDeviceWdmGetAttachedDevice), + VFWDFEXPORT(WdfDeviceWdmGetPhysicalDevice), + VFWDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp), + VFWDFEXPORT(WdfDeviceAddDependentUsageDeviceObject), + VFWDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice), + VFWDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice), + VFWDFEXPORT(WdfDeviceClearRemovalRelationsDevices), + VFWDFEXPORT(WdfDeviceGetDriver), + VFWDFEXPORT(WdfDeviceRetrieveDeviceName), + VFWDFEXPORT(WdfDeviceAssignMofResourceName), + VFWDFEXPORT(WdfDeviceGetIoTarget), + VFWDFEXPORT(WdfDeviceGetDevicePnpState), + VFWDFEXPORT(WdfDeviceGetDevicePowerState), + VFWDFEXPORT(WdfDeviceGetDevicePowerPolicyState), + VFWDFEXPORT(WdfDeviceAssignS0IdleSettings), + VFWDFEXPORT(WdfDeviceAssignSxWakeSettings), + VFWDFEXPORT(WdfDeviceOpenRegistryKey), + VFWDFEXPORT(WdfDeviceSetSpecialFileSupport), + VFWDFEXPORT(WdfDeviceSetCharacteristics), + VFWDFEXPORT(WdfDeviceGetCharacteristics), + VFWDFEXPORT(WdfDeviceGetAlignmentRequirement), + VFWDFEXPORT(WdfDeviceSetAlignmentRequirement), + VFWDFEXPORT(WdfDeviceInitFree), + VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks), + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks), + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership), + VFWDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback), + VFWDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback), + VFWDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback), + VFWDFEXPORT(WdfDeviceInitSetIoType), + VFWDFEXPORT(WdfDeviceInitSetExclusive), + VFWDFEXPORT(WdfDeviceInitSetPowerNotPageable), + VFWDFEXPORT(WdfDeviceInitSetPowerPageable), + VFWDFEXPORT(WdfDeviceInitSetPowerInrush), + VFWDFEXPORT(WdfDeviceInitSetDeviceType), + VFWDFEXPORT(WdfDeviceInitAssignName), + VFWDFEXPORT(WdfDeviceInitAssignSDDLString), + VFWDFEXPORT(WdfDeviceInitSetDeviceClass), + VFWDFEXPORT(WdfDeviceInitSetCharacteristics), + VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig), + VFWDFEXPORT(WdfDeviceInitSetRequestAttributes), + VFWDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback), + VFWDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback), + VFWDFEXPORT(WdfDeviceCreate), + VFWDFEXPORT(WdfDeviceSetStaticStopRemove), + VFWDFEXPORT(WdfDeviceCreateDeviceInterface), + VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState), + VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString), + VFWDFEXPORT(WdfDeviceCreateSymbolicLink), + VFWDFEXPORT(WdfDeviceQueryProperty), + VFWDFEXPORT(WdfDeviceAllocAndQueryProperty), + VFWDFEXPORT(WdfDeviceSetPnpCapabilities), + VFWDFEXPORT(WdfDeviceSetPowerCapabilities), + VFWDFEXPORT(WdfDeviceSetBusInformationForChildren), + VFWDFEXPORT(WdfDeviceIndicateWakeStatus), + VFWDFEXPORT(WdfDeviceSetFailed), + VFWDFEXPORT(WdfDeviceStopIdleNoTrack), + VFWDFEXPORT(WdfDeviceResumeIdleNoTrack), + VFWDFEXPORT(WdfDeviceGetFileObject), + VFWDFEXPORT(WdfDeviceEnqueueRequest), + VFWDFEXPORT(WdfDeviceGetDefaultQueue), + VFWDFEXPORT(WdfDeviceConfigureRequestDispatching), + VFWDFEXPORT(WdfDmaEnablerCreate), + VFWDFEXPORT(WdfDmaEnablerGetMaximumLength), + VFWDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements), + VFWDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements), + VFWDFEXPORT(WdfDmaTransactionCreate), + VFWDFEXPORT(WdfDmaTransactionInitialize), + VFWDFEXPORT(WdfDmaTransactionInitializeUsingRequest), + VFWDFEXPORT(WdfDmaTransactionExecute), + VFWDFEXPORT(WdfDmaTransactionRelease), + VFWDFEXPORT(WdfDmaTransactionDmaCompleted), + VFWDFEXPORT(WdfDmaTransactionDmaCompletedWithLength), + VFWDFEXPORT(WdfDmaTransactionDmaCompletedFinal), + VFWDFEXPORT(WdfDmaTransactionGetBytesTransferred), + VFWDFEXPORT(WdfDmaTransactionSetMaximumLength), + VFWDFEXPORT(WdfDmaTransactionGetRequest), + VFWDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength), + VFWDFEXPORT(WdfDmaTransactionGetDevice), + VFWDFEXPORT(WdfDpcCreate), + VFWDFEXPORT(WdfDpcEnqueue), + VFWDFEXPORT(WdfDpcCancel), + VFWDFEXPORT(WdfDpcGetParentObject), + VFWDFEXPORT(WdfDpcWdmGetDpc), + VFWDFEXPORT(WdfDriverCreate), + VFWDFEXPORT(WdfDriverGetRegistryPath), + VFWDFEXPORT(WdfDriverWdmGetDriverObject), + VFWDFEXPORT(WdfDriverOpenParametersRegistryKey), + VFWDFEXPORT(WdfWdmDriverGetWdfDriverHandle), + VFWDFEXPORT(WdfDriverRegisterTraceInfo), + VFWDFEXPORT(WdfDriverRetrieveVersionString), + VFWDFEXPORT(WdfDriverIsVersionAvailable), + VFWDFEXPORT(WdfFdoInitWdmGetPhysicalDevice), + VFWDFEXPORT(WdfFdoInitOpenRegistryKey), + VFWDFEXPORT(WdfFdoInitQueryProperty), + VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty), + VFWDFEXPORT(WdfFdoInitSetEventCallbacks), + VFWDFEXPORT(WdfFdoInitSetFilter), + VFWDFEXPORT(WdfFdoInitSetDefaultChildListConfig), + VFWDFEXPORT(WdfFdoQueryForInterface), + VFWDFEXPORT(WdfFdoGetDefaultChildList), + VFWDFEXPORT(WdfFdoAddStaticChild), + VFWDFEXPORT(WdfFdoLockStaticChildListForIteration), + VFWDFEXPORT(WdfFdoRetrieveNextStaticChild), + VFWDFEXPORT(WdfFdoUnlockStaticChildListFromIteration), + VFWDFEXPORT(WdfFileObjectGetFileName), + VFWDFEXPORT(WdfFileObjectGetFlags), + VFWDFEXPORT(WdfFileObjectGetDevice), + VFWDFEXPORT(WdfFileObjectWdmGetFileObject), + VFWDFEXPORT(WdfInterruptCreate), + VFWDFEXPORT(WdfInterruptQueueDpcForIsr), + VFWDFEXPORT(WdfInterruptSynchronize), + VFWDFEXPORT(WdfInterruptAcquireLock), + VFWDFEXPORT(WdfInterruptReleaseLock), + VFWDFEXPORT(WdfInterruptEnable), + VFWDFEXPORT(WdfInterruptDisable), + VFWDFEXPORT(WdfInterruptWdmGetInterrupt), + VFWDFEXPORT(WdfInterruptGetInfo), + VFWDFEXPORT(WdfInterruptSetPolicy), + VFWDFEXPORT(WdfInterruptGetDevice), + VFWDFEXPORT(WdfIoQueueCreate), + VFWDFEXPORT(WdfIoQueueGetState), + VFWDFEXPORT(WdfIoQueueStart), + VFWDFEXPORT(WdfIoQueueStop), + VFWDFEXPORT(WdfIoQueueStopSynchronously), + VFWDFEXPORT(WdfIoQueueGetDevice), + VFWDFEXPORT(WdfIoQueueRetrieveNextRequest), + VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject), + VFWDFEXPORT(WdfIoQueueFindRequest), + VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest), + VFWDFEXPORT(WdfIoQueueDrainSynchronously), + VFWDFEXPORT(WdfIoQueueDrain), + VFWDFEXPORT(WdfIoQueuePurgeSynchronously), + VFWDFEXPORT(WdfIoQueuePurge), + VFWDFEXPORT(WdfIoQueueReadyNotify), + VFWDFEXPORT(WdfIoTargetCreate), + VFWDFEXPORT(WdfIoTargetOpen), + VFWDFEXPORT(WdfIoTargetCloseForQueryRemove), + VFWDFEXPORT(WdfIoTargetClose), + VFWDFEXPORT(WdfIoTargetStart), + VFWDFEXPORT(WdfIoTargetStop), + VFWDFEXPORT(WdfIoTargetGetState), + VFWDFEXPORT(WdfIoTargetGetDevice), + VFWDFEXPORT(WdfIoTargetQueryTargetProperty), + VFWDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty), + VFWDFEXPORT(WdfIoTargetQueryForInterface), + VFWDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject), + VFWDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice), + VFWDFEXPORT(WdfIoTargetWdmGetTargetFileObject), + VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle), + VFWDFEXPORT(WdfIoTargetSendReadSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForRead), + VFWDFEXPORT(WdfIoTargetSendWriteSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForWrite), + VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl), + VFWDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl), + VFWDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers), + VFWDFEXPORT(WdfMemoryCreate), + VFWDFEXPORT(WdfMemoryCreatePreallocated), + VFWDFEXPORT(WdfMemoryGetBuffer), + VFWDFEXPORT(WdfMemoryAssignBuffer), + VFWDFEXPORT(WdfMemoryCopyToBuffer), + VFWDFEXPORT(WdfMemoryCopyFromBuffer), + VFWDFEXPORT(WdfLookasideListCreate), + VFWDFEXPORT(WdfMemoryCreateFromLookaside), + VFWDFEXPORT(WdfDeviceMiniportCreate), + VFWDFEXPORT(WdfDriverMiniportUnload), + VFWDFEXPORT(WdfObjectGetTypedContextWorker), + VFWDFEXPORT(WdfObjectAllocateContext), + VFWDFEXPORT(WdfObjectContextGetObject), + VFWDFEXPORT(WdfObjectReferenceActual), + VFWDFEXPORT(WdfObjectDereferenceActual), + VFWDFEXPORT(WdfObjectCreate), + VFWDFEXPORT(WdfObjectDelete), + VFWDFEXPORT(WdfObjectQuery), + VFWDFEXPORT(WdfPdoInitAllocate), + VFWDFEXPORT(WdfPdoInitSetEventCallbacks), + VFWDFEXPORT(WdfPdoInitAssignDeviceID), + VFWDFEXPORT(WdfPdoInitAssignInstanceID), + VFWDFEXPORT(WdfPdoInitAddHardwareID), + VFWDFEXPORT(WdfPdoInitAddCompatibleID), + VFWDFEXPORT(WdfPdoInitAddDeviceText), + VFWDFEXPORT(WdfPdoInitSetDefaultLocale), + VFWDFEXPORT(WdfPdoInitAssignRawDevice), + VFWDFEXPORT(WdfPdoMarkMissing), + VFWDFEXPORT(WdfPdoRequestEject), + VFWDFEXPORT(WdfPdoGetParent), + VFWDFEXPORT(WdfPdoRetrieveIdentificationDescription), + VFWDFEXPORT(WdfPdoRetrieveAddressDescription), + VFWDFEXPORT(WdfPdoUpdateAddressDescription), + VFWDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice), + VFWDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice), + VFWDFEXPORT(WdfPdoClearEjectionRelationsDevices), + VFWDFEXPORT(WdfDeviceAddQueryInterface), + VFWDFEXPORT(WdfRegistryOpenKey), + VFWDFEXPORT(WdfRegistryCreateKey), + VFWDFEXPORT(WdfRegistryClose), + VFWDFEXPORT(WdfRegistryWdmGetHandle), + VFWDFEXPORT(WdfRegistryRemoveKey), + VFWDFEXPORT(WdfRegistryRemoveValue), + VFWDFEXPORT(WdfRegistryQueryValue), + VFWDFEXPORT(WdfRegistryQueryMemory), + VFWDFEXPORT(WdfRegistryQueryMultiString), + VFWDFEXPORT(WdfRegistryQueryUnicodeString), + VFWDFEXPORT(WdfRegistryQueryString), + VFWDFEXPORT(WdfRegistryQueryULong), + VFWDFEXPORT(WdfRegistryAssignValue), + VFWDFEXPORT(WdfRegistryAssignMemory), + VFWDFEXPORT(WdfRegistryAssignMultiString), + VFWDFEXPORT(WdfRegistryAssignUnicodeString), + VFWDFEXPORT(WdfRegistryAssignString), + VFWDFEXPORT(WdfRegistryAssignULong), + VFWDFEXPORT(WdfRequestCreate), + VFWDFEXPORT(WdfRequestCreateFromIrp), + VFWDFEXPORT(WdfRequestReuse), + VFWDFEXPORT(WdfRequestChangeTarget), + VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType), + VFWDFEXPORT(WdfRequestWdmFormatUsingStackLocation), + VFWDFEXPORT(WdfRequestSend), + VFWDFEXPORT(WdfRequestGetStatus), + VFWDFEXPORT(WdfRequestMarkCancelable), + VFWDFEXPORT(WdfRequestUnmarkCancelable), + VFWDFEXPORT(WdfRequestIsCanceled), + VFWDFEXPORT(WdfRequestCancelSentRequest), + VFWDFEXPORT(WdfRequestIsFrom32BitProcess), + VFWDFEXPORT(WdfRequestSetCompletionRoutine), + VFWDFEXPORT(WdfRequestGetCompletionParams), + VFWDFEXPORT(WdfRequestAllocateTimer), + VFWDFEXPORT(WdfRequestComplete), + VFWDFEXPORT(WdfRequestCompleteWithPriorityBoost), + VFWDFEXPORT(WdfRequestCompleteWithInformation), + VFWDFEXPORT(WdfRequestGetParameters), + VFWDFEXPORT(WdfRequestRetrieveInputMemory), + VFWDFEXPORT(WdfRequestRetrieveOutputMemory), + VFWDFEXPORT(WdfRequestRetrieveInputBuffer), + VFWDFEXPORT(WdfRequestRetrieveOutputBuffer), + VFWDFEXPORT(WdfRequestRetrieveInputWdmMdl), + VFWDFEXPORT(WdfRequestRetrieveOutputWdmMdl), + VFWDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer), + VFWDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer), + VFWDFEXPORT(WdfRequestSetInformation), + VFWDFEXPORT(WdfRequestGetInformation), + VFWDFEXPORT(WdfRequestGetFileObject), + VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForRead), + VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite), + VFWDFEXPORT(WdfRequestGetRequestorMode), + VFWDFEXPORT(WdfRequestForwardToIoQueue), + VFWDFEXPORT(WdfRequestGetIoQueue), + VFWDFEXPORT(WdfRequestRequeue), + VFWDFEXPORT(WdfRequestStopAcknowledge), + VFWDFEXPORT(WdfRequestWdmGetIrp), + VFWDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber), + VFWDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType), + VFWDFEXPORT(WdfIoResourceRequirementsListAppendIoResList), + VFWDFEXPORT(WdfIoResourceRequirementsListInsertIoResList), + VFWDFEXPORT(WdfIoResourceRequirementsListGetCount), + VFWDFEXPORT(WdfIoResourceRequirementsListGetIoResList), + VFWDFEXPORT(WdfIoResourceRequirementsListRemove), + VFWDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList), + VFWDFEXPORT(WdfIoResourceListCreate), + VFWDFEXPORT(WdfIoResourceListAppendDescriptor), + VFWDFEXPORT(WdfIoResourceListInsertDescriptor), + VFWDFEXPORT(WdfIoResourceListUpdateDescriptor), + VFWDFEXPORT(WdfIoResourceListGetCount), + VFWDFEXPORT(WdfIoResourceListGetDescriptor), + VFWDFEXPORT(WdfIoResourceListRemove), + VFWDFEXPORT(WdfIoResourceListRemoveByDescriptor), + VFWDFEXPORT(WdfCmResourceListAppendDescriptor), + VFWDFEXPORT(WdfCmResourceListInsertDescriptor), + VFWDFEXPORT(WdfCmResourceListGetCount), + VFWDFEXPORT(WdfCmResourceListGetDescriptor), + VFWDFEXPORT(WdfCmResourceListRemove), + VFWDFEXPORT(WdfCmResourceListRemoveByDescriptor), + VFWDFEXPORT(WdfStringCreate), + VFWDFEXPORT(WdfStringGetUnicodeString), + VFWDFEXPORT(WdfObjectAcquireLock), + VFWDFEXPORT(WdfObjectReleaseLock), + VFWDFEXPORT(WdfWaitLockCreate), + VFWDFEXPORT(WdfWaitLockAcquire), + VFWDFEXPORT(WdfWaitLockRelease), + VFWDFEXPORT(WdfSpinLockCreate), + VFWDFEXPORT(WdfSpinLockAcquire), + VFWDFEXPORT(WdfSpinLockRelease), + VFWDFEXPORT(WdfTimerCreate), + VFWDFEXPORT(WdfTimerStart), + VFWDFEXPORT(WdfTimerStop), + VFWDFEXPORT(WdfTimerGetParentObject), + VFWDFEXPORT(WdfUsbTargetDeviceCreate), + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation), + VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor), + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor), + VFWDFEXPORT(WdfUsbTargetDeviceQueryString), + VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString), + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString), + VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces), + VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig), + VFWDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle), + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber), + VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously), + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer), + VFWDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous), + VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously), + VFWDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously), + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort), + VFWDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously), + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb), + VFWDFEXPORT(WdfUsbTargetPipeGetInformation), + VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint), + VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint), + VFWDFEXPORT(WdfUsbTargetPipeGetType), + VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck), + VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite), + VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead), + VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader), + VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort), + VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset), + VFWDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb), + VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber), + VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints), + VFWDFEXPORT(WdfUsbInterfaceGetDescriptor), + VFWDFEXPORT(WdfUsbInterfaceSelectSetting), + VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation), + VFWDFEXPORT(WdfUsbTargetDeviceGetInterface), + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex), + VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes), + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe), + VFWDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle), + VFWDFEXPORT(WdfVerifierDbgBreakPoint), + VFWDFEXPORT(WdfVerifierKeBugCheck), + VFWDFEXPORT(WdfWmiProviderCreate), + VFWDFEXPORT(WdfWmiProviderGetDevice), + VFWDFEXPORT(WdfWmiProviderIsEnabled), + VFWDFEXPORT(WdfWmiProviderGetTracingHandle), + VFWDFEXPORT(WdfWmiInstanceCreate), + VFWDFEXPORT(WdfWmiInstanceRegister), + VFWDFEXPORT(WdfWmiInstanceDeregister), + VFWDFEXPORT(WdfWmiInstanceGetDevice), + VFWDFEXPORT(WdfWmiInstanceGetProvider), + VFWDFEXPORT(WdfWmiInstanceFireEvent), + VFWDFEXPORT(WdfWorkItemCreate), + VFWDFEXPORT(WdfWorkItemEnqueue), + VFWDFEXPORT(WdfWorkItemGetParentObject), + VFWDFEXPORT(WdfWorkItemFlush), + VFWDFEXPORT(WdfCommonBufferCreateWithConfig), + VFWDFEXPORT(WdfDmaEnablerGetFragmentLength), + VFWDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter), + VFWDFEXPORT(WdfUsbInterfaceGetNumSettings), + VFWDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject), + VFWDFEXPORT(WdfDeviceGetSystemPowerAction), + VFWDFEXPORT(WdfInterruptSetExtendedPolicy), + VFWDFEXPORT(WdfIoQueueAssignForwardProgressPolicy), + VFWDFEXPORT(WdfPdoInitAssignContainerID), + VFWDFEXPORT(WdfPdoInitAllowForwardingRequestToParent), + VFWDFEXPORT(WdfRequestMarkCancelableEx), + VFWDFEXPORT(WdfRequestIsReserved), + VFWDFEXPORT(WdfRequestForwardToParentDeviceIoQueue), + VFWDFEXPORT(WdfCxDeviceInitAllocate), + VFWDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback), + VFWDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback), + VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes), + VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig), + VFWDFEXPORT(WdfDeviceWdmDispatchIrp), + VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue), + VFWDFEXPORT(WdfDeviceInitSetRemoveLockOptions), + VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback), + VFWDFEXPORT(WdfDmaEnablerConfigureSystemProfile), + VFWDFEXPORT(WdfDmaTransactionInitializeUsingOffset), + VFWDFEXPORT(WdfDmaTransactionGetTransferInfo), + VFWDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback), + VFWDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback), + VFWDFEXPORT(WdfDmaTransactionSetImmediateExecution), + VFWDFEXPORT(WdfDmaTransactionAllocateResources), + VFWDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset), + VFWDFEXPORT(WdfDmaTransactionFreeResources), + VFWDFEXPORT(WdfDmaTransactionCancel), + VFWDFEXPORT(WdfDmaTransactionWdmGetTransferContext), + VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr), + VFWDFEXPORT(WdfInterruptTryToAcquireLock), + VFWDFEXPORT(WdfIoQueueStopAndPurge), + VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously), + VFWDFEXPORT(WdfIoTargetPurge), + VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters), + VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability), + VFWDFEXPORT(WdfUsbTargetDeviceCreateUrb), + VFWDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb), + VFWDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings), + VFWDFEXPORT(WdfDmaTransactionStopSystemTransfer), + VFWDFEXPORT(WdfCxVerifierKeBugCheck), + VFWDFEXPORT(WdfInterruptReportActive), + VFWDFEXPORT(WdfInterruptReportInactive), + VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure), + VFWDFEXPORT(WdfGetTriageInfo), + VFWDFEXPORT(WdfDeviceInitSetIoTypeEx), + VFWDFEXPORT(WdfDeviceQueryPropertyEx), + VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx), + VFWDFEXPORT(WdfDeviceAssignProperty), + VFWDFEXPORT(WdfFdoInitQueryPropertyEx), + VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx), + VFWDFEXPORT(WdfDeviceStopIdleActual), + VFWDFEXPORT(WdfDeviceResumeIdleActual), + VFWDFEXPORT(WdfDeviceGetSelfIoTarget), + VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget), + VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue), + VFWDFEXPORT(WdfDeviceOpenDevicemapKey), + } +}; + +#endif // VF_FX_DYNAMICS_GENERATE_TABLE + +#endif // _VFFXDYNAMICS_H_ + diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf10.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf10.h new file mode 100644 index 00000000000..df34914553b --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf10.h @@ -0,0 +1,2173 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _WDF_V1_0_TYPES_H_ +#define _WDF_V1_0_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_0 { + WdfFunctionTableNumEntries_V1_0 = 383, +} WDFFUNCENUM_V1_0; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_0 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_0; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_0 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_0; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_0 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_0; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_0 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_0; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_0 *PWDF_CHILD_RETRIEVE_INFO_V1_0; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_0 *PCWDF_CHILD_RETRIEVE_INFO_V1_0; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_0 *PWDF_CHILD_LIST_CONFIG_V1_0; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_0 *PCWDF_CHILD_LIST_CONFIG_V1_0; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_0 *PWDF_CHILD_LIST_ITERATOR_V1_0; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_0 *PCWDF_CHILD_LIST_ITERATOR_V1_0; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_0 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_0; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_0 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_0; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_0 *PWDF_FILEOBJECT_CONFIG_V1_0; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_0 *PCWDF_FILEOBJECT_CONFIG_V1_0; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_0 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_0; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_0 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_0; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_0 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_0; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_0 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_0; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_0 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_0; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_0 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_0; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_0 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_0; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_0 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_0; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_0 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_0; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_0 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_0; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0; +typedef struct _WDF_DEVICE_STATE_V1_0 *PWDF_DEVICE_STATE_V1_0; +typedef const struct _WDF_DEVICE_STATE_V1_0 *PCWDF_DEVICE_STATE_V1_0; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_0 *PWDF_DEVICE_PNP_CAPABILITIES_V1_0; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_0 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_0; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_0 *PWDF_DEVICE_POWER_CAPABILITIES_V1_0; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_0 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_0; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_0 *PWDF_DMA_ENABLER_CONFIG_V1_0; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_0 *PCWDF_DMA_ENABLER_CONFIG_V1_0; +typedef struct _WDF_DPC_CONFIG_V1_0 *PWDF_DPC_CONFIG_V1_0; +typedef const struct _WDF_DPC_CONFIG_V1_0 *PCWDF_DPC_CONFIG_V1_0; +typedef struct _WDF_DRIVER_CONFIG_V1_0 *PWDF_DRIVER_CONFIG_V1_0; +typedef const struct _WDF_DRIVER_CONFIG_V1_0 *PCWDF_DRIVER_CONFIG_V1_0; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_0 *PWDF_FDO_EVENT_CALLBACKS_V1_0; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_0 *PCWDF_FDO_EVENT_CALLBACKS_V1_0; +typedef struct _WDF_DRIVER_GLOBALS_V1_0 *PWDF_DRIVER_GLOBALS_V1_0; +typedef const struct _WDF_DRIVER_GLOBALS_V1_0 *PCWDF_DRIVER_GLOBALS_V1_0; +typedef struct _WDF_INTERRUPT_CONFIG_V1_0 *PWDF_INTERRUPT_CONFIG_V1_0; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_0 *PCWDF_INTERRUPT_CONFIG_V1_0; +typedef struct _WDF_INTERRUPT_INFO_V1_0 *PWDF_INTERRUPT_INFO_V1_0; +typedef const struct _WDF_INTERRUPT_INFO_V1_0 *PCWDF_INTERRUPT_INFO_V1_0; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_0 *PWDF_IO_QUEUE_CONFIG_V1_0; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_0 *PCWDF_IO_QUEUE_CONFIG_V1_0; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_0 *PWDF_IO_TARGET_OPEN_PARAMS_V1_0; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_0 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_0; +typedef struct _WDFMEMORY_OFFSET_V1_0 *PWDFMEMORY_OFFSET_V1_0; +typedef const struct _WDFMEMORY_OFFSET_V1_0 *PCWDFMEMORY_OFFSET_V1_0; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_0 *PWDF_MEMORY_DESCRIPTOR_V1_0; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_0 *PCWDF_MEMORY_DESCRIPTOR_V1_0; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_0 *PWDF_OBJECT_ATTRIBUTES_V1_0; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_0 *PCWDF_OBJECT_ATTRIBUTES_V1_0; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_0; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_0; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_0 *PWDF_PDO_EVENT_CALLBACKS_V1_0; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_0 *PCWDF_PDO_EVENT_CALLBACKS_V1_0; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_0 *PWDF_QUERY_INTERFACE_CONFIG_V1_0; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_0 *PCWDF_QUERY_INTERFACE_CONFIG_V1_0; +typedef struct _WDF_REQUEST_PARAMETERS_V1_0 *PWDF_REQUEST_PARAMETERS_V1_0; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_0 *PCWDF_REQUEST_PARAMETERS_V1_0; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_0 *PWDF_REQUEST_COMPLETION_PARAMS_V1_0; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_0 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_0; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_0 *PWDF_REQUEST_REUSE_PARAMS_V1_0; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_0 *PCWDF_REQUEST_REUSE_PARAMS_V1_0; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_0 *PWDF_REQUEST_SEND_OPTIONS_V1_0; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_0 *PCWDF_REQUEST_SEND_OPTIONS_V1_0; +typedef struct _WDF_TIMER_CONFIG_V1_0 *PWDF_TIMER_CONFIG_V1_0; +typedef const struct _WDF_TIMER_CONFIG_V1_0 *PCWDF_TIMER_CONFIG_V1_0; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_0 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_0; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_0 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_0; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_0 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_0; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_0 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_0; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_0 *PWDF_USB_DEVICE_INFORMATION_V1_0; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_0 *PCWDF_USB_DEVICE_INFORMATION_V1_0; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_0 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_0; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_0 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_0; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_0 *PWDF_USB_PIPE_INFORMATION_V1_0; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_0 *PCWDF_USB_PIPE_INFORMATION_V1_0; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_0 *PWDF_WMI_PROVIDER_CONFIG_V1_0; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_0 *PCWDF_WMI_PROVIDER_CONFIG_V1_0; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_0 *PWDF_WMI_INSTANCE_CONFIG_V1_0; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_0 *PCWDF_WMI_INSTANCE_CONFIG_V1_0; +typedef struct _WDF_WORKITEM_CONFIG_V1_0 *PWDF_WORKITEM_CONFIG_V1_0; +typedef const struct _WDF_WORKITEM_CONFIG_V1_0 *PCWDF_WORKITEM_CONFIG_V1_0; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_0 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_0; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_0; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_0 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_0, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_0; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_0 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_0 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_0, *PWDF_CHILD_RETRIEVE_INFO_V1_0; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_0, *PWDF_CHILD_LIST_CONFIG_V1_0; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_0, *PWDF_CHILD_LIST_ITERATOR_V1_0; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfClassExtension.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_0 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_0 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_0, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_0; + +// End of versioning of structures for wdfClassExtension.h + +// +// Versioning of structures for wdfClassExtensionList.h +// +// End of versioning of structures for wdfClassExtensionList.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_0, *PWDF_FILEOBJECT_CONFIG_V1_0; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_0 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_0; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_0 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_0; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_0 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_0; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_0, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_0; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_0, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_0; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_0; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_0; + +typedef struct _WDF_DEVICE_STATE_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_0, *PWDF_DEVICE_STATE_V1_0; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_0, *PWDF_DEVICE_PNP_CAPABILITIES_V1_0; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_0, *PWDF_DEVICE_POWER_CAPABILITIES_V1_0; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + +} WDF_DMA_ENABLER_CONFIG_V1_0, *PWDF_DMA_ENABLER_CONFIG_V1_0; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_0 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_0, *PWDF_DPC_CONFIG_V1_0; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + +} WDF_DRIVER_CONFIG_V1_0, *PWDF_DRIVER_CONFIG_V1_0; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_0; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_0, *PWDF_FDO_EVENT_CALLBACKS_V1_0; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_0 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_0, *PWDF_DRIVER_GLOBALS_V1_0; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_0 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_0, *PWDF_INTERRUPT_CONFIG_V1_0; + +typedef struct _WDF_INTERRUPT_INFO_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PHYSICAL_ADDRESS MessageAddress; + + KAFFINITY TargetProcessorSet; + + ULONG MessageData; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + +} WDF_INTERRUPT_INFO_V1_0, *PWDF_INTERRUPT_INFO_V1_0; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_0 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + +} WDF_IO_QUEUE_CONFIG_V1_0, *PWDF_IO_QUEUE_CONFIG_V1_0; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_0, *PWDF_IO_TARGET_OPEN_PARAMS_V1_0; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_0 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_0, *PWDFMEMORY_OFFSET_V1_0; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_0 { + + + + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_0 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_0, *PWDF_MEMORY_DESCRIPTOR_V1_0; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_0 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_0 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_0, *PWDF_OBJECT_ATTRIBUTES_V1_0; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_0; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_0 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_0, *PWDF_PDO_EVENT_CALLBACKS_V1_0; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_0 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + + + + // + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_0, *PWDF_QUERY_INTERFACE_CONFIG_V1_0; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_0 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_0, *PWDF_REQUEST_PARAMETERS_V1_0; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_0 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_0, *PWDF_REQUEST_COMPLETION_PARAMS_V1_0; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_0, *PWDF_REQUEST_REUSE_PARAMS_V1_0; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_0, *PWDF_REQUEST_SEND_OPTIONS_V1_0; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_0 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + LONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_TIMER_CONFIG_V1_0, *PWDF_TIMER_CONFIG_V1_0; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_0 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_0, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_0; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_0 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_0 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_0, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_0; + + + + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_0, *PWDF_USB_DEVICE_INFORMATION_V1_0; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_0 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_0, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_0; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_0 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_0; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_0; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_0, *PWDF_USB_PIPE_INFORMATION_V1_0; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_0, *PWDF_WMI_PROVIDER_CONFIG_V1_0; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_0 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_0, *PWDF_WMI_INSTANCE_CONFIG_V1_0; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_0 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_0, *PWDF_WORKITEM_CONFIG_V1_0; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_0_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf11.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf11.h new file mode 100644 index 00000000000..f6374f50f3b --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf11.h @@ -0,0 +1,2203 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _WDF_V1_1_TYPES_H_ +#define _WDF_V1_1_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_1 { + WdfFunctionTableNumEntries_V1_1 = 386, +} WDFFUNCENUM_V1_1; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_1 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_1; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_1 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_1; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_1 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_1; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_1 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_1; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_1 *PWDF_CHILD_RETRIEVE_INFO_V1_1; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_1 *PCWDF_CHILD_RETRIEVE_INFO_V1_1; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_1 *PWDF_CHILD_LIST_CONFIG_V1_1; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_1 *PCWDF_CHILD_LIST_CONFIG_V1_1; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_1 *PWDF_CHILD_LIST_ITERATOR_V1_1; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_1 *PCWDF_CHILD_LIST_ITERATOR_V1_1; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_1 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_1; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_1 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_1; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_1 *PWDF_COMMON_BUFFER_CONFIG_V1_1; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_1 *PCWDF_COMMON_BUFFER_CONFIG_V1_1; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_1 *PWDF_FILEOBJECT_CONFIG_V1_1; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_1 *PCWDF_FILEOBJECT_CONFIG_V1_1; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_1 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_1; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_1 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_1; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_1 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_1; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_1 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_1; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_1 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_1; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_1 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_1; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_1 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_1; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_1 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_1; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_1 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_1; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_1 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_1; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1; +typedef struct _WDF_DEVICE_STATE_V1_1 *PWDF_DEVICE_STATE_V1_1; +typedef const struct _WDF_DEVICE_STATE_V1_1 *PCWDF_DEVICE_STATE_V1_1; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_1 *PWDF_DEVICE_PNP_CAPABILITIES_V1_1; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_1 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_1; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_1 *PWDF_DEVICE_POWER_CAPABILITIES_V1_1; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_1 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_1; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_1 *PWDF_DMA_ENABLER_CONFIG_V1_1; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_1 *PCWDF_DMA_ENABLER_CONFIG_V1_1; +typedef struct _WDF_DPC_CONFIG_V1_1 *PWDF_DPC_CONFIG_V1_1; +typedef const struct _WDF_DPC_CONFIG_V1_1 *PCWDF_DPC_CONFIG_V1_1; +typedef struct _WDF_DRIVER_CONFIG_V1_1 *PWDF_DRIVER_CONFIG_V1_1; +typedef const struct _WDF_DRIVER_CONFIG_V1_1 *PCWDF_DRIVER_CONFIG_V1_1; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_1 *PWDF_FDO_EVENT_CALLBACKS_V1_1; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_1 *PCWDF_FDO_EVENT_CALLBACKS_V1_1; +typedef struct _WDF_DRIVER_GLOBALS_V1_1 *PWDF_DRIVER_GLOBALS_V1_1; +typedef const struct _WDF_DRIVER_GLOBALS_V1_1 *PCWDF_DRIVER_GLOBALS_V1_1; +typedef struct _WDF_INTERRUPT_CONFIG_V1_1 *PWDF_INTERRUPT_CONFIG_V1_1; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_1 *PCWDF_INTERRUPT_CONFIG_V1_1; +typedef struct _WDF_INTERRUPT_INFO_V1_1 *PWDF_INTERRUPT_INFO_V1_1; +typedef const struct _WDF_INTERRUPT_INFO_V1_1 *PCWDF_INTERRUPT_INFO_V1_1; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_1 *PWDF_IO_QUEUE_CONFIG_V1_1; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_1 *PCWDF_IO_QUEUE_CONFIG_V1_1; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_1 *PWDF_IO_TARGET_OPEN_PARAMS_V1_1; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_1 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_1; +typedef struct _WDFMEMORY_OFFSET_V1_1 *PWDFMEMORY_OFFSET_V1_1; +typedef const struct _WDFMEMORY_OFFSET_V1_1 *PCWDFMEMORY_OFFSET_V1_1; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_1 *PWDF_MEMORY_DESCRIPTOR_V1_1; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_1 *PCWDF_MEMORY_DESCRIPTOR_V1_1; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_1 *PWDF_OBJECT_ATTRIBUTES_V1_1; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_1 *PCWDF_OBJECT_ATTRIBUTES_V1_1; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_1 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_1; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_1 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_1; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_1 *PWDF_PDO_EVENT_CALLBACKS_V1_1; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_1 *PCWDF_PDO_EVENT_CALLBACKS_V1_1; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_1 *PWDF_QUERY_INTERFACE_CONFIG_V1_1; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_1 *PCWDF_QUERY_INTERFACE_CONFIG_V1_1; +typedef struct _WDF_REQUEST_PARAMETERS_V1_1 *PWDF_REQUEST_PARAMETERS_V1_1; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_1 *PCWDF_REQUEST_PARAMETERS_V1_1; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_1 *PWDF_REQUEST_COMPLETION_PARAMS_V1_1; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_1 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_1; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_1 *PWDF_REQUEST_REUSE_PARAMS_V1_1; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_1 *PCWDF_REQUEST_REUSE_PARAMS_V1_1; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_1 *PWDF_REQUEST_SEND_OPTIONS_V1_1; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_1 *PCWDF_REQUEST_SEND_OPTIONS_V1_1; +typedef struct _WDF_TIMER_CONFIG_V1_1 *PWDF_TIMER_CONFIG_V1_1; +typedef const struct _WDF_TIMER_CONFIG_V1_1 *PCWDF_TIMER_CONFIG_V1_1; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_1 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_1; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_1 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_1; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_1 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_1; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_1 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_1; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_1 *PWDF_USB_DEVICE_INFORMATION_V1_1; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_1 *PCWDF_USB_DEVICE_INFORMATION_V1_1; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_1 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_1; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_1 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_1; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_1 *PWDF_USB_PIPE_INFORMATION_V1_1; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_1 *PCWDF_USB_PIPE_INFORMATION_V1_1; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_1 *PWDF_WMI_PROVIDER_CONFIG_V1_1; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_1 *PCWDF_WMI_PROVIDER_CONFIG_V1_1; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_1 *PWDF_WMI_INSTANCE_CONFIG_V1_1; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_1 *PCWDF_WMI_INSTANCE_CONFIG_V1_1; +typedef struct _WDF_WORKITEM_CONFIG_V1_1 *PWDF_WORKITEM_CONFIG_V1_1; +typedef const struct _WDF_WORKITEM_CONFIG_V1_1 *PCWDF_WORKITEM_CONFIG_V1_1; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_1 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_1; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_1; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_1 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_1, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_1; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_1 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_1 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_1, *PWDF_CHILD_RETRIEVE_INFO_V1_1; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_1, *PWDF_CHILD_LIST_CONFIG_V1_1; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_1, *PWDF_CHILD_LIST_ITERATOR_V1_1; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfClassExtension.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_1 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_1 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_1, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_1; + +// End of versioning of structures for wdfClassExtension.h + +// +// Versioning of structures for wdfClassExtensionList.h +// +// End of versioning of structures for wdfClassExtensionList.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_1, *PWDF_COMMON_BUFFER_CONFIG_V1_1; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_1, *PWDF_FILEOBJECT_CONFIG_V1_1; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_1 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_1; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_1 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_1; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_1 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_1; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_1, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_1; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_1, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_1; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_1; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_1; + +typedef struct _WDF_DEVICE_STATE_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_1, *PWDF_DEVICE_STATE_V1_1; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_1, *PWDF_DEVICE_PNP_CAPABILITIES_V1_1; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_1, *PWDF_DEVICE_POWER_CAPABILITIES_V1_1; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + +} WDF_DMA_ENABLER_CONFIG_V1_1, *PWDF_DMA_ENABLER_CONFIG_V1_1; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_1 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_1, *PWDF_DPC_CONFIG_V1_1; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + +} WDF_DRIVER_CONFIG_V1_1, *PWDF_DRIVER_CONFIG_V1_1; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_1; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_1, *PWDF_FDO_EVENT_CALLBACKS_V1_1; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_1 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_1, *PWDF_DRIVER_GLOBALS_V1_1; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_1 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_1, *PWDF_INTERRUPT_CONFIG_V1_1; + +typedef struct _WDF_INTERRUPT_INFO_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + PHYSICAL_ADDRESS MessageAddress; + + KAFFINITY TargetProcessorSet; + + ULONG MessageData; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + +} WDF_INTERRUPT_INFO_V1_1, *PWDF_INTERRUPT_INFO_V1_1; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_1 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + +} WDF_IO_QUEUE_CONFIG_V1_1, *PWDF_IO_QUEUE_CONFIG_V1_1; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_1, *PWDF_IO_TARGET_OPEN_PARAMS_V1_1; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_1 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_1, *PWDFMEMORY_OFFSET_V1_1; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_1 { + + + + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_1 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_1, *PWDF_MEMORY_DESCRIPTOR_V1_1; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_1 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_1 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_1, *PWDF_OBJECT_ATTRIBUTES_V1_1; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_1 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_1 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_1, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_1; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_1 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_1, *PWDF_PDO_EVENT_CALLBACKS_V1_1; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_1 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + + + + // + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_1, *PWDF_QUERY_INTERFACE_CONFIG_V1_1; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_1 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_1, *PWDF_REQUEST_PARAMETERS_V1_1; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_1 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_1, *PWDF_REQUEST_COMPLETION_PARAMS_V1_1; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_1, *PWDF_REQUEST_REUSE_PARAMS_V1_1; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_1, *PWDF_REQUEST_SEND_OPTIONS_V1_1; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_1 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + LONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_TIMER_CONFIG_V1_1, *PWDF_TIMER_CONFIG_V1_1; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_1 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_1, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_1; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_1 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_1 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_1, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_1; + + + + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_1, *PWDF_USB_DEVICE_INFORMATION_V1_1; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_1 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_1, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_1; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_1 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_1; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_1; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_1, *PWDF_USB_PIPE_INFORMATION_V1_1; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_1, *PWDF_WMI_PROVIDER_CONFIG_V1_1; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_1 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_1 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_1, *PWDF_WMI_INSTANCE_CONFIG_V1_1; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_1 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_1, *PWDF_WORKITEM_CONFIG_V1_1; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_1_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf111.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf111.h new file mode 100644 index 00000000000..1763eaa9ee0 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf111.h @@ -0,0 +1,2896 @@ +#ifndef _WDF_V1_11_TYPES_H_ +#define _WDF_V1_11_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_11 { + WdfFunctionTableNumEntries_V1_11 = 432, +} WDFFUNCENUM_V1_11; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_11 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_11; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_11 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_11; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_11 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_11; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_11 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_11; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_11 *PWDF_CHILD_RETRIEVE_INFO_V1_11; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_11 *PCWDF_CHILD_RETRIEVE_INFO_V1_11; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_11 *PWDF_CHILD_LIST_CONFIG_V1_11; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_11 *PCWDF_CHILD_LIST_CONFIG_V1_11; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_11 *PWDF_CHILD_LIST_ITERATOR_V1_11; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_11 *PCWDF_CHILD_LIST_ITERATOR_V1_11; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_11 *PWDF_COMMON_BUFFER_CONFIG_V1_11; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_11 *PCWDF_COMMON_BUFFER_CONFIG_V1_11; +typedef struct _WDFCX_FILEOBJECT_CONFIG_V1_11 *PWDFCX_FILEOBJECT_CONFIG_V1_11; +typedef const struct _WDFCX_FILEOBJECT_CONFIG_V1_11 *PCWDFCX_FILEOBJECT_CONFIG_V1_11; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_11 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_11; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_11 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_11; +typedef struct _WDF_CLASS_VERSION_V1_11 *PWDF_CLASS_VERSION_V1_11; +typedef const struct _WDF_CLASS_VERSION_V1_11 *PCWDF_CLASS_VERSION_V1_11; +typedef struct _WDF_CLASS_BIND_INFO_V1_11 *PWDF_CLASS_BIND_INFO_V1_11; +typedef const struct _WDF_CLASS_BIND_INFO_V1_11 *PCWDF_CLASS_BIND_INFO_V1_11; +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_11 *PWDF_CLASS_LIBRARY_INFO_V1_11; +typedef const struct _WDF_CLASS_LIBRARY_INFO_V1_11 *PCWDF_CLASS_LIBRARY_INFO_V1_11; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_11 *PWDF_FILEOBJECT_CONFIG_V1_11; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_11 *PCWDF_FILEOBJECT_CONFIG_V1_11; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_11 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_11; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_11 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_11; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_11 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_11; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_11 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_11; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_11 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_11; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_11 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_11; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_11 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_11; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_11 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_11; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_11 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_11; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_11 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_11; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11; +typedef struct _WDF_DEVICE_STATE_V1_11 *PWDF_DEVICE_STATE_V1_11; +typedef const struct _WDF_DEVICE_STATE_V1_11 *PCWDF_DEVICE_STATE_V1_11; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_11 *PWDF_DEVICE_PNP_CAPABILITIES_V1_11; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_11 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_11; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_11 *PWDF_DEVICE_POWER_CAPABILITIES_V1_11; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_11 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_11; +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V1_11 *PWDF_REMOVE_LOCK_OPTIONS_V1_11; +typedef const struct _WDF_REMOVE_LOCK_OPTIONS_V1_11 *PCWDF_REMOVE_LOCK_OPTIONS_V1_11; +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_11 *PWDF_POWER_FRAMEWORK_SETTINGS_V1_11; +typedef const struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_11 *PCWDF_POWER_FRAMEWORK_SETTINGS_V1_11; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_11 *PWDF_DMA_ENABLER_CONFIG_V1_11; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_11 *PCWDF_DMA_ENABLER_CONFIG_V1_11; +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11 *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11; +typedef const struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11 *PCWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11; +typedef struct _WDF_DPC_CONFIG_V1_11 *PWDF_DPC_CONFIG_V1_11; +typedef const struct _WDF_DPC_CONFIG_V1_11 *PCWDF_DPC_CONFIG_V1_11; +typedef struct _WDF_DRIVER_CONFIG_V1_11 *PWDF_DRIVER_CONFIG_V1_11; +typedef const struct _WDF_DRIVER_CONFIG_V1_11 *PCWDF_DRIVER_CONFIG_V1_11; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_11 *PWDF_FDO_EVENT_CALLBACKS_V1_11; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_11 *PCWDF_FDO_EVENT_CALLBACKS_V1_11; +typedef struct _WDF_DRIVER_GLOBALS_V1_11 *PWDF_DRIVER_GLOBALS_V1_11; +typedef const struct _WDF_DRIVER_GLOBALS_V1_11 *PCWDF_DRIVER_GLOBALS_V1_11; +typedef struct _WDF_INTERRUPT_CONFIG_V1_11 *PWDF_INTERRUPT_CONFIG_V1_11; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_11 *PCWDF_INTERRUPT_CONFIG_V1_11; +typedef struct _WDF_INTERRUPT_INFO_V1_11 *PWDF_INTERRUPT_INFO_V1_11; +typedef const struct _WDF_INTERRUPT_INFO_V1_11 *PCWDF_INTERRUPT_INFO_V1_11; +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_11 *PWDF_INTERRUPT_EXTENDED_POLICY_V1_11; +typedef const struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_11 *PCWDF_INTERRUPT_EXTENDED_POLICY_V1_11; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_11 *PWDF_IO_QUEUE_CONFIG_V1_11; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_11 *PCWDF_IO_QUEUE_CONFIG_V1_11; +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11 *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11; +typedef const struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11 *PCWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_11 *PWDF_IO_TARGET_OPEN_PARAMS_V1_11; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_11 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_11; +typedef struct _WDFMEMORY_OFFSET_V1_11 *PWDFMEMORY_OFFSET_V1_11; +typedef const struct _WDFMEMORY_OFFSET_V1_11 *PCWDFMEMORY_OFFSET_V1_11; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_11 *PWDF_MEMORY_DESCRIPTOR_V1_11; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_11 *PCWDF_MEMORY_DESCRIPTOR_V1_11; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_11 *PWDF_OBJECT_ATTRIBUTES_V1_11; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_11 *PCWDF_OBJECT_ATTRIBUTES_V1_11; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_11 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_11; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_11 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_11; +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V1_11 *PWDF_CUSTOM_TYPE_CONTEXT_V1_11; +typedef const struct _WDF_CUSTOM_TYPE_CONTEXT_V1_11 *PCWDF_CUSTOM_TYPE_CONTEXT_V1_11; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_11 *PWDF_PDO_EVENT_CALLBACKS_V1_11; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_11 *PCWDF_PDO_EVENT_CALLBACKS_V1_11; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_11 *PWDF_QUERY_INTERFACE_CONFIG_V1_11; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_11 *PCWDF_QUERY_INTERFACE_CONFIG_V1_11; +typedef struct _WDF_REQUEST_PARAMETERS_V1_11 *PWDF_REQUEST_PARAMETERS_V1_11; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_11 *PCWDF_REQUEST_PARAMETERS_V1_11; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_11 *PWDF_REQUEST_COMPLETION_PARAMS_V1_11; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_11 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_11; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_11 *PWDF_REQUEST_REUSE_PARAMS_V1_11; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_11 *PCWDF_REQUEST_REUSE_PARAMS_V1_11; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_11 *PWDF_REQUEST_SEND_OPTIONS_V1_11; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_11 *PCWDF_REQUEST_SEND_OPTIONS_V1_11; +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_11 *PWDF_REQUEST_FORWARD_OPTIONS_V1_11; +typedef const struct _WDF_REQUEST_FORWARD_OPTIONS_V1_11 *PCWDF_REQUEST_FORWARD_OPTIONS_V1_11; +typedef struct _WDF_TIMER_CONFIG_V1_11 *PWDF_TIMER_CONFIG_V1_11; +typedef const struct _WDF_TIMER_CONFIG_V1_11 *PCWDF_TIMER_CONFIG_V1_11; +typedef struct _WDFOBJECT_TRIAGE_INFO_V1_11 *PWDFOBJECT_TRIAGE_INFO_V1_11; +typedef const struct _WDFOBJECT_TRIAGE_INFO_V1_11 *PCWDFOBJECT_TRIAGE_INFO_V1_11; +typedef struct _WDFCONTEXT_TRIAGE_INFO_V1_11 *PWDFCONTEXT_TRIAGE_INFO_V1_11; +typedef const struct _WDFCONTEXT_TRIAGE_INFO_V1_11 *PCWDFCONTEXT_TRIAGE_INFO_V1_11; +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_11 *PWDFCONTEXTTYPE_TRIAGE_INFO_V1_11; +typedef const struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_11 *PCWDFCONTEXTTYPE_TRIAGE_INFO_V1_11; +typedef struct _WDFQUEUE_TRIAGE_INFO_V1_11 *PWDFQUEUE_TRIAGE_INFO_V1_11; +typedef const struct _WDFQUEUE_TRIAGE_INFO_V1_11 *PCWDFQUEUE_TRIAGE_INFO_V1_11; +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_11 *PWDFFWDPROGRESS_TRIAGE_INFO_V1_11; +typedef const struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_11 *PCWDFFWDPROGRESS_TRIAGE_INFO_V1_11; +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V1_11 *PWDFIRPQUEUE_TRIAGE_INFO_V1_11; +typedef const struct _WDFIRPQUEUE_TRIAGE_INFO_V1_11 *PCWDFIRPQUEUE_TRIAGE_INFO_V1_11; +typedef struct _WDFREQUEST_TRIAGE_INFO_V1_11 *PWDFREQUEST_TRIAGE_INFO_V1_11; +typedef const struct _WDFREQUEST_TRIAGE_INFO_V1_11 *PCWDFREQUEST_TRIAGE_INFO_V1_11; +typedef struct _WDFDEVICE_TRIAGE_INFO_V1_11 *PWDFDEVICE_TRIAGE_INFO_V1_11; +typedef const struct _WDFDEVICE_TRIAGE_INFO_V1_11 *PCWDFDEVICE_TRIAGE_INFO_V1_11; +typedef struct _WDFIRP_TRIAGE_INFO_V1_11 *PWDFIRP_TRIAGE_INFO_V1_11; +typedef const struct _WDFIRP_TRIAGE_INFO_V1_11 *PCWDFIRP_TRIAGE_INFO_V1_11; +typedef struct _WDF_TRIAGE_INFO_V1_11 *PWDF_TRIAGE_INFO_V1_11; +typedef const struct _WDF_TRIAGE_INFO_V1_11 *PCWDF_TRIAGE_INFO_V1_11; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_11 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_11; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_11 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_11; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_11 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_11; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_11 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_11; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_11 *PWDF_USB_DEVICE_INFORMATION_V1_11; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_11 *PCWDF_USB_DEVICE_INFORMATION_V1_11; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_11 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_11; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_11 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_11; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_11 *PWDF_USB_PIPE_INFORMATION_V1_11; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_11 *PCWDF_USB_PIPE_INFORMATION_V1_11; +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_11 *PWDF_USB_DEVICE_CREATE_CONFIG_V1_11; +typedef const struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_11 *PCWDF_USB_DEVICE_CREATE_CONFIG_V1_11; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_11 *PWDF_WMI_PROVIDER_CONFIG_V1_11; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_11 *PCWDF_WMI_PROVIDER_CONFIG_V1_11; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_11 *PWDF_WMI_INSTANCE_CONFIG_V1_11; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_11 *PCWDF_WMI_INSTANCE_CONFIG_V1_11; +typedef struct _WDF_WORKITEM_CONFIG_V1_11 *PWDF_WORKITEM_CONFIG_V1_11; +typedef const struct _WDF_WORKITEM_CONFIG_V1_11 *PCWDF_WORKITEM_CONFIG_V1_11; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_11 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_11; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_11; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_11 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_11, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_11; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_11 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_11 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_11, *PWDF_CHILD_RETRIEVE_INFO_V1_11; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_11, *PWDF_CHILD_LIST_CONFIG_V1_11; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_11, *PWDF_CHILD_LIST_ITERATOR_V1_11; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_11, *PWDF_COMMON_BUFFER_CONFIG_V1_11; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfcx.h +// +typedef struct _WDFCX_FILEOBJECT_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDFCX_DEVICE_FILE_CREATE EvtCxDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDFCX_FILEOBJECT_CONFIG_V1_11, *PWDFCX_FILEOBJECT_CONFIG_V1_11; + +// End of versioning of structures for wdfcx.h + +// +// Versioning of structures for wdfcxbase.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_11 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_11 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_11, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_11; + +typedef struct _WDF_CLASS_VERSION_V1_11 { + WDF_MAJOR_VERSION Major; + + WDF_MINOR_VERSION Minor; + + WDF_BUILD_NUMBER Build; + +} WDF_CLASS_VERSION_V1_11; + +typedef struct _WDF_CLASS_BIND_INFO_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Name of the class to bind to + // + PWSTR ClassName; + + // + // Version information for the class + // + WDF_CLASS_VERSION_V1_11 Version; + + // + // Function export table from the class driver to resolve on bind + // + PFN_WDF_CLASS_EXPORT * FunctionTable; + + // + // Number of entries in FunctionTable + // + ULONG FunctionTableCount; + + // + // Optional field where the client specify additional information + // for the class driver to resolve + // + PVOID ClassBindInfo; + + // + // Optional bind callback. If set, WdfVersionBindClass will not + // be called and it will be up to ClientClassBind to call this function + // if required. + // + PFN_WDF_CLIENT_BIND_CLASS ClientBindClass; + + // + // Optional unbind callback. If set, WdfVersionUnbindClass will not be + // called and it will be up to ClientClassUnbind to call this function + // if required. + // + PFN_WDF_CLIENT_UNBIND_CLASS ClientUnbindClass; + + // + // Diagnostic cookie to use during debugging + // + PVOID ClassModule; + +} WDF_CLASS_BIND_INFO_V1_11, * PWDF_CLASS_BIND_INFO_V1_11; + +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Version of this class library + // + WDF_CLASS_VERSION_V1_11 Version; + + // + // Callback to be called by the loader to initialize the class library + // + PFN_WDF_CLASS_LIBRARY_INITIALIZE ClassLibraryInitialize; + + // + // Callback to be called by the loader to deinitialize the class library + // after succesful initialization (immediately before the class library will + // be unloaded). + // + PFN_WDF_CLASS_LIBRARY_DEINITIALIZE ClassLibraryDeinitialize; + + // + // Callback to be called by the loader when a client driver has request to + // be bound to this class library. + // + PFN_WDF_CLASS_LIBRARY_BIND_CLIENT ClassLibraryBindClient; + + // + // Callback to be called by the loader when a previously bound client driver + // is being unloaded. + // + PFN_WDF_CLASS_LIBRARY_UNBIND_CLIENT ClassLibraryUnbindClient; + +} WDF_CLASS_LIBRARY_INFO_V1_11, *PWDF_CLASS_LIBRARY_INFO_V1_11; + +// End of versioning of structures for wdfcxbase.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_11, *PWDF_FILEOBJECT_CONFIG_V1_11; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_11 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_11; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_11 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_11; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_11 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_11; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX EvtDeviceUsageNotificationEx; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_11, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_11; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_11, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_11; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + + // + // This field determines how the IdleTimeout field is used. + // + // If the value is DriverManagedIdleTimeout, then the idle timeout value + // is determined by the IdleTimeout field of this structure. + // + // If the value is SystemManagedIdleTimeout, then the timeout value is + // determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). The IdleTimeout field + // is ignored on these operating systems. On operating systems where the + // PoFx is not available, the behavior is same as DriverManagedIdleTimeout. + // + // If the value is SystemManagedIdleTimeoutWithHint, then the timeout value + // is determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). In addition, the value + // specified in the IdleTimeout field is provided as a hint to the PoFx in + // determining when the device should be allowed to enter a low-power state. + // Since it is only a hint, the actual duration after which the PoFx allows + // the device to enter a low-power state might be greater than or less than + // the IdleTimeout value. On operating systems where the PoFx is not + // available, the behavior is same as DriverManagedIdleTimeout. + // + WDF_POWER_POLICY_IDLE_TIMEOUT_TYPE IdleTimeoutType; + + // + // This field forces the device to avoid idling in the D3cold power state. + // WDF will ensure, with help from the bus drivers, that the device will + // idle in a D-state that can successfully generate a wake signal, if + // necessary. If the client specifies that DxState == PowerDeviceD3, this + // setting allows the client to distinguish betwen D3hot and D3cold. If + // the client sets DxState == PowerDeviceMaximum, then WDF will pick the + // deepest idle state identified by the bus driver. If that deepest state + // is D3cold, this field allows the client to override that and choose + // D3hot. + // + // If WdfTrue, device will not use D3cold in S0. + // If WdfFalse, device will use D3cold in S0 if the ACPI firmware indicates + // that the device can enter that state, if DxState above does not + // specify some other D-state and, if the device is armed for + // wake, that it can generate its wake signal from D3cold. + // If WdfUseDefault, this setting will be derived from the driver's INF, + // specifically the presence or absence of the following two lines in + // the DDInstall.HW section: + // Include=machine.inf + // Needs=PciD3ColdSupported + // + WDF_TRI_STATE ExcludeD3Cold; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_11; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_11; + +typedef struct _WDF_DEVICE_STATE_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_11, *PWDF_DEVICE_STATE_V1_11; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_11, *PWDF_DEVICE_PNP_CAPABILITIES_V1_11; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_11, *PWDF_DEVICE_POWER_CAPABILITIES_V1_11; + +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REMOVE_LOCK_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REMOVE_LOCK_OPTIONS_V1_11, *PWDF_REMOVE_LOCK_OPTIONS_V1_11; + +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_11 { + // + // Size of the structure, in bytes. + // + ULONG Size; + + // + // Client driver's callback function that is invoked after KMDF has + // registered with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE EvtDeviceWdmPostPoFxRegisterDevice; + + // + // Client driver's callback function that is invoked before KMDF + // unregisters with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE EvtDeviceWdmPrePoFxUnregisterDevice; + + // + // Pointer to a PO_FX_COMPONENT structure that describes the only component + // in the single-component device. This field can be NULL if the client + // driver wants KMDF to use the default specification for this component + // (i.e. support for F0 only). + // + PPO_FX_COMPONENT Component; + + // + // Client driver's PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_STATE_CALLBACK callback function. + // This field can be NULL if the client driver does not wish to specify + // this callback. + // + PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback; + + // + // Client driver's PO_FX_POWER_CONTROL_CALLBACK callback function. This + // field can be NULL if the client driver does not wish to specify this + // callback. + // + PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + + // + // Context value that is passed in to the ComponentIdleStateCallback and + // PowerControlCallback callback functions. + // + PVOID PoFxDeviceContext; + +} WDF_POWER_FRAMEWORK_SETTINGS_V1_11, *PWDF_POWER_FRAMEWORK_SETTINGS_V1_11; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + + // + // Overrides the address width specified by the DMA profile. + // + ULONG AddressWidthOverride; + + // + // Overrides the version of the WDM DMA interfaces that WDF uses + // (0 for default). + // + ULONG WdmDmaVersionOverride; + + // + // Bit field combination of values from the WDF_DMA_ENABLER_CONFIG_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_DMA_ENABLER_CONFIG_V1_11, *PWDF_DMA_ENABLER_CONFIG_V1_11; + +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Specifies that the transfer is controlled by the device's DMA + // request line. + // + // + BOOLEAN DemandMode; + + // + // Specifies that the DMA engine will loop back to the beginning + // of the buffer once it reaches the end. + // + // + BOOLEAN LoopedTransfer; + + // + // Width of the register to DMA to/from + // + // + DMA_WIDTH DmaWidth; + + // + // The adress at which to write to the device + // + PHYSICAL_ADDRESS DeviceAddress; + + // + // The translated resource descriptor for the DMA channel assigned + // the device during EvtDevicePrepareHardware + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR DmaDescriptor; + +} WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11, *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_11; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_11 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_11, *PWDF_DPC_CONFIG_V1_11; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V1_11, *PWDF_DRIVER_CONFIG_V1_11; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_11; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_11, *PWDF_FDO_EVENT_CALLBACKS_V1_11; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_11 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_11, *PWDF_DRIVER_GLOBALS_V1_11; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinternal.h +// +// End of versioning of structures for wdfinternal.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_11 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + + // + // TRUE: Interrupt is reported inactive on explicit power down + // instead of disconnecting it. + // FALSE: Interrupt is disconnected instead of reporting inactive + // on explicit power down. + // DEFAULT: Framework decides the right value. + // + WDF_TRI_STATE ReportInactiveOnPowerDown; + +} WDF_INTERRUPT_CONFIG_V1_11, *PWDF_INTERRUPT_CONFIG_V1_11; + +typedef struct _WDF_INTERRUPT_INFO_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + + DECLSPEC_ALIGN(8) USHORT Group; + +} WDF_INTERRUPT_INFO_V1_11, *PWDF_INTERRUPT_INFO_V1_11; + +// +// Interrupt Extended Policy Configuration Structure +// +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + WDF_INTERRUPT_POLICY Policy; + + WDF_INTERRUPT_PRIORITY Priority; + + GROUP_AFFINITY TargetProcessorSetAndGroup; + +} WDF_INTERRUPT_EXTENDED_POLICY_V1_11, *PWDF_INTERRUPT_EXTENDED_POLICY_V1_11; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_11 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + + WDFDRIVER Driver; + +} WDF_IO_QUEUE_CONFIG_V1_11, *PWDF_IO_QUEUE_CONFIG_V1_11; + +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11 { + ULONG Size; + + ULONG TotalForwardProgressRequests; + + // + // Specify the type of the policy here. + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY ForwardProgressReservedPolicy; + + // + // Structure which contains the policy specific fields + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY_SETTINGS ForwardProgressReservePolicySettings; + + // + // Callback for reserved request given at initialization time + // + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; + + // + // Callback for reserved request given at run time + // + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateRequestResources; + +} WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11, *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_11; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_11, *PWDF_IO_TARGET_OPEN_PARAMS_V1_11; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_11 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_11, *PWDFMEMORY_OFFSET_V1_11; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_11 { + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_11 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_11, *PWDF_MEMORY_DESCRIPTOR_V1_11; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_11 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_11 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_11, *PWDF_OBJECT_ATTRIBUTES_V1_11; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_11 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_11 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_11, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_11; + +// +// Core structure for supporting custom types, see macros below. +// +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V1_11 { + ULONG Size; + + ULONG_PTR Data; + +} WDF_CUSTOM_TYPE_CONTEXT_V1_11, *PWDF_CUSTOM_TYPE_CONTEXT_V1_11; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_11 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + + // + // Called when reporting the PDO missing to PnP manager in response to + // IRP_MN_QUERY_DEVICE_RELATIONS for Bus Relations. + // + PFN_WDF_DEVICE_REPORTED_MISSING EvtDeviceReportedMissing; + +} WDF_PDO_EVENT_CALLBACKS_V1_11, *PWDF_PDO_EVENT_CALLBACKS_V1_11; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_11 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_11, *PWDF_QUERY_INTERFACE_CONFIG_V1_11; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_11 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_11, *PWDF_REQUEST_PARAMETERS_V1_11; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_11 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_11, *PWDF_REQUEST_COMPLETION_PARAMS_V1_11; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_11, *PWDF_REQUEST_REUSE_PARAMS_V1_11; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_11, *PWDF_REQUEST_SEND_OPTIONS_V1_11; + +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_FORWARD_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REQUEST_FORWARD_OPTIONS_V1_11, *PWDF_REQUEST_FORWARD_OPTIONS_V1_11; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_11 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + +} WDF_TIMER_CONFIG_V1_11, *PWDF_TIMER_CONFIG_V1_11; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftriage.h +// +typedef struct _WDFOBJECT_TRIAGE_INFO_V1_11 { + // value + ULONG RawObjectSize; + + ULONG ObjectType; + + ULONG TotalObjectSize; + + ULONG ChildListHead; + + ULONG ChildEntry; + + ULONG Globals; + + ULONG ParentObject; + +} WDFOBJECT_TRIAGE_INFO_V1_11, *PWDFOBJECT_TRIAGE_INFO_V1_11; + +typedef struct _WDFCONTEXT_TRIAGE_INFO_V1_11 { + // value + ULONG HeaderSize; + + ULONG NextHeader; + + ULONG Object; + + ULONG TypeInfoPtr; + + ULONG Context; + +} WDFCONTEXT_TRIAGE_INFO_V1_11, *PWDFCONTEXT_TRIAGE_INFO_V1_11; + +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_11 { + // value + ULONG TypeInfoSize; + + ULONG ContextSize; + + ULONG ContextName; + +} WDFCONTEXTTYPE_TRIAGE_INFO_V1_11, *PWDFCONTEXTTYPE_TRIAGE_INFO_V1_11; + +typedef struct _WDFQUEUE_TRIAGE_INFO_V1_11 { + // value + ULONG QueueSize; + + ULONG IrpQueue1; + + ULONG IrpQueue2; + + ULONG RequestList1; + + ULONG RequestList2; + + ULONG FwdProgressContext; + + ULONG PkgIo; + +} WDFQUEUE_TRIAGE_INFO_V1_11, *PWDFQUEUE_TRIAGE_INFO_V1_11; + +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_11 { + ULONG ReservedRequestList; + + ULONG ReservedRequestInUseList; + + ULONG PendedIrpList; + +} WDFFWDPROGRESS_TRIAGE_INFO_V1_11, *PWDFFWDPROGRESS_TRIAGE_INFO_V1_11; + +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V1_11 { + // value + ULONG IrpQueueSize; + + ULONG IrpListHeader; + + ULONG IrpListEntry; + + ULONG IrpContext; + +} WDFIRPQUEUE_TRIAGE_INFO_V1_11, *PWDFIRPQUEUE_TRIAGE_INFO_V1_11; + +typedef struct _WDFREQUEST_TRIAGE_INFO_V1_11 { + // value + ULONG RequestSize; + + ULONG CsqContext; + + // WDF irp wrapper, see below. + ULONG FxIrp; + + ULONG ListEntryQueueOwned; + + ULONG ListEntryQueueOwned2; + + ULONG RequestListEntry; + + ULONG FwdProgressList; + +} WDFREQUEST_TRIAGE_INFO_V1_11, *PWDFREQUEST_TRIAGE_INFO_V1_11; + +typedef struct _WDFDEVICE_TRIAGE_INFO_V1_11 { + // value + ULONG DeviceInitSize; + + ULONG DeviceDriver; + +} WDFDEVICE_TRIAGE_INFO_V1_11, *PWDFDEVICE_TRIAGE_INFO_V1_11; + +typedef struct _WDFIRP_TRIAGE_INFO_V1_11 { + // value + ULONG FxIrpSize; + + ULONG IrpPtr; + +} WDFIRP_TRIAGE_INFO_V1_11, *PWDFIRP_TRIAGE_INFO_V1_11; + +typedef struct _WDF_TRIAGE_INFO_V1_11 { + // + // Version. + // + ULONG WdfMajorVersion; + + ULONG WdfMinorVersion; + + ULONG TriageInfoMajorVersion; + + ULONG TriageInfoMinorVersion; + + // + // Reserved pointer. + // + PVOID Reserved; + + // + // WDF objects triage info. + // + PWDFOBJECT_TRIAGE_INFO_V1_11 WdfObjectTriageInfo; + + PWDFCONTEXT_TRIAGE_INFO_V1_11 WdfContextTriageInfo; + + PWDFCONTEXTTYPE_TRIAGE_INFO_V1_11 WdfContextTypeTriageInfo; + + PWDFQUEUE_TRIAGE_INFO_V1_11 WdfQueueTriageInfo; + + PWDFFWDPROGRESS_TRIAGE_INFO_V1_11 WdfFwdProgressTriageInfo; + + PWDFIRPQUEUE_TRIAGE_INFO_V1_11 WdfIrpQueueTriageInfo; + + PWDFREQUEST_TRIAGE_INFO_V1_11 WdfRequestTriageInfo; + + PWDFDEVICE_TRIAGE_INFO_V1_11 WdfDeviceTriageInfo; + + PWDFIRP_TRIAGE_INFO_V1_11 WdfIrpTriageInfo; + +} WDF_TRIAGE_INFO_V1_11, *PWDF_TRIAGE_INFO_V1_11; + +// End of versioning of structures for wdftriage.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_11 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_11, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_11; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_11 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_11 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_11, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_11; + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_11, *PWDF_USB_DEVICE_INFORMATION_V1_11; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_11 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_11, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_11; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_11 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_11; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_11; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_11, *PWDF_USB_PIPE_INFORMATION_V1_11; + +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD Client Contraction of the Wdf Client + // + ULONG USBDClientContractVersion; + +} WDF_USB_DEVICE_CREATE_CONFIG_V1_11, *PWDF_USB_DEVICE_CREATE_CONFIG_V1_11; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_11, *PWDF_WMI_PROVIDER_CONFIG_V1_11; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_11 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_11 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_11, *PWDF_WMI_INSTANCE_CONFIG_V1_11; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_11 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_11, *PWDF_WORKITEM_CONFIG_V1_11; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_11_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf113.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf113.h new file mode 100644 index 00000000000..74794dc5d9d --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf113.h @@ -0,0 +1,3064 @@ +#ifndef _WDF_V1_13_TYPES_H_ +#define _WDF_V1_13_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_13 { + WdfFunctionTableNumEntries_V1_13 = 438, +} WDFFUNCENUM_V1_13; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_13 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_13; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_13 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_13; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_13 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_13; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_13 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_13; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_13 *PWDF_CHILD_RETRIEVE_INFO_V1_13; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_13 *PCWDF_CHILD_RETRIEVE_INFO_V1_13; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_13 *PWDF_CHILD_LIST_CONFIG_V1_13; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_13 *PCWDF_CHILD_LIST_CONFIG_V1_13; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_13 *PWDF_CHILD_LIST_ITERATOR_V1_13; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_13 *PCWDF_CHILD_LIST_ITERATOR_V1_13; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_13 *PWDF_COMMON_BUFFER_CONFIG_V1_13; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_13 *PCWDF_COMMON_BUFFER_CONFIG_V1_13; +typedef struct _WDFCX_FILEOBJECT_CONFIG_V1_13 *PWDFCX_FILEOBJECT_CONFIG_V1_13; +typedef const struct _WDFCX_FILEOBJECT_CONFIG_V1_13 *PCWDFCX_FILEOBJECT_CONFIG_V1_13; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_13 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_13; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_13 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_13; +typedef struct _WDF_CLASS_VERSION_V1_13 *PWDF_CLASS_VERSION_V1_13; +typedef const struct _WDF_CLASS_VERSION_V1_13 *PCWDF_CLASS_VERSION_V1_13; +typedef struct _WDF_CLASS_BIND_INFO_V1_13 *PWDF_CLASS_BIND_INFO_V1_13; +typedef const struct _WDF_CLASS_BIND_INFO_V1_13 *PCWDF_CLASS_BIND_INFO_V1_13; +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_13 *PWDF_CLASS_LIBRARY_INFO_V1_13; +typedef const struct _WDF_CLASS_LIBRARY_INFO_V1_13 *PCWDF_CLASS_LIBRARY_INFO_V1_13; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_13 *PWDF_FILEOBJECT_CONFIG_V1_13; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_13 *PCWDF_FILEOBJECT_CONFIG_V1_13; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_13 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_13; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_13 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_13; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_13 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_13; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_13 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_13; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_13 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_13; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_13 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_13; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_13 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_13; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_13 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_13; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_13 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_13; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_13 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_13; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13; +typedef struct _WDF_DEVICE_STATE_V1_13 *PWDF_DEVICE_STATE_V1_13; +typedef const struct _WDF_DEVICE_STATE_V1_13 *PCWDF_DEVICE_STATE_V1_13; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_13 *PWDF_DEVICE_PNP_CAPABILITIES_V1_13; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_13 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_13; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_13 *PWDF_DEVICE_POWER_CAPABILITIES_V1_13; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_13 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_13; +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V1_13 *PWDF_REMOVE_LOCK_OPTIONS_V1_13; +typedef const struct _WDF_REMOVE_LOCK_OPTIONS_V1_13 *PCWDF_REMOVE_LOCK_OPTIONS_V1_13; +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_13 *PWDF_POWER_FRAMEWORK_SETTINGS_V1_13; +typedef const struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_13 *PCWDF_POWER_FRAMEWORK_SETTINGS_V1_13; +typedef struct _WDF_IO_TYPE_CONFIG_V1_13 *PWDF_IO_TYPE_CONFIG_V1_13; +typedef const struct _WDF_IO_TYPE_CONFIG_V1_13 *PCWDF_IO_TYPE_CONFIG_V1_13; +typedef struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_13 *PWDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_13; +typedef const struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_13 *PCWDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_13; +typedef struct _WDF_DEVICE_PROPERTY_DATA_V1_13 *PWDF_DEVICE_PROPERTY_DATA_V1_13; +typedef const struct _WDF_DEVICE_PROPERTY_DATA_V1_13 *PCWDF_DEVICE_PROPERTY_DATA_V1_13; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_13 *PWDF_DMA_ENABLER_CONFIG_V1_13; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_13 *PCWDF_DMA_ENABLER_CONFIG_V1_13; +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13 *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13; +typedef const struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13 *PCWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13; +typedef struct _WDF_DPC_CONFIG_V1_13 *PWDF_DPC_CONFIG_V1_13; +typedef const struct _WDF_DPC_CONFIG_V1_13 *PCWDF_DPC_CONFIG_V1_13; +typedef struct _WDF_DRIVER_CONFIG_V1_13 *PWDF_DRIVER_CONFIG_V1_13; +typedef const struct _WDF_DRIVER_CONFIG_V1_13 *PCWDF_DRIVER_CONFIG_V1_13; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_13 *PWDF_FDO_EVENT_CALLBACKS_V1_13; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_13 *PCWDF_FDO_EVENT_CALLBACKS_V1_13; +typedef struct _WDF_DRIVER_GLOBALS_V1_13 *PWDF_DRIVER_GLOBALS_V1_13; +typedef const struct _WDF_DRIVER_GLOBALS_V1_13 *PCWDF_DRIVER_GLOBALS_V1_13; +typedef struct _WDF_INTERRUPT_CONFIG_V1_13 *PWDF_INTERRUPT_CONFIG_V1_13; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_13 *PCWDF_INTERRUPT_CONFIG_V1_13; +typedef struct _WDF_INTERRUPT_INFO_V1_13 *PWDF_INTERRUPT_INFO_V1_13; +typedef const struct _WDF_INTERRUPT_INFO_V1_13 *PCWDF_INTERRUPT_INFO_V1_13; +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_13 *PWDF_INTERRUPT_EXTENDED_POLICY_V1_13; +typedef const struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_13 *PCWDF_INTERRUPT_EXTENDED_POLICY_V1_13; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_13 *PWDF_IO_QUEUE_CONFIG_V1_13; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_13 *PCWDF_IO_QUEUE_CONFIG_V1_13; +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13 *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13; +typedef const struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13 *PCWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_13 *PWDF_IO_TARGET_OPEN_PARAMS_V1_13; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_13 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_13; +typedef struct _WDFMEMORY_OFFSET_V1_13 *PWDFMEMORY_OFFSET_V1_13; +typedef const struct _WDFMEMORY_OFFSET_V1_13 *PCWDFMEMORY_OFFSET_V1_13; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_13 *PWDF_MEMORY_DESCRIPTOR_V1_13; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_13 *PCWDF_MEMORY_DESCRIPTOR_V1_13; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_13 *PWDF_OBJECT_ATTRIBUTES_V1_13; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_13 *PCWDF_OBJECT_ATTRIBUTES_V1_13; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_13 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_13; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_13 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_13; +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V1_13 *PWDF_CUSTOM_TYPE_CONTEXT_V1_13; +typedef const struct _WDF_CUSTOM_TYPE_CONTEXT_V1_13 *PCWDF_CUSTOM_TYPE_CONTEXT_V1_13; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_13 *PWDF_PDO_EVENT_CALLBACKS_V1_13; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_13 *PCWDF_PDO_EVENT_CALLBACKS_V1_13; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_13 *PWDF_QUERY_INTERFACE_CONFIG_V1_13; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_13 *PCWDF_QUERY_INTERFACE_CONFIG_V1_13; +typedef struct _WDF_REQUEST_PARAMETERS_V1_13 *PWDF_REQUEST_PARAMETERS_V1_13; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_13 *PCWDF_REQUEST_PARAMETERS_V1_13; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_13 *PWDF_REQUEST_COMPLETION_PARAMS_V1_13; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_13 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_13; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_13 *PWDF_REQUEST_REUSE_PARAMS_V1_13; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_13 *PCWDF_REQUEST_REUSE_PARAMS_V1_13; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_13 *PWDF_REQUEST_SEND_OPTIONS_V1_13; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_13 *PCWDF_REQUEST_SEND_OPTIONS_V1_13; +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_13 *PWDF_REQUEST_FORWARD_OPTIONS_V1_13; +typedef const struct _WDF_REQUEST_FORWARD_OPTIONS_V1_13 *PCWDF_REQUEST_FORWARD_OPTIONS_V1_13; +typedef struct _WDF_TIMER_CONFIG_V1_13 *PWDF_TIMER_CONFIG_V1_13; +typedef const struct _WDF_TIMER_CONFIG_V1_13 *PCWDF_TIMER_CONFIG_V1_13; +typedef struct _WDFOBJECT_TRIAGE_INFO_V1_13 *PWDFOBJECT_TRIAGE_INFO_V1_13; +typedef const struct _WDFOBJECT_TRIAGE_INFO_V1_13 *PCWDFOBJECT_TRIAGE_INFO_V1_13; +typedef struct _WDFCONTEXT_TRIAGE_INFO_V1_13 *PWDFCONTEXT_TRIAGE_INFO_V1_13; +typedef const struct _WDFCONTEXT_TRIAGE_INFO_V1_13 *PCWDFCONTEXT_TRIAGE_INFO_V1_13; +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_13 *PWDFCONTEXTTYPE_TRIAGE_INFO_V1_13; +typedef const struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_13 *PCWDFCONTEXTTYPE_TRIAGE_INFO_V1_13; +typedef struct _WDFQUEUE_TRIAGE_INFO_V1_13 *PWDFQUEUE_TRIAGE_INFO_V1_13; +typedef const struct _WDFQUEUE_TRIAGE_INFO_V1_13 *PCWDFQUEUE_TRIAGE_INFO_V1_13; +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_13 *PWDFFWDPROGRESS_TRIAGE_INFO_V1_13; +typedef const struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_13 *PCWDFFWDPROGRESS_TRIAGE_INFO_V1_13; +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V1_13 *PWDFIRPQUEUE_TRIAGE_INFO_V1_13; +typedef const struct _WDFIRPQUEUE_TRIAGE_INFO_V1_13 *PCWDFIRPQUEUE_TRIAGE_INFO_V1_13; +typedef struct _WDFREQUEST_TRIAGE_INFO_V1_13 *PWDFREQUEST_TRIAGE_INFO_V1_13; +typedef const struct _WDFREQUEST_TRIAGE_INFO_V1_13 *PCWDFREQUEST_TRIAGE_INFO_V1_13; +typedef struct _WDFDEVICE_TRIAGE_INFO_V1_13 *PWDFDEVICE_TRIAGE_INFO_V1_13; +typedef const struct _WDFDEVICE_TRIAGE_INFO_V1_13 *PCWDFDEVICE_TRIAGE_INFO_V1_13; +typedef struct _WDFIRP_TRIAGE_INFO_V1_13 *PWDFIRP_TRIAGE_INFO_V1_13; +typedef const struct _WDFIRP_TRIAGE_INFO_V1_13 *PCWDFIRP_TRIAGE_INFO_V1_13; +typedef struct _WDF_TRIAGE_INFO_V1_13 *PWDF_TRIAGE_INFO_V1_13; +typedef const struct _WDF_TRIAGE_INFO_V1_13 *PCWDF_TRIAGE_INFO_V1_13; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_13 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_13; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_13 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_13; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_13 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_13; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_13 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_13; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_13 *PWDF_USB_DEVICE_INFORMATION_V1_13; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_13 *PCWDF_USB_DEVICE_INFORMATION_V1_13; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_13 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_13; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_13 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_13; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_13 *PWDF_USB_PIPE_INFORMATION_V1_13; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_13 *PCWDF_USB_PIPE_INFORMATION_V1_13; +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_13 *PWDF_USB_DEVICE_CREATE_CONFIG_V1_13; +typedef const struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_13 *PCWDF_USB_DEVICE_CREATE_CONFIG_V1_13; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_13 *PWDF_WMI_PROVIDER_CONFIG_V1_13; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_13 *PCWDF_WMI_PROVIDER_CONFIG_V1_13; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_13 *PWDF_WMI_INSTANCE_CONFIG_V1_13; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_13 *PCWDF_WMI_INSTANCE_CONFIG_V1_13; +typedef struct _WDF_WORKITEM_CONFIG_V1_13 *PWDF_WORKITEM_CONFIG_V1_13; +typedef const struct _WDF_WORKITEM_CONFIG_V1_13 *PCWDF_WORKITEM_CONFIG_V1_13; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_13 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_13; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_13; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_13 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_13, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_13; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_13 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_13 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_13, *PWDF_CHILD_RETRIEVE_INFO_V1_13; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_13, *PWDF_CHILD_LIST_CONFIG_V1_13; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_13, *PWDF_CHILD_LIST_ITERATOR_V1_13; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_13, *PWDF_COMMON_BUFFER_CONFIG_V1_13; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfcx.h +// +typedef struct _WDFCX_FILEOBJECT_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDFCX_DEVICE_FILE_CREATE EvtCxDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDFCX_FILEOBJECT_CONFIG_V1_13, *PWDFCX_FILEOBJECT_CONFIG_V1_13; + +// End of versioning of structures for wdfcx.h + +// +// Versioning of structures for wdfcxbase.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_13 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_13 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_13, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_13; + +typedef struct _WDF_CLASS_VERSION_V1_13 { + WDF_MAJOR_VERSION Major; + + WDF_MINOR_VERSION Minor; + + WDF_BUILD_NUMBER Build; + +} WDF_CLASS_VERSION_V1_13; + +typedef struct _WDF_CLASS_BIND_INFO_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Name of the class to bind to + // + PWSTR ClassName; + + // + // Version information for the class + // + WDF_CLASS_VERSION_V1_13 Version; + + // + // Function export table from the class driver to resolve on bind + // + PFN_WDF_CLASS_EXPORT * FunctionTable; + + // + // Number of entries in FunctionTable + // + ULONG FunctionTableCount; + + // + // Optional field where the client specify additional information + // for the class driver to resolve + // + PVOID ClassBindInfo; + + // + // Optional bind callback. If set, WdfVersionBindClass will not + // be called and it will be up to ClientClassBind to call this function + // if required. + // + PFN_WDF_CLIENT_BIND_CLASS ClientBindClass; + + // + // Optional unbind callback. If set, WdfVersionUnbindClass will not be + // called and it will be up to ClientClassUnbind to call this function + // if required. + // + PFN_WDF_CLIENT_UNBIND_CLASS ClientUnbindClass; + + // + // Diagnostic cookie to use during debugging + // + PVOID ClassModule; + +} WDF_CLASS_BIND_INFO_V1_13, * PWDF_CLASS_BIND_INFO_V1_13; + +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Version of this class library + // + WDF_CLASS_VERSION_V1_13 Version; + + // + // Callback to be called by the loader to initialize the class library + // + PFN_WDF_CLASS_LIBRARY_INITIALIZE ClassLibraryInitialize; + + // + // Callback to be called by the loader to deinitialize the class library + // after succesful initialization (immediately before the class library will + // be unloaded). + // + PFN_WDF_CLASS_LIBRARY_DEINITIALIZE ClassLibraryDeinitialize; + + // + // Callback to be called by the loader when a client driver has request to + // be bound to this class library. + // + PFN_WDF_CLASS_LIBRARY_BIND_CLIENT ClassLibraryBindClient; + + // + // Callback to be called by the loader when a previously bound client driver + // is being unloaded. + // + PFN_WDF_CLASS_LIBRARY_UNBIND_CLIENT ClassLibraryUnbindClient; + +} WDF_CLASS_LIBRARY_INFO_V1_13, *PWDF_CLASS_LIBRARY_INFO_V1_13; + +// End of versioning of structures for wdfcxbase.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_13, *PWDF_FILEOBJECT_CONFIG_V1_13; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_13 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_13; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_13 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_13; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_13 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_13; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX EvtDeviceUsageNotificationEx; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_13, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_13; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_13, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_13; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + + // + // This field determines how the IdleTimeout field is used. + // + // If the value is DriverManagedIdleTimeout, then the idle timeout value + // is determined by the IdleTimeout field of this structure. + // + // If the value is SystemManagedIdleTimeout, then the timeout value is + // determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). The IdleTimeout field + // is ignored on these operating systems. On operating systems where the + // PoFx is not available, the behavior is same as DriverManagedIdleTimeout. + // + // If the value is SystemManagedIdleTimeoutWithHint, then the timeout value + // is determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). In addition, the value + // specified in the IdleTimeout field is provided as a hint to the PoFx in + // determining when the device should be allowed to enter a low-power state. + // Since it is only a hint, the actual duration after which the PoFx allows + // the device to enter a low-power state might be greater than or less than + // the IdleTimeout value. On operating systems where the PoFx is not + // available, the behavior is same as DriverManagedIdleTimeout. + // + WDF_POWER_POLICY_IDLE_TIMEOUT_TYPE IdleTimeoutType; + + // + // This field forces the device to avoid idling in the D3cold power state. + // WDF will ensure, with help from the bus drivers, that the device will + // idle in a D-state that can successfully generate a wake signal, if + // necessary. If the client specifies that DxState == PowerDeviceD3, this + // setting allows the client to distinguish betwen D3hot and D3cold. If + // the client sets DxState == PowerDeviceMaximum, then WDF will pick the + // deepest idle state identified by the bus driver. If that deepest state + // is D3cold, this field allows the client to override that and choose + // D3hot. + // + // If WdfTrue, device will not use D3cold in S0. + // If WdfFalse, device will use D3cold in S0 if the ACPI firmware indicates + // that the device can enter that state, if DxState above does not + // specify some other D-state and, if the device is armed for + // wake, that it can generate its wake signal from D3cold. + // If WdfUseDefault, this setting will be derived from the driver's INF, + // specifically the presence or absence of the following two lines in + // the DDInstall.HW section: + // Include=machine.inf + // Needs=PciD3ColdSupported + // + WDF_TRI_STATE ExcludeD3Cold; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_13; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_13; + +typedef struct _WDF_DEVICE_STATE_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_13, *PWDF_DEVICE_STATE_V1_13; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_13, *PWDF_DEVICE_PNP_CAPABILITIES_V1_13; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_13, *PWDF_DEVICE_POWER_CAPABILITIES_V1_13; + +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REMOVE_LOCK_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REMOVE_LOCK_OPTIONS_V1_13, *PWDF_REMOVE_LOCK_OPTIONS_V1_13; + +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_13 { + // + // Size of the structure, in bytes. + // + ULONG Size; + + // + // Client driver's callback function that is invoked after KMDF has + // registered with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE EvtDeviceWdmPostPoFxRegisterDevice; + + // + // Client driver's callback function that is invoked before KMDF + // unregisters with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE EvtDeviceWdmPrePoFxUnregisterDevice; + + // + // Pointer to a PO_FX_COMPONENT structure that describes the only component + // in the single-component device. This field can be NULL if the client + // driver wants KMDF to use the default specification for this component + // (i.e. support for F0 only). + // + PPO_FX_COMPONENT Component; + + // + // Client driver's PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_STATE_CALLBACK callback function. + // This field can be NULL if the client driver does not wish to specify + // this callback. + // + PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback; + + // + // Client driver's PO_FX_POWER_CONTROL_CALLBACK callback function. This + // field can be NULL if the client driver does not wish to specify this + // callback. + // + PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + + // + // Context value that is passed in to the ComponentIdleStateCallback and + // PowerControlCallback callback functions. + // + PVOID PoFxDeviceContext; + +} WDF_POWER_FRAMEWORK_SETTINGS_V1_13, *PWDF_POWER_FRAMEWORK_SETTINGS_V1_13; + +typedef struct _WDF_IO_TYPE_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // + // Identifies the method that the driver will use to access data buffers + // that it receives for read and write requests. + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for read and write requests. Note that UMDF + // driver provides just a preference, and not a guarantee.Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE ReadWriteIoType; + + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for IOCTL requests. Note that UMDF + // driver provides just a preference, and not a guarantee. Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE DeviceControlIoType; + + // + // + // Optional, Provides the smallest buffer size (in bytes) for which + // UMDF will use direct access for the buffers. For example, set + // DirectTransferThreshold to "12288" to indicate that UMDF should use buffered + // access for all buffers that are smaller than 12 kilobytes, and direct + // access for buffers equal to or greater than that. Typically, you + // do not need to provide this value because UMDF uses a value that provides + // the best performance. Note that there are other requirements that must be + // met in order to get direct access of buffers. See Docs for details. + // + ULONG DirectTransferThreshold; + +} WDF_IO_TYPE_CONFIG_V1_13, *PWDF_IO_TYPE_CONFIG_V1_13; + +typedef struct _WDF_DEVICE_PROPERTY_DATA_V1_13 { + // + // Size of this structure + // + _In_ ULONG Size; + + // + // A pointer to a DEVPROPKEY structure that specifies the device + // property key. + // + _In_ const DEVPROPKEY * PropertyKey; + + // + // A locale identifier. Set this parameter either to a language-specific + // LCID value or to LOCALE_NEUTRAL. The LOCALE_NEUTRAL LCID specifies + // that the property is language-neutral (that is, not specific to any + // language). Do not set this parameter to LOCALE_SYSTEM_DEFAULT or + // LOCALE_USER_DEFAULT. For more information about language-specific + // LCID values, see LCID Structure. + // + _In_ LCID Lcid; + + // + // Set this parameter to PLUGPLAY_PROPERTY_PERSISTENT if the property + // value set by this routine should persist across computer restarts. + // Otherwise, set Flags to zero. Ignored for Query DDIs. + // + _In_ ULONG Flags; + +} WDF_DEVICE_PROPERTY_DATA_V1_13, *PWDF_DEVICE_PROPERTY_DATA_V1_13; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + + // + // Overrides the address width specified by the DMA profile. + // + ULONG AddressWidthOverride; + + // + // Overrides the version of the WDM DMA interfaces that WDF uses + // (0 for default). + // + ULONG WdmDmaVersionOverride; + + // + // Bit field combination of values from the WDF_DMA_ENABLER_CONFIG_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_DMA_ENABLER_CONFIG_V1_13, *PWDF_DMA_ENABLER_CONFIG_V1_13; + +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Specifies that the transfer is controlled by the device's DMA + // request line. + // + // + BOOLEAN DemandMode; + + // + // Specifies that the DMA engine will loop back to the beginning + // of the buffer once it reaches the end. + // + // + BOOLEAN LoopedTransfer; + + // + // Width of the register to DMA to/from + // + // + DMA_WIDTH DmaWidth; + + // + // The adress at which to write to the device + // + PHYSICAL_ADDRESS DeviceAddress; + + // + // The translated resource descriptor for the DMA channel assigned + // the device during EvtDevicePrepareHardware + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR DmaDescriptor; + +} WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13, *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_13; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_13 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_13, *PWDF_DPC_CONFIG_V1_13; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V1_13, *PWDF_DRIVER_CONFIG_V1_13; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_13; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_13, *PWDF_FDO_EVENT_CALLBACKS_V1_13; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_13 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_13, *PWDF_DRIVER_GLOBALS_V1_13; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfhwaccess.h +// +// End of versioning of structures for wdfhwaccess.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinternal.h +// +// End of versioning of structures for wdfinternal.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_13 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + + // + // TRUE: Interrupt is reported inactive on explicit power down + // instead of disconnecting it. + // FALSE: Interrupt is disconnected instead of reporting inactive + // on explicit power down. + // DEFAULT: Framework decides the right value. + // + WDF_TRI_STATE ReportInactiveOnPowerDown; + + // + // TRUE: Interrupt is used to wake the device from low-power states + // and when the device is armed for wake this interrupt should + // remain connected. + // FALSE: Interrupt is not used to wake the device from low-power states. + // This is the default. + // + BOOLEAN CanWakeDevice; + +} WDF_INTERRUPT_CONFIG_V1_13, *PWDF_INTERRUPT_CONFIG_V1_13; + +typedef struct _WDF_INTERRUPT_INFO_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + + DECLSPEC_ALIGN(8) USHORT Group; + +} WDF_INTERRUPT_INFO_V1_13, *PWDF_INTERRUPT_INFO_V1_13; + +// +// Interrupt Extended Policy Configuration Structure +// +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + WDF_INTERRUPT_POLICY Policy; + + WDF_INTERRUPT_PRIORITY Priority; + + GROUP_AFFINITY TargetProcessorSetAndGroup; + +} WDF_INTERRUPT_EXTENDED_POLICY_V1_13, *PWDF_INTERRUPT_EXTENDED_POLICY_V1_13; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_13 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + + WDFDRIVER Driver; + +} WDF_IO_QUEUE_CONFIG_V1_13, *PWDF_IO_QUEUE_CONFIG_V1_13; + +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13 { + ULONG Size; + + ULONG TotalForwardProgressRequests; + + // + // Specify the type of the policy here. + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY ForwardProgressReservedPolicy; + + // + // Structure which contains the policy specific fields + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY_SETTINGS ForwardProgressReservePolicySettings; + + // + // Callback for reserved request given at initialization time + // + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; + + // + // Callback for reserved request given at run time + // + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateRequestResources; + +} WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13, *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_13; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + // + // The requested access to the file or device, which can be summarized as + // read, write, both or neither zero). For more information about + // this member, see the dwDesiredAccess parameter of CreateFile in the + // Windows SDK. Note that ACCESS_MASK data type is a DWORD value. + // + // + ACCESS_MASK DesiredAccess; + + // + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // A zero value means exclusive access to the target. + // + // + // + // The type of sharing to allow for the file. For more information about + // this member, see the dwShareMode parameter of CreateFile in the + // Windows SDK. A value of 0 means exclusive access. + // + // + ULONG ShareAccess; + + // + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // Additional flags and attributes for the file. For more information about + // this member, see the dwFlagsAndAttributes parameter of CreateFile + // in the Windows SDK. + // + // + ULONG FileAttributes; + + // + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // The action to take if the file already exists. For more information + // about this member, see the dwCreationDisposition parameter of + // CreateFile in the Windows SDK. + // + // + ULONG CreateDisposition; + + // + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + // + // + // + PVOID EaBuffer; + + // + // + // + ULONG EaBufferLength; + + // + // + // + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + + // ========== WdfIoTargetOpenLocalTargetByFile begin ========== + // + // + // A UNICODE_STRING-formatted string that contains the + // name of the file to create a file object from. This parameter is + // optional, and is applicable only when Type parameter is + // WdfIoTargetOpenLocalTargetByFile. The driver can leave this member + // unchanged if the driver does not have to create the file object + // from a file name. If the driver must supply a name, the string that + // the driver passes must not contain any path separator characters + // ("/" or "\"). + // + UNICODE_STRING FileName; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_13, *PWDF_IO_TARGET_OPEN_PARAMS_V1_13; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_13 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_13, *PWDFMEMORY_OFFSET_V1_13; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_13 { + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_13 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_13, *PWDF_MEMORY_DESCRIPTOR_V1_13; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_13 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_13 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_13, *PWDF_OBJECT_ATTRIBUTES_V1_13; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_13 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_13 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_13, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_13; + +// +// Core structure for supporting custom types, see macros below. +// +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V1_13 { + ULONG Size; + + ULONG_PTR Data; + +} WDF_CUSTOM_TYPE_CONTEXT_V1_13, *PWDF_CUSTOM_TYPE_CONTEXT_V1_13; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_13 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + + // + // Called when reporting the PDO missing to PnP manager in response to + // IRP_MN_QUERY_DEVICE_RELATIONS for Bus Relations. + // + PFN_WDF_DEVICE_REPORTED_MISSING EvtDeviceReportedMissing; + +} WDF_PDO_EVENT_CALLBACKS_V1_13, *PWDF_PDO_EVENT_CALLBACKS_V1_13; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_13 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_13, *PWDF_QUERY_INTERFACE_CONFIG_V1_13; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_13 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_13, *PWDF_REQUEST_PARAMETERS_V1_13; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_13 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_13, *PWDF_REQUEST_COMPLETION_PARAMS_V1_13; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_13, *PWDF_REQUEST_REUSE_PARAMS_V1_13; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_13, *PWDF_REQUEST_SEND_OPTIONS_V1_13; + +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_FORWARD_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REQUEST_FORWARD_OPTIONS_V1_13, *PWDF_REQUEST_FORWARD_OPTIONS_V1_13; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfroletypes.h +// +// End of versioning of structures for wdfroletypes.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_13 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + + // + // If this is TRUE, high resolution timers will be used. The default + // value is FALSE + // + DECLSPEC_ALIGN(8) BOOLEAN UseHighResolutionTimer; + +} WDF_TIMER_CONFIG_V1_13, *PWDF_TIMER_CONFIG_V1_13; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftriage.h +// +typedef struct _WDFOBJECT_TRIAGE_INFO_V1_13 { + // value + ULONG RawObjectSize; + + ULONG ObjectType; + + ULONG TotalObjectSize; + + ULONG ChildListHead; + + ULONG ChildEntry; + + ULONG Globals; + + ULONG ParentObject; + +} WDFOBJECT_TRIAGE_INFO_V1_13, *PWDFOBJECT_TRIAGE_INFO_V1_13; + +typedef struct _WDFCONTEXT_TRIAGE_INFO_V1_13 { + // value + ULONG HeaderSize; + + ULONG NextHeader; + + ULONG Object; + + ULONG TypeInfoPtr; + + ULONG Context; + +} WDFCONTEXT_TRIAGE_INFO_V1_13, *PWDFCONTEXT_TRIAGE_INFO_V1_13; + +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_13 { + // value + ULONG TypeInfoSize; + + ULONG ContextSize; + + ULONG ContextName; + +} WDFCONTEXTTYPE_TRIAGE_INFO_V1_13, *PWDFCONTEXTTYPE_TRIAGE_INFO_V1_13; + +typedef struct _WDFQUEUE_TRIAGE_INFO_V1_13 { + // value + ULONG QueueSize; + + ULONG IrpQueue1; + + ULONG IrpQueue2; + + ULONG RequestList1; + + ULONG RequestList2; + + ULONG FwdProgressContext; + + ULONG PkgIo; + +} WDFQUEUE_TRIAGE_INFO_V1_13, *PWDFQUEUE_TRIAGE_INFO_V1_13; + +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_13 { + ULONG ReservedRequestList; + + ULONG ReservedRequestInUseList; + + ULONG PendedIrpList; + +} WDFFWDPROGRESS_TRIAGE_INFO_V1_13, *PWDFFWDPROGRESS_TRIAGE_INFO_V1_13; + +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V1_13 { + // value + ULONG IrpQueueSize; + + ULONG IrpListHeader; + + ULONG IrpListEntry; + + ULONG IrpContext; + +} WDFIRPQUEUE_TRIAGE_INFO_V1_13, *PWDFIRPQUEUE_TRIAGE_INFO_V1_13; + +typedef struct _WDFREQUEST_TRIAGE_INFO_V1_13 { + // value + ULONG RequestSize; + + ULONG CsqContext; + + // WDF irp wrapper, see below. + ULONG FxIrp; + + ULONG ListEntryQueueOwned; + + ULONG ListEntryQueueOwned2; + + ULONG RequestListEntry; + + ULONG FwdProgressList; + +} WDFREQUEST_TRIAGE_INFO_V1_13, *PWDFREQUEST_TRIAGE_INFO_V1_13; + +typedef struct _WDFDEVICE_TRIAGE_INFO_V1_13 { + // value + ULONG DeviceInitSize; + + ULONG DeviceDriver; + +} WDFDEVICE_TRIAGE_INFO_V1_13, *PWDFDEVICE_TRIAGE_INFO_V1_13; + +typedef struct _WDFIRP_TRIAGE_INFO_V1_13 { + // value + ULONG FxIrpSize; + + ULONG IrpPtr; + +} WDFIRP_TRIAGE_INFO_V1_13, *PWDFIRP_TRIAGE_INFO_V1_13; + +typedef struct _WDF_TRIAGE_INFO_V1_13 { + // + // Version. + // + ULONG WdfMajorVersion; + + ULONG WdfMinorVersion; + + ULONG TriageInfoMajorVersion; + + ULONG TriageInfoMinorVersion; + + // + // Reserved pointer. + // + PVOID Reserved; + + // + // WDF objects triage info. + // + PWDFOBJECT_TRIAGE_INFO_V1_13 WdfObjectTriageInfo; + + PWDFCONTEXT_TRIAGE_INFO_V1_13 WdfContextTriageInfo; + + PWDFCONTEXTTYPE_TRIAGE_INFO_V1_13 WdfContextTypeTriageInfo; + + PWDFQUEUE_TRIAGE_INFO_V1_13 WdfQueueTriageInfo; + + PWDFFWDPROGRESS_TRIAGE_INFO_V1_13 WdfFwdProgressTriageInfo; + + PWDFIRPQUEUE_TRIAGE_INFO_V1_13 WdfIrpQueueTriageInfo; + + PWDFREQUEST_TRIAGE_INFO_V1_13 WdfRequestTriageInfo; + + PWDFDEVICE_TRIAGE_INFO_V1_13 WdfDeviceTriageInfo; + + PWDFIRP_TRIAGE_INFO_V1_13 WdfIrpTriageInfo; + +} WDF_TRIAGE_INFO_V1_13, *PWDF_TRIAGE_INFO_V1_13; + +// End of versioning of structures for wdftriage.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_13 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_13, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_13; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_13 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_13 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_13, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_13; + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_13, *PWDF_USB_DEVICE_INFORMATION_V1_13; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_13 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_13, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_13; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_13 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_13; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_13; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_13, *PWDF_USB_PIPE_INFORMATION_V1_13; + +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD Client Contraction of the Wdf Client + // + ULONG USBDClientContractVersion; + +} WDF_USB_DEVICE_CREATE_CONFIG_V1_13, *PWDF_USB_DEVICE_CREATE_CONFIG_V1_13; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_13 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_13, *PWDF_WMI_PROVIDER_CONFIG_V1_13; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_13 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_13 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_13, *PWDF_WMI_INSTANCE_CONFIG_V1_13; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_13 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_13, *PWDF_WORKITEM_CONFIG_V1_13; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_13_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf115.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf115.h new file mode 100644 index 00000000000..a0d9043bd5f --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf115.h @@ -0,0 +1,3079 @@ +#ifndef _WDF_V1_15_TYPES_H_ +#define _WDF_V1_15_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_15 { + WdfFunctionTableNumEntries_V1_15 = 444, +} WDFFUNCENUM_V1_15; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_15 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_15; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_15 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_15; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_15 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_15; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_15 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_15; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_15 *PWDF_CHILD_RETRIEVE_INFO_V1_15; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_15 *PCWDF_CHILD_RETRIEVE_INFO_V1_15; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_15 *PWDF_CHILD_LIST_CONFIG_V1_15; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_15 *PCWDF_CHILD_LIST_CONFIG_V1_15; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_15 *PWDF_CHILD_LIST_ITERATOR_V1_15; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_15 *PCWDF_CHILD_LIST_ITERATOR_V1_15; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_15 *PWDF_COMMON_BUFFER_CONFIG_V1_15; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_15 *PCWDF_COMMON_BUFFER_CONFIG_V1_15; +typedef struct _WDFCX_FILEOBJECT_CONFIG_V1_15 *PWDFCX_FILEOBJECT_CONFIG_V1_15; +typedef const struct _WDFCX_FILEOBJECT_CONFIG_V1_15 *PCWDFCX_FILEOBJECT_CONFIG_V1_15; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_15 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_15; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_15 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_15; +typedef struct _WDF_CLASS_VERSION_V1_15 *PWDF_CLASS_VERSION_V1_15; +typedef const struct _WDF_CLASS_VERSION_V1_15 *PCWDF_CLASS_VERSION_V1_15; +typedef struct _WDF_CLASS_BIND_INFO_V1_15 *PWDF_CLASS_BIND_INFO_V1_15; +typedef const struct _WDF_CLASS_BIND_INFO_V1_15 *PCWDF_CLASS_BIND_INFO_V1_15; +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_15 *PWDF_CLASS_LIBRARY_INFO_V1_15; +typedef const struct _WDF_CLASS_LIBRARY_INFO_V1_15 *PCWDF_CLASS_LIBRARY_INFO_V1_15; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_15 *PWDF_FILEOBJECT_CONFIG_V1_15; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_15 *PCWDF_FILEOBJECT_CONFIG_V1_15; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_15 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_15; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_15 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_15; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_15 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_15; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_15 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_15; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_15 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_15; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_15 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_15; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_15 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_15; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_15 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_15; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_15 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_15; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_15 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_15; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15; +typedef struct _WDF_DEVICE_STATE_V1_15 *PWDF_DEVICE_STATE_V1_15; +typedef const struct _WDF_DEVICE_STATE_V1_15 *PCWDF_DEVICE_STATE_V1_15; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_15 *PWDF_DEVICE_PNP_CAPABILITIES_V1_15; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_15 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_15; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_15 *PWDF_DEVICE_POWER_CAPABILITIES_V1_15; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_15 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_15; +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V1_15 *PWDF_REMOVE_LOCK_OPTIONS_V1_15; +typedef const struct _WDF_REMOVE_LOCK_OPTIONS_V1_15 *PCWDF_REMOVE_LOCK_OPTIONS_V1_15; +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_15 *PWDF_POWER_FRAMEWORK_SETTINGS_V1_15; +typedef const struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_15 *PCWDF_POWER_FRAMEWORK_SETTINGS_V1_15; +typedef struct _WDF_IO_TYPE_CONFIG_V1_15 *PWDF_IO_TYPE_CONFIG_V1_15; +typedef const struct _WDF_IO_TYPE_CONFIG_V1_15 *PCWDF_IO_TYPE_CONFIG_V1_15; +typedef struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_15 *PWDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_15; +typedef const struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_15 *PCWDF_DEVICE_INTERFACE_PROPERTY_DATA_V1_15; +typedef struct _WDF_DEVICE_PROPERTY_DATA_V1_15 *PWDF_DEVICE_PROPERTY_DATA_V1_15; +typedef const struct _WDF_DEVICE_PROPERTY_DATA_V1_15 *PCWDF_DEVICE_PROPERTY_DATA_V1_15; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_15 *PWDF_DMA_ENABLER_CONFIG_V1_15; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_15 *PCWDF_DMA_ENABLER_CONFIG_V1_15; +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15 *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15; +typedef const struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15 *PCWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15; +typedef struct _WDF_DPC_CONFIG_V1_15 *PWDF_DPC_CONFIG_V1_15; +typedef const struct _WDF_DPC_CONFIG_V1_15 *PCWDF_DPC_CONFIG_V1_15; +typedef struct _WDF_DRIVER_CONFIG_V1_15 *PWDF_DRIVER_CONFIG_V1_15; +typedef const struct _WDF_DRIVER_CONFIG_V1_15 *PCWDF_DRIVER_CONFIG_V1_15; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_15 *PWDF_FDO_EVENT_CALLBACKS_V1_15; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_15 *PCWDF_FDO_EVENT_CALLBACKS_V1_15; +typedef struct _WDF_DRIVER_GLOBALS_V1_15 *PWDF_DRIVER_GLOBALS_V1_15; +typedef const struct _WDF_DRIVER_GLOBALS_V1_15 *PCWDF_DRIVER_GLOBALS_V1_15; +typedef struct _WDF_INTERRUPT_CONFIG_V1_15 *PWDF_INTERRUPT_CONFIG_V1_15; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_15 *PCWDF_INTERRUPT_CONFIG_V1_15; +typedef struct _WDF_INTERRUPT_INFO_V1_15 *PWDF_INTERRUPT_INFO_V1_15; +typedef const struct _WDF_INTERRUPT_INFO_V1_15 *PCWDF_INTERRUPT_INFO_V1_15; +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_15 *PWDF_INTERRUPT_EXTENDED_POLICY_V1_15; +typedef const struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_15 *PCWDF_INTERRUPT_EXTENDED_POLICY_V1_15; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_15 *PWDF_IO_QUEUE_CONFIG_V1_15; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_15 *PCWDF_IO_QUEUE_CONFIG_V1_15; +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15 *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15; +typedef const struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15 *PCWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_15 *PWDF_IO_TARGET_OPEN_PARAMS_V1_15; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_15 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_15; +typedef struct _WDFMEMORY_OFFSET_V1_15 *PWDFMEMORY_OFFSET_V1_15; +typedef const struct _WDFMEMORY_OFFSET_V1_15 *PCWDFMEMORY_OFFSET_V1_15; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_15 *PWDF_MEMORY_DESCRIPTOR_V1_15; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_15 *PCWDF_MEMORY_DESCRIPTOR_V1_15; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_15 *PWDF_OBJECT_ATTRIBUTES_V1_15; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_15 *PCWDF_OBJECT_ATTRIBUTES_V1_15; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_15 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_15; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_15 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_15; +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V1_15 *PWDF_CUSTOM_TYPE_CONTEXT_V1_15; +typedef const struct _WDF_CUSTOM_TYPE_CONTEXT_V1_15 *PCWDF_CUSTOM_TYPE_CONTEXT_V1_15; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_15 *PWDF_PDO_EVENT_CALLBACKS_V1_15; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_15 *PCWDF_PDO_EVENT_CALLBACKS_V1_15; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_15 *PWDF_QUERY_INTERFACE_CONFIG_V1_15; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_15 *PCWDF_QUERY_INTERFACE_CONFIG_V1_15; +typedef struct _WDF_REQUEST_PARAMETERS_V1_15 *PWDF_REQUEST_PARAMETERS_V1_15; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_15 *PCWDF_REQUEST_PARAMETERS_V1_15; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_15 *PWDF_REQUEST_COMPLETION_PARAMS_V1_15; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_15 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_15; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_15 *PWDF_REQUEST_REUSE_PARAMS_V1_15; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_15 *PCWDF_REQUEST_REUSE_PARAMS_V1_15; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_15 *PWDF_REQUEST_SEND_OPTIONS_V1_15; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_15 *PCWDF_REQUEST_SEND_OPTIONS_V1_15; +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_15 *PWDF_REQUEST_FORWARD_OPTIONS_V1_15; +typedef const struct _WDF_REQUEST_FORWARD_OPTIONS_V1_15 *PCWDF_REQUEST_FORWARD_OPTIONS_V1_15; +typedef struct _WDF_TIMER_CONFIG_V1_15 *PWDF_TIMER_CONFIG_V1_15; +typedef const struct _WDF_TIMER_CONFIG_V1_15 *PCWDF_TIMER_CONFIG_V1_15; +typedef struct _WDFOBJECT_TRIAGE_INFO_V1_15 *PWDFOBJECT_TRIAGE_INFO_V1_15; +typedef const struct _WDFOBJECT_TRIAGE_INFO_V1_15 *PCWDFOBJECT_TRIAGE_INFO_V1_15; +typedef struct _WDFCONTEXT_TRIAGE_INFO_V1_15 *PWDFCONTEXT_TRIAGE_INFO_V1_15; +typedef const struct _WDFCONTEXT_TRIAGE_INFO_V1_15 *PCWDFCONTEXT_TRIAGE_INFO_V1_15; +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_15 *PWDFCONTEXTTYPE_TRIAGE_INFO_V1_15; +typedef const struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_15 *PCWDFCONTEXTTYPE_TRIAGE_INFO_V1_15; +typedef struct _WDFQUEUE_TRIAGE_INFO_V1_15 *PWDFQUEUE_TRIAGE_INFO_V1_15; +typedef const struct _WDFQUEUE_TRIAGE_INFO_V1_15 *PCWDFQUEUE_TRIAGE_INFO_V1_15; +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_15 *PWDFFWDPROGRESS_TRIAGE_INFO_V1_15; +typedef const struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_15 *PCWDFFWDPROGRESS_TRIAGE_INFO_V1_15; +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V1_15 *PWDFIRPQUEUE_TRIAGE_INFO_V1_15; +typedef const struct _WDFIRPQUEUE_TRIAGE_INFO_V1_15 *PCWDFIRPQUEUE_TRIAGE_INFO_V1_15; +typedef struct _WDFREQUEST_TRIAGE_INFO_V1_15 *PWDFREQUEST_TRIAGE_INFO_V1_15; +typedef const struct _WDFREQUEST_TRIAGE_INFO_V1_15 *PCWDFREQUEST_TRIAGE_INFO_V1_15; +typedef struct _WDFDEVICE_TRIAGE_INFO_V1_15 *PWDFDEVICE_TRIAGE_INFO_V1_15; +typedef const struct _WDFDEVICE_TRIAGE_INFO_V1_15 *PCWDFDEVICE_TRIAGE_INFO_V1_15; +typedef struct _WDFIRP_TRIAGE_INFO_V1_15 *PWDFIRP_TRIAGE_INFO_V1_15; +typedef const struct _WDFIRP_TRIAGE_INFO_V1_15 *PCWDFIRP_TRIAGE_INFO_V1_15; +typedef struct _WDF_TRIAGE_INFO_V1_15 *PWDF_TRIAGE_INFO_V1_15; +typedef const struct _WDF_TRIAGE_INFO_V1_15 *PCWDF_TRIAGE_INFO_V1_15; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_15 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_15; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_15 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_15; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_15 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_15; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_15 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_15; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_15 *PWDF_USB_DEVICE_INFORMATION_V1_15; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_15 *PCWDF_USB_DEVICE_INFORMATION_V1_15; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_15 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_15; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_15 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_15; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_15 *PWDF_USB_PIPE_INFORMATION_V1_15; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_15 *PCWDF_USB_PIPE_INFORMATION_V1_15; +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_15 *PWDF_USB_DEVICE_CREATE_CONFIG_V1_15; +typedef const struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_15 *PCWDF_USB_DEVICE_CREATE_CONFIG_V1_15; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_15 *PWDF_WMI_PROVIDER_CONFIG_V1_15; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_15 *PCWDF_WMI_PROVIDER_CONFIG_V1_15; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_15 *PWDF_WMI_INSTANCE_CONFIG_V1_15; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_15 *PCWDF_WMI_INSTANCE_CONFIG_V1_15; +typedef struct _WDF_WORKITEM_CONFIG_V1_15 *PWDF_WORKITEM_CONFIG_V1_15; +typedef const struct _WDF_WORKITEM_CONFIG_V1_15 *PCWDF_WORKITEM_CONFIG_V1_15; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_15 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_15; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_15; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_15 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_15, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_15; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_15 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_15 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_15, *PWDF_CHILD_RETRIEVE_INFO_V1_15; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_15, *PWDF_CHILD_LIST_CONFIG_V1_15; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_15, *PWDF_CHILD_LIST_ITERATOR_V1_15; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_15, *PWDF_COMMON_BUFFER_CONFIG_V1_15; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfcx.h +// +typedef struct _WDFCX_FILEOBJECT_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDFCX_DEVICE_FILE_CREATE EvtCxDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDFCX_FILEOBJECT_CONFIG_V1_15, *PWDFCX_FILEOBJECT_CONFIG_V1_15; + +// End of versioning of structures for wdfcx.h + +// +// Versioning of structures for wdfcxbase.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_15 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_15 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_15, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_15; + +typedef struct _WDF_CLASS_VERSION_V1_15 { + WDF_MAJOR_VERSION Major; + + WDF_MINOR_VERSION Minor; + + WDF_BUILD_NUMBER Build; + +} WDF_CLASS_VERSION_V1_15; + +typedef struct _WDF_CLASS_BIND_INFO_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Name of the class to bind to + // + PWSTR ClassName; + + // + // Version information for the class + // + WDF_CLASS_VERSION_V1_15 Version; + + // + // Function export table from the class driver to resolve on bind + // + PFN_WDF_CLASS_EXPORT * FunctionTable; + + // + // Number of entries in FunctionTable + // + ULONG FunctionTableCount; + + // + // Optional field where the client specify additional information + // for the class driver to resolve + // + PVOID ClassBindInfo; + + // + // Optional bind callback. If set, WdfVersionBindClass will not + // be called and it will be up to ClientClassBind to call this function + // if required. + // + PFN_WDF_CLIENT_BIND_CLASS ClientBindClass; + + // + // Optional unbind callback. If set, WdfVersionUnbindClass will not be + // called and it will be up to ClientClassUnbind to call this function + // if required. + // + PFN_WDF_CLIENT_UNBIND_CLASS ClientUnbindClass; + + // + // Diagnostic cookie to use during debugging + // + PVOID ClassModule; + +} WDF_CLASS_BIND_INFO_V1_15, * PWDF_CLASS_BIND_INFO_V1_15; + +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Version of this class library + // + WDF_CLASS_VERSION_V1_15 Version; + + // + // Callback to be called by the loader to initialize the class library + // + PFN_WDF_CLASS_LIBRARY_INITIALIZE ClassLibraryInitialize; + + // + // Callback to be called by the loader to deinitialize the class library + // after succesful initialization (immediately before the class library will + // be unloaded). + // + PFN_WDF_CLASS_LIBRARY_DEINITIALIZE ClassLibraryDeinitialize; + + // + // Callback to be called by the loader when a client driver has request to + // be bound to this class library. + // + PFN_WDF_CLASS_LIBRARY_BIND_CLIENT ClassLibraryBindClient; + + // + // Callback to be called by the loader when a previously bound client driver + // is being unloaded. + // + PFN_WDF_CLASS_LIBRARY_UNBIND_CLIENT ClassLibraryUnbindClient; + +} WDF_CLASS_LIBRARY_INFO_V1_15, *PWDF_CLASS_LIBRARY_INFO_V1_15; + +// End of versioning of structures for wdfcxbase.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_15, *PWDF_FILEOBJECT_CONFIG_V1_15; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_15 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_15; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_15 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_15; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_15 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_15; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX EvtDeviceUsageNotificationEx; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_15, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_15; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_15, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_15; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + + // + // This field determines how the IdleTimeout field is used. + // + // If the value is DriverManagedIdleTimeout, then the idle timeout value + // is determined by the IdleTimeout field of this structure. + // + // If the value is SystemManagedIdleTimeout, then the timeout value is + // determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). The IdleTimeout field + // is ignored on these operating systems. On operating systems where the + // PoFx is not available, the behavior is same as DriverManagedIdleTimeout. + // + // If the value is SystemManagedIdleTimeoutWithHint, then the timeout value + // is determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). In addition, the value + // specified in the IdleTimeout field is provided as a hint to the PoFx in + // determining when the device should be allowed to enter a low-power state. + // Since it is only a hint, the actual duration after which the PoFx allows + // the device to enter a low-power state might be greater than or less than + // the IdleTimeout value. On operating systems where the PoFx is not + // available, the behavior is same as DriverManagedIdleTimeout. + // + WDF_POWER_POLICY_IDLE_TIMEOUT_TYPE IdleTimeoutType; + + // + // This field forces the device to avoid idling in the D3cold power state. + // WDF will ensure, with help from the bus drivers, that the device will + // idle in a D-state that can successfully generate a wake signal, if + // necessary. If the client specifies that DxState == PowerDeviceD3, this + // setting allows the client to distinguish betwen D3hot and D3cold. If + // the client sets DxState == PowerDeviceMaximum, then WDF will pick the + // deepest idle state identified by the bus driver. If that deepest state + // is D3cold, this field allows the client to override that and choose + // D3hot. + // + // If WdfTrue, device will not use D3cold in S0. + // If WdfFalse, device will use D3cold in S0 if the ACPI firmware indicates + // that the device can enter that state, if DxState above does not + // specify some other D-state and, if the device is armed for + // wake, that it can generate its wake signal from D3cold. + // If WdfUseDefault, this setting will be derived from the driver's INF, + // specifically the presence or absence of the following two lines in + // the DDInstall.HW section: + // Include=machine.inf + // Needs=PciD3ColdSupported + // + WDF_TRI_STATE ExcludeD3Cold; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_15; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_15; + +typedef struct _WDF_DEVICE_STATE_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_15, *PWDF_DEVICE_STATE_V1_15; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_15, *PWDF_DEVICE_PNP_CAPABILITIES_V1_15; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_15, *PWDF_DEVICE_POWER_CAPABILITIES_V1_15; + +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REMOVE_LOCK_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REMOVE_LOCK_OPTIONS_V1_15, *PWDF_REMOVE_LOCK_OPTIONS_V1_15; + +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V1_15 { + // + // Size of the structure, in bytes. + // + ULONG Size; + + // + // Client driver's callback function that is invoked after KMDF has + // registered with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE EvtDeviceWdmPostPoFxRegisterDevice; + + // + // Client driver's callback function that is invoked before KMDF + // unregisters with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE EvtDeviceWdmPrePoFxUnregisterDevice; + + // + // Pointer to a PO_FX_COMPONENT structure that describes the only component + // in the single-component device. This field can be NULL if the client + // driver wants KMDF to use the default specification for this component + // (i.e. support for F0 only). + // + PPO_FX_COMPONENT Component; + + // + // Client driver's PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_STATE_CALLBACK callback function. + // This field can be NULL if the client driver does not wish to specify + // this callback. + // + PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback; + + // + // Client driver's PO_FX_POWER_CONTROL_CALLBACK callback function. This + // field can be NULL if the client driver does not wish to specify this + // callback. + // + PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + + // + // Context value that is passed in to the ComponentIdleStateCallback and + // PowerControlCallback callback functions. + // + PVOID PoFxDeviceContext; + +} WDF_POWER_FRAMEWORK_SETTINGS_V1_15, *PWDF_POWER_FRAMEWORK_SETTINGS_V1_15; + +typedef struct _WDF_IO_TYPE_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // + // Identifies the method that the driver will use to access data buffers + // that it receives for read and write requests. + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for read and write requests. Note that UMDF + // driver provides just a preference, and not a guarantee.Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE ReadWriteIoType; + + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for IOCTL requests. Note that UMDF + // driver provides just a preference, and not a guarantee. Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE DeviceControlIoType; + + // + // + // Optional, Provides the smallest buffer size (in bytes) for which + // UMDF will use direct access for the buffers. For example, set + // DirectTransferThreshold to "12288" to indicate that UMDF should use buffered + // access for all buffers that are smaller than 12 kilobytes, and direct + // access for buffers equal to or greater than that. Typically, you + // do not need to provide this value because UMDF uses a value that provides + // the best performance. Note that there are other requirements that must be + // met in order to get direct access of buffers. See Docs for details. + // + ULONG DirectTransferThreshold; + +} WDF_IO_TYPE_CONFIG_V1_15, *PWDF_IO_TYPE_CONFIG_V1_15; + +typedef struct _WDF_DEVICE_PROPERTY_DATA_V1_15 { + // + // Size of this structure + // + _In_ ULONG Size; + + // + // A pointer to a DEVPROPKEY structure that specifies the device + // property key. + // + _In_ const DEVPROPKEY * PropertyKey; + + // + // A locale identifier. Set this parameter either to a language-specific + // LCID value or to LOCALE_NEUTRAL. The LOCALE_NEUTRAL LCID specifies + // that the property is language-neutral (that is, not specific to any + // language). Do not set this parameter to LOCALE_SYSTEM_DEFAULT or + // LOCALE_USER_DEFAULT. For more information about language-specific + // LCID values, see LCID Structure. + // + _In_ LCID Lcid; + + // + // Set this parameter to PLUGPLAY_PROPERTY_PERSISTENT if the property + // value set by this routine should persist across computer restarts. + // Otherwise, set Flags to zero. Ignored for Query DDIs. + // + _In_ ULONG Flags; + +} WDF_DEVICE_PROPERTY_DATA_V1_15, *PWDF_DEVICE_PROPERTY_DATA_V1_15; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDevicePri.h +// +// End of versioning of structures for wdfDevicePri.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + + // + // Overrides the address width specified by the DMA profile. + // + ULONG AddressWidthOverride; + + // + // Overrides the version of the WDM DMA interfaces that WDF uses + // (0 for default). + // + ULONG WdmDmaVersionOverride; + + // + // Bit field combination of values from the WDF_DMA_ENABLER_CONFIG_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_DMA_ENABLER_CONFIG_V1_15, *PWDF_DMA_ENABLER_CONFIG_V1_15; + +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Specifies that the transfer is controlled by the device's DMA + // request line. + // + // + BOOLEAN DemandMode; + + // + // Specifies that the DMA engine will loop back to the beginning + // of the buffer once it reaches the end. + // + // + BOOLEAN LoopedTransfer; + + // + // Width of the register to DMA to/from + // + // + DMA_WIDTH DmaWidth; + + // + // The adress at which to write to the device + // + PHYSICAL_ADDRESS DeviceAddress; + + // + // The translated resource descriptor for the DMA channel assigned + // the device during EvtDevicePrepareHardware + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR DmaDescriptor; + +} WDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15, *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V1_15; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_15 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_15, *PWDF_DPC_CONFIG_V1_15; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V1_15, *PWDF_DRIVER_CONFIG_V1_15; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_15; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_15, *PWDF_FDO_EVENT_CALLBACKS_V1_15; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_15 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_15, *PWDF_DRIVER_GLOBALS_V1_15; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfhid.h +// +// End of versioning of structures for wdfhid.h + +// +// Versioning of structures for wdfhwaccess.h +// +// End of versioning of structures for wdfhwaccess.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinternal.h +// +// End of versioning of structures for wdfinternal.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_15 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + + // + // TRUE: Interrupt is reported inactive on explicit power down + // instead of disconnecting it. + // FALSE: Interrupt is disconnected instead of reporting inactive + // on explicit power down. + // DEFAULT: Framework decides the right value. + // + WDF_TRI_STATE ReportInactiveOnPowerDown; + + // + // TRUE: Interrupt is used to wake the device from low-power states + // and when the device is armed for wake this interrupt should + // remain connected. + // FALSE: Interrupt is not used to wake the device from low-power states. + // This is the default. + // + BOOLEAN CanWakeDevice; + +} WDF_INTERRUPT_CONFIG_V1_15, *PWDF_INTERRUPT_CONFIG_V1_15; + +typedef struct _WDF_INTERRUPT_INFO_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + + DECLSPEC_ALIGN(8) USHORT Group; + +} WDF_INTERRUPT_INFO_V1_15, *PWDF_INTERRUPT_INFO_V1_15; + +// +// Interrupt Extended Policy Configuration Structure +// +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + WDF_INTERRUPT_POLICY Policy; + + WDF_INTERRUPT_PRIORITY Priority; + + GROUP_AFFINITY TargetProcessorSetAndGroup; + +} WDF_INTERRUPT_EXTENDED_POLICY_V1_15, *PWDF_INTERRUPT_EXTENDED_POLICY_V1_15; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_15 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + + WDFDRIVER Driver; + +} WDF_IO_QUEUE_CONFIG_V1_15, *PWDF_IO_QUEUE_CONFIG_V1_15; + +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15 { + ULONG Size; + + ULONG TotalForwardProgressRequests; + + // + // Specify the type of the policy here. + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY ForwardProgressReservedPolicy; + + // + // Structure which contains the policy specific fields + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY_SETTINGS ForwardProgressReservePolicySettings; + + // + // Callback for reserved request given at initialization time + // + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; + + // + // Callback for reserved request given at run time + // + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateRequestResources; + +} WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15, *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_15; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + // + // The requested access to the file or device, which can be summarized as + // read, write, both or neither zero). For more information about + // this member, see the dwDesiredAccess parameter of CreateFile in the + // Windows SDK. Note that ACCESS_MASK data type is a DWORD value. + // + // + ACCESS_MASK DesiredAccess; + + // + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // A zero value means exclusive access to the target. + // + // + // + // The type of sharing to allow for the file. For more information about + // this member, see the dwShareMode parameter of CreateFile in the + // Windows SDK. A value of 0 means exclusive access. + // + // + ULONG ShareAccess; + + // + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // Additional flags and attributes for the file. For more information about + // this member, see the dwFlagsAndAttributes parameter of CreateFile + // in the Windows SDK. + // + // + ULONG FileAttributes; + + // + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // The action to take if the file already exists. For more information + // about this member, see the dwCreationDisposition parameter of + // CreateFile in the Windows SDK. + // + // + ULONG CreateDisposition; + + // + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + // + // + // + PVOID EaBuffer; + + // + // + // + ULONG EaBufferLength; + + // + // + // + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + + // ========== WdfIoTargetOpenLocalTargetByFile begin ========== + // + // + // A UNICODE_STRING-formatted string that contains the + // name of the file to create a file object from. This parameter is + // optional, and is applicable only when Type parameter is + // WdfIoTargetOpenLocalTargetByFile. The driver can leave this member + // unchanged if the driver does not have to create the file object + // from a file name. If the driver must supply a name, the string that + // the driver passes must not contain any path separator characters + // ("/" or "\"). + // + UNICODE_STRING FileName; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_15, *PWDF_IO_TARGET_OPEN_PARAMS_V1_15; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfIoTargetPri.h +// +// End of versioning of structures for wdfIoTargetPri.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_15 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_15, *PWDFMEMORY_OFFSET_V1_15; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_15 { + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_15 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_15, *PWDF_MEMORY_DESCRIPTOR_V1_15; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_15 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_15 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_15, *PWDF_OBJECT_ATTRIBUTES_V1_15; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_15 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_15 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_15, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_15; + +// +// Core structure for supporting custom types, see macros below. +// +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V1_15 { + ULONG Size; + + ULONG_PTR Data; + +} WDF_CUSTOM_TYPE_CONTEXT_V1_15, *PWDF_CUSTOM_TYPE_CONTEXT_V1_15; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_15 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + + // + // Called when reporting the PDO missing to PnP manager in response to + // IRP_MN_QUERY_DEVICE_RELATIONS for Bus Relations. + // + PFN_WDF_DEVICE_REPORTED_MISSING EvtDeviceReportedMissing; + +} WDF_PDO_EVENT_CALLBACKS_V1_15, *PWDF_PDO_EVENT_CALLBACKS_V1_15; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_15 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_15, *PWDF_QUERY_INTERFACE_CONFIG_V1_15; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_15 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_15, *PWDF_REQUEST_PARAMETERS_V1_15; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_15 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_15, *PWDF_REQUEST_COMPLETION_PARAMS_V1_15; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_15, *PWDF_REQUEST_REUSE_PARAMS_V1_15; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_15, *PWDF_REQUEST_SEND_OPTIONS_V1_15; + +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_FORWARD_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REQUEST_FORWARD_OPTIONS_V1_15, *PWDF_REQUEST_FORWARD_OPTIONS_V1_15; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfroletypes.h +// +// End of versioning of structures for wdfroletypes.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_15 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + + // + // If this is TRUE, high resolution timers will be used. The default + // value is FALSE + // + DECLSPEC_ALIGN(8) BOOLEAN UseHighResolutionTimer; + +} WDF_TIMER_CONFIG_V1_15, *PWDF_TIMER_CONFIG_V1_15; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftriage.h +// +typedef struct _WDFOBJECT_TRIAGE_INFO_V1_15 { + // value + ULONG RawObjectSize; + + ULONG ObjectType; + + ULONG TotalObjectSize; + + ULONG ChildListHead; + + ULONG ChildEntry; + + ULONG Globals; + + ULONG ParentObject; + +} WDFOBJECT_TRIAGE_INFO_V1_15, *PWDFOBJECT_TRIAGE_INFO_V1_15; + +typedef struct _WDFCONTEXT_TRIAGE_INFO_V1_15 { + // value + ULONG HeaderSize; + + ULONG NextHeader; + + ULONG Object; + + ULONG TypeInfoPtr; + + ULONG Context; + +} WDFCONTEXT_TRIAGE_INFO_V1_15, *PWDFCONTEXT_TRIAGE_INFO_V1_15; + +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V1_15 { + // value + ULONG TypeInfoSize; + + ULONG ContextSize; + + ULONG ContextName; + +} WDFCONTEXTTYPE_TRIAGE_INFO_V1_15, *PWDFCONTEXTTYPE_TRIAGE_INFO_V1_15; + +typedef struct _WDFQUEUE_TRIAGE_INFO_V1_15 { + // value + ULONG QueueSize; + + ULONG IrpQueue1; + + ULONG IrpQueue2; + + ULONG RequestList1; + + ULONG RequestList2; + + ULONG FwdProgressContext; + + ULONG PkgIo; + +} WDFQUEUE_TRIAGE_INFO_V1_15, *PWDFQUEUE_TRIAGE_INFO_V1_15; + +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V1_15 { + ULONG ReservedRequestList; + + ULONG ReservedRequestInUseList; + + ULONG PendedIrpList; + +} WDFFWDPROGRESS_TRIAGE_INFO_V1_15, *PWDFFWDPROGRESS_TRIAGE_INFO_V1_15; + +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V1_15 { + // value + ULONG IrpQueueSize; + + ULONG IrpListHeader; + + ULONG IrpListEntry; + + ULONG IrpContext; + +} WDFIRPQUEUE_TRIAGE_INFO_V1_15, *PWDFIRPQUEUE_TRIAGE_INFO_V1_15; + +typedef struct _WDFREQUEST_TRIAGE_INFO_V1_15 { + // value + ULONG RequestSize; + + ULONG CsqContext; + + // WDF irp wrapper, see below. + ULONG FxIrp; + + ULONG ListEntryQueueOwned; + + ULONG ListEntryQueueOwned2; + + ULONG RequestListEntry; + + ULONG FwdProgressList; + +} WDFREQUEST_TRIAGE_INFO_V1_15, *PWDFREQUEST_TRIAGE_INFO_V1_15; + +typedef struct _WDFDEVICE_TRIAGE_INFO_V1_15 { + // value + ULONG DeviceInitSize; + + ULONG DeviceDriver; + +} WDFDEVICE_TRIAGE_INFO_V1_15, *PWDFDEVICE_TRIAGE_INFO_V1_15; + +typedef struct _WDFIRP_TRIAGE_INFO_V1_15 { + // value + ULONG FxIrpSize; + + ULONG IrpPtr; + +} WDFIRP_TRIAGE_INFO_V1_15, *PWDFIRP_TRIAGE_INFO_V1_15; + +typedef struct _WDF_TRIAGE_INFO_V1_15 { + // + // Version. + // + ULONG WdfMajorVersion; + + ULONG WdfMinorVersion; + + ULONG TriageInfoMajorVersion; + + ULONG TriageInfoMinorVersion; + + // + // Reserved pointer. + // + PVOID Reserved; + + // + // WDF objects triage info. + // + PWDFOBJECT_TRIAGE_INFO_V1_15 WdfObjectTriageInfo; + + PWDFCONTEXT_TRIAGE_INFO_V1_15 WdfContextTriageInfo; + + PWDFCONTEXTTYPE_TRIAGE_INFO_V1_15 WdfContextTypeTriageInfo; + + PWDFQUEUE_TRIAGE_INFO_V1_15 WdfQueueTriageInfo; + + PWDFFWDPROGRESS_TRIAGE_INFO_V1_15 WdfFwdProgressTriageInfo; + + PWDFIRPQUEUE_TRIAGE_INFO_V1_15 WdfIrpQueueTriageInfo; + + PWDFREQUEST_TRIAGE_INFO_V1_15 WdfRequestTriageInfo; + + PWDFDEVICE_TRIAGE_INFO_V1_15 WdfDeviceTriageInfo; + + PWDFIRP_TRIAGE_INFO_V1_15 WdfIrpTriageInfo; + +} WDF_TRIAGE_INFO_V1_15, *PWDF_TRIAGE_INFO_V1_15; + +// End of versioning of structures for wdftriage.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_15 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_15, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_15; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_15 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_15 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_15, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_15; + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_15, *PWDF_USB_DEVICE_INFORMATION_V1_15; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_15 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_15, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_15; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_15 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_15; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_15; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_15, *PWDF_USB_PIPE_INFORMATION_V1_15; + +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD Client Contraction of the Wdf Client + // + ULONG USBDClientContractVersion; + +} WDF_USB_DEVICE_CREATE_CONFIG_V1_15, *PWDF_USB_DEVICE_CREATE_CONFIG_V1_15; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_15, *PWDF_WMI_PROVIDER_CONFIG_V1_15; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_15 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_15, *PWDF_WMI_INSTANCE_CONFIG_V1_15; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_15 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_15, *PWDF_WORKITEM_CONFIG_V1_15; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_15_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf15.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf15.h new file mode 100644 index 00000000000..bb41df32b09 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf15.h @@ -0,0 +1,2209 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _WDF_V1_5_TYPES_H_ +#define _WDF_V1_5_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_5 { + WdfFunctionTableNumEntries_V1_5 = 387, +} WDFFUNCENUM_V1_5; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_5 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_5; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_5 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_5; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_5 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_5; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_5 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_5; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_5 *PWDF_CHILD_RETRIEVE_INFO_V1_5; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_5 *PCWDF_CHILD_RETRIEVE_INFO_V1_5; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_5 *PWDF_CHILD_LIST_CONFIG_V1_5; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_5 *PCWDF_CHILD_LIST_CONFIG_V1_5; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_5 *PWDF_CHILD_LIST_ITERATOR_V1_5; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_5 *PCWDF_CHILD_LIST_ITERATOR_V1_5; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_5 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_5; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_5 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_5; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_5 *PWDF_COMMON_BUFFER_CONFIG_V1_5; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_5 *PCWDF_COMMON_BUFFER_CONFIG_V1_5; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_5 *PWDF_FILEOBJECT_CONFIG_V1_5; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_5 *PCWDF_FILEOBJECT_CONFIG_V1_5; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_5 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_5; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_5 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_5; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_5 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_5; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_5 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_5; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_5 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_5; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_5 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_5; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_5 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_5; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_5 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_5; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_5; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_5; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5; +typedef struct _WDF_DEVICE_STATE_V1_5 *PWDF_DEVICE_STATE_V1_5; +typedef const struct _WDF_DEVICE_STATE_V1_5 *PCWDF_DEVICE_STATE_V1_5; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_5 *PWDF_DEVICE_PNP_CAPABILITIES_V1_5; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_5 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_5; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_5 *PWDF_DEVICE_POWER_CAPABILITIES_V1_5; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_5 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_5; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_5 *PWDF_DMA_ENABLER_CONFIG_V1_5; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_5 *PCWDF_DMA_ENABLER_CONFIG_V1_5; +typedef struct _WDF_DPC_CONFIG_V1_5 *PWDF_DPC_CONFIG_V1_5; +typedef const struct _WDF_DPC_CONFIG_V1_5 *PCWDF_DPC_CONFIG_V1_5; +typedef struct _WDF_DRIVER_CONFIG_V1_5 *PWDF_DRIVER_CONFIG_V1_5; +typedef const struct _WDF_DRIVER_CONFIG_V1_5 *PCWDF_DRIVER_CONFIG_V1_5; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_5 *PWDF_FDO_EVENT_CALLBACKS_V1_5; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_5 *PCWDF_FDO_EVENT_CALLBACKS_V1_5; +typedef struct _WDF_DRIVER_GLOBALS_V1_5 *PWDF_DRIVER_GLOBALS_V1_5; +typedef const struct _WDF_DRIVER_GLOBALS_V1_5 *PCWDF_DRIVER_GLOBALS_V1_5; +typedef struct _WDF_INTERRUPT_CONFIG_V1_5 *PWDF_INTERRUPT_CONFIG_V1_5; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_5 *PCWDF_INTERRUPT_CONFIG_V1_5; +typedef struct _WDF_INTERRUPT_INFO_V1_5 *PWDF_INTERRUPT_INFO_V1_5; +typedef const struct _WDF_INTERRUPT_INFO_V1_5 *PCWDF_INTERRUPT_INFO_V1_5; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_5 *PWDF_IO_QUEUE_CONFIG_V1_5; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_5 *PCWDF_IO_QUEUE_CONFIG_V1_5; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_5 *PWDF_IO_TARGET_OPEN_PARAMS_V1_5; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_5 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_5; +typedef struct _WDFMEMORY_OFFSET_V1_5 *PWDFMEMORY_OFFSET_V1_5; +typedef const struct _WDFMEMORY_OFFSET_V1_5 *PCWDFMEMORY_OFFSET_V1_5; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_5 *PWDF_MEMORY_DESCRIPTOR_V1_5; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_5 *PCWDF_MEMORY_DESCRIPTOR_V1_5; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_5 *PWDF_OBJECT_ATTRIBUTES_V1_5; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_5 *PCWDF_OBJECT_ATTRIBUTES_V1_5; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_5 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_5; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_5 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_5; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_5 *PWDF_PDO_EVENT_CALLBACKS_V1_5; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_5 *PCWDF_PDO_EVENT_CALLBACKS_V1_5; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_5 *PWDF_QUERY_INTERFACE_CONFIG_V1_5; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_5 *PCWDF_QUERY_INTERFACE_CONFIG_V1_5; +typedef struct _WDF_REQUEST_PARAMETERS_V1_5 *PWDF_REQUEST_PARAMETERS_V1_5; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_5 *PCWDF_REQUEST_PARAMETERS_V1_5; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_5 *PWDF_REQUEST_COMPLETION_PARAMS_V1_5; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_5 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_5; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_5 *PWDF_REQUEST_REUSE_PARAMS_V1_5; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_5 *PCWDF_REQUEST_REUSE_PARAMS_V1_5; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_5 *PWDF_REQUEST_SEND_OPTIONS_V1_5; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_5 *PCWDF_REQUEST_SEND_OPTIONS_V1_5; +typedef struct _WDF_TIMER_CONFIG_V1_5 *PWDF_TIMER_CONFIG_V1_5; +typedef const struct _WDF_TIMER_CONFIG_V1_5 *PCWDF_TIMER_CONFIG_V1_5; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_5 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_5; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_5 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_5; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_5 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_5; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_5 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_5; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_5 *PWDF_USB_DEVICE_INFORMATION_V1_5; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_5 *PCWDF_USB_DEVICE_INFORMATION_V1_5; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_5 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_5; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_5 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_5; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_5 *PWDF_USB_PIPE_INFORMATION_V1_5; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_5 *PCWDF_USB_PIPE_INFORMATION_V1_5; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_5 *PWDF_WMI_PROVIDER_CONFIG_V1_5; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_5 *PCWDF_WMI_PROVIDER_CONFIG_V1_5; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_5 *PWDF_WMI_INSTANCE_CONFIG_V1_5; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_5 *PCWDF_WMI_INSTANCE_CONFIG_V1_5; +typedef struct _WDF_WORKITEM_CONFIG_V1_5 *PWDF_WORKITEM_CONFIG_V1_5; +typedef const struct _WDF_WORKITEM_CONFIG_V1_5 *PCWDF_WORKITEM_CONFIG_V1_5; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_5 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_5; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_5; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_5 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_5, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_5; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_5 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_5 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_5, *PWDF_CHILD_RETRIEVE_INFO_V1_5; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_5, *PWDF_CHILD_LIST_CONFIG_V1_5; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_5, *PWDF_CHILD_LIST_ITERATOR_V1_5; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfClassExtension.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_5 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_5 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_5, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_5; + +// End of versioning of structures for wdfClassExtension.h + +// +// Versioning of structures for wdfClassExtensionList.h +// +// End of versioning of structures for wdfClassExtensionList.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_5, *PWDF_COMMON_BUFFER_CONFIG_V1_5; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_5, *PWDF_FILEOBJECT_CONFIG_V1_5; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_5 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_5; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_5 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_5; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_5 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_5; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_5, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_5; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_5; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_5; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5; + +typedef struct _WDF_DEVICE_STATE_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_5, *PWDF_DEVICE_STATE_V1_5; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_5, *PWDF_DEVICE_PNP_CAPABILITIES_V1_5; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_5, *PWDF_DEVICE_POWER_CAPABILITIES_V1_5; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + +} WDF_DMA_ENABLER_CONFIG_V1_5, *PWDF_DMA_ENABLER_CONFIG_V1_5; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_5 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_5, *PWDF_DPC_CONFIG_V1_5; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V1_5, *PWDF_DRIVER_CONFIG_V1_5; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_5; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_5, *PWDF_FDO_EVENT_CALLBACKS_V1_5; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_5 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_5, *PWDF_DRIVER_GLOBALS_V1_5; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_5 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_5, *PWDF_INTERRUPT_CONFIG_V1_5; + +typedef struct _WDF_INTERRUPT_INFO_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + +} WDF_INTERRUPT_INFO_V1_5, *PWDF_INTERRUPT_INFO_V1_5; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_5 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + +} WDF_IO_QUEUE_CONFIG_V1_5, *PWDF_IO_QUEUE_CONFIG_V1_5; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_5, *PWDF_IO_TARGET_OPEN_PARAMS_V1_5; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_5 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_5, *PWDFMEMORY_OFFSET_V1_5; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_5 { + + + + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_5 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_5, *PWDF_MEMORY_DESCRIPTOR_V1_5; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_5 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_5 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_5, *PWDF_OBJECT_ATTRIBUTES_V1_5; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_5 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_5 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_5, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_5; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_5 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_5, *PWDF_PDO_EVENT_CALLBACKS_V1_5; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_5 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + + + + // + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_5, *PWDF_QUERY_INTERFACE_CONFIG_V1_5; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_5 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_5, *PWDF_REQUEST_PARAMETERS_V1_5; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_5 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_5, *PWDF_REQUEST_COMPLETION_PARAMS_V1_5; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_5, *PWDF_REQUEST_REUSE_PARAMS_V1_5; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_5, *PWDF_REQUEST_SEND_OPTIONS_V1_5; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_5 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + LONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_TIMER_CONFIG_V1_5, *PWDF_TIMER_CONFIG_V1_5; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_5 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_5, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_5; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_5 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_5 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_5, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_5; + + + + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_5, *PWDF_USB_DEVICE_INFORMATION_V1_5; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_5 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_5, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_5; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_5 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_5; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_5; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_5, *PWDF_USB_PIPE_INFORMATION_V1_5; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_5, *PWDF_WMI_PROVIDER_CONFIG_V1_5; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_5 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_5 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_5, *PWDF_WMI_INSTANCE_CONFIG_V1_5; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_5 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_5, *PWDF_WORKITEM_CONFIG_V1_5; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_5_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf17.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf17.h new file mode 100644 index 00000000000..f4d3793717d --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf17.h @@ -0,0 +1,2228 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _WDF_V1_7_TYPES_H_ +#define _WDF_V1_7_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_7 { + WdfFunctionTableNumEntries_V1_7 = 387, +} WDFFUNCENUM_V1_7; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_7 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_7; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_7 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_7; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_7 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_7; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_7 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_7; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_7 *PWDF_CHILD_RETRIEVE_INFO_V1_7; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_7 *PCWDF_CHILD_RETRIEVE_INFO_V1_7; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_7 *PWDF_CHILD_LIST_CONFIG_V1_7; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_7 *PCWDF_CHILD_LIST_CONFIG_V1_7; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_7 *PWDF_CHILD_LIST_ITERATOR_V1_7; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_7 *PCWDF_CHILD_LIST_ITERATOR_V1_7; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_7 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_7; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_7 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_7; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_7 *PWDF_COMMON_BUFFER_CONFIG_V1_7; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_7 *PCWDF_COMMON_BUFFER_CONFIG_V1_7; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_7 *PWDF_FILEOBJECT_CONFIG_V1_7; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_7 *PCWDF_FILEOBJECT_CONFIG_V1_7; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_7 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_7; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_7 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_7; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_7 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_7; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_7 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_7; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_7 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_7; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_7 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_7; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_7 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_7; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_7 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_7; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_7 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_7; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_7 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_7; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7; +typedef struct _WDF_DEVICE_STATE_V1_7 *PWDF_DEVICE_STATE_V1_7; +typedef const struct _WDF_DEVICE_STATE_V1_7 *PCWDF_DEVICE_STATE_V1_7; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_7 *PWDF_DEVICE_PNP_CAPABILITIES_V1_7; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_7 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_7; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_7 *PWDF_DEVICE_POWER_CAPABILITIES_V1_7; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_7 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_7; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_7 *PWDF_DMA_ENABLER_CONFIG_V1_7; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_7 *PCWDF_DMA_ENABLER_CONFIG_V1_7; +typedef struct _WDF_DPC_CONFIG_V1_7 *PWDF_DPC_CONFIG_V1_7; +typedef const struct _WDF_DPC_CONFIG_V1_7 *PCWDF_DPC_CONFIG_V1_7; +typedef struct _WDF_DRIVER_CONFIG_V1_7 *PWDF_DRIVER_CONFIG_V1_7; +typedef const struct _WDF_DRIVER_CONFIG_V1_7 *PCWDF_DRIVER_CONFIG_V1_7; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_7 *PWDF_FDO_EVENT_CALLBACKS_V1_7; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_7 *PCWDF_FDO_EVENT_CALLBACKS_V1_7; +typedef struct _WDF_DRIVER_GLOBALS_V1_7 *PWDF_DRIVER_GLOBALS_V1_7; +typedef const struct _WDF_DRIVER_GLOBALS_V1_7 *PCWDF_DRIVER_GLOBALS_V1_7; +typedef struct _WDF_INTERRUPT_CONFIG_V1_7 *PWDF_INTERRUPT_CONFIG_V1_7; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_7 *PCWDF_INTERRUPT_CONFIG_V1_7; +typedef struct _WDF_INTERRUPT_INFO_V1_7 *PWDF_INTERRUPT_INFO_V1_7; +typedef const struct _WDF_INTERRUPT_INFO_V1_7 *PCWDF_INTERRUPT_INFO_V1_7; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_7 *PWDF_IO_QUEUE_CONFIG_V1_7; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_7 *PCWDF_IO_QUEUE_CONFIG_V1_7; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_7 *PWDF_IO_TARGET_OPEN_PARAMS_V1_7; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_7 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_7; +typedef struct _WDFMEMORY_OFFSET_V1_7 *PWDFMEMORY_OFFSET_V1_7; +typedef const struct _WDFMEMORY_OFFSET_V1_7 *PCWDFMEMORY_OFFSET_V1_7; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_7 *PWDF_MEMORY_DESCRIPTOR_V1_7; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_7 *PCWDF_MEMORY_DESCRIPTOR_V1_7; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_7 *PWDF_OBJECT_ATTRIBUTES_V1_7; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_7 *PCWDF_OBJECT_ATTRIBUTES_V1_7; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_7 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_7; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_7 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_7; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_7 *PWDF_PDO_EVENT_CALLBACKS_V1_7; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_7 *PCWDF_PDO_EVENT_CALLBACKS_V1_7; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_7 *PWDF_QUERY_INTERFACE_CONFIG_V1_7; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_7 *PCWDF_QUERY_INTERFACE_CONFIG_V1_7; +typedef struct _WDF_REQUEST_PARAMETERS_V1_7 *PWDF_REQUEST_PARAMETERS_V1_7; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_7 *PCWDF_REQUEST_PARAMETERS_V1_7; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_7 *PWDF_REQUEST_COMPLETION_PARAMS_V1_7; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_7 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_7; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_7 *PWDF_REQUEST_REUSE_PARAMS_V1_7; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_7 *PCWDF_REQUEST_REUSE_PARAMS_V1_7; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_7 *PWDF_REQUEST_SEND_OPTIONS_V1_7; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_7 *PCWDF_REQUEST_SEND_OPTIONS_V1_7; +typedef struct _WDF_TIMER_CONFIG_V1_7 *PWDF_TIMER_CONFIG_V1_7; +typedef const struct _WDF_TIMER_CONFIG_V1_7 *PCWDF_TIMER_CONFIG_V1_7; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_7 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_7; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_7 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_7; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_7 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_7; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_7 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_7; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_7 *PWDF_USB_DEVICE_INFORMATION_V1_7; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_7 *PCWDF_USB_DEVICE_INFORMATION_V1_7; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_7 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_7; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_7 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_7; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_7 *PWDF_USB_PIPE_INFORMATION_V1_7; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_7 *PCWDF_USB_PIPE_INFORMATION_V1_7; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_7 *PWDF_WMI_PROVIDER_CONFIG_V1_7; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_7 *PCWDF_WMI_PROVIDER_CONFIG_V1_7; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_7 *PWDF_WMI_INSTANCE_CONFIG_V1_7; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_7 *PCWDF_WMI_INSTANCE_CONFIG_V1_7; +typedef struct _WDF_WORKITEM_CONFIG_V1_7 *PWDF_WORKITEM_CONFIG_V1_7; +typedef const struct _WDF_WORKITEM_CONFIG_V1_7 *PCWDF_WORKITEM_CONFIG_V1_7; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_7 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_7; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_7; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_7 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_7, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_7; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_7 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_7 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_7, *PWDF_CHILD_RETRIEVE_INFO_V1_7; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_7, *PWDF_CHILD_LIST_CONFIG_V1_7; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_7, *PWDF_CHILD_LIST_ITERATOR_V1_7; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfClassExtension.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_7 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_7 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_7, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_7; + +// End of versioning of structures for wdfClassExtension.h + +// +// Versioning of structures for wdfClassExtensionList.h +// +// End of versioning of structures for wdfClassExtensionList.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_7, *PWDF_COMMON_BUFFER_CONFIG_V1_7; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_7, *PWDF_FILEOBJECT_CONFIG_V1_7; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_7 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_7; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_7 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_7; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_7 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_7; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_7, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_7; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_7, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_7; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_7; + +typedef struct _WDF_DEVICE_STATE_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_7, *PWDF_DEVICE_STATE_V1_7; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_7, *PWDF_DEVICE_PNP_CAPABILITIES_V1_7; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_7, *PWDF_DEVICE_POWER_CAPABILITIES_V1_7; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + +} WDF_DMA_ENABLER_CONFIG_V1_7, *PWDF_DMA_ENABLER_CONFIG_V1_7; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_7 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_7, *PWDF_DPC_CONFIG_V1_7; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V1_7, *PWDF_DRIVER_CONFIG_V1_7; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_7; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_7, *PWDF_FDO_EVENT_CALLBACKS_V1_7; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_7 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_7, *PWDF_DRIVER_GLOBALS_V1_7; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_7 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_7, *PWDF_INTERRUPT_CONFIG_V1_7; + +typedef struct _WDF_INTERRUPT_INFO_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + +} WDF_INTERRUPT_INFO_V1_7, *PWDF_INTERRUPT_INFO_V1_7; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_7 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + +} WDF_IO_QUEUE_CONFIG_V1_7, *PWDF_IO_QUEUE_CONFIG_V1_7; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_7, *PWDF_IO_TARGET_OPEN_PARAMS_V1_7; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_7 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_7, *PWDFMEMORY_OFFSET_V1_7; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_7 { + + + + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_7 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_7, *PWDF_MEMORY_DESCRIPTOR_V1_7; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_7 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_7 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_7, *PWDF_OBJECT_ATTRIBUTES_V1_7; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_7 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_7 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_7, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_7; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_7 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_7, *PWDF_PDO_EVENT_CALLBACKS_V1_7; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_7 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + + + + // + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_7, *PWDF_QUERY_INTERFACE_CONFIG_V1_7; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_7 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_7, *PWDF_REQUEST_PARAMETERS_V1_7; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_7 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_7, *PWDF_REQUEST_COMPLETION_PARAMS_V1_7; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_7, *PWDF_REQUEST_REUSE_PARAMS_V1_7; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_7, *PWDF_REQUEST_SEND_OPTIONS_V1_7; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_7 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + LONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_TIMER_CONFIG_V1_7, *PWDF_TIMER_CONFIG_V1_7; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_7 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_7, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_7; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_7 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_7 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_7, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_7; + + + + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_7, *PWDF_USB_DEVICE_INFORMATION_V1_7; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_7 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_7, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_7; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_7 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_7; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_7; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_7, *PWDF_USB_PIPE_INFORMATION_V1_7; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_7, *PWDF_WMI_PROVIDER_CONFIG_V1_7; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_7 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_7 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_7, *PWDF_WMI_INSTANCE_CONFIG_V1_7; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_7 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_7, *PWDF_WORKITEM_CONFIG_V1_7; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_7_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/inc/private/wdf19.h b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf19.h new file mode 100644 index 00000000000..507c63ca61c --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/inc/private/wdf19.h @@ -0,0 +1,2410 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _WDF_V1_9_TYPES_H_ +#define _WDF_V1_9_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V1_9 { + WdfFunctionTableNumEntries_V1_9 = 396, +} WDFFUNCENUM_V1_9; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_9 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_9; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_9 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_9; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_9 *PWDF_QUEUE_FATAL_ERROR_DATA_V1_9; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_9 *PCWDF_QUEUE_FATAL_ERROR_DATA_V1_9; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_9 *PWDF_CHILD_RETRIEVE_INFO_V1_9; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V1_9 *PCWDF_CHILD_RETRIEVE_INFO_V1_9; +typedef struct _WDF_CHILD_LIST_CONFIG_V1_9 *PWDF_CHILD_LIST_CONFIG_V1_9; +typedef const struct _WDF_CHILD_LIST_CONFIG_V1_9 *PCWDF_CHILD_LIST_CONFIG_V1_9; +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_9 *PWDF_CHILD_LIST_ITERATOR_V1_9; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V1_9 *PCWDF_CHILD_LIST_ITERATOR_V1_9; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_9 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_9; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_9 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_9; +typedef struct _WDF_CLASS_VERSION_V1_9 *PWDF_CLASS_VERSION_V1_9; +typedef const struct _WDF_CLASS_VERSION_V1_9 *PCWDF_CLASS_VERSION_V1_9; +typedef struct _WDF_CLASS_BIND_INFO_V1_9 *PWDF_CLASS_BIND_INFO_V1_9; +typedef const struct _WDF_CLASS_BIND_INFO_V1_9 *PCWDF_CLASS_BIND_INFO_V1_9; +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_9 *PWDF_CLASS_LIBRARY_INFO_V1_9; +typedef const struct _WDF_CLASS_LIBRARY_INFO_V1_9 *PCWDF_CLASS_LIBRARY_INFO_V1_9; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_9 *PWDF_COMMON_BUFFER_CONFIG_V1_9; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V1_9 *PCWDF_COMMON_BUFFER_CONFIG_V1_9; +typedef struct _WDF_FILEOBJECT_CONFIG_V1_9 *PWDF_FILEOBJECT_CONFIG_V1_9; +typedef const struct _WDF_FILEOBJECT_CONFIG_V1_9 *PCWDF_FILEOBJECT_CONFIG_V1_9; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_9 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_9; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_9 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V1_9; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_9 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_9; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_9 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V1_9; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_9 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_9; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_9 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_9; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_9 *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_9; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_9 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V1_9; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_9 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_9; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_9 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V1_9; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9; +typedef struct _WDF_DEVICE_STATE_V1_9 *PWDF_DEVICE_STATE_V1_9; +typedef const struct _WDF_DEVICE_STATE_V1_9 *PCWDF_DEVICE_STATE_V1_9; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_9 *PWDF_DEVICE_PNP_CAPABILITIES_V1_9; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V1_9 *PCWDF_DEVICE_PNP_CAPABILITIES_V1_9; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_9 *PWDF_DEVICE_POWER_CAPABILITIES_V1_9; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V1_9 *PCWDF_DEVICE_POWER_CAPABILITIES_V1_9; +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_9 *PWDF_DMA_ENABLER_CONFIG_V1_9; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V1_9 *PCWDF_DMA_ENABLER_CONFIG_V1_9; +typedef struct _WDF_DPC_CONFIG_V1_9 *PWDF_DPC_CONFIG_V1_9; +typedef const struct _WDF_DPC_CONFIG_V1_9 *PCWDF_DPC_CONFIG_V1_9; +typedef struct _WDF_DRIVER_CONFIG_V1_9 *PWDF_DRIVER_CONFIG_V1_9; +typedef const struct _WDF_DRIVER_CONFIG_V1_9 *PCWDF_DRIVER_CONFIG_V1_9; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_9 *PWDF_FDO_EVENT_CALLBACKS_V1_9; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V1_9 *PCWDF_FDO_EVENT_CALLBACKS_V1_9; +typedef struct _WDF_DRIVER_GLOBALS_V1_9 *PWDF_DRIVER_GLOBALS_V1_9; +typedef const struct _WDF_DRIVER_GLOBALS_V1_9 *PCWDF_DRIVER_GLOBALS_V1_9; +typedef struct _WDF_INTERRUPT_CONFIG_V1_9 *PWDF_INTERRUPT_CONFIG_V1_9; +typedef const struct _WDF_INTERRUPT_CONFIG_V1_9 *PCWDF_INTERRUPT_CONFIG_V1_9; +typedef struct _WDF_INTERRUPT_INFO_V1_9 *PWDF_INTERRUPT_INFO_V1_9; +typedef const struct _WDF_INTERRUPT_INFO_V1_9 *PCWDF_INTERRUPT_INFO_V1_9; +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_9 *PWDF_INTERRUPT_EXTENDED_POLICY_V1_9; +typedef const struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_9 *PCWDF_INTERRUPT_EXTENDED_POLICY_V1_9; +typedef struct _WDF_IO_QUEUE_CONFIG_V1_9 *PWDF_IO_QUEUE_CONFIG_V1_9; +typedef const struct _WDF_IO_QUEUE_CONFIG_V1_9 *PCWDF_IO_QUEUE_CONFIG_V1_9; +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9 *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9; +typedef const struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9 *PCWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_9 *PWDF_IO_TARGET_OPEN_PARAMS_V1_9; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V1_9 *PCWDF_IO_TARGET_OPEN_PARAMS_V1_9; +typedef struct _WDFMEMORY_OFFSET_V1_9 *PWDFMEMORY_OFFSET_V1_9; +typedef const struct _WDFMEMORY_OFFSET_V1_9 *PCWDFMEMORY_OFFSET_V1_9; +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_9 *PWDF_MEMORY_DESCRIPTOR_V1_9; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V1_9 *PCWDF_MEMORY_DESCRIPTOR_V1_9; +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_9 *PWDF_OBJECT_ATTRIBUTES_V1_9; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V1_9 *PCWDF_OBJECT_ATTRIBUTES_V1_9; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_9 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_9; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_9 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_9; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_9 *PWDF_PDO_EVENT_CALLBACKS_V1_9; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V1_9 *PCWDF_PDO_EVENT_CALLBACKS_V1_9; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_9 *PWDF_QUERY_INTERFACE_CONFIG_V1_9; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V1_9 *PCWDF_QUERY_INTERFACE_CONFIG_V1_9; +typedef struct _WDF_REQUEST_PARAMETERS_V1_9 *PWDF_REQUEST_PARAMETERS_V1_9; +typedef const struct _WDF_REQUEST_PARAMETERS_V1_9 *PCWDF_REQUEST_PARAMETERS_V1_9; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_9 *PWDF_REQUEST_COMPLETION_PARAMS_V1_9; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V1_9 *PCWDF_REQUEST_COMPLETION_PARAMS_V1_9; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_9 *PWDF_REQUEST_REUSE_PARAMS_V1_9; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V1_9 *PCWDF_REQUEST_REUSE_PARAMS_V1_9; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_9 *PWDF_REQUEST_SEND_OPTIONS_V1_9; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V1_9 *PCWDF_REQUEST_SEND_OPTIONS_V1_9; +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_9 *PWDF_REQUEST_FORWARD_OPTIONS_V1_9; +typedef const struct _WDF_REQUEST_FORWARD_OPTIONS_V1_9 *PCWDF_REQUEST_FORWARD_OPTIONS_V1_9; +typedef struct _WDF_TIMER_CONFIG_V1_9 *PWDF_TIMER_CONFIG_V1_9; +typedef const struct _WDF_TIMER_CONFIG_V1_9 *PCWDF_TIMER_CONFIG_V1_9; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_9 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_9; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_9 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V1_9; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_9 *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_9; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_9 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V1_9; +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_9 *PWDF_USB_DEVICE_INFORMATION_V1_9; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V1_9 *PCWDF_USB_DEVICE_INFORMATION_V1_9; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_9 *PWDF_USB_INTERFACE_SETTING_PAIR_V1_9; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_9 *PCWDF_USB_INTERFACE_SETTING_PAIR_V1_9; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9; +typedef struct _WDF_USB_PIPE_INFORMATION_V1_9 *PWDF_USB_PIPE_INFORMATION_V1_9; +typedef const struct _WDF_USB_PIPE_INFORMATION_V1_9 *PCWDF_USB_PIPE_INFORMATION_V1_9; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_9 *PWDF_WMI_PROVIDER_CONFIG_V1_9; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V1_9 *PCWDF_WMI_PROVIDER_CONFIG_V1_9; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_9 *PWDF_WMI_INSTANCE_CONFIG_V1_9; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V1_9 *PCWDF_WMI_INSTANCE_CONFIG_V1_9; +typedef struct _WDF_WORKITEM_CONFIG_V1_9 *PWDF_WORKITEM_CONFIG_V1_9; +typedef const struct _WDF_WORKITEM_CONFIG_V1_9 *PCWDF_WORKITEM_CONFIG_V1_9; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_9 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V1_9; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V1_9; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V1_9 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V1_9, *PWDF_QUEUE_FATAL_ERROR_DATA_V1_9; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V1_9 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V1_9 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V1_9, *PWDF_CHILD_RETRIEVE_INFO_V1_9; + +typedef struct _WDF_CHILD_LIST_CONFIG_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V1_9, *PWDF_CHILD_LIST_CONFIG_V1_9; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V1_9, *PWDF_CHILD_LIST_ITERATOR_V1_9; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfClassExtension.h +// +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V1_9 { + PCWDF_CLASS_EXTENSION_DESCRIPTOR_V1_9 Next; + + ULONG Size; + + PFN_WDF_CLASS_EXTENSIONIN_BIND Bind; + + PFN_WDF_CLASS_EXTENSIONIN_UNBIND Unbind; + +} WDF_CLASS_EXTENSION_DESCRIPTOR_V1_9, *PWDF_CLASS_EXTENSION_DESCRIPTOR_V1_9; + +typedef struct _WDF_CLASS_VERSION_V1_9 { + WDF_MAJOR_VERSION Major; + + WDF_MINOR_VERSION Minor; + + WDF_BUILD_NUMBER Build; + +} WDF_CLASS_VERSION_V1_9; + +typedef struct _WDF_CLASS_BIND_INFO_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Name of the class to bind to + // + PWSTR ClassName; + + // + // Version information for the class + // + WDF_CLASS_VERSION_V1_9 Version; + + // + // Function export table from the class driver to resolve on bind + // + PFN_WDF_CLASS_EXPORT * FunctionTable; + + // + // Number of entries in FunctionTable + // + ULONG FunctionTableCount; + + // + // Optional field where the client specify additional information + // for the class driver to resolve + // + PVOID ClassBindInfo; + + // + // Optional bind callback. If set, WdfVersionBindClass will not + // be called and it will be up to ClientClassBind to call this function + // if required. + // + PFN_WDF_CLIENT_BIND_CLASS ClientBindClass; + + // + // Optional unbind callback. If set, WdfVersionUnbindClass will not be + // called and it will be up to ClientClassUnbind to call this function + // if required. + // + PFN_WDF_CLIENT_UNBIND_CLASS ClientUnbindClass; + + // + // Diagnostic cookie to use during debugging + // + PVOID ClassModule; + +} WDF_CLASS_BIND_INFO_V1_9, * PWDF_CLASS_BIND_INFO_V1_9; + +typedef struct _WDF_CLASS_LIBRARY_INFO_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Version of this class library + // + WDF_CLASS_VERSION_V1_9 Version; + + // + // Callback to be called by the loader to initialize the class library + // + PFN_WDF_CLASS_LIBRARY_INITIALIZE ClassLibraryInitialize; + + // + // Callback to be called by the loader to deinitialize the class library + // after succesful initialization (immediately before the class library will + // be unloaded). + // + PFN_WDF_CLASS_LIBRARY_DEINITIALIZE ClassLibraryDeinitialize; + + // + // Callback to be called by the loader when a client driver has request to + // be bound to this class library. + // + PFN_WDF_CLASS_LIBRARY_BIND_CLIENT ClassLibraryBindClient; + + // + // Callback to be called by the loader when a previously bound client driver + // is being unloaded. + // + PFN_WDF_CLASS_LIBRARY_UNBIND_CLIENT ClassLibraryUnbindClient; + +} WDF_CLASS_LIBRARY_INFO_V1_9, *PWDF_CLASS_LIBRARY_INFO_V1_9; + +// End of versioning of structures for wdfClassExtension.h + +// +// Versioning of structures for wdfClassExtensionList.h +// +// End of versioning of structures for wdfClassExtensionList.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +typedef struct _WDF_COMMON_BUFFER_CONFIG_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Alignment requirement of the buffer address + // + ULONG AlignmentRequirement; + +} WDF_COMMON_BUFFER_CONFIG_V1_9, *PWDF_COMMON_BUFFER_CONFIG_V1_9; + +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V1_9, *PWDF_FILEOBJECT_CONFIG_V1_9; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_9 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V1_9; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_9 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V1_9; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_9 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V1_9; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_9, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_9; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_9, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_9; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_9; + +typedef struct _WDF_DEVICE_STATE_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V1_9, *PWDF_DEVICE_STATE_V1_9; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V1_9, *PWDF_DEVICE_PNP_CAPABILITIES_V1_9; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V1_9, *PWDF_DEVICE_POWER_CAPABILITIES_V1_9; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +typedef struct _WDF_DMA_ENABLER_CONFIG_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // One of the above WDF_DMA_PROFILES + // + WDF_DMA_PROFILE Profile; + + // + // Maximum DMA Transfer handled in bytes. + // + size_t MaximumLength; + + // + // The various DMA PnP/Power event callbacks + // + PFN_WDF_DMA_ENABLER_FILL EvtDmaEnablerFill; + + PFN_WDF_DMA_ENABLER_FLUSH EvtDmaEnablerFlush; + + PFN_WDF_DMA_ENABLER_DISABLE EvtDmaEnablerDisable; + + PFN_WDF_DMA_ENABLER_ENABLE EvtDmaEnablerEnable; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START EvtDmaEnablerSelfManagedIoStart; + + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP EvtDmaEnablerSelfManagedIoStop; + +} WDF_DMA_ENABLER_CONFIG_V1_9, *PWDF_DMA_ENABLER_CONFIG_V1_9; + +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +typedef struct _WDF_DPC_CONFIG_V1_9 { + ULONG Size; + + PFN_WDF_DPC EvtDpcFunc; + + // + // If this is TRUE, the DPC will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_DPC_CONFIG_V1_9, *PWDF_DPC_CONFIG_V1_9; + +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V1_9, *PWDF_DRIVER_CONFIG_V1_9; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V1_9; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V1_9, *PWDF_FDO_EVENT_CALLBACKS_V1_9; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V1_9 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V1_9, *PWDF_DRIVER_GLOBALS_V1_9; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_9 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_9, *PWDF_INTERRUPT_CONFIG_V1_9; + +typedef struct _WDF_INTERRUPT_INFO_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + + DECLSPEC_ALIGN(8) USHORT Group; + +} WDF_INTERRUPT_INFO_V1_9, *PWDF_INTERRUPT_INFO_V1_9; + +// +// Interrupt Extended Policy Configuration Structure +// +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + WDF_INTERRUPT_POLICY Policy; + + WDF_INTERRUPT_PRIORITY Priority; + + GROUP_AFFINITY TargetProcessorSetAndGroup; + +} WDF_INTERRUPT_EXTENDED_POLICY_V1_9, *PWDF_INTERRUPT_EXTENDED_POLICY_V1_9; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_9 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + +} WDF_IO_QUEUE_CONFIG_V1_9, *PWDF_IO_QUEUE_CONFIG_V1_9; + +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9 { + ULONG Size; + + ULONG TotalForwardProgressRequests; + + // + // Specify the type of the policy here. + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY ForwardProgressReservedPolicy; + + // + // Structure which contains the policy specific fields + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY_SETTINGS ForwardProgressReservePolicySettings; + + // + // Callback for reserved request given at initialization time + // + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; + + // + // Callback for reserved request given at run time + // + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateRequestResources; + +} WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9, *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V1_9; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_9, *PWDF_IO_TARGET_OPEN_PARAMS_V1_9; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V1_9 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V1_9, *PWDFMEMORY_OFFSET_V1_9; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V1_9 { + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V1_9 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V1_9, *PWDF_MEMORY_DESCRIPTOR_V1_9; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V1_9 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_9 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V1_9, *PWDF_OBJECT_ATTRIBUTES_V1_9; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_9 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V1_9 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_9, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_9; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_9 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_9, *PWDF_PDO_EVENT_CALLBACKS_V1_9; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V1_9 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V1_9, *PWDF_QUERY_INTERFACE_CONFIG_V1_9; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V1_9 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V1_9, *PWDF_REQUEST_PARAMETERS_V1_9; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_9 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V1_9, *PWDF_REQUEST_COMPLETION_PARAMS_V1_9; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V1_9, *PWDF_REQUEST_REUSE_PARAMS_V1_9; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V1_9, *PWDF_REQUEST_SEND_OPTIONS_V1_9; + +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_FORWARD_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REQUEST_FORWARD_OPTIONS_V1_9, *PWDF_REQUEST_FORWARD_OPTIONS_V1_9; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_9 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + +} WDF_TIMER_CONFIG_V1_9, *PWDF_TIMER_CONFIG_V1_9; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V1_9 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V1_9, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V1_9; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V1_9 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V1_9 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V1_9, *PWDF_USB_CONTINUOUS_READER_CONFIG_V1_9; + +typedef struct _WDF_USB_DEVICE_INFORMATION_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V1_9, *PWDF_USB_DEVICE_INFORMATION_V1_9; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V1_9 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V1_9, *PWDF_USB_INTERFACE_SETTING_PAIR_V1_9; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V1_9 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V1_9; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V1_9; + +typedef struct _WDF_USB_PIPE_INFORMATION_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V1_9, *PWDF_USB_PIPE_INFORMATION_V1_9; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V1_9, *PWDF_WMI_PROVIDER_CONFIG_V1_9; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V1_9 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V1_9 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V1_9, *PWDF_WMI_INSTANCE_CONFIG_V1_9; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V1_9 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V1_9, *PWDF_WORKITEM_CONFIG_V1_9; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V1_9_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/corepriv.hpp b/sdk/lib/drivers/wdf/kmdf/src/core/corepriv.hpp new file mode 100644 index 00000000000..81888584756 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/corepriv.hpp @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + corepriv.hpp + +Abstract: + + Main driver framework private header. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + + +extern "C" { +#include +#include "wdf.h" +} + +#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf" + diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxbugcheckcallback.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxbugcheckcallback.cpp new file mode 100644 index 00000000000..1a9935e4e8b --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxbugcheckcallback.cpp @@ -0,0 +1,1219 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxBugcheckCallback.cpp + +Abstract: + + This module contains the bugcheck callback functions for determining whether + a wdf driver caused a bugcheck and for capturing the IFR data to the mini- + dump file. + +Revision History: + + + +--*/ + + +#include "fxcorepch.hpp" +#include "FxIFR.h" +#include "fxIFRKm.h" // kernel mode only IFR definitions +#include "FxLdr.h" +#include "FxBugcheck.h" + +#include + +// +// Disable warnings of features used by the standard headers +// +// Disable warning C4115: named type definition in parentheses +// Disable warning C4200: nonstandard extension used : zero-sized array in struct/union +// Disable warning C4201: nonstandard extension used : nameless struct/union +// Disable warning C4214: nonstandard extension used : bit field types other than int +// +#pragma warning(disable:4115 4200 4201 4214) +#include +#pragma warning(default:4115 4200 4201 4214) + + +extern "C" { + +// +// Private methods. +// +_Must_inspect_result_ +BOOLEAN +FxpIsAddressKnownToWdf( + __in PVOID Address, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +_Must_inspect_result_ +NTSTATUS +FxpGetImageBase( + __in PDRIVER_OBJECT DriverObject, + __out PVOID* ImageBase, + __out PULONG ImageSize + ); + +_Must_inspect_result_ +BOOLEAN +FxpBugCheckCallbackFilter( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +KBUGCHECK_REASON_CALLBACK_ROUTINE FxpBugCheckCallback; + +KBUGCHECK_REASON_CALLBACK_ROUTINE FxpLibraryBugCheckCallback; + +_Must_inspect_result_ +BOOLEAN +FxpIsAddressKnownToWdf( + __in PVOID Address, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +/*++ + +Routine Description: + + This routine will check the address to determine if it falls within the + image of a WDF component (Library, Client driver or Class Extension). + This is accomplished by traversing the WdfLdrGlobals.LoadedModuleList + and comparing each image start/end address with Address. + +Arguments: + + PVOID Address - The address to be checked, and it need not be currently + paged in. In other words, it is NOT used in this routine as an + address, but more as a simple scaler into a 4GB (x86) array. + + NOTE - Do not attempt to validatate Address, say via MmIsAddressValid(Address). + Address's memory could be paged out, but Address is still valid. + + PFX_DRIVER_GLOBALS FxDriverGlobals - Driver's globals. + +Return Value: + + TRUE indicates something was found, either library, client or both. + FALSE indicates either not found or invalid parameters. + +--*/ +{ + + if (NULL == Address || NULL == FxDriverGlobals) { + return FALSE; + } + + if (Address >= FxDriverGlobals->ImageAddress && + Address < WDF_PTR_ADD_OFFSET(FxDriverGlobals->ImageAddress, + FxDriverGlobals->ImageSize)) { + return TRUE; + } + + return FALSE; +} + +_Must_inspect_result_ +NTSTATUS +FxpGetImageBase( + __in PDRIVER_OBJECT DriverObject, + __out PVOID* ImageBase, + __out PULONG ImageSize + ) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + ULONG modulesSize = 0; + AUX_MODULE_EXTENDED_INFO* modules = NULL; + AUX_MODULE_EXTENDED_INFO* module; + PVOID addressInImage = NULL; + ULONG numberOfModules; + ULONG i; + + // + // Basic validation. + // + if (NULL == DriverObject || NULL == ImageBase || NULL == ImageSize) { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + + // + // Get the address of a well known entry in the Image. + // + addressInImage = (PVOID) DriverObject->DriverStart; + ASSERT(addressInImage != NULL); + + // + // Initialize the AUX Kernel Library. + // + status = AuxKlibInitialize(); + if (!NT_SUCCESS(status)) { + goto exit; + } + + // + // Get size of area needed for loaded modules. + // + status = AuxKlibQueryModuleInformation(&modulesSize, + sizeof(AUX_MODULE_EXTENDED_INFO), + NULL); + + if (!NT_SUCCESS(status) || (0 == modulesSize)) { + goto exit; + } + + numberOfModules = modulesSize / sizeof(AUX_MODULE_EXTENDED_INFO); + + // + // Allocate returned-sized memory for the modules area. + // + modules = (AUX_MODULE_EXTENDED_INFO*) ExAllocatePoolWithTag(PagedPool, + modulesSize, + '30LW'); + if (NULL == modules) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + + // + // Request the modules array be filled with module information. + // + status = AuxKlibQueryModuleInformation(&modulesSize, + sizeof(AUX_MODULE_EXTENDED_INFO), + modules); + + if (!NT_SUCCESS(status)) { + goto exit; + } + + // + // Traverse list, searching for the well known address in Image for which the + // module's Image Base Address is in its range. + // + module = modules; + + for (i=0; i < numberOfModules; i++) { + + if (addressInImage >= module->BasicInfo.ImageBase && + addressInImage < WDF_PTR_ADD_OFFSET(module->BasicInfo.ImageBase, + module->ImageSize)) { + + *ImageBase = module->BasicInfo.ImageBase; + *ImageSize = module->ImageSize; + + status = STATUS_SUCCESS; + goto exit; + } + module++; + } + + status = STATUS_NOT_FOUND; + +exit: + + if (modules != NULL) { + ExFreePool(modules); + modules = NULL; + } + + return status; +} + +_Must_inspect_result_ +BOOLEAN +FxpBugCheckCallbackFilter( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals + ) +/*++ + +Routine Description: + + This routine evaluates whether the driver's IFR data has to be written to + the mini-dump file. + +Arguments: + + FxDriverGlobals - The driver globals of the wdf driver. + +Return Value: + + TRUE - Indicates this driver's IFR log is to be captured in dump. + FALSE - Indicates this driver's log is (probably) not of interest. + +--*/ +{ + PVOID codeAddr = NULL; + BOOLEAN found = FALSE; + KBUGCHECK_DATA bugCheckData = {0}; + + if (FxDriverGlobals->FxForceLogsInMiniDump) { + return TRUE; + } + + // + // Retrieve the bugcheck parameters. + // + bugCheckData.BugCheckDataSize = sizeof(KBUGCHECK_DATA); + AuxKlibGetBugCheckData(&bugCheckData); + + // + // Check whether the code address that caused the bugcheck is from this wdf + // driver. + // + switch (bugCheckData.BugCheckCode) { + + case KERNEL_APC_PENDING_DURING_EXIT: // 0x20 + codeAddr = (PVOID)bugCheckData.Parameter1; + found = FxpIsAddressKnownToWdf(codeAddr, FxDriverGlobals); + break; + + case KMODE_EXCEPTION_NOT_HANDLED: // 0x1E + case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED: // 0x7E + case KERNEL_MODE_EXCEPTION_NOT_HANDLED: // 0x8E + codeAddr = (PVOID)bugCheckData.Parameter2; + found = FxpIsAddressKnownToWdf(codeAddr, FxDriverGlobals); + break; + + case PAGE_FAULT_IN_NONPAGED_AREA: // 0x50 + codeAddr = (PVOID)bugCheckData.Parameter3; + found = FxpIsAddressKnownToWdf(codeAddr, FxDriverGlobals); + break; + + case IRQL_NOT_LESS_OR_EQUAL: // 0xA + case DRIVER_IRQL_NOT_LESS_OR_EQUAL: // 0xD1 + codeAddr = (PVOID)bugCheckData.Parameter4; + found = FxpIsAddressKnownToWdf(codeAddr, FxDriverGlobals); + break; + } + + // + // If the code address was found in the wdf driver, then set the flag in the + // driver globals to indicate that the IFR data has to be written to the + // mini-dump. + // + if (found) { + FxDriverGlobals->FxForceLogsInMiniDump = TRUE; + } + + + + + + + + + + + + + + + + return found; +} + +VOID +FxpBugCheckCallback( + __in KBUGCHECK_CALLBACK_REASON Reason, + __in PKBUGCHECK_REASON_CALLBACK_RECORD Record, + __inout PVOID ReasonSpecificData, + __in ULONG ReasonSpecificLength + ) + +/*++ + +Routine Description: + + BugCheck callback routine for WDF + +Arguments: + + Reason - Must be KbCallbackSecondaryData + Record - Supplies the bugcheck record previously registered + ReasonSpecificData - Pointer to KBUGCHECK_SECONDARY_DUMP_DATA + ReasonSpecificLength - Sizeof(ReasonSpecificData) + +Return Value: + + None + +Notes: + When a bugcheck happens the kernel bugcheck processor will make two passes + of all registered BugCheckCallbackRecord routines. The first pass, called + the "sizing pass" essentially queries all the callbacks to collect the + total size of the secondary dump data. In the second pass the actual data + is captured to the dump. + +--*/ + +{ + PKBUGCHECK_SECONDARY_DUMP_DATA dumpData; + PFX_DRIVER_GLOBALS fxDriverGlobals; + ULONG logSize; + BOOLEAN writeLog = FALSE; + + UNREFERENCED_PARAMETER(Reason); + UNREFERENCED_PARAMETER(ReasonSpecificLength); + + ASSERT(ReasonSpecificLength >= sizeof(KBUGCHECK_SECONDARY_DUMP_DATA)); + ASSERT(Reason == KbCallbackSecondaryDumpData); + + dumpData = (PKBUGCHECK_SECONDARY_DUMP_DATA) ReasonSpecificData; + + // + // See if the IFR's minimum amount of data can fit in the dump + // + if (dumpData->MaximumAllowed < FxIFRMinLogSize) { + return; + } + + // + // Get the driver globals containing the bugcheck callback record. + // + fxDriverGlobals = CONTAINING_RECORD(Record, + FX_DRIVER_GLOBALS, + BugCheckCallbackRecord); + + // + // If there is not IFR data, then this bugcheck callback does not have any + // data to write to the minidump. + // + if (NULL == fxDriverGlobals->WdfLogHeader) { + return; + } + + // + // Size is the length of the buffer which we log to. It should also include + // the size of the header (which was subtracted out in FxIFRStart). + // + logSize = ((PWDF_IFR_HEADER) fxDriverGlobals->WdfLogHeader)->Size + + sizeof(WDF_IFR_HEADER); + + ASSERT(FxIFRMinLogSize <= logSize && logSize <= FxIFRMaxLogSize); + + // + // Check whether log can fit in the dump. + // + if (logSize > dumpData->MaximumAllowed) { + return; + } + + // + // Check whether this log is the one to copy. + // + if (FxpBugCheckCallbackFilter(fxDriverGlobals)) { + // + // Let everyone know that we got the best match. + // + FxLibraryGlobals.BestDriverForDumpLog = fxDriverGlobals; + + // + // Exact match driver. + // + writeLog = TRUE; + } + else if (NULL == FxLibraryGlobals.BestDriverForDumpLog) { + // + // So far we didn't get a perfect match. Make a best effort + // to find a good candidate for the driver dump log. + // + if (fxDriverGlobals->FxTrackDriverForMiniDumpLog && + FxLibraryGlobals.DriverTracker.GetCurrentTrackedDriver() == + fxDriverGlobals) { + // + // Best effort match driver. + // + writeLog = TRUE; + } + } + + if (writeLog) { + dumpData->OutBuffer = fxDriverGlobals->WdfLogHeader; + dumpData->OutBufferLength = logSize; + dumpData->Guid = WdfDumpGuid; + } +} + +VOID +FxRegisterBugCheckCallback( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PDRIVER_OBJECT DriverObject + ) +{ + UNICODE_STRING funcName; + PKBUGCHECK_REASON_CALLBACK_RECORD callbackRecord; + PFN_KE_REGISTER_BUGCHECK_REASON_CALLBACK funcPtr; + BOOLEAN enableDriverTracking; + + // + // If any problem during this setup, disable driver tracking. + // + enableDriverTracking = FxDriverGlobals->FxTrackDriverForMiniDumpLog; + FxDriverGlobals->FxTrackDriverForMiniDumpLog = FALSE; + + // + // Zero out callback record. + // + callbackRecord = &FxDriverGlobals->BugCheckCallbackRecord; + RtlZeroMemory(callbackRecord, sizeof(KBUGCHECK_REASON_CALLBACK_RECORD)); + + // + // Get the Image base address and size before registering the bugcheck + // callbacks. If the image base address and size cannot be computed, + // then the bugcheck callbacks depend on these values being properly + // set. + // + FxDriverGlobals->ImageAddress = NULL; + FxDriverGlobals->ImageSize = 0; + + if (!NT_SUCCESS(FxpGetImageBase(DriverObject, + &FxDriverGlobals->ImageAddress, + &FxDriverGlobals->ImageSize))) { + goto Done; + } + + + + + + + + + + + // + // The KeRegisterBugCheckReasonCallback exists for xp sp1 and above. So + // check whether this function is defined on the current OS and register + // for the bugcheck callback only if this function is defined. + // + RtlInitUnicodeString(&funcName, L"KeRegisterBugCheckReasonCallback"); + funcPtr = (PFN_KE_REGISTER_BUGCHECK_REASON_CALLBACK) + MmGetSystemRoutineAddress(&funcName); + + if (NULL == funcPtr) { + goto Done; + } + + // + // Register this driver with driver tracker. + // + if (enableDriverTracking) { + if (NT_SUCCESS(FxLibraryGlobals.DriverTracker.Register( + FxDriverGlobals))) { + FxDriverGlobals->FxTrackDriverForMiniDumpLog = TRUE; + } + } + + // + // Initialize the callback record. + // + KeInitializeCallbackRecord(callbackRecord); + + // + // Register the bugcheck callback. + // + funcPtr(callbackRecord, + FxpBugCheckCallback, + KbCallbackSecondaryDumpData, + (PUCHAR)FxDriverGlobals->Public.DriverName); + + ASSERT(callbackRecord->CallbackRoutine != NULL); + +Done:; +} + +VOID +FxUnregisterBugCheckCallback( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + UNICODE_STRING funcName; + PKBUGCHECK_REASON_CALLBACK_RECORD callbackRecord; + PFN_KE_DEREGISTER_BUGCHECK_REASON_CALLBACK funcPtr; + + callbackRecord = &FxDriverGlobals->BugCheckCallbackRecord; + if (NULL == callbackRecord->CallbackRoutine) { + goto Done; + } + + // + // The KeDeregisterBugCheckReasonCallback exists for xp sp1 and above. So + // check whether this function is defined on the current OS and deregister + // from the bugcheck callback only if this function is defined. + // + RtlInitUnicodeString(&funcName, L"KeDeregisterBugCheckReasonCallback"); + funcPtr = (PFN_KE_DEREGISTER_BUGCHECK_REASON_CALLBACK) + MmGetSystemRoutineAddress(&funcName); + + if (NULL == funcPtr) { + goto Done; + } + + funcPtr(callbackRecord); + callbackRecord->CallbackRoutine = NULL; + + // + // Deregister this driver with driver tracker. + // + if (FxDriverGlobals->FxTrackDriverForMiniDumpLog) { + FxLibraryGlobals.DriverTracker.Deregister(FxDriverGlobals); + } + +Done:; +} + +VOID +FxpLibraryBugCheckCallback( + __in KBUGCHECK_CALLBACK_REASON Reason, + __in PKBUGCHECK_REASON_CALLBACK_RECORD /* Record */, + __inout PVOID ReasonSpecificData, + __in ULONG ReasonSpecificLength + ) + +/*++ + +Routine Description: + + Global (framework-library) BugCheck callback routine for WDF + +Arguments: + + Reason - Must be KbCallbackSecondaryData + Record - Supplies the bugcheck record previously registered + ReasonSpecificData - Pointer to KBUGCHECK_SECONDARY_DUMP_DATA + ReasonSpecificLength - Sizeof(ReasonSpecificData) + +Return Value: + + None + +Notes: + When a bugcheck happens the kernel bugcheck processor will make two passes + of all registered BugCheckCallbackRecord routines. The first pass, called + the "sizing pass" essentially queries all the callbacks to collect the + total size of the secondary dump data. In the second pass the actual data + is captured to the dump. + +--*/ + +{ + PKBUGCHECK_SECONDARY_DUMP_DATA dumpData; + ULONG dumpSize; + + UNREFERENCED_PARAMETER(Reason); + UNREFERENCED_PARAMETER(ReasonSpecificLength); + + ASSERT(ReasonSpecificLength >= sizeof(KBUGCHECK_SECONDARY_DUMP_DATA)); + ASSERT(Reason == KbCallbackSecondaryDumpData); + + dumpData = (PKBUGCHECK_SECONDARY_DUMP_DATA) ReasonSpecificData; + dumpSize = FxLibraryGlobals.BugCheckDriverInfoIndex * + sizeof(FX_DUMP_DRIVER_INFO_ENTRY); + // + // See if the bugcheck driver info is more than can fit in the dump + // + if (dumpData->MaximumAllowed < dumpSize) { + dumpSize = EXP_ALIGN_DOWN_ON_BOUNDARY( + dumpData->MaximumAllowed, + sizeof(FX_DUMP_DRIVER_INFO_ENTRY)); + } + + if (0 == dumpSize) { + goto Done; + } + + // + // Ok, provide the info about the bugcheck data. + // + dumpData->OutBuffer = FxLibraryGlobals.BugCheckDriverInfo; + dumpData->OutBufferLength = dumpSize; + dumpData->Guid = WdfDumpGuid2; + +Done:; +} + +VOID +FxInitializeBugCheckDriverInfo() +{ + NTSTATUS status; + UNICODE_STRING funcName; + PKBUGCHECK_REASON_CALLBACK_RECORD callbackRecord; + PFN_KE_REGISTER_BUGCHECK_REASON_CALLBACK funcPtr; + SIZE_T arraySize; + ULONG arrayCount; + + + callbackRecord = &FxLibraryGlobals.BugCheckCallbackRecord; + RtlZeroMemory(callbackRecord, sizeof(KBUGCHECK_REASON_CALLBACK_RECORD)); + + FxLibraryGlobals.BugCheckDriverInfoCount = 0; + FxLibraryGlobals.BugCheckDriverInfoIndex = 0; + FxLibraryGlobals.BugCheckDriverInfo = NULL; + + + + + + + + + + + // + // The KeRegisterBugCheckReasonCallback exists for xp sp1 and above. So + // check whether this function is defined on the current OS and register + // for the bugcheck callback only if this function is defined. + // + RtlInitUnicodeString(&funcName, L"KeRegisterBugCheckReasonCallback"); + funcPtr = (PFN_KE_REGISTER_BUGCHECK_REASON_CALLBACK) + MmGetSystemRoutineAddress(&funcName); + + if (NULL == funcPtr) { + goto Done; + } + + arraySize = sizeof(FX_DUMP_DRIVER_INFO_ENTRY) * FX_DUMP_DRIVER_INFO_INCREMENT; + arrayCount = FX_DUMP_DRIVER_INFO_INCREMENT; + + FxLibraryGlobals.BugCheckDriverInfo = + (PFX_DUMP_DRIVER_INFO_ENTRY)MxMemory::MxAllocatePoolWithTag( + NonPagedPool, + arraySize, + FX_TAG); + + if (NULL == FxLibraryGlobals.BugCheckDriverInfo) { + goto Done; + } + + FxLibraryGlobals.BugCheckDriverInfoCount = arrayCount; + + // + // Init first entry for the framework. + // + FxLibraryGlobals.BugCheckDriverInfo[0].FxDriverGlobals = NULL; + FxLibraryGlobals.BugCheckDriverInfo[0].Version.Major = __WDF_MAJOR_VERSION; + FxLibraryGlobals.BugCheckDriverInfo[0].Version.Minor = __WDF_MINOR_VERSION; + FxLibraryGlobals.BugCheckDriverInfo[0].Version.Build = __WDF_BUILD_NUMBER; + + status = RtlStringCbCopyA( + FxLibraryGlobals.BugCheckDriverInfo[0].DriverName, + sizeof(FxLibraryGlobals.BugCheckDriverInfo[0].DriverName), + WdfLdrType); + + if (!NT_SUCCESS(status)) { + ASSERT(FALSE); + FxLibraryGlobals.BugCheckDriverInfo[0].DriverName[0] = '\0'; + } + + FxLibraryGlobals.BugCheckDriverInfoIndex++; + + // + // Initialize the callback record. + // + KeInitializeCallbackRecord(callbackRecord); + + // + // Register the bugcheck callback. + // + funcPtr(callbackRecord, + FxpLibraryBugCheckCallback, + KbCallbackSecondaryDumpData, + (PUCHAR)WdfLdrType); + + ASSERT(callbackRecord->CallbackRoutine != NULL); + +Done:; +} + +VOID +FxUninitializeBugCheckDriverInfo() +{ + UNICODE_STRING funcName; + PKBUGCHECK_REASON_CALLBACK_RECORD callbackRecord; + PFN_KE_DEREGISTER_BUGCHECK_REASON_CALLBACK funcPtr; + + // + // Deregister callback. + // + + + + + + + + callbackRecord = &FxLibraryGlobals.BugCheckCallbackRecord; + if (NULL == callbackRecord->CallbackRoutine) { + goto Done; + } + + // + // The KeDeregisterBugCheckReasonCallback exists for xp sp1 and above. So + // check whether this function is defined on the current OS and deregister + // from the bugcheck callback only if this function is defined. + // + RtlInitUnicodeString(&funcName, L"KeDeregisterBugCheckReasonCallback"); + funcPtr = (PFN_KE_DEREGISTER_BUGCHECK_REASON_CALLBACK) + MmGetSystemRoutineAddress(&funcName); + + if (NULL == funcPtr) { + goto Done; + } + + funcPtr(callbackRecord); + callbackRecord->CallbackRoutine = NULL; + + // + // Release memory. + // + if (NULL == FxLibraryGlobals.BugCheckDriverInfo) { + goto Done; + } + + // + // Dynamic KMDF framework is unloading, make sure there is only one entry + // left in the driver info array; the framework lib was using this entry + // to store its version. + // + ASSERT(1 == FxLibraryGlobals.BugCheckDriverInfoIndex); + + FxLibraryGlobals.BugCheckDriverInfoIndex = 0; + FxLibraryGlobals.BugCheckDriverInfoCount = 0; + + MxMemory::MxFreePool(FxLibraryGlobals.BugCheckDriverInfo); + FxLibraryGlobals.BugCheckDriverInfo = NULL; + +Done:; +} + +VOID +FxCacheBugCheckDriverInfo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + KIRQL irql; + PFX_DUMP_DRIVER_INFO_ENTRY driverInfo = NULL; + PFX_DUMP_DRIVER_INFO_ENTRY oldDriverInfo = NULL; + ULONG newCount = 0; + + // + // Clear driver index (0-based). Drivers do not use index 0. + // + FxDriverGlobals->BugCheckDriverInfoIndex = 0; + + if (NULL == FxLibraryGlobals.BugCheckDriverInfo) { + return; + } + + FxLibraryGlobals.FxDriverGlobalsListLock.Acquire(&irql); + + // + // Make sure we have enough space, else allocate some more memory. + // + if (FxLibraryGlobals.BugCheckDriverInfoIndex >= + FxLibraryGlobals.BugCheckDriverInfoCount) { + + // + // Just exit if no more space in dump buffer. + // + if ((FX_MAX_DUMP_DRIVER_INFO_COUNT - FX_DUMP_DRIVER_INFO_INCREMENT) < + FxLibraryGlobals.BugCheckDriverInfoCount) { + ASSERT(FALSE); + goto Done; + } + + newCount = FxLibraryGlobals.BugCheckDriverInfoCount + + FX_DUMP_DRIVER_INFO_INCREMENT; + + // + // Allocate new buffer to hold driver info. + // + driverInfo = (PFX_DUMP_DRIVER_INFO_ENTRY)MxMemory::MxAllocatePoolWithTag( + NonPagedPool, + sizeof(FX_DUMP_DRIVER_INFO_ENTRY)* newCount, + FX_TAG); + + if (NULL == driverInfo) { + goto Done; + } + + // + // Copy data from old to new buffer. + // + RtlCopyMemory(driverInfo, + FxLibraryGlobals.BugCheckDriverInfo, + FxLibraryGlobals.BugCheckDriverInfoCount * + sizeof(FX_DUMP_DRIVER_INFO_ENTRY)); + // + // Ok, replace global pointer and its count. + // + oldDriverInfo = FxLibraryGlobals.BugCheckDriverInfo; + FxLibraryGlobals.BugCheckDriverInfo = driverInfo; + FxLibraryGlobals.BugCheckDriverInfoCount = newCount; + driverInfo = NULL; // just in case. + + // + // Free old memory. + // + MxMemory::MxFreePool(oldDriverInfo); + oldDriverInfo = NULL; + } + + ASSERT(FxLibraryGlobals.BugCheckDriverInfoIndex < + FxLibraryGlobals.BugCheckDriverInfoCount); + // + // Compute ptr to free entry. + // + driverInfo = FxLibraryGlobals.BugCheckDriverInfo + + FxLibraryGlobals.BugCheckDriverInfoIndex; + // + // Cache some of this driver's info. + // + driverInfo->FxDriverGlobals = FxDriverGlobals; + driverInfo->Version = FxDriverGlobals->WdfBindInfo->Version; + + C_ASSERT(sizeof(driverInfo->DriverName) == + sizeof(FxDriverGlobals->Public.DriverName)); + RtlCopyMemory(driverInfo->DriverName, + FxDriverGlobals->Public.DriverName, + sizeof(driverInfo->DriverName)); + driverInfo->DriverName[ARRAY_SIZE(driverInfo->DriverName) - 1] = '\0'; + + // + // Cache this index for later when the driver is removed. + // + FxDriverGlobals->BugCheckDriverInfoIndex = + FxLibraryGlobals.BugCheckDriverInfoIndex; + + // + // Update global index. + // + FxLibraryGlobals.BugCheckDriverInfoIndex++; + +Done: + + FxLibraryGlobals.FxDriverGlobalsListLock.Release(irql); +} + +VOID +FxPurgeBugCheckDriverInfo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + KIRQL irql; + PFX_DUMP_DRIVER_INFO_ENTRY driverInfo = NULL; + ULONG driverIndex = 0; + ULONG shiftCount = 0; + ULONG i = 0; + + FxLibraryGlobals.FxDriverGlobalsListLock.Acquire(&irql); + + // + // Zero means 'not used'. + // + driverIndex = FxDriverGlobals->BugCheckDriverInfoIndex; + if (0 == driverIndex) { + goto Done; + } + + // + // Check if feature is not supported. + // + if (NULL == FxLibraryGlobals.BugCheckDriverInfo) { + ASSERT(FALSE); // driverIndex > 0 with NULL array? + goto Done; + } + + + ASSERT(FxLibraryGlobals.BugCheckDriverInfoIndex <= + FxLibraryGlobals.BugCheckDriverInfoCount); + + // + // Index boundary validation. + // + if (driverIndex >= FxLibraryGlobals.BugCheckDriverInfoIndex) { + ASSERT(FALSE); + goto Done; + } + + // + // Compute ptr to driver info. + // + driverInfo = FxLibraryGlobals.BugCheckDriverInfo + driverIndex; + + // + // Double-check that this is the same driver. + // + if (driverInfo->FxDriverGlobals != FxDriverGlobals) { + ASSERT(FALSE); + goto Done; + } + + // + // Shift memory to fill hole and update global free index. + // + shiftCount = FxLibraryGlobals.BugCheckDriverInfoIndex - driverIndex - 1; + if (shiftCount > 0) { + RtlMoveMemory(driverInfo, + driverInfo + 1, + shiftCount * sizeof(FX_DUMP_DRIVER_INFO_ENTRY)); + } + + FxLibraryGlobals.BugCheckDriverInfoIndex--; + + // + // Update cached index for all 'shifted' drivers. + // + for (i = driverIndex; i < FxLibraryGlobals.BugCheckDriverInfoIndex; ++i) { + FxLibraryGlobals.BugCheckDriverInfo[i].FxDriverGlobals-> + BugCheckDriverInfoIndex--; + } + +Done: + + FxLibraryGlobals.FxDriverGlobalsListLock.Release(irql); +} + +// +// Driver usage tracker functions +// +NTSTATUS +FX_DRIVER_TRACKER_CACHE_AWARE::Initialize() +{ + // + // Global initialization. It balances the global Uninitialize function. + // The real init is actually done by the Register function the first time + // a driver registers with the device tracker. + // + m_DriverUsage = NULL; + m_PoolToFree = NULL; + m_EntrySize = 0; + m_Number = 0; + + return STATUS_SUCCESS; +} + +VOID +FX_DRIVER_TRACKER_CACHE_AWARE::Uninitialize() +{ + if (m_PoolToFree != NULL) { + +#ifdef DBG + for (ULONG index = 0; index < m_Number; ++index) { + PFX_DRIVER_TRACKER_ENTRY driverUsage = NULL; + driverUsage = GetProcessorDriverEntryRef(index); + ASSERT(NULL == driverUsage->FxDriverGlobals); + } +#endif + MxMemory::MxFreePool(m_PoolToFree); + m_PoolToFree = NULL; + } + + m_DriverUsage = NULL; + m_Number = 0; +} + +NTSTATUS +FX_DRIVER_TRACKER_CACHE_AWARE::Register( + __in PFX_DRIVER_GLOBALS /* FxDriverGlobals */ + ) +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + ULONG paddedSize = 0; + ULONG index = 0; + PFX_DRIVER_TRACKER_ENTRY pool = NULL; + PFX_DRIVER_TRACKER_ENTRY driverUsage = NULL; + UNICODE_STRING funcName; + PVOID funcPtr = NULL; + + // + // Nothing to do if tracker is already initialized. No need for a lock + // here since PnP already serializes driver initialization. + // + if (m_PoolToFree != NULL) { + ASSERT(m_DriverUsage != NULL && m_Number != 0); + status = STATUS_SUCCESS; + goto Done; + } + + // + // Intialize the procgrp down level library. + // + WdmlibProcgrpInitialize(); + + // + // Capture maximum number of processors. + // + RtlInitUnicodeString(&funcName, L"KeQueryMaximumProcessorCountEx"); + funcPtr = MmGetSystemRoutineAddress(&funcName); + if (funcPtr != NULL) { + // + // Win 7 and forward. + // + m_Number = ((PFN_KE_QUERY_MAXIMUM_PROCESSOR_COUNT_EX)funcPtr)( + ALL_PROCESSOR_GROUPS); + } + else { + RtlInitUnicodeString(&funcName, L"KeQueryMaximumProcessorCount"); + funcPtr = MmGetSystemRoutineAddress(&funcName); + if (funcPtr != NULL) { + // + // Windows Server 2008. + // + m_Number = ((PFN_KE_QUERY_MAXIMUM_PROCESSOR_COUNT)funcPtr)(); + } + else { + if ((5 == FxLibraryGlobals.OsVersionInfo.dwMajorVersion && + 0 < FxLibraryGlobals.OsVersionInfo.dwMinorVersion) || + (6 == FxLibraryGlobals.OsVersionInfo.dwMajorVersion && + 0 == FxLibraryGlobals.OsVersionInfo.dwMinorVersion)){ + // + // XP (Major=5, Minor>0) and Vista (Major=6, Minor=0). + // + m_Number = (ULONG)(*((CCHAR *)&KeNumberProcessors)); + } + else { + // + // This feature is not supported for Windows 2000. + // + ASSERT(FALSE); + status = STATUS_NOT_SUPPORTED; + goto Done; + } + } + } + + // + // Validate upper bound. + // + if (m_Number > FX_DRIVER_TRACKER_MAX_CPUS) { + status = STATUS_NOT_SUPPORTED; + goto Done; + } + + // + // Determine padded size of each tracking entry structure. + // + if (m_Number > 1 ) { + RtlInitUnicodeString(&funcName, L"KeGetRecommendedSharedDataAlignment"); + funcPtr = MmGetSystemRoutineAddress(&funcName); + + if (funcPtr != NULL) { + // + //XP and forward + // + paddedSize = ((PFN_KE_GET_RECOMMENDED_SHARED_DATA_ALIGNMENT)funcPtr)(); + ASSERT ((paddedSize & (paddedSize - 1)) == 0); + } + else { + // + // This feature is not supported for Windows 2000. + // + status = STATUS_NOT_SUPPORTED; + goto Done; + } + } + else { + paddedSize = sizeof(FX_DRIVER_TRACKER_ENTRY); + } + + ASSERT(sizeof(FX_DRIVER_TRACKER_ENTRY) <= paddedSize); + + // + // Remember the size. + // + m_EntrySize = paddedSize; + + pool = (PFX_DRIVER_TRACKER_ENTRY)MxMemory::MxAllocatePoolWithTag( + NonPagedPool, + paddedSize * m_Number, + FX_TAG); + if (NULL == pool) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // + // Check if pool is aligned if this is a multi-proc. + // + if ((m_Number > 1) && !EXP_IS_PTR_ALIGNED_ON_BOUNDARY(pool, paddedSize)) { + // + // We will allocate a padded size, free the old pool. + // + ExFreePool(pool); + + // + // Allocate enough padding so we can start the refs on an aligned boundary + // + pool = (PFX_DRIVER_TRACKER_ENTRY)MxMemory::MxAllocatePoolWithTag( + NonPagedPool, + paddedSize * m_Number + paddedSize, + FX_TAG); + if (NULL == pool) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + driverUsage = (PFX_DRIVER_TRACKER_ENTRY) + EXP_ALIGN_UP_PTR_ON_BOUNDARY(pool, paddedSize); + + } + else { + // + // Already aligned pool. + // + driverUsage = pool; + } + + // + // Remember the pool block to free. + // + m_PoolToFree = pool; + m_DriverUsage = driverUsage; + + // + // Init driver usage entries. + // + for (index = 0; index < m_Number; ++index) { + driverUsage = GetProcessorDriverEntryRef(index); + driverUsage->FxDriverGlobals = NULL; + } + + // + // All done. + // + status = STATUS_SUCCESS; + +Done: + return status; +} + +VOID +FX_DRIVER_TRACKER_CACHE_AWARE::Deregister( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + ULONG index = 0; + PFX_DRIVER_TRACKER_ENTRY driverUsage = NULL; + + // + // Cleanup any refs to this driver's globals. + // + if (m_PoolToFree != NULL) { + + ASSERT(m_DriverUsage != NULL && m_Number != 0); + + for (index = 0; index < m_Number; ++index) { + driverUsage = GetProcessorDriverEntryRef(index); + if (driverUsage->FxDriverGlobals == FxDriverGlobals) { + driverUsage->FxDriverGlobals = NULL; + } + } + } +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxchildlist.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxchildlist.cpp new file mode 100644 index 00000000000..d5adf0fa7d2 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxchildlist.cpp @@ -0,0 +1,3268 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxChildList.cpp + +Abstract: + + This module implements the FxChildList class + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "fxcorepch.hpp" + +extern "C" { +#include "FxChildList.tmh" +} + +FxDeviceDescriptionEntry::FxDeviceDescriptionEntry( + __inout FxChildList* DeviceList, + __in ULONG AddressDescriptionSize, + __in ULONG IdentificationDescriptionSize + ) +{ + m_IdentificationDescription = + (PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER) WDF_PTR_ADD_OFFSET( + this, WDF_ALIGN_SIZE_UP(sizeof(*this), sizeof(PVOID))); + + m_IdentificationDescription->IdentificationDescriptionSize = + AddressDescriptionSize; + + if (IdentificationDescriptionSize > 0) { + m_AddressDescription = + (PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER) WDF_PTR_ADD_OFFSET( + m_IdentificationDescription, + WDF_ALIGN_SIZE_UP(AddressDescriptionSize, sizeof(PVOID))); + + m_AddressDescription->AddressDescriptionSize = + IdentificationDescriptionSize; + } + + InitializeListHead(&m_DescriptionLink); + InitializeListHead(&m_ModificationLink); + + m_ModificationState = ModificationInsert; + + m_DeviceList = DeviceList; + + m_FoundInLastScan = FALSE; + m_ProcessingSurpriseRemove = FALSE; + m_PendingDeleteOnScanEnd = FALSE; + + // + // The parent DO can go away while the child still exists (stuck in a + // suprise remove state w/an open handle). As such, when the parent is + // destroyed, it will release its reference on the FxChildList. Each + // description will have its own reference to the list to keep the list + // alive as long as the child DO exists. + // + m_DeviceList->ADDREF(this); +} + +FxDeviceDescriptionEntry::~FxDeviceDescriptionEntry() +{ + m_DeviceList->RELEASE(this); +} + +_Must_inspect_result_ +PVOID +FxDeviceDescriptionEntry::operator new( + __in size_t AllocatorBlock, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t TotalDescriptionSize + ) +{ + PVOID p; + + UNREFERENCED_PARAMETER(AllocatorBlock); + + p = FxPoolAllocate(FxDriverGlobals, NonPagedPool, TotalDescriptionSize); + + if (p != NULL) { + RtlZeroMemory(p, TotalDescriptionSize); + } + + return p; +} + +VOID +FxDeviceDescriptionEntry::DeviceSurpriseRemoved( + VOID + ) +{ + KIRQL irql; + + KeAcquireSpinLock(&m_DeviceList->m_ListLock, &irql); + m_ProcessingSurpriseRemove = TRUE; + KeReleaseSpinLock(&m_DeviceList->m_ListLock, irql); +} + +BOOLEAN +FxDeviceDescriptionEntry::IsDeviceReportedMissing( + VOID + ) +/*++ + +Routine Description: + This function tells the caller if the description has been reported missing + to the Pnp manager. It does not change the actual state of the description, + unlike IsDeviceRemoved(). + +Arguments: + None + +Return Value: + TRUE if it has been reported missing, FALSE otherwise + + --*/ +{ + KIRQL irql; + BOOLEAN result; + + KeAcquireSpinLock(&m_DeviceList->m_ListLock, &irql); + if (m_DescriptionState == DescriptionReportedMissing) { + result = TRUE; + } + else { + result = FALSE; + } + KeReleaseSpinLock(&m_DeviceList->m_ListLock, irql); + + return result; +} + +BOOLEAN +FxDeviceDescriptionEntry::IsDeviceRemoved( + VOID + ) +{ + KIRQL irql; + BOOLEAN removed; + FxChildList* pList; + + pList = GetParentList(); + removed = FALSE; + FxVerifierCheckIrqlLevel(m_DeviceList->GetDriverGlobals(), PASSIVE_LEVEL); + + KeAcquireSpinLock(&m_DeviceList->m_ListLock, &irql); + + m_ProcessingSurpriseRemove = FALSE; + + if (m_DescriptionState == DescriptionReportedMissing) { + // + // We should delete this entry as it was reported missing. + // + ASSERT(m_ModificationState == ModificationUnspecified); + + m_DescriptionState = DescriptionUnspecified; + + // + // Remove from the current list if no scan going on. + // Note that the description entry can't be removed from list if scan + // count is > 0 because it might be part of an iterator that driver is + // still using to iterate thru the child list. + // + if (pList->GetScanCount() == 0) { + // + // Remove from the current list + // + RemoveEntryList(&m_DescriptionLink); + InitializeListHead(&m_DescriptionLink); + } + else { + // + // The entry will be removed and deleted when scan count goes to + // zero by the scanning thread, so make sure pdo deosn't reference + // the entry any more. + // + m_PendingDeleteOnScanEnd = TRUE; + if (m_Pdo != NULL) { + m_Pdo->GetPdoPkg()->m_Description = NULL; + } + } + + removed = TRUE; + + // + // No need to add a reference to m_DeviceList becuase as we hold a + // reference to it already. This reference is bound by the lifetime + // of this object, so we can always safely touch m_DeviceList even if + // the FDO is gone before the child is removed. + // + } + + KeReleaseSpinLock(&m_DeviceList->m_ListLock, irql); + + return removed; +} + +VOID +FxDeviceDescriptionEntry::ProcessDeviceRemoved( + VOID + ) +{ + LIST_ENTRY freeHead; + KIRQL irql; + FxChildList* pList; + + FxVerifierCheckIrqlLevel(m_DeviceList->GetDriverGlobals(), PASSIVE_LEVEL); + + pList = GetParentList(); + InitializeListHead(&freeHead); + KeAcquireSpinLock(&m_DeviceList->m_ListLock, &irql); + + // + // Remove from the current list. In some cases the entry may not be in any + // list in which case RemoveEntryList() will be a noop. + // Note that the description entry can't be removed from list if scan count + // is > 0 because it might be part of an iterator that driver is still using + // to iterate thru the child list. + // + if (pList->GetScanCount() == 0 || IsListEmpty(&m_DescriptionLink)) { + RemoveEntryList(&m_DescriptionLink); + + // + // Instead of reimplementing a single description cleanup, just use the + // version which cleans up a list. + // + InsertTailList(&freeHead, &m_DescriptionLink); + } + else { + // + // The entry will be removed when scan count goes to zero. + // + ASSERT(m_ModificationState == ModificationUnspecified && + m_DescriptionState == DescriptionUnspecified); + m_PendingDeleteOnScanEnd = TRUE; + } + + KeReleaseSpinLock(&m_DeviceList->m_ListLock, irql); + + m_DeviceList->DrainFreeListHead(&freeHead); +} + +_Must_inspect_result_ +FxDeviceDescriptionEntry* +FxDeviceDescriptionEntry::Clone( + __inout PLIST_ENTRY FreeListHead + ) +{ + FxDeviceDescriptionEntry* pNewEntry; + NTSTATUS status; + + pNewEntry = new(m_DeviceList->GetDriverGlobals(), + m_DeviceList->m_TotalDescriptionSize) + FxDeviceDescriptionEntry(m_DeviceList, + m_DeviceList->m_IdentificationDescriptionSize, + m_DeviceList->m_AddressDescriptionSize); + + if (pNewEntry == NULL) { + return NULL; + } + + status = m_DeviceList->DuplicateId(pNewEntry->m_IdentificationDescription, + m_IdentificationDescription); + + if (NT_SUCCESS(status) && m_DeviceList->HasAddressDescriptions()) { + status = m_DeviceList->DuplicateAddress(pNewEntry->m_AddressDescription, + m_AddressDescription); + } + + if (NT_SUCCESS(status)) { + pNewEntry->m_FoundInLastScan = TRUE; + } + else { + // + // Free it later + // + InsertTailList(FreeListHead, &pNewEntry->m_DescriptionLink); + pNewEntry = NULL; + } + + return pNewEntry; +} + +FxChildList::FxChildList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t TotalDescriptionSize, + __in FxDevice* Device, + __in BOOLEAN Static + ) : + FxNonPagedObject(FX_TYPE_CHILD_LIST,sizeof(FxChildList), FxDriverGlobals), + m_TotalDescriptionSize(TotalDescriptionSize), + m_EvtCreateDevice(FxDriverGlobals), + m_EvtScanForChildren(FxDriverGlobals) +{ + // + // Transaction link into list of FxChildList pointers maintained by + // FxDevice's pnp package. + // + m_TransactionLink.SetTransactionedObject(this); + + m_Device = Device; + + m_IdentificationDescriptionSize = 0; + m_AddressDescriptionSize = 0; + + m_EvtIdentificationDescriptionDuplicate = NULL; + m_EvtIdentificationDescriptionCopy = NULL; + m_EvtIdentificationDescriptionCleanup = NULL; + m_EvtIdentificationDescriptionCompare = NULL; + + m_EvtAddressDescriptionDuplicate = NULL; + m_EvtAddressDescriptionCopy = NULL; + m_EvtAddressDescriptionCleanup = NULL; + + KeInitializeSpinLock(&m_ListLock); + InitializeListHead(&m_DescriptionListHead); + InitializeListHead(&m_ModificationListHead); + + m_State = ListUnlocked; + + m_InvalidationNeeded = FALSE; + m_StaticList = Static; + m_IsAdded = FALSE; + + m_EnumRetries = 0; + + m_ScanTag = NULL; + m_ScanCount = 0; + + // + // We want all waiters on the event to be satisfied, not just the first one + // + m_ScanEvent.Initialize(NotificationEvent, TRUE); + + MarkDisposeOverride(ObjectDoNotLock); +} + +BOOLEAN +FxChildList::Dispose( + VOID + ) +{ + if (m_IsAdded) { + ASSERT(m_Device != NULL); + m_Device->RemoveChildList(this); + } + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::_CreateAndInit( + __out FxChildList** ChildList, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES ListAttributes, + __in size_t TotalDescriptionSize, + __in FxDevice* Device, + __in PWDF_CHILD_LIST_CONFIG ListConfig, + __in BOOLEAN Static + ) +{ + NTSTATUS ntStatus; + FxChildList *childList = NULL; + + // + // Initialize + // + *ChildList = NULL; + + // + // Allocate a new child list object + // + childList = new(FxDriverGlobals, ListAttributes) + FxChildList(FxDriverGlobals, TotalDescriptionSize, Device, Static); + if (childList == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "No memory for WDFCHILDLIST handle, %!STATUS!", + ntStatus); + goto exit; + } + + // + // Initialize the child list object + // + childList->Initialize(ListConfig); + + *ChildList = childList; + ntStatus = STATUS_SUCCESS; + +exit: + if (!NT_SUCCESS(ntStatus)) { + if (NULL != childList) { + childList->DeleteFromFailedCreate(); + } + } + return ntStatus; +} + +_Must_inspect_result_ +VOID +FxChildList::Initialize( + __in PWDF_CHILD_LIST_CONFIG Config + ) +{ + // + // Driver cannot call WdfObjectDelete on this handle + // + MarkNoDeleteDDI(); + + m_IdentificationDescriptionSize = Config->IdentificationDescriptionSize; + m_AddressDescriptionSize = Config->AddressDescriptionSize; + + m_EvtCreateDevice.m_Method = Config->EvtChildListCreateDevice; + m_EvtScanForChildren.m_Method = Config->EvtChildListScanForChildren; + + m_EvtIdentificationDescriptionDuplicate = Config->EvtChildListIdentificationDescriptionDuplicate; + m_EvtIdentificationDescriptionCopy = Config->EvtChildListIdentificationDescriptionCopy; + m_EvtIdentificationDescriptionCleanup = Config->EvtChildListIdentificationDescriptionCleanup; + m_EvtIdentificationDescriptionCompare = Config->EvtChildListIdentificationDescriptionCompare; + + m_EvtAddressDescriptionDuplicate = Config->EvtChildListAddressDescriptionDuplicate; + m_EvtAddressDescriptionCopy = Config->EvtChildListAddressDescriptionCopy; + m_EvtAddressDescriptionCleanup = Config->EvtChildListAddressDescriptionCleanup; + + m_EvtChildListDeviceReenumerated = Config->EvtChildListDeviceReenumerated; + + // + // Add this ChildList to the parent device's list of children lists. + // + m_Device->AddChildList(this); + m_IsAdded = TRUE; +} + +WDFDEVICE +FxChildList::GetDevice( + VOID + ) +{ + return m_Device->GetHandle(); +} + +FxDevice* +FxChildList::GetDeviceFromId( + __inout PWDF_CHILD_RETRIEVE_INFO Info + ) +{ + FxDeviceDescriptionEntry* pEntry; + FxDevice* device; + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS status; + KIRQL irql; + + device = NULL; + + KeAcquireSpinLock(&m_ListLock, &irql); + + pEntry = SearchBackwardsForMatchingModificationLocked( + Info->IdentificationDescription); + + if (pEntry != NULL && pEntry->m_ModificationState == ModificationInsert) { + status = WdfChildListRetrieveDeviceNotYetCreated; + } + else { + pEntry = SearchBackwardsForMatchingDescriptionLocked( + Info->IdentificationDescription); + + if (pEntry != NULL) { + if (pEntry->m_DescriptionState == DescriptionPresentNeedsInstantiation) { + status = WdfChildListRetrieveDeviceNotYetCreated; + } + else { + status = WdfChildListRetrieveDeviceSuccess; + device = pEntry->m_Pdo; + } + } + else { + status = WdfChildListRetrieveDeviceNoSuchDevice; + } + } + + if (pEntry != NULL && Info->AddressDescription != NULL) { + CopyAddress(Info->AddressDescription, + pEntry->m_AddressDescription); + } + + KeReleaseSpinLock(&m_ListLock, irql); + + Info->Status = status; + + return device; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::GetAddressDescription( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + FxDeviceDescriptionEntry* pEntry; + NTSTATUS status; + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + + pEntry = SearchBackwardsForMatchingModificationLocked( + IdentificationDescription); + + if (pEntry == NULL) { + pEntry = SearchBackwardsForMatchingDescriptionLocked( + IdentificationDescription); + } + + if (pEntry != NULL) { + CopyAddress(AddressDescription, pEntry->m_AddressDescription); + status = STATUS_SUCCESS; + } + else { + status = STATUS_NO_SUCH_DEVICE; + } + + KeReleaseSpinLock(&m_ListLock, irql); + + return status; +} + +VOID +FxChildList::GetAddressDescriptionFromEntry( + __in FxDeviceDescriptionEntry* Entry, + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + CopyAddress(AddressDescription, Entry->m_AddressDescription); + KeReleaseSpinLock(&m_ListLock, irql); +} + +VOID +FxChildList::BeginScan( + __out_opt PULONG ScanTag + ) +{ + FxDeviceDescriptionEntry* pEntry; + PLIST_ENTRY ple; + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + + // KeClearEvent is faster than KeResetEvent for putting event to not-signaled state + m_ScanEvent.Clear(); + m_ScanCount++; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Begin scan on WDFCHILDLIST %p, scan count %d", + GetHandle(), m_ScanCount); + + if (ScanTag != NULL) { + if (m_ScanTag != NULL) { + *m_ScanTag = ScanTagCancelled; + } + + *ScanTag = ScanTagActive; + m_ScanTag = ScanTag; + } + + // + // Start by walking over all entries and setting their FoundInLastScan + // fields to FALSE. We need to set both present items in the Desc list + // and inserts in the Mod list. It's actually easier just to walk over + // everything. + // + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = ple->Flink) { + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + pEntry->m_FoundInLastScan = FALSE; + } + + for (ple = m_ModificationListHead.Flink; + ple != &m_ModificationListHead; + ple = ple->Flink) { + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(ple); + pEntry->m_FoundInLastScan = FALSE; + } + + KeReleaseSpinLock(&m_ListLock, irql); +} + +VOID +FxChildList::EndScan( + __inout_opt PULONG ScanTag + ) +{ + PLIST_ENTRY pCur, pNext; + LIST_ENTRY freeHead; + FxDeviceDescriptionEntry* pEntry; + KIRQL irql; + + InitializeListHead(&freeHead); + + KeAcquireSpinLock(&m_ListLock, &irql); + + if (ScanTag != NULL) { + if (*ScanTag != ScanTagActive) { + ASSERT(*ScanTag == ScanTagCancelled); + KeReleaseSpinLock(&m_ListLock, irql); + return; + } + + *ScanTag = ScanTagFinished; + m_ScanTag = NULL; + } + + m_ScanCount--; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "End scan on WDFCHILDLIST %p, scan count %d", + GetHandle(), m_ScanCount); + + if (m_ScanCount == 0) { + // + // Walk over all modification entries and remove any pending insert that + // wasn't seen in the scan. Note that MarkDescriptionNotPresentWorker will + // enqueue the entry to be freed later. + // + // Also, convert any clones of devices not reported as present to + // removal modifications so that the original is still reported missing. + // + for (pCur = m_ModificationListHead.Flink; + pCur != &m_ModificationListHead; + pCur = pNext) { + + pNext = pCur->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(pCur); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "entry %p modified in last scan, " + "mod state %!FxChildListModificationState!," + "desc state %!FxChildListDescriptionState!", + pEntry, pEntry->m_ModificationState, + pEntry->m_DescriptionState); + + if (pEntry->m_FoundInLastScan == FALSE) { + switch (pEntry->m_ModificationState) { + case ModificationInsert: + // + // Insertion that never made through to the end of a scan. + // + MarkModificationNotPresentWorker(&freeHead, pEntry); + break; + + case ModificationClone: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "clone of PDO WDFDEVICE %p, !devobj %p dropped because " + "it is missing", pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject()); + + // + // We were asked for a clone in the middle of a scan and the + // device was not reported, so it is now missing. Convert + // the clone modification to a remove modification. + // + pEntry->m_ModificationState = ModificationRemoveNotify; + + // + // Remove the modification from the current mod list. It + // will be re-added below when we iterate over the + // descriptions list. + // + RemoveEntryList(&pEntry->m_ModificationLink); + InitializeListHead(&pEntry->m_ModificationLink); + + // + // We can only have been cloning a device which is present + // and not yet reported missing to the OS. + // + ASSERT(pEntry->m_DescriptionState == + DescriptionInstantiatedHasObject); + break; + } + } + } + + // + // Walk over all desc entries and remove anything that wasn't found in the + // scan. Since MarkDescriptionNotPresentWorker doesn't drain the + // modifications, we don't have to worry about any entries disappearing. + // + for (pCur = m_DescriptionListHead.Flink; + pCur != &m_DescriptionListHead; + pCur = pCur->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(pCur); + + if (pEntry->m_PendingDeleteOnScanEnd) { + // + // The entry was pnp removed but was not removed from list + // because scan count was > 0. It is safe to remove and delete + // it now. + + // Update the current pointer before the entry is removed. + pCur = pCur->Blink; + + RemoveEntryList(&pEntry->m_DescriptionLink); + InsertTailList(&freeHead, &pEntry->m_DescriptionLink); + pEntry = NULL; + continue; + } + else if (pEntry->IsPresent() && pEntry->m_FoundInLastScan == FALSE) { + if (pEntry->m_Pdo != NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "marking PDO WDFDEVICE %p, !devobj %p as not present", + pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject()); + + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "marking PDO (entry %p) which needs instantiation as " + "not present", pEntry); + } + + MarkDescriptionNotPresentWorker(pEntry, TRUE); + } + } + + // + // Attempt to drain any mods we made. + // + ProcessModificationsLocked(&freeHead); + + // + // We need to check m_KnownPdo here because if this + // object is attached to a PDO, the PDO's devobj could be in a state where + // PnP does not know it is a PDO yet. m_KnownPdo + // is set when the PDO receives a start device and by the time start + // device arrives, we definitely know the PDO is known the PnP. + // + // No need to hold a lock while checking m_KnownPdo + // because if miss the transition from FALSE to TRUE, relations will + // automaticaly be invalidated by the cause of that transition (start + // device arrival). PnP automatically sends a QDR after a successful + // start. + // + + if (m_InvalidationNeeded) { + PDEVICE_OBJECT pdo; + + // + // This does the m_KnownPdo check. + // + pdo = m_Device->GetSafePhysicalDevice(); + + if (pdo != NULL) { + m_InvalidationNeeded = FALSE; + IoInvalidateDeviceRelations(pdo, BusRelations); + } + } + + m_ScanEvent.Set(); + } + + KeReleaseSpinLock(&m_ListLock, irql); + + // + // Free structures outside of any internal WDF lock + // + DrainFreeListHead(&freeHead); +} + +VOID +FxChildList::CancelScan( + __in BOOLEAN EndTheScan, + __inout_opt PULONG ScanTag + ) +{ + *ScanTag = ScanTagCancelled; + + if (EndTheScan) { + EndScan(ScanTag); + } +} + +VOID +FxChildList::InitIterator( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + Iterator->Reserved[DescriptionIndex] = &m_DescriptionListHead; + + if (Iterator->Flags & WdfRetrievePendingChildren) { + Iterator->Reserved[ModificationIndex] = ULongToPtr(1); + } +} + +VOID +FxChildList::BeginIteration( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + KIRQL irql; + + // + // Almost the same semantic as BeginScan except we don't mark all of the + // children as missing when we start. + // + KeAcquireSpinLock(&m_ListLock, &irql); + + InitIterator(Iterator); + // + // Set the scanevent to non-signaled state. Some code paths such as + // PDO eject will wait for the completion of child list iteration or scan + // so that a QDR that follows eject is guaranteed to pick up the change in + // PDO state that the code path made. Note that scan and iteration can be + // nested and in that case this event will be clear each time but it will be + // set (signalled) only after all the iteration and scan opeartions have + // completed. + // + m_ScanEvent.Clear(); + m_ScanCount++; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Begin iteration on WDFCHILDLIST %p, scan count %d", + GetHandle(), m_ScanCount); + + KeReleaseSpinLock(&m_ListLock, irql); +} + +VOID +FxChildList::EndIteration( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "end iteration on WDFCHILDLIST"); + + // + // Semantic is exactly the same as EndScan. Basically, all changes are + // delayed until there are no more active scans, so the end of an interation + // is the same as the end of a scan. + // + EndScan(); + + RtlZeroMemory(&Iterator->Reserved[0], sizeof(Iterator->Reserved)); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::GetNextDevice( + __out WDFDEVICE* Device, + __inout PWDF_CHILD_LIST_ITERATOR Iterator, + __inout_opt PWDF_CHILD_RETRIEVE_INFO Info + ) +{ + FxDeviceDescriptionEntry* pEntry; + PLIST_ENTRY ple; + NTSTATUS status; + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS dstatus = WdfChildListRetrieveDeviceNoSuchDevice; + ULONG cur, i; + KIRQL irql; + BOOLEAN found; + + pEntry = NULL; + status = STATUS_NO_MORE_ENTRIES; + + KeAcquireSpinLock(&m_ListLock, &irql); + + ASSERT(m_ScanCount > 0); + if (m_ScanCount == 0) { + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFCHILDLIST %p cannot retrieve next device if the list is not " + "locked for iteration, %!STATUS!", GetHandle(), status); + + goto Done; + } + + ple = (PLIST_ENTRY) Iterator->Reserved[DescriptionIndex]; + + if (ple != NULL) { + if (GetDriverGlobals()->FxVerifierOn) { + status = VerifyDescriptionEntry(ple); + if (!NT_SUCCESS(status)) { + goto Done; + } + } + + found = FALSE; + + // + // Try to find the next entry + // + for (ple = ple->Flink; ple != &m_DescriptionListHead; ple = ple->Flink) { + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + if (pEntry->MatchStateToFlags(Iterator->Flags)) { + // + // An item was found + // + found = TRUE; + + // + // Call the caller's compare function to further refine the match + // if necessary. + // + if (Info != NULL && + Info->EvtChildListIdentificationDescriptionCompare != NULL) { + + found = Info->EvtChildListIdentificationDescriptionCompare( + GetHandle(), + Info->IdentificationDescription, + pEntry->m_IdentificationDescription); + } + + if (found) { + break; + } + } + } + + if (found) { + // + // We can safely store the description entry because we are + // guaranteed it will stay in the description list until m_ScanCount + // reaches zero. In that case, the caller would need to call + // EndIteration + // + Iterator->Reserved[DescriptionIndex] = ple; + + if (pEntry->m_Pdo != NULL) { + *Device = pEntry->m_Pdo->GetHandle(); + dstatus = WdfChildListRetrieveDeviceSuccess; + } + else { + dstatus = WdfChildListRetrieveDeviceNotYetCreated; + } + + if (Info != NULL) { + if (Info->IdentificationDescription != NULL) { + CopyId(Info->IdentificationDescription, + pEntry->m_IdentificationDescription); + } + if (Info->AddressDescription != NULL) { + CopyAddress(Info->AddressDescription, + pEntry->m_AddressDescription); + } + + Info->Status = dstatus; + } + + status = STATUS_SUCCESS; + } + else { + Iterator->Reserved[DescriptionIndex] = NULL; + ple = NULL; + status = STATUS_NO_MORE_ENTRIES; + } + } + + cur = PtrToUlong(Iterator->Reserved[ModificationIndex]); + + if ((Iterator->Flags & WdfRetrievePendingChildren) == 0 || + cur == 0) { + goto Done; + } + + + // + // Walk the modification list. Since this list can change from call to call + // to GetNextDevice we can't rely on the previous entry still being present + // so we must use an index into the list. This is not guaranteed to + // enumerate all pending additions, but it should be good enough. + // + found = FALSE; + + for (i = 1, ple = m_ModificationListHead.Flink; + ple != &m_ModificationListHead; + ple = ple->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(ple); + + if (pEntry->m_ModificationState == ModificationInsert) { + i++; + + if (i > cur) { + found = TRUE; + + if (Info != NULL && + Info->EvtChildListIdentificationDescriptionCompare != NULL) { + + found = Info->EvtChildListIdentificationDescriptionCompare( + GetHandle(), + Info->IdentificationDescription, + pEntry->m_IdentificationDescription); + } + + if (found) { + // + // Store the next item number + // + Iterator->Reserved[ModificationIndex] = ULongToPtr(i); + + if (Info != NULL) { + if (Info->IdentificationDescription != NULL) { + CopyId(Info->IdentificationDescription, + pEntry->m_IdentificationDescription); + } + if (Info->AddressDescription != NULL) { + CopyAddress(Info->AddressDescription, + pEntry->m_AddressDescription); + } + + Info->Status = WdfChildListRetrieveDeviceNotYetCreated; + } + + status = STATUS_SUCCESS; + break; + } + } + } + } + + if (found == FALSE) { + Iterator->Reserved[ModificationIndex] = ULongToPtr(0); + } + +Done: + KeReleaseSpinLock(&m_ListLock, irql); + + return status; +} + +WDFDEVICE +FxChildList::GetNextStaticDevice( + __in WDFDEVICE PreviousDevice, + __in ULONG Flags + ) +{ + FxStaticChildDescription *pStatic; + FxDeviceDescriptionEntry* pEntry; + WDFDEVICE result; + PLIST_ENTRY ple; + KIRQL irql; + BOOLEAN isNext; + + ASSERT(m_StaticList); + + result = NULL; + + if (PreviousDevice == NULL) { + // + // No previous handle, we want the first device we find + // + isNext = TRUE; + } + else { + // + // We have a previuos handle, find it in the list first before setting + // isNext. + // + isNext = FALSE; + } + + KeAcquireSpinLock(&m_ListLock, &irql); + + ASSERT(m_ScanCount > 0); + if (m_ScanCount == 0) { + goto Done; + } + + // + // Try to find the next entry + // + if (Flags & WdfRetrievePresentChildren) { + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = ple->Flink) { + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + // + // If the entry is marked pending delete, skip it, because the + // relationship between entry and its PDO has been removed and PDO + // may have actually been deleted by this time. The only reason + // this entry is here is because there is still a scan going on + // and the entry can't be removed in the midst of a scan. + // + if (pEntry->m_PendingDeleteOnScanEnd) { + continue; + } + + pStatic = CONTAINING_RECORD(pEntry->m_IdentificationDescription, + FxStaticChildDescription, + Header); + + // + // Only return a handle if it is in a state in which the caller is + // interested in hearing about. + // + if (isNext && pEntry->MatchStateToFlags(Flags)) { + result = pStatic->Pdo->GetHandle(); + break; + } + else if (pStatic->Pdo->GetHandle() == PreviousDevice) { + isNext = TRUE; + } + } + } + + // + // We have taken care of all the other states (reported, pending removal, + // removed) in the previuos loop. + // + if (result == NULL && (Flags & WdfRetrievePendingChildren)) { + // + // Walk the modification list. Since this list can change from call to + // call, there is no way to definitively give the driver a snapshot of + // this list of modifications. + // + for (ple = m_ModificationListHead.Flink; + ple != &m_ModificationListHead; + ple = ple->Flink) { + BOOLEAN check; + + check = FALSE; + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(ple); + + if (pEntry->m_PendingDeleteOnScanEnd) { + continue; + } + + pStatic = CONTAINING_RECORD(pEntry->m_IdentificationDescription, + FxStaticChildDescription, + Header); + + // + // Only return a handle if it is in a state in which the caller is + // interested in hearing about. + // + if (isNext && pEntry->m_ModificationState == ModificationInsert) { + result = pStatic->Pdo->GetHandle(); + break; + } + else if (pStatic->Pdo->GetHandle() == PreviousDevice) { + isNext = TRUE; + } + } + } + +Done: + KeReleaseSpinLock(&m_ListLock, irql); + + return result; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::UpdateAsMissing( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Description + ) +{ + FxDeviceDescriptionEntry* pEntry; + LIST_ENTRY freeHead; + NTSTATUS status; + KIRQL irql; + + // + // Assume success + // + status = STATUS_SUCCESS; + InitializeListHead(&freeHead); + + KeAcquireSpinLock(&m_ListLock, &irql); + + pEntry = SearchBackwardsForMatchingModificationLocked(Description); + + if (pEntry != NULL) { + + + + + + + + + MarkModificationNotPresentWorker(&freeHead, pEntry); + } + else { + pEntry = SearchBackwardsForMatchingDescriptionLocked(Description); + + if (pEntry != NULL) { + if (pEntry->IsPresent()) { + MarkDescriptionNotPresentWorker(pEntry, FALSE); + } + } + else { + // + // Couldn't find anything + // + status = STATUS_NO_SUCH_DEVICE; + } + } + + ProcessModificationsLocked(&freeHead); + + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::UpdateDeviceAsMissing( + __in FxDevice* Device + ) +/*++ + +Routine Description: + Same as UpdateAsMissing except instead of a device description, we have the + device itself. + +Arguments: + Device - the device to mark as missing + +Return Value: + NTSTATUS + + --*/ +{ + FxDeviceDescriptionEntry* pEntry; + LIST_ENTRY freeHead, *ple; + KIRQL irql; + BOOLEAN found; + CfxDevice *pdo; + + found = FALSE; + pdo = NULL; + InitializeListHead(&freeHead); + + KeAcquireSpinLock(&m_ListLock, &irql); + + for (ple = m_ModificationListHead.Blink; + ple != &m_ModificationListHead; + ple = ple->Blink) { + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(ple); + + // + // Static PDO may not be populated in m_Pdo yet, so check the PDO + // from id description. + // + if (m_StaticList) { + pdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription, + FxStaticChildDescription, + Header)->Pdo; + } + else { + pdo = pEntry->m_Pdo; + } + + if (pdo == Device) { + found = TRUE; + MarkModificationNotPresentWorker(&freeHead, pEntry); + break; + } + } + + if (found == FALSE) { + for (ple = m_DescriptionListHead.Blink; + ple != &m_DescriptionListHead; + ple = ple->Blink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + // + // Static PDO may not be populated in m_Pdo yet, so check the PDO + // from id description. + // + if (m_StaticList) { + pdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription, + FxStaticChildDescription, + Header)->Pdo; + } + else { + pdo = pEntry->m_Pdo; + } + + if (pdo == Device) { + found = TRUE; + + if (pEntry->IsPresent()) { + MarkDescriptionNotPresentWorker(pEntry, FALSE); + } + + break; + } + } + } + + ProcessModificationsLocked(&freeHead); + + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); + + if (found) { + return STATUS_SUCCESS; + } + else { + return STATUS_NO_SUCH_DEVICE; + } +} + +BOOLEAN +FxChildList::ReenumerateEntryLocked( + __inout FxDeviceDescriptionEntry* Entry, + __in BOOLEAN FromQDR + ) +{ + BOOLEAN result; + + // + // Check to see if there are modifications pending + // + if (IsListEmpty(&Entry->m_ModificationLink) && Entry->IsPresent()) { + // + // No mods pending... + // + + // + // We can only go down this path if the device was reported to the system + // b/c the stack on our PDO is the one invoking this call. + // + ASSERT(Entry->m_DescriptionState == DescriptionInstantiatedHasObject); + + if (FromQDR == FALSE) { + // + // The entry has not been reported as missing by the driver, try to + // clone it and insert a modification. + // + Entry->m_ModificationState = ModificationClone; + InsertTailList(&m_ModificationListHead, &Entry->m_ModificationLink); + } + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Inserting clone modification for PDO WDFDEVICE %p, !devobj %p", + Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject()); + + result = TRUE; + } + else { + // + // If there is a pending modification, we don't do anything. + // If the device is already not present, we don't do anything. + // + // ModficiationRemove or + // ModficiationRemoveNotify: we would be reenumerating a device which + // is being removed which is not what we want + // + // ModificationClone: we would be cloning a clone which is not what + // we want either + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Requested reenumeration for PDO WDFDEVICE %p, !devobj %p" + " no possible (pending mod %d, currently present %d)", + Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject(), + IsListEmpty(&Entry->m_ModificationLink), Entry->IsPresent()); + + result = FALSE; + } + + return result; +} + +VOID +FxChildList::ReenumerateEntry( + __inout FxDeviceDescriptionEntry* Entry + ) +{ + LIST_ENTRY freeHead; + KIRQL irql; + + InitializeListHead(&freeHead); + + KeAcquireSpinLock(&m_ListLock, &irql); + (void) ReenumerateEntryLocked(Entry, FALSE); + ProcessModificationsLocked(&freeHead); + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); +} + + +VOID +FxChildList::UpdateAllAsPresent( + __in_opt PULONG ScanTag + ) +{ + PLIST_ENTRY pCur, pNext; + LIST_ENTRY freeHead; + FxDeviceDescriptionEntry* pEntry; + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + + if (ScanTag != NULL) { + if (*ScanTag != ScanTagActive) { + ASSERT(*ScanTag == ScanTagCancelled); + KeReleaseSpinLock(&m_ListLock, irql); + return; + } + } + + // + // Walk over all mod entries and ensure any inserts are still marked + // present. + // + for (pCur = m_ModificationListHead.Flink; + pCur != &m_ModificationListHead; + pCur = pNext) { + + pNext = pCur->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(pCur); + + if (pEntry->m_ModificationState == ModificationInsert) { + pEntry->m_FoundInLastScan = TRUE; + } + } + + // + // Walk over all desc entries and ensure they are marked present. + // + for (pCur = m_DescriptionListHead.Flink; + pCur != &m_DescriptionListHead; + pCur = pCur->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(pCur); + + if (pEntry->IsPresent()) { + ASSERT(pEntry->m_ModificationState != ModificationRemoveNotify); + + if (pEntry->m_ModificationState != ModificationRemove) { + pEntry->m_FoundInLastScan = TRUE; + } + } + } + + // + // Attempt to drain any mods we made. + // + InitializeListHead(&freeHead); + ProcessModificationsLocked(&freeHead); + + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::Add( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription, + __in_opt PULONG ScanTag + ) +{ + LIST_ENTRY freeHead; + KIRQL irql; + NTSTATUS status; + FxDeviceDescriptionEntry* pEntry; + BOOLEAN allocNewEntry; + + if (ScanTag != NULL) { + if (*ScanTag != ScanTagActive) { + ASSERT(*ScanTag == ScanTagCancelled); + + // + // The descriptions are duplicated if needed, so no need to clean + // them up + // + // CleanupDescriptions(IdentificationDescription, + // AddressDescription); + + return STATUS_CANCELLED; + } + } + + status = STATUS_UNSUCCESSFUL; + allocNewEntry = FALSE; + InitializeListHead(&freeHead); + + KeAcquireSpinLock(&m_ListLock, &irql); + + pEntry = SearchBackwardsForMatchingModificationLocked( + IdentificationDescription + ); + + if (pEntry != NULL) { + switch (pEntry->m_ModificationState) { + case ModificationInsert: + if (HasAddressDescriptions()) { + CopyAddress(pEntry->m_AddressDescription, + AddressDescription); + } + + // + // There is already a pending insert operation. All we need do is + // update the stored description. + // + pEntry->m_FoundInLastScan = TRUE; + + status = STATUS_OBJECT_NAME_EXISTS; + break; + + case ModificationRemove: + case ModificationRemoveNotify: + // + // We found a pending remove. Therefore we need to add an insert + // operation to the end of the mod list. + // + allocNewEntry = TRUE; + break; + + default: + ASSERTMSG("Invalid description modification state\n", FALSE); + break; + } + } + else { + // + // There are no matching modifications queued in the list. Go examine + // the main list. We can't modify any of the child links right now + // because the list might be locked down, but it is scannable! + // + pEntry = SearchBackwardsForMatchingDescriptionLocked( + IdentificationDescription + ); + + if (pEntry != NULL && pEntry->IsPresent()) { + // + // This is an update. Enqueue it through this node. + // + ASSERT(pEntry->m_ModificationState == ModificationUnspecified); + + if (HasAddressDescriptions()) { + CopyAddress(pEntry->m_AddressDescription, + AddressDescription); + } + + pEntry->m_FoundInLastScan = TRUE; + status = STATUS_OBJECT_NAME_EXISTS; + } + else { + // + // Either no entry was found, or a "missing" entry was identified + // instead. In both cases we need to add an insert operation to the + // end of the modification list. + // + allocNewEntry = TRUE; + } + } + + if (allocNewEntry) { + + pEntry = + new(GetDriverGlobals(), m_TotalDescriptionSize) + FxDeviceDescriptionEntry(this, + m_IdentificationDescriptionSize, + m_AddressDescriptionSize); + + if (pEntry != NULL) { + status = DuplicateId(pEntry->m_IdentificationDescription, + IdentificationDescription); + + if (NT_SUCCESS(status) && HasAddressDescriptions()) { + status = DuplicateAddress(pEntry->m_AddressDescription, + AddressDescription); + } + + if (NT_SUCCESS(status)) { + pEntry->m_FoundInLastScan = TRUE; + InsertTailList(&m_ModificationListHead, + &pEntry->m_ModificationLink); + + if (m_StaticList) { + FxDevice* pPdo; + + pPdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription, + FxStaticChildDescription, + Header)->Pdo; + + // + // The device is no longer deletable by the driver writer + // + pPdo->MarkNoDeleteDDI(); + + // + // Plug in the description like we do for dynamic PDOs in + // FxPkgPdo::Initialize. + // + pPdo->GetPdoPkg()->m_Description = pEntry; + + // + // Let the device know it was inserted into the list. This + // used to know in pPdo::DeleteObject how to proceed. + // + pPdo->GetPdoPkg()->m_AddedToStaticList = TRUE; + } + } + else { + InsertTailList(&freeHead, &pEntry->m_DescriptionLink); + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + ProcessModificationsLocked(&freeHead); + + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); + + return status; +} + +VOID +FxChildList::UpdateAddressDescriptionFromEntry( + __inout FxDeviceDescriptionEntry* Entry, + __in PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + CopyAddress(Entry->m_AddressDescription, AddressDescription); + KeReleaseSpinLock(&m_ListLock, irql); + + + + + + +} + +BOOLEAN +FxChildList::CloneEntryLocked( + __inout PLIST_ENTRY FreeListHead, + __inout FxDeviceDescriptionEntry* Entry, + __in BOOLEAN FromQDR + ) +{ + FxDeviceDescriptionEntry* pClone; + BOOLEAN invalidateRelations; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "attempting to clone PDO WDFDEVICE %p, !devobj %p, From QDR %d", + Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject(), FromQDR); + + invalidateRelations = FALSE; + + pClone = Entry->Clone(FreeListHead); + + if (pClone != NULL) { + // + // Check to see if the driver writer OKs the cloning, aka + // reenumeration. + // + if (m_EvtChildListDeviceReenumerated != NULL && + m_EvtChildListDeviceReenumerated( + GetHandle(), + Entry->m_Pdo->GetHandle(), + Entry->m_AddressDescription, + pClone->m_AddressDescription) == FALSE){ + // + // The clone will be freed later by the caller by placing + // it on the free list. + // + InsertTailList(FreeListHead, &pClone->m_DescriptionLink); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "clone successful (new entry is %p), marking PDO " + "WDFDEVICE %p, !devobj %p as missing", pClone, + Entry->m_Pdo->GetHandle(), Entry->m_Pdo->GetDeviceObject()); + + // + // Setup the state of the clone + // + pClone->m_DescriptionState = DescriptionPresentNeedsInstantiation; + pClone->m_ModificationState = ModificationUnspecified; + + // + // This is important that this is last. If a subsequent + // modification arrives for this device, we want to find the + // clone before the old device. Since all changes search the + // list backwards, inserting at the tail accomplishes this. + // + InsertTailList(&m_DescriptionListHead, + &pClone->m_DescriptionLink); + + if (FromQDR == FALSE) { + Entry->m_DescriptionState = DescriptionNotPresent; + invalidateRelations = TRUE; + } + } + } + else { + // + // Could not allocate a clone, do not anything. + // + DO_NOTHING(); + } + + // + // Convert the original device's modification state back to a + // unspecified in all cases. + // + Entry->m_ModificationState = ModificationUnspecified; + + return invalidateRelations; +} + +VOID +FxChildList::ProcessModificationsLocked( + __inout PLIST_ENTRY FreeListHead + ) +{ + FxDeviceDescriptionEntry *pEntry; + PLIST_ENTRY pCur, pNext; + BOOLEAN invalidateRelations; + + // + // If the list is locked or there are still active scans, we must not process + // any modifications. + // + if (m_State != ListUnlocked || m_ScanCount > 0) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Not processing modifications on WDFCHILDLIST %p (list state %d, " + "scan count %d)", GetObjectHandle(), m_State, m_ScanCount); + return; + } + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Begin processing modifications on WDFCHILDLIST %p", GetObjectHandle()); + + // + // First do the mod updates. As quick as possible. Note that we need to + // update + // + for (pCur = m_ModificationListHead.Flink; + pCur != &m_ModificationListHead; + pCur = pNext) { + + pNext = pCur->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(pCur); + + switch (pEntry->m_ModificationState) { + case ModificationRemoveNotify: + + + + + + + + + + + + + + + + pEntry->m_ModificationState = ModificationRemove; + break; + + default: + break; + } + } + + invalidateRelations = FALSE; + while(!IsListEmpty(&m_ModificationListHead)) { + pCur = RemoveHeadList(&m_ModificationListHead); + + InitializeListHead(pCur); + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(pCur); + + ASSERT(pEntry->m_ModificationState == ModificationInsert || + pEntry->m_ModificationState == ModificationClone || + pEntry->m_ModificationState == ModificationRemove); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "entry %p, mod state is %!FxChildListModificationState!", + pEntry, pEntry->m_ModificationState); + + switch (pEntry->m_ModificationState) { + case ModificationRemove: + // + // Remove's are stacked on top of the entry they need to take out. + // + ASSERT(pEntry->IsPresent()); + + pEntry->m_ModificationState = ModificationUnspecified; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "processing remove on entry %p, description state is " + "%!FxChildListDescriptionState!", + pEntry, pEntry->m_DescriptionState); + + switch (pEntry->m_DescriptionState) { + case DescriptionPresentNeedsInstantiation: + // + // We got to the entry before a DO could be created for it or + // an instantiation failed. If deleeted before creation, the + // list entry points to itself. If the instantiation failed, + // the list entry is in the description list and must be + // removed from it. + // + // Mark it for deletion now (outside of the lock being held). + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "entry %p never reported to pnp, mark for deletion", pEntry); + + RemoveEntryList(&pEntry->m_DescriptionLink); + InsertTailList(FreeListHead, &pEntry->m_DescriptionLink); + break; + + case DescriptionInstantiatedHasObject: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "committing PDO WDFDEVICE %p, !devobj %p as not present", + pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject()); + + pEntry->m_DescriptionState = DescriptionNotPresent; + invalidateRelations = TRUE; + break; + + default: + ASSERTMSG("Invalid description state\n", FALSE); + break; + } + + break; + + case ModificationInsert: + // + // CurEntry is our entry to insert into the list. We simply "move" + // the mod entries to desc entries. + // + ASSERT(pEntry->m_DescriptionState == DescriptionUnspecified); + pEntry->m_DescriptionState = DescriptionPresentNeedsInstantiation; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "marking entry %p as needing instantiation", pEntry); + + InsertTailList(&m_DescriptionListHead, &pEntry->m_DescriptionLink); + pEntry->m_ModificationState = ModificationUnspecified; + invalidateRelations = TRUE; + break; + + case ModificationClone: + invalidateRelations = CloneEntryLocked(FreeListHead, pEntry, FALSE); + break; + + default: + ASSERTMSG("Invalid description modification state\n", FALSE); + break; + } + } + + if (invalidateRelations) { + PDEVICE_OBJECT pdo; + + if (m_ScanCount) { + m_InvalidationNeeded = TRUE; + } + else if ((pdo = m_Device->GetSafePhysicalDevice()) != NULL) { + // + // See previous usage of m_Device->m_KnownPdo for + // comments on why a lock is not necessary when reading its value. + // + m_InvalidationNeeded = FALSE; + IoInvalidateDeviceRelations(pdo, BusRelations); + } + else { + m_InvalidationNeeded = TRUE; + } + } + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "end processing modifications on WDFCHILDLIST %p", GetObjectHandle()); +} + +VOID +FxChildList::MarkDescriptionNotPresentWorker( + __inout FxDeviceDescriptionEntry* DescriptionEntry, + __in BOOLEAN ModificationCanBeQueued + ) +/*++ + +Routine Description: + + This worker function marks the passed in mod or desc entry in the device + list "not present". The change is enqueued in the mod list but the mod + list is not drained. + +Arguments: + + DescriptionEntry - Entry to be marked as "not present". + + ModificationCanBeQueued - whether the caller allows for this description + to be a modification already queued on the modification list + +Assumes: + DescriptionEntry->IsPresent() == TRUE + +Return Value: + None + +--*/ +{ + BOOLEAN queueMod; + + ASSERT(DescriptionEntry->IsPresent()); + + queueMod = FALSE; + + if (ModificationCanBeQueued) { + if (IsListEmpty(&DescriptionEntry->m_ModificationLink)) { + queueMod = TRUE; + } + else { + // + // If the modification is queued, it must be removal + // + ASSERT(DescriptionEntry->m_ModificationState == + ModificationRemoveNotify); + ASSERT(DescriptionEntry->m_FoundInLastScan == FALSE); + } + } + else { + queueMod = TRUE; + } + + if (queueMod) { + ASSERT(IsListEmpty(&DescriptionEntry->m_ModificationLink)); + ASSERT(DescriptionEntry->m_ModificationState == ModificationUnspecified); + + // + // Add a removal modification entry into the modification list. + // The ModificationRemoveNotify state will be converted into + // ModificationRemove later while the list lock is still being held. + // + DescriptionEntry->m_ModificationState = ModificationRemoveNotify; + DescriptionEntry->m_FoundInLastScan = FALSE; + + InsertTailList(&m_ModificationListHead, + &DescriptionEntry->m_ModificationLink); + } +} + +VOID +FxChildList::MarkModificationNotPresentWorker( + __inout PLIST_ENTRY FreeListHead, + __inout FxDeviceDescriptionEntry* ModificationEntry + ) +/*++ + +Routine Description: + + This worker function marks the passed in mod or desc entry in the device + list "not present". The change is enqueued in the mod list but the mod + list is not drained. + +Arguments: + + FreeListHead - Free list of entries. + + ModificationEntry - Entry to be marked as "not present". + +Return Value: + None + +--*/ +{ + switch (ModificationEntry->m_ModificationState) { + case ModificationInsert: + // + // This one was never reported to the OS. Remove it now. + // + RemoveEntryList(&ModificationEntry->m_ModificationLink); + InitializeListHead(&ModificationEntry->m_ModificationLink); + + if (IsStaticList()) { + // + // There is a corner case of a static PDO being added and + // immediately marked as missing before it has a chance to move to + // description list. This case is handled here by marking the + // modification state to ModificationNeedsPnpRemoval. Fx cannot just + // delete the description because there is a driver-created PDO + // associated with the description and it needs to be cleaned up. + // + ModificationEntry->m_ModificationState = ModificationNeedsPnpRemoval; + ASSERT(ModificationEntry->m_DescriptionState == DescriptionUnspecified); + } + + ASSERT(IsListEmpty(&ModificationEntry->m_DescriptionLink)); + InsertTailList(FreeListHead, &ModificationEntry->m_DescriptionLink); + break; + + case ModificationClone: + // + // In between the PDOs stack asking for a reenumeration and applying + // this change, the bus driver has reported the child as missing. + // Convert the clone modification to a removal modification. + // + + // + // MarkDescriptionNotPresentWorker expects that m_ModificationEntry is + // not in any list and points to itself. + // + RemoveEntryList(&ModificationEntry->m_ModificationLink); + InitializeListHead(&ModificationEntry->m_ModificationLink); + + MarkDescriptionNotPresentWorker(ModificationEntry, FALSE); + break; + + default: + DO_NOTHING(); + break; + } +} + +VOID +FxChildList::DrainFreeListHead( + __inout PLIST_ENTRY FreeListHead + ) +{ + FxDeviceDescriptionEntry *pEntry; + FxDevice* pPdo; + PLIST_ENTRY pCur; + + while (!IsListEmpty(FreeListHead)) { + pCur = RemoveHeadList(FreeListHead); + InitializeListHead(pCur); + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(pCur); + + // + // If this is a static list and the entry has not yet been instantiated, + // tell PnP to remove the device. + // + // There is a corner case of a static PDO being added and + // immediately marked as missing before it has a chance to move to + // description list. This case is handled here by checking the + // modification state of ModificationNeedsPnpRemoval. Fx cannot just + // delete the description because there is a driver-created PDO + // associated with the description and it needs to be cleaned up. + // + if (m_StaticList && + (pEntry->m_DescriptionState == DescriptionPresentNeedsInstantiation || + pEntry->m_ModificationState == ModificationNeedsPnpRemoval )) { + + pPdo = CONTAINING_RECORD(pEntry->m_IdentificationDescription, + FxStaticChildDescription, + Header)->Pdo; + + // + // The pnp removal path expects that there is no modifcation pending + // when removing the description. + // + if (pEntry->m_ModificationState == ModificationNeedsPnpRemoval) { + ASSERT(pEntry->m_DescriptionState == DescriptionUnspecified); + ASSERT(IsListEmpty(&pEntry->m_ModificationLink)); + + pEntry->m_ModificationState = ModificationUnspecified; + } + + // + // Change the state to reported missing (which is what we are basically + // simulating here anyways) so that when we process the entry again + // when the PDO really goes away we cleanup the entry. + // + // Also, when posting PnpEventRemove to the child, child will + // call FxDeviceDescriptionEntry::IsDeviceRemoved which checks for + // reported missing before reporting if the device has been removed + // (and we want the device to be reported as removed). + // + pEntry->m_DescriptionState = DescriptionReportedMissing; + + // + // Not yet reported to PnP, so it should be in the initial state + // + ASSERT(pPdo->GetDevicePnpState() == WdfDevStatePnpInit); + + // + // m_Description should be set when the FxPkgPdo was created + // + ASSERT(pPdo->GetPdoPkg()->m_Description != NULL); + + // + // Since the pPdo->m_PkgPnp->m_DeviceRemoveProcessed == NULL, the + // pnp state machine will delete the PDO. We are simulating the same + // situation where an FDO is in the remove path and is telling each + // of its removed PDOs to delete themselves. + // + pPdo->m_PkgPnp->PnpProcessEvent(PnpEventRemove); + } + else { + CleanupDescriptions(pEntry->m_IdentificationDescription, + pEntry->m_AddressDescription); + + delete pEntry; + } + } +} + +FxDeviceDescriptionEntry* +FxChildList::SearchBackwardsForMatchingModificationLocked( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id + ) +{ + PLIST_ENTRY ple; + FxDeviceDescriptionEntry* pEntry; + + for (ple = m_ModificationListHead.Blink; + ple != &m_ModificationListHead; + ple = ple->Blink) { + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(ple); + + if (CompareId(pEntry->m_IdentificationDescription, Id)) { + return pEntry; + } + } + + return NULL; +} + +FxDeviceDescriptionEntry* +FxChildList::SearchBackwardsForMatchingDescriptionLocked( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id + ) +{ + PLIST_ENTRY ple; + FxDeviceDescriptionEntry* pEntry; + + for (ple = m_DescriptionListHead.Blink; + ple != &m_DescriptionListHead; + ple = ple->Blink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + if (CompareId(pEntry->m_IdentificationDescription, Id)) { + return pEntry; + } + } + + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::VerifyDescriptionEntry( + __in PLIST_ENTRY Entry + ) +{ + if (Entry == &m_DescriptionListHead) { + return STATUS_SUCCESS; + } + else { + PLIST_ENTRY ple; + + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = ple->Flink) { + if (Entry == ple) { + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_PARAMETER; + } +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::VerifyModificationEntry( + __in PLIST_ENTRY Entry + ) +{ + if (Entry == &m_ModificationListHead) { + return STATUS_SUCCESS; + } + else { + PLIST_ENTRY ple; + + for (ple = m_ModificationListHead.Flink; + ple != &m_ModificationListHead; + ple = ple->Flink) { + if (Entry == ple) { + return STATUS_SUCCESS; + } + } + + return STATUS_INVALID_PARAMETER; + } +} + +BOOLEAN +FxChildList::CreateDevice( + __inout FxDeviceDescriptionEntry* Entry, + __inout PBOOLEAN InvalidateRelations + ) +{ + WDFDEVICE_INIT init(m_Device->GetDriver()); + NTSTATUS status; + KIRQL irql; + + init.CreatedOnStack = TRUE; + init.SetPdo(m_Device); + init.Pdo.DescriptionEntry = Entry; + + if (m_StaticList) { + init.CreatedDevice = + CONTAINING_RECORD(Entry->m_IdentificationDescription, + FxStaticChildDescription, + Header)->Pdo; + } + else { + // + // This description needs a device, create it now. + // + status = m_EvtCreateDevice.Invoke( + GetHandle(), Entry->m_IdentificationDescription, &init); + + if (status == STATUS_RETRY) { + if (init.CreatedDevice != NULL) { + // + // Destroy any allocations assocated with the device. + // + init.CreatedDevice->Destroy(); + } + + *InvalidateRelations = TRUE; + + return FALSE; + } + + if (NT_SUCCESS(status)) { + // + // Make sure that a framework device was actually created + // + if (init.CreatedDevice == NULL) { + // + // Driver didn't actually create the device, even though its + // EvtChildListCreateDevice returned a successful return code. + // Change the status to indicate an error, so that we enter the + // error handling code below. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtChildListCreateDevice returned a successful status " + "%!STATUS! but did not create a device object", status); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + status = STATUS_INVALID_DEVICE_OBJECT_PARAMETER; + } + } + + if (!NT_SUCCESS(status)) { + if (init.CreatedDevice != NULL) { + KeAcquireSpinLock(&m_ListLock, &irql); + // + // Set to missing so that when the pnp machine evaluates whether the + // PDO has been reported missing or not, it chooses missing and + // deletes the PDO immediately. + // + Entry->m_DescriptionState = DescriptionReportedMissing; + + if (Entry->m_ModificationState != ModificationUnspecified) { + // + // Cannot be ModificationInsert since this device ID is already + // in the list. + // + // Cannot be ModificationClone since the FDO for this device + // is the only one who can ask for that and since PDO creation + // failed, there is no FDO. + // + // Cannot be ModificationRemove because the list is locked + // against changes and ModificationRemoveNotify becomes + // ModificationRemove only after the list has been unlocked. + // + ASSERT(Entry->m_ModificationState == ModificationRemoveNotify); + + // + // Remove the modification from the list. The call to + // DeleteDeviceFromFailedCreate below will destroy this + // Entry due to the pnp state machine deleting the PDO. + // + RemoveEntryList(&Entry->m_ModificationLink); + } + KeReleaseSpinLock(&m_ListLock, irql); + + ASSERT(init.CreatedDevice->IsPnp()); + ASSERT(init.CreatedDevice->GetDevicePnpState() == WdfDevStatePnpInit); + ASSERT(init.CreatedDevice->GetPdoPkg()->m_Description != NULL); + + ASSERT(Entry->m_Pdo == NULL); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p created, but EvtChildListCreateDevice " + "returned status %!STATUS!", init.CreatedDevice->GetHandle(), + init.CreatedDevice->GetDeviceObject(), status); + + // + // Simulate a remove event coming to the device. After this call + // returns, init.CreatedDevice is no longer a valid pointer! + // + // Please note that DeleteDeviceFromFailedCreate just returns + // the passed status back unless device is a filter, in which + // case it changes it to success. + // + // It is not really the status of DeleteDeviceFromFailedCreate + // operation, which is why we don't check it. + // + (void) init.CreatedDevice->DeleteDeviceFromFailedCreate( + status, + TRUE); + + init.CreatedDevice = NULL; + } + else { + LIST_ENTRY freeHead; + + InitializeListHead(&freeHead); + + // + // Add a modification that this entry is now gone. If there is + // an active scan and it has added this device, there would + // be no entry in the modification case list because the add + // would have updated the description entry. + // + KeAcquireSpinLock(&m_ListLock, &irql); + MarkDescriptionNotPresentWorker(Entry, TRUE); + ProcessModificationsLocked(&freeHead); + KeReleaseSpinLock(&m_ListLock, irql); + + // + // Free structures outside of any internal WDF lock + // + DrainFreeListHead(&freeHead); + } + + return FALSE; + } + } + + // + // Assign m_Pdo here once we have a fully baked and created device. We only + // assign m_Pdo after we have completely initalized device because we check + // for m_Pdo in PostParentToD0. + // + Entry->m_Pdo = init.CreatedDevice; + Entry->m_DescriptionState = DescriptionInstantiatedHasObject; + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::ProcessBusRelations( + __inout PDEVICE_RELATIONS *DeviceRelations + ) +{ + LIST_ENTRY freeHead; + PLIST_ENTRY ple, pNext; + FxDeviceDescriptionEntry* pEntry; + PDEVICE_RELATIONS pPriorRelations, pNewRelations; + PDEVICE_OBJECT pDevice; + BOOLEAN needToReportMissingChildren, invalidateRelations, cleanupRelations; + ULONG additionalCount, totalCount, i; + size_t size; + NTSTATUS status; + KIRQL irql; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxVerifierCheckIrqlLevel(GetDriverGlobals(), PASSIVE_LEVEL); + + pNewRelations = NULL; + invalidateRelations = FALSE; + cleanupRelations = TRUE; + InitializeListHead(&freeHead); + pFxDriverGlobals = GetDriverGlobals(); + + // + // Get the count of DO's we will need to add. While we're at it, free any + // extensions that never got a chance for a DO, and note extensions that + // will need to wait for a remove IRP. + // + KeAcquireSpinLock(&m_ListLock, &irql); + + m_State = ListLockedForEnum; + + additionalCount = 0; + needToReportMissingChildren = FALSE; + + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = ple->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + switch (pEntry->m_DescriptionState) { + + case DescriptionPresentNeedsInstantiation: + case DescriptionInstantiatedHasObject: + // + // We'll be needing a DO here. + // + additionalCount++; + break; + + case DescriptionNotPresent: + // + // We will now report the description as missing + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p in a not present state, need to " + "report as missing", + pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject()); + + needToReportMissingChildren = TRUE; + break; + + case DescriptionReportedMissing: + // + // Already reported missing in a previous handling of QDR + // + break; + + default: + ASSERTMSG("Invalid description state\n", FALSE); + break; + } + } + + KeReleaseSpinLock(&m_ListLock, irql); + + pPriorRelations = *DeviceRelations; + + // + // If we have + // 1) no devices in the list AND + // a) we have nothing to report OR + // b) we have something to report and there are previous relations (which + // if left unchanged will be used to report our missing devices) + // + // THEN nothing else to do except marking the NotPresent children as + // missing, unlock the list and return the special return + // code STATUS_NOT_SUPPORTED indicating this condition. + // + if (additionalCount == 0 && + (needToReportMissingChildren == FALSE || pPriorRelations != NULL)) { + // + // We have nothing to add, nor subtract from prior allocations. Note + // the careful logic with counting missing children - the OS does not + // treat no list and an empty list identically. As such we must be + // sure to return some kind of list in the case where we reported + // something previously. + // + // Mark the NotPresent children as Missing + // We can walk the ChildList without holding the spinlock because we set + // m_State to ListLockedForEnum. + // + if (needToReportMissingChildren) { + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = pNext) { + pNext = ple->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + if (pEntry->m_DescriptionState == DescriptionNotPresent) { + // + // We will now report the description as missing + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p reported as missing to pnp", + pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject()); + + pEntry->m_DescriptionState = DescriptionReportedMissing; + pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked; + } + } + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Nothing to report on WDFCHILDLIST %p, returning early", GetHandle()); + } + + cleanupRelations = FALSE; + status = STATUS_NOT_SUPPORTED; + goto Done; + } + + // + // Adjust the count for any existing relations. + // + totalCount = additionalCount; + if (pPriorRelations != NULL) { + totalCount += pPriorRelations->Count; + } + + size = _ComputeRelationsSize(totalCount); + + pNewRelations = (PDEVICE_RELATIONS) + ExAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag); + + if (pNewRelations == NULL) { + // + // We can't add our information. + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate relations for %d devices", + totalCount); + + // + // Just like above, STATUS_NOT_SUPPORTED is a special value indicating + // to the caller that the QDR has not been handled and that the caller + // should not change the status or the existing relations in the irp. + // + cleanupRelations = FALSE; + status = STATUS_NOT_SUPPORTED; + + m_EnumRetries++; + if (m_EnumRetries <= FX_CHILD_LIST_MAX_RETRIES) { + invalidateRelations = TRUE; + } + else { + if (needToReportMissingChildren) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFCHILDLIST %p could not allocate relations required for " + "reporting children as missing after max retries", + GetHandle()); + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFCHILDLIST %p retried %d times to report relations, but " + "failed each time", GetHandle(), FX_CHILD_LIST_MAX_RETRIES); + } + + if (pPriorRelations == NULL) { + // + // If the prior relations are NULL we can just return failure and + // not affect anyone else's state that had previous thought they + // committed a relations structure back to pnp (which we tried to + // update but could not b/c of no memory). + // + // By returning failure that is != STATUS_NOT_SUPPORTED, the pnp + // manager will not process a change in the relations. + // + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + // + // Do *not* throw away the old list and return error because that + // will put the driver which created the existing relations into an + // inconsistent state with respect to the pnp manager state if we + // fail it here and the pnp manager never seeds the changes. + // + // Instead, we must process the failure locally and mark each object + // which is already reported as present as missing. + // + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = pNext) { + + pNext = ple->Flink; + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + switch (pEntry->m_DescriptionState) { + case DescriptionPresentNeedsInstantiation: + // + // This description can stay in this state b/c we will just + // ask for another QDR. + // + break; + + case DescriptionInstantiatedHasObject: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p being marked as missing " + "because of failure to allocate device relations and " + "an already existing relations %p", + pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject(), pPriorRelations); + + KeAcquireSpinLock(&m_ListLock, &irql); + if (m_StaticList == FALSE) { + if (ReenumerateEntryLocked(pEntry, TRUE)) { + DoTraceLevelMessage( + pFxDriverGlobals, + TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p being cloned " + "because of the failure to allocate device " + "relations", + pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject()); + + (void) CloneEntryLocked(&freeHead, pEntry, TRUE); + } + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, + TRACE_LEVEL_WARNING, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p is a statically " + "enumerated PDO therefore can not be cloned and is " + "being marked missing because of failure to " + "allocate device relations. It will be surprise " + "removed by pnp manager. Bus driver may continue " + "to function normally but will lose this child PDO", + pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject()); + } + pEntry->m_DescriptionState = DescriptionReportedMissing; + pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked; + KeReleaseSpinLock(&m_ListLock, irql); + break; + + case DescriptionNotPresent: + // + // We will now report the description as missing + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p reported as missing to pnp " + "(by using existing relations)", + pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject()); + + pEntry->m_DescriptionState = DescriptionReportedMissing; + pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked; + break; + } + } + } + + goto Done; + } + + RtlZeroMemory(pNewRelations, size); + + if (pPriorRelations != NULL && pPriorRelations->Count > 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFCHILDLIST %p prior relations %p contained %d objects", + GetHandle(), pPriorRelations, pPriorRelations->Count + ); + + RtlCopyMemory(pNewRelations, + pPriorRelations, + _ComputeRelationsSize(pPriorRelations->Count)); + } + + // + // We can walk the ChildList without holding the spinlock because we set + // m_State to ListLockedForEnum. + // + status = STATUS_SUCCESS; + + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = pNext) { + pNext = ple->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + switch (pEntry->m_DescriptionState) { + case DescriptionPresentNeedsInstantiation: + // + // This extension needs a device handle. Create one now. + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Creating PDO device object from reported device"); + if (CreateDevice(pEntry, &invalidateRelations) == FALSE) { + break; + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO created successfully, WDFDEVICE %p !devobj %p", + pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject()); + + // || || Fall through || || + // \/ \/ \/ \/ + case DescriptionInstantiatedHasObject: + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Reporting PDO WDFDEVICE %p !devobj %p", + pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetDeviceObject()); + + pDevice = pEntry->m_Pdo->GetDeviceObject(); + ObReferenceObject(pDevice); + pNewRelations->Objects[pNewRelations->Count] = pDevice; + pNewRelations->Count++; + break; + + case DescriptionNotPresent: + // + // We will now report the description as missing + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p reported as missing to pnp", + pEntry->m_Pdo->GetHandle(), pEntry->m_Pdo->GetDeviceObject()); + + pEntry->m_DescriptionState = DescriptionReportedMissing; + pEntry->m_ReportedMissingCallbackState = CallbackNeedsToBeInvoked; + + break; + + case DescriptionReportedMissing: + break; + + default: + ASSERTMSG("Invalid description state\n", FALSE); + break; + } + } + +Done: + KeAcquireSpinLock(&m_ListLock, &irql); + + // + // Make sure that the description we just dequeued is not on the modification + // list. + // + m_State = ListUnlocked; + ProcessModificationsLocked(&freeHead); + + if (NT_SUCCESS(status)) { + m_EnumRetries = 0; + } + + KeReleaseSpinLock(&m_ListLock, irql); + + if (invalidateRelations) { + // + // We failed for some reason or other. Queue up a new attempt. + // + // NOTE: no need to check m_Device->m_KnownPdo here + // because we are in the middle of a QDR for m_Device which means + // that it, or its stack, is already known to PnP. + // + IoInvalidateDeviceRelations(m_Device->GetPhysicalDevice(), BusRelations); + } + + DrainFreeListHead(&freeHead); + + if (cleanupRelations) { + if (pPriorRelations != NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Freeing prior relations %p", pPriorRelations); + + ExFreePool(pPriorRelations); + pPriorRelations = NULL; + } + + if (!NT_SUCCESS(status) && pNewRelations != NULL) { + for(i = 0; i < pNewRelations->Count; i++) { + ObDereferenceObject(pNewRelations->Objects[i]); + } + + ExFreePool(pNewRelations); + pNewRelations = NULL; + } + + *DeviceRelations = pNewRelations; + } + + return status; +} + +VOID +FxChildList::InvokeReportedMissingCallback( + VOID + ) +{ + PLIST_ENTRY ple, pNext; + KIRQL irql; + FxDeviceDescriptionEntry* pEntry; + LIST_ENTRY freeHead; + + InitializeListHead(&freeHead); + + // + // Prevent modification list processing so that we can walk the + // description list safely. + // + KeAcquireSpinLock(&m_ListLock, &irql); + m_State = ListLockedForEnum; + KeReleaseSpinLock(&m_ListLock, irql); + + // + // Invoke the ReportedMissing callback if present for children reported + // missing. + // + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = pNext) { + pNext = ple->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + if (pEntry->m_ReportedMissingCallbackState == CallbackNeedsToBeInvoked) { + (pEntry->m_Pdo->GetPdoPkg())->m_DeviceReportedMissing.Invoke( + pEntry->m_Pdo->GetHandle()); + + pEntry->m_ReportedMissingCallbackState = CallbackInvoked; + } + } + + KeAcquireSpinLock(&m_ListLock, &irql); + m_State = ListUnlocked; + ProcessModificationsLocked(&freeHead); + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); +} + +VOID +FxChildList::PostParentToD0( + VOID + ) +{ + FxDeviceDescriptionEntry* pEntry; + PLIST_ENTRY ple; + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = ple->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + if (pEntry->m_PendingDeleteOnScanEnd) { + COVERAGE_TRAP(); + continue; + } + + if (pEntry->m_Pdo != NULL) { + pEntry->m_Pdo->m_PkgPnp->PowerProcessEvent(PowerParentToD0); + } + } + KeReleaseSpinLock(&m_ListLock, irql); +} + +VOID +FxChildList::IndicateWakeStatus( + __in NTSTATUS WaitWakeStatus + ) +/*++ + +Routine Description: + Propagates the wait wake status to all the child PDOs. This will cause any + pended wait wake requests to be completed with the given wait wake status. + +Arguments: + WaitWakeStatus - The NTSTATUS value to use for compeleting any pended wait + wake requests on the child PDOs. + +Return Value: + None + + --*/ +{ + FxDeviceDescriptionEntry* pEntry; + PLIST_ENTRY ple; + KIRQL irql; + + KeAcquireSpinLock(&m_ListLock, &irql); + for (ple = m_DescriptionListHead.Flink; + ple != &m_DescriptionListHead; + ple = ple->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(ple); + + if (pEntry->m_PendingDeleteOnScanEnd) { + COVERAGE_TRAP(); + continue; + } + + if (pEntry->m_Pdo != NULL) { + ASSERT(pEntry->m_Pdo->m_PkgPnp->m_SharedPower.m_WaitWakeOwner == TRUE); + pEntry->m_Pdo->m_PkgPnp->PowerIndicateWaitWakeStatus(WaitWakeStatus); + } + } + KeReleaseSpinLock(&m_ListLock, irql); +} + +VOID +FxChildList::NotifyDeviceSurpriseRemove( + VOID + ) +/*++ + +Routine Description: + Notification through IFxStateChangeNotification that the parent device is + being surprise removed + +Arguments: + None + +Return Value: + None + + --*/ +{ + PLIST_ENTRY pCur, pNext; + LIST_ENTRY freeHead; + FxDeviceDescriptionEntry* pEntry; + KIRQL irql; + + InitializeListHead(&freeHead); + + FxVerifierCheckIrqlLevel(GetDriverGlobals(), PASSIVE_LEVEL); + + KeAcquireSpinLock(&m_ListLock, &irql); + + // + // Walk over all mod entries and remove any pending inserts. Note that + // MarkModificationNotPresentWorker will add any such INSERTs found in the + // mod list to the free list. + // + for (pCur = m_ModificationListHead.Flink; + pCur != &m_ModificationListHead; + pCur = pNext) { + + pNext = pCur->Flink; + + pEntry = FxDeviceDescriptionEntry::_FromModificationLink(pCur); + + if (pEntry->m_ModificationState == ModificationInsert) { + MarkModificationNotPresentWorker(&freeHead, pEntry); + } + } + + // + // Walk over all desc entries and remove them. Since + // MarkDescriptionNotPresentWorker doesn't drain the mods, + // we don't have to worry about any entries disappearing. + // + for (pCur = m_DescriptionListHead.Flink; + pCur != &m_DescriptionListHead; + pCur = pCur->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(pCur); + + if (pEntry->IsPresent()) { + MarkDescriptionNotPresentWorker(pEntry, TRUE); + } + } + + // + // Attempt to drain any mods we made. + // + ProcessModificationsLocked(&freeHead); + + // + // Walk over all desc entries and advance them to missing. + // + for (pCur = m_DescriptionListHead.Flink; + pCur != &m_DescriptionListHead; + pCur = pCur->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(pCur); + + if (pEntry->m_DescriptionState == DescriptionNotPresent) { + pEntry->m_DescriptionState = DescriptionReportedMissing; + } + } + + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); +} + +VOID +FxChildList::NotifyDeviceRemove( + __inout PLONG ChildCount + ) +/*++ + +Routine Description: + Notification through IFxStateChangeNotification that the parent device is + being removed. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PLIST_ENTRY pCur; + LIST_ENTRY freeHead; + FxDeviceDescriptionEntry* pEntry; + KIRQL irql; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFCHILDLIST %p: removing children", GetHandle()); + + InitializeListHead(&freeHead); + pEntry = NULL; + + FxVerifierCheckIrqlLevel(GetDriverGlobals(), PASSIVE_LEVEL); + + // + // Surprise remove handling covers the first stage of processing. This will + // process the modification list, esp the insert modifications which will + // be cleaned up. + // + NotifyDeviceSurpriseRemove(); + + KeAcquireSpinLock(&m_ListLock, &irql); + + ProcessModificationsLocked(&freeHead); + + m_State = ListLockedForParentRemove; + + for ( ; ; ) { + + // + // Find the first child which was not surprise removed. If surprise + // removed and not yet removed, then there is an outstanding handle + // which has not yet been closed. + // + for (pCur = m_DescriptionListHead.Flink; + pCur != &m_DescriptionListHead; + pCur = pCur->Flink) { + + pEntry = FxDeviceDescriptionEntry::_FromDescriptionLink(pCur); + + ASSERT(pEntry->m_DescriptionState == DescriptionReportedMissing); + + if (pEntry->m_ProcessingSurpriseRemove == FALSE) { + break; + } + } + + // + // If we are at the end of the list, we are done + // + if (pCur == &m_DescriptionListHead) { + break; + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Removing entry %p, WDFDEVICE %p, PDO %p", + pEntry, pEntry->m_Pdo->GetHandle(), + pEntry->m_Pdo->GetPhysicalDevice()); + + ASSERT(pEntry->m_ModificationState == ModificationUnspecified); + RemoveEntryList(&pEntry->m_DescriptionLink); + InitializeListHead(&pEntry->m_DescriptionLink); + + KeReleaseSpinLock(&m_ListLock, irql); + + // + // Go through FxPkgPdo to handle cleanup. CleanupOrphanedDevice will + // free this entry. + // + ASSERT(pEntry->m_Pdo != NULL); + ASSERT(pEntry->m_PendingDeleteOnScanEnd == FALSE); + + pEntry->m_Pdo->SetParentWaitingOnRemoval(); + InterlockedIncrement(ChildCount); + + // + // Start the child going away + // + pEntry->m_Pdo->m_PkgPnp->PnpProcessEvent(PnpEventParentRemoved); + + KeAcquireSpinLock(&m_ListLock, &irql); + } + + m_State = ListUnlocked; + ProcessModificationsLocked(&freeHead); + + KeReleaseSpinLock(&m_ListLock, irql); + + DrainFreeListHead(&freeHead); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::_ValidateConfig( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_CHILD_LIST_CONFIG Config, + __in size_t* TotalDescriptionSize + ) +{ + NTSTATUS status; + + if (Config == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid Config, NULL is not allowed, %!STATUS!", status); + return status; + } + + if (Config->Size != sizeof(WDF_CHILD_LIST_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Config->Size incorrect, expected %d, got %d, %!STATUS!", + sizeof(WDF_CHILD_LIST_CONFIG), Config->Size, status); + return status; + } + if (Config->IdentificationDescriptionSize == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Config->IdentificationDescriptionSize must be non zero, " + "%!STATUS!", status); + return status; + } + if (Config->EvtChildListCreateDevice == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Config->EvtChildListCreateDevice, NULL is not allowed, " + "%!STATUS!", status); + return status; + } + + return _ComputeTotalDescriptionSize(FxDriverGlobals, + Config, + TotalDescriptionSize); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::_ComputeTotalDescriptionSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_CHILD_LIST_CONFIG Config, + __in size_t* TotalDescriptionSize + ) +{ + size_t addressAligned, idAligned; + NTSTATUS status; + + *TotalDescriptionSize = 0; + + // + // FxDeviceDescriptionEntry::operator new() will allocate a block of memory + // that is + // size = + // WDF_ALIGN_SIZE_UP(sizeof(FxDeviceDescriptionEntry), sizeof(PVOID)) + + // WDF_ALIGN_SIZE_UP(AddressDescriptionSize, sizeof(PVOID)) + + // WDF_ALIGN_SIZE_UP(IdentificationDescriptionSize, sizeof(PVOID)); + // + // Validate the size now beforehand, not every we allocate + // + // + // Test for overflow + // + idAligned = WDF_ALIGN_SIZE_UP(Config->IdentificationDescriptionSize, + sizeof(PVOID)); + if (idAligned < Config->IdentificationDescriptionSize) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Config->IdentificationDescriptionSize %d too large" + "%!STATUS!", Config->IdentificationDescriptionSize, + status); + return status; + } + + addressAligned = WDF_ALIGN_SIZE_UP(Config->AddressDescriptionSize, + sizeof(PVOID)); + if (addressAligned < Config->AddressDescriptionSize) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Config->AddressDescriptionSize %d too large, %!STATUS!", + Config->AddressDescriptionSize, status); + return status; + } + + status = RtlSizeTAdd( + WDF_ALIGN_SIZE_UP(sizeof(FxDeviceDescriptionEntry), sizeof(PVOID)), + idAligned, + TotalDescriptionSize + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not add ID description size to block size, %!STATUS!", + status); + return status; + } + + status = RtlSizeTAdd(*TotalDescriptionSize, + addressAligned, + TotalDescriptionSize); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not add address description size to block size, %!STATUS!", + status); + return status; + } + + return STATUS_SUCCESS; +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxchildlistapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxchildlistapi.cpp new file mode 100644 index 00000000000..7d04ec796ae --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxchildlistapi.cpp @@ -0,0 +1,804 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxChildListApi.cpp + +Abstract: + + This module exposes the "C" interface to the FxChildList object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "fxcorepch.hpp" + +extern "C" { +#include "FxChildListAPI.tmh" +} + +// +// extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfChildListCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_CHILD_LIST_CONFIG Config, + __in_opt + PWDF_OBJECT_ATTRIBUTES DeviceListAttributes, + __out + WDFCHILDLIST* DeviceList + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + FxChildList* pList; + size_t totalDescriptionSize = 0; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter, WDFDEVICE %p", Device); + + FxPointerNotNull(pFxDriverGlobals, Config); + FxPointerNotNull(pFxDriverGlobals, DeviceList); + + *DeviceList = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxChildList::_ValidateConfig(pFxDriverGlobals, + Config, + &totalDescriptionSize); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p Config is invalid", Device); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, + DeviceListAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pDevice->AllocateEnumInfo(); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxChildList::_CreateAndInit(&pList, + pFxDriverGlobals, + DeviceListAttributes, + totalDescriptionSize, + pDevice, + Config); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pList->Commit(DeviceListAttributes, + (WDFOBJECT*)DeviceList, + pDevice); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not convert object to handle, %!STATUS!", + status); + pList->DeleteFromFailedCreate(); + } + + if (NT_SUCCESS(status)) { + pDevice->SetDeviceTelemetryInfoFlags(DeviceInfoHasDynamicChildren); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfChildListGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + return pList->GetDevice(); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfChildListRetrieveAddressDescription)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __inout + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + FxPointerNotNull(pFxDriverGlobals, IdentificationDescription); + FxPointerNotNull(pFxDriverGlobals, AddressDescription); + + if (pList->GetIdentificationDescriptionSize() != + IdentificationDescription->IdentificationDescriptionSize) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "identification description size %d incorrect, expected %d, %!STATUS!", + IdentificationDescription->IdentificationDescriptionSize, + pList->GetIdentificationDescriptionSize(), status); + + return status; + } + + if (pList->HasAddressDescriptions() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "cannot retrieve an address description from a list" + " which was not initialized to use them, %!STATUS!", + status); + + return status; + } + + if (pList->GetAddressDescriptionSize() != + AddressDescription->AddressDescriptionSize) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "description size %d incorrect, expected %d, %!STATUS!", + AddressDescription->AddressDescriptionSize, + pList->GetAddressDescriptionSize(), status); + + return status; + } + + status = pList->GetAddressDescription(IdentificationDescription, + AddressDescription); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit: WDFCHILDLIST %p, %!STATUS!", + DeviceList, status); + + return status; + +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfChildListBeginScan)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + pList->BeginScan(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfChildListEndScan)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + pList->EndScan(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfChildListBeginIteration)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + FxPointerNotNull(pFxDriverGlobals, Iterator); + + if (Iterator->Size != sizeof(WDF_CHILD_LIST_ITERATOR)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Iterator Size %d not correct, expected %d, %!STATUS!", + Iterator->Size, sizeof(WDF_CHILD_LIST_ITERATOR), + STATUS_INFO_LENGTH_MISMATCH); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if ((Iterator->Flags & ~WdfRetrieveAllChildren) != 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Iterator Flags 0x%x not correct, valid mask 0x%x, %!STATUS!", + Iterator->Flags, WdfRetrieveAllChildren, STATUS_INVALID_PARAMETER); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + RtlZeroMemory(&Iterator->Reserved[0], sizeof(Iterator->Reserved)); + + pList->BeginIteration(Iterator); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfChildListRetrieveNextDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_LIST_ITERATOR Iterator, + __out + WDFDEVICE* Device, + __inout_opt + PWDF_CHILD_RETRIEVE_INFO Info + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Iterator); + FxPointerNotNull(pFxDriverGlobals, Device); + + *Device = NULL; + + if (Iterator->Size != sizeof(WDF_CHILD_LIST_ITERATOR)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Iterator Size %d not correct, expected %d, %!STATUS!", + Iterator->Size, sizeof(WDF_CHILD_LIST_ITERATOR), status); + return status; + } + + if ((Iterator->Flags & ~WdfRetrieveAllChildren) != 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Iterator Flags 0x%x not correct, valid mask 0x%x, %!STATUS!", + Iterator->Flags, WdfRetrieveAllChildren, status); + return status; + } + + if (Info != NULL) { + if (Info->Size != sizeof(WDF_CHILD_RETRIEVE_INFO)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid RetrieveInfo Size %d, expected %d, %!STATUS!", + Info->Size, sizeof(WDF_CHILD_RETRIEVE_INFO), status); + return status; + } + if (Info->IdentificationDescription != NULL + && + pList->GetIdentificationDescriptionSize() != + Info->IdentificationDescription->IdentificationDescriptionSize) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "identification description size %d incorrect, expected %d" + "%!STATUS!", + Info->IdentificationDescription->IdentificationDescriptionSize, + pList->GetIdentificationDescriptionSize(), status); + + return status; + } + + if (Info->AddressDescription != NULL) { + if (pList->HasAddressDescriptions() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "cannot retrieve an address description from a list" + " which was not initialized to use them, %!STATUS!", + status); + + return status; + } + else if (pList->GetAddressDescriptionSize() != + Info->AddressDescription->AddressDescriptionSize) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "address description size %d incorrect, expected %d, %!STATUS!", + Info->AddressDescription->AddressDescriptionSize, + pList->GetAddressDescriptionSize(), status); + + return status; + } + } + } + + return pList->GetNextDevice(Device, Iterator, Info); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfChildListEndIteration)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + FxChildList* pList; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + FxPointerNotNull(pFxDriverGlobals, Iterator); + + if (Iterator->Size != sizeof(WDF_CHILD_LIST_ITERATOR)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Iterator Size %d not correct, expected %d, %!STATUS!", + Iterator->Size, sizeof(WDF_CHILD_LIST_ITERATOR), + STATUS_INFO_LENGTH_MISMATCH); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if ((Iterator->Flags & ~WdfRetrieveAllChildren) != 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Iterator Flags 0x%x not correct, valid mask 0x%x, %!STATUS!", + Iterator->Flags, WdfRetrieveAllChildren, STATUS_INVALID_PARAMETER); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pList->EndIteration(Iterator); +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __in_opt + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + FxPointerNotNull(pFxDriverGlobals, IdentificationDescription); + + if (AddressDescription != NULL) { + if (pList->HasAddressDescriptions() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "cannot retrieve an address description from a list" + " which was not initialized to use them, %!STATUS!", status); + + return status; + } + if (pList->GetAddressDescriptionSize() != + AddressDescription->AddressDescriptionSize) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "address description size %d incorrect, expected %d, %!STATUS!", + AddressDescription->AddressDescriptionSize, + pList->GetAddressDescriptionSize(), status); + + return status; + } + } + else { + if (pList->HasAddressDescriptions()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Must provide a valid AddressDescription because the" + " WDFCHILDLIST 0x%p is configured with AddressDescriptionSize," + " %!STATUS!", DeviceList, status); + + return status; + } + } + + if (pList->GetIdentificationDescriptionSize() != + IdentificationDescription->IdentificationDescriptionSize) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "identification description size %d incorrect, expected %d, %!STATUS!", + IdentificationDescription->IdentificationDescriptionSize, + pList->GetIdentificationDescriptionSize(), status); + + return status; + } + + status = pList->Add(IdentificationDescription, AddressDescription); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit: WDFCHILDLIST %p, %!STATUS!", DeviceList, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxChildList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, IdentificationDescription); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + if (pList->GetIdentificationDescriptionSize() != + IdentificationDescription->IdentificationDescriptionSize) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "identification description size %d incorrect, expected %d, %!STATUS!", + IdentificationDescription->IdentificationDescriptionSize, + pList->GetIdentificationDescriptionSize(), status); + + return status; + } + + status = pList->UpdateAsMissing(IdentificationDescription); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit: WDFCHILDLIST %p, %!STATUS!", + DeviceList, status); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxChildList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + pList->UpdateAllAsPresent(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit: WDFCHILDLIST %p", DeviceList); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfChildListRetrievePdo)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __inout + PWDF_CHILD_RETRIEVE_INFO RetrieveInfo + ) +{ + FxChildList* pList; + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER pId; + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER pAddr; + FxDevice* device; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + FxPointerNotNull(pFxDriverGlobals, RetrieveInfo); + + if (RetrieveInfo->Size != sizeof(WDF_CHILD_RETRIEVE_INFO)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid RetrieveInfo Size %x, expected %d, %!STATUS!", + RetrieveInfo->Size, sizeof(WDF_CHILD_RETRIEVE_INFO), + STATUS_INFO_LENGTH_MISMATCH); + return NULL; + } + + pId = RetrieveInfo->IdentificationDescription; + if (pId == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid ID Description, %!STATUS!", + STATUS_INVALID_PARAMETER); + return NULL; + } + + if (pList->GetIdentificationDescriptionSize() != + pId->IdentificationDescriptionSize) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "identification description size %d incorrect, expected %d", + pId->IdentificationDescriptionSize, + pList->GetIdentificationDescriptionSize()); + + return NULL; + } + + pAddr = RetrieveInfo->AddressDescription; + if (pAddr != NULL) { + if (pList->HasAddressDescriptions() == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "cannot retrieve an address description from a list" + " which was not initialized to use them, %!STATUS!", + STATUS_INVALID_DEVICE_REQUEST); + return NULL; + } + else if (pList->GetAddressDescriptionSize() != pAddr->AddressDescriptionSize) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "address description size %d incorrect, expected %d", + pAddr->AddressDescriptionSize, pList->GetAddressDescriptionSize()); + + return NULL; + } + } + + RetrieveInfo->Status = WdfChildListRetrieveDeviceUndefined; + + device = pList->GetDeviceFromId(RetrieveInfo); + + WDFDEVICE handle; + + if (device != NULL) { + handle = device->GetHandle(); + } + else { + handle = NULL; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit: WDFCHILDLIST %p, WDFDEVICE Pdo %p, " + "%!WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS!", + DeviceList, handle, RetrieveInfo->Status); + + return handle; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfChildListRequestChildEject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCHILDLIST DeviceList, + __in + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ) +{ + FxChildList* pList; + FxDevice* device; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DeviceList, + FX_TYPE_CHILD_LIST, + (PVOID*)&pList, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter: WDFCHILDLIST %p", DeviceList); + + FxPointerNotNull(pFxDriverGlobals, IdentificationDescription); + + if (pList->GetIdentificationDescriptionSize() != + IdentificationDescription->IdentificationDescriptionSize) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "identification description size 0x%x incorrect, expected 0x%x", + IdentificationDescription->IdentificationDescriptionSize, + pList->GetIdentificationDescriptionSize()); + + return FALSE; + } + + WDF_CHILD_RETRIEVE_INFO info; + + WDF_CHILD_RETRIEVE_INFO_INIT(&info, IdentificationDescription); + + device = pList->GetDeviceFromId(&info); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "found: WDFCHILDLIST %p, WDFDEVICE PDO %p", + DeviceList, device == NULL ? NULL : device->GetHandle()); + + if (device != NULL) { + PDEVICE_OBJECT pdo; + + // + // Make sure we have a valid PDO that can be ejected + // + pdo = device->GetSafePhysicalDevice(); + + if (pdo != NULL) { + IoRequestDeviceEject(pdo); + return TRUE; + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PDO WDFDEVICE %p not reported yet to pnp, cannot eject!", + device->GetHandle()); + } + } + + return FALSE; +} + +} // extern "C" of entire file diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxcorepch.hpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxcorepch.hpp new file mode 100644 index 00000000000..1fa1da5dc8f --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxcorepch.hpp @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxcorepch.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in fx\core + +Author: + +Environment: + Kernel mode only + +Revision History: + +--*/ + +#ifndef __FX_CORE_PCH_H__ +#define __FX_CORE_PCH_H__ + +#include "corepriv.hpp" +#include + +#endif // __FX_CORE_PCH_H__ diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxdevicefdoapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxdevicefdoapi.cpp new file mode 100644 index 00000000000..509d19dd368 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxdevicefdoapi.cpp @@ -0,0 +1,464 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceFdoApi.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "fxcorepch.hpp" + +extern "C" { +#include "FxDeviceFdoApi.tmh" +} + +// +// Extern "C" the rest of the file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfFdoAddStaticChild)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Fdo, + __in + WDFDEVICE Child + ) +/*++ + +Routine Description: + Adds a statically enumerated child to the static device list. + +Arguments: + Fdo - the parent of the child + + Child - the child to add + +Return Value: + NTSTATUS + + --*/ + +{ + FxStaticChildDescription description; + FxDevice* pFdo; + FxDevice* pPdo; + FxPkgFdo* pPkgFdo; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Fdo, + FX_TYPE_DEVICE, + (PVOID*)&pFdo); + + // + // Verify type + // + if (pFdo->IsLegacy() || pFdo->IsFdo() == FALSE) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFdo->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p is either legacy or is not a Fdo, %!STATUS!", + Fdo, status); + + return status; + } + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Child, + FX_TYPE_DEVICE, + (PVOID*)&pPdo); + + if (pPdo->IsLegacy() || pPdo->IsPdo() == FALSE) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFdo->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE Child 0x%p is either legacy or is not a PDO, %!STATUS!", + Child, status); + + return status; + } + + pPkgFdo = pFdo->GetFdoPkg(); + + // + // Try to add the device to the list. We use the FxDevice* of the PDO as the + // unique ID in the list. + // + description.Header.IdentificationDescriptionSize = sizeof(description); + description.Pdo = pPdo; + + status = pPkgFdo->m_StaticDeviceList->Add(&description.Header, NULL, NULL); + + if (NT_SUCCESS(status)) { + pFdo->SetDeviceTelemetryInfoFlags(DeviceInfoHasStaticChildren); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfFdoLockStaticChildListForIteration)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Fdo + ) +/*++ + +Routine Description: + Locks the static child list for iteration. Any adds or removes that occur + while the list is locked are pended until it is unlocked. Locking can + be nested. When the unlock count is zero, the changes are evaluated. + +Arguments: + Fdo - the parent who owns the list of static children + +Return Value: + None + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_CHILD_LIST_ITERATOR iterator; + FxDevice* pDevice; + FxPkgFdo* pPkgFdo; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Fdo, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + // + // Verify type + // + if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid WDFDEVICE %p is not an FDO", Fdo); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pPkgFdo = pDevice->GetFdoPkg(); + + // + // Create a fake iterator to begin iteration. We will not need it in the + // retrieve next static child call. + // + WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrieveAllChildren); + + pPkgFdo->m_StaticDeviceList->BeginIteration(&iterator); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfFdoRetrieveNextStaticChild)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Fdo, + __in + WDFDEVICE PreviousChild, + __in + ULONG Flags + ) +/*++ + +Routine Description: + Returns the next static child in the list based on the PreviousChild and + Flags values. + +Arguments: + Fdo - the parent which owns the static child list + + PreviousChild - The child returned on the last call to this DDI. If NULL, + returns the first static child specified by the Flags criteria + + Flags - combination of values from WDF_RETRIEVE_CHILD_FLAGS. + WdfRetrievePresentChildren - reports children who have been reported as + present to pnp + WdfRetrieveMissingChildren = reports children who have been reported as + missing to pnp + WdfRetrievePendingChildren = reports children who have been added to the + list, but not yet reported to pnp + +Return Value: + next WDFDEVICE handle representing a static child or NULL + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + FxPkgFdo* pPkgFdo; + WDFDEVICE next; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Fdo, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + // + // validate Flags + // + if (Flags == 0 || (Flags & ~WdfRetrieveAllChildren) != 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid Flags 0x%x", Flags); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + + // + // Verify type + // + if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not an FDO", Fdo); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + + pPkgFdo = pDevice->GetFdoPkg(); + + next = pPkgFdo->m_StaticDeviceList->GetNextStaticDevice(PreviousChild, Flags); + + return next; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfFdoUnlockStaticChildListFromIteration)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Fdo + ) +/*++ + +Routine Description: + Unlocks the static child list from iteration. Upon the last unlock, any + pended modifications to the list will be applied. + +Arguments: + Fdo - the parent who owns the static child list + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_CHILD_LIST_ITERATOR iterator; + FxDevice* pDevice; + FxPkgFdo* pPkgFdo; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Fdo, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + // + // Verify type + // + if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not an FDO", Fdo); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Local iterator used to end iteration. WdfRetrieveAllChildren is an + // arbitrary value. + // + WDF_CHILD_LIST_ITERATOR_INIT(&iterator, WdfRetrieveAllChildren); + + pPkgFdo = pDevice->GetFdoPkg(); + pPkgFdo->m_StaticDeviceList->EndIteration(&iterator); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfFdoQueryForInterface)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Fdo, + __in + LPCGUID InterfaceType, + __out + PINTERFACE Interface, + __in + USHORT Size, + __in + USHORT Version, + __in_opt + PVOID InterfaceSpecificData + ) +/*++ + +Routine Description: + Sends a query interface pnp request to the top of the stack (which means that + the request will travel through this device before going down the stack). + +Arguments: + Fdo - the device stack which is being queried + + InterfaceType - interface type specifier + + Interface - Interface block which will be filled in by the component which + responds to the query interface + + Size - size in bytes of Interfce + + Version - version of InterfaceType being requested + + InterfaceSpecificData - Additional data associated with Interface + +Return Value: + NTSTATUS + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDeviceBase* pDeviceBase; + FxDevice* pDevice; + FxQueryInterfaceParams params = { (PVOID*) &pDevice, FX_TYPE_DEVICE, 0 }; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Fdo, + FX_TYPE_DEVICE_BASE, + (PVOID*)&pDeviceBase, + &pFxDriverGlobals); + + pDevice = NULL; + + FxPointerNotNull(pFxDriverGlobals, InterfaceType); + FxPointerNotNull(pFxDriverGlobals, Interface); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // See if we have a full fledged WDFDEVICE or a miniport WDFDEVICE + // + if (NT_SUCCESS(pDeviceBase->QueryInterface(¶ms))) { + // + // Verify type + // + if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p Device is either legacy or is not a Fdo %!STATUS!", + Fdo, status); + + return status; + } + } + else { + // + // miniport WDFDEVICE, nothing to check + // + DO_NOTHING(); + } + + return pDeviceBase->QueryForInterface( + InterfaceType, Interface, Size, Version, InterfaceSpecificData); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFCHILDLIST +WDFEXPORT(WdfFdoGetDefaultChildList)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Fdo + ) +/*++ + +Routine Description: + Returns the default dynamic child list associated with the FDO. For a + valid handle to be returned, the driver must have configured the default + list in its device init phase. + +Arguments: + Fdo - the FDO being asked to return the handle + +Return Value: + a valid handle value or NULL + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + FxPkgFdo* pPkgFdo; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Fdo, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + // + // Verify type + // + if (pDevice->IsLegacy() || (pDevice->IsFdo() == FALSE)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not an FDO", Fdo); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + + pPkgFdo = pDevice->GetFdoPkg(); + + if (pPkgFdo->m_DefaultDeviceList != NULL) { + return (WDFCHILDLIST) pPkgFdo->m_DefaultDeviceList->GetObjectHandle(); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Default child list for FDO %p not configured, call " + "WdfFdoInitSetDefaultChildListConfig to do so", Fdo); + return NULL; + } +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxdevicepdoapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxdevicepdoapi.cpp new file mode 100644 index 00000000000..c33c614e290 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxdevicepdoapi.cpp @@ -0,0 +1,491 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDevicePdoApi.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "fxcorepch.hpp" + +extern "C" { +#include "FxDevicePdoApi.tmh" +} + +NTSTATUS +GetPdoPackageFromDeviceHandle( + __in + IN PFX_DRIVER_GLOBALS CallersGlobals, + __in + WDFDEVICE Device, + __in + PCHAR FunctionName, + __out + FxPkgPdo **Package, + __out + PFX_DRIVER_GLOBALS* ObjectGlobals, + __out_opt + FxDevice **OutDevice = NULL + ) +{ + NTSTATUS status; + FxDevice *pDevice; + + FxObjectHandleGetPtrAndGlobals(CallersGlobals, + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + ObjectGlobals); + + // + // If the optional "OutDevice" argument is present, return the pointer + // to the device. + // + if (OutDevice != NULL) { + *OutDevice = pDevice; + } + + // + // Check to see if a PDO package is installed on the device. + // + if (pDevice->IsPdo()) { + *Package = (FxPkgPdo *) pDevice->GetPdoPkg(); + status = STATUS_SUCCESS; + } + else { + DoTraceLevelMessage((*ObjectGlobals), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "%s: Incorrect device handle supplied (0x%p). " + "Device is not a PDO.", FunctionName, Device); + + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + +// +// Extern "C" the rest of the file file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoMarkMissing)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxPkgPdo *pPkgPdo; + FxDevice *pDevice; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals, + &pDevice); + + if (NT_SUCCESS(status)) { + // + // Check to see if the device is enumerated off of a child list. If so, + // have the child list object perform any necessary actions. + // + status = pPkgPdo->m_OwningChildList->UpdateDeviceAsMissing(pDevice); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfPdoRequestEject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + NTSTATUS status; + FxPkgPdo *pPkgPdo; + FxDevice *pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals, + &pDevice); + + if (NT_SUCCESS(status)) { + PDEVICE_OBJECT pdo; + + pdo = pDevice->GetSafePhysicalDevice(); + + if (pdo != NULL) { + IoRequestDeviceEject(pdo); + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PDO WDFDEVICE %p not reported yet to pnp, cannot eject!", + Device); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Can only eject PDOs, %!STATUS!", status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfPdoGetParent)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxPkgPdo *pPkgPdo; + FxDevice *pDevice; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals, + &pDevice); + + if (NT_SUCCESS(status)) { + return pDevice->m_ParentDevice->GetHandle(); + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Can only eject PDOs, %!STATUS!", status); + + return NULL; + } +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoRetrieveIdentificationDescription)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __inout + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxPkgPdo *pPkgPdo; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, IdentificationDescription); + + if (NT_SUCCESS(status)) { + FxChildList* pList; + + if (pPkgPdo->m_Description == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + pList = pPkgPdo->m_Description->GetParentList(); + + // + // The fact that a statically enumerated PDO is enumerated using an + // FxChildList should not be exposed to the driver. Besides, the driver + // does not know the definition of the identificaiton descirption anyways. + // + if (pList->IsStaticList() || + pList->GetIdentificationDescriptionSize() != + IdentificationDescription->IdentificationDescriptionSize) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + pList->CopyId(IdentificationDescription, + pPkgPdo->m_Description->GetId()); + + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoRetrieveAddressDescription)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __inout + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxPkgPdo *pPkgPdo; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, AddressDescription); + + if (NT_SUCCESS(status)) { + FxChildList* pList; + + if (pPkgPdo->m_Description == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + pList = pPkgPdo->m_Description->GetParentList(); + + // + // A call to pList->IsStaticList() in the if below is not needed because + // a static list does not have address descriptions. Make sure this + // assumption is not violated through the ASSERT(). + // + ASSERT(pList->IsStaticList() == FALSE); + + if (pList->HasAddressDescriptions() == FALSE || + pList->GetAddressDescriptionSize() != + AddressDescription->AddressDescriptionSize) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + pList->GetAddressDescriptionFromEntry(pPkgPdo->m_Description, + AddressDescription); + + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfPdoUpdateAddressDescription)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __inout + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxPkgPdo *pPkgPdo; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, AddressDescription); + + if (NT_SUCCESS(status)) { + FxChildList* pList; + + if (pPkgPdo->m_Description == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + pList = pPkgPdo->m_Description->GetParentList(); + + if (pList->GetAddressDescriptionSize() != + AddressDescription->AddressDescriptionSize) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + pList->UpdateAddressDescriptionFromEntry(pPkgPdo->m_Description, + AddressDescription); + + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PDEVICE_OBJECT PhysicalDevice + ) +/*++ + +Routine Description: + Registers a PDO from another non descendant (not verifiable though) pnp + stack to be reported as also requiring eject when this PDO is ejected. + + The PDO could be another device enumerated by this driver. + +Arguments: + Device - the PDO for this driver + + PhysicalDevice - PDO for the other stack + +Return Value: + NTSTATUS + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxPkgPdo* pPkgPdo; + NTSTATUS status; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PhysicalDevice); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = pPkgPdo->AddEjectionDevice(PhysicalDevice); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PDEVICE_OBJECT PhysicalDevice + ) +/*++ + +Routine Description: + Deregisters a PDO from another non descendant (not verifiable though) pnp + stack so that it will not be reported as also requiring eject when this PDO + is ejected. + +Arguments: + Device - the PDO for this driver + + PhysicalDevice - PDO for the other stack + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxPkgPdo* pPkgPdo; + NTSTATUS status; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PhysicalDevice); + + if (!NT_SUCCESS(status)) { + return; // status; + } + + pPkgPdo->RemoveEjectionDevice(PhysicalDevice); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfPdoClearEjectionRelationsDevices)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +/*++ + +Routine Description: + Deregisters all PDOs so that they will not be reported as also requiring + eject when this PDO is ejected. + +Arguments: + Device - this driver's PDO + +Return Value: + None + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxPkgPdo* pPkgPdo; + NTSTATUS status; + + status = GetPdoPackageFromDeviceHandle(GetFxDriverGlobals(DriverGlobals), + Device, + __FUNCTION__, + &pPkgPdo, + &pFxDriverGlobals); + + if (!NT_SUCCESS(status)) { + return; // status; + } + + pPkgPdo->ClearEjectionDevicesList(); +} + +} // extern "C" + diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxdpc.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxdpc.cpp new file mode 100644 index 00000000000..e1d6e165a16 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxdpc.cpp @@ -0,0 +1,412 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDpc.hpp + +Abstract: + + This module implements a frameworks managed DPC that + can synchrononize with driver frameworks object locks. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#include "fxcorepch.hpp" + +#include "FxDpc.hpp" + +// Tracing support +extern "C" { +#include "FxDpc.tmh" +} + +// +// Public constructors +// + +FxDpc::FxDpc( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_DPC, sizeof(FxDpc), FxDriverGlobals) +{ + m_Object = NULL; + m_CallbackLock = NULL; + m_CallbackLockObject = NULL; + m_Callback = NULL; + m_RunningDown = FALSE; + + // + // Mark the object has having passive level dispose so that KeFlushQueuedDpcs + // can be called in Dispose(). + // + MarkPassiveDispose(ObjectDoNotLock); + + MarkDisposeOverride(ObjectDoNotLock); +} + + +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()); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDpc::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_DPC_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObject* ParentObject, + __out WDFDPC* Dpc + ) +/*++ + +Routine Description: + + Create an FxDpc factory method + +Arguments: + + All arguments have been valided by the FxDpcApi stub. + +Returns: + + NTSTATUS + +--*/ +{ + FxDpc* pFxDpc; + NTSTATUS status; + + pFxDpc = new(FxDriverGlobals, Attributes) FxDpc(FxDriverGlobals); + + if (pFxDpc == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pFxDpc->Initialize( + Attributes, + Config, + ParentObject, + Dpc + ); + + if (!NT_SUCCESS(status)) { + pFxDpc->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDpc::Initialize( + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_DPC_CONFIG Config, + __in FxObject* ParentObject, + __out WDFDPC* Dpc + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxHasCallbacks* pCallbacks; + NTSTATUS status; + KDPC* pDpc; + + pFxDriverGlobals = GetDriverGlobals(); + pDpc = NULL; + pCallbacks = NULL; + + pDpc = &m_Dpc; + + // + // Set user's callback function + // + m_Callback = Config->EvtDpcFunc; + + // + // Initialize the DPC to point to our thunk + // + KeInitializeDpc( + pDpc, // Dpc + FxDpcThunk, // DeferredRoutine + this // DeferredContext + ); + + // + // As long as we are associated, the parent object holds a reference + // count on the DPC. + // + // We keep an extra reference count since on Dispose, we wait until + // all outstanding DPC's complete before allowing finalization. + // + // This reference must be taken early before we return any failure, + // since Dispose() expects this extra reference, and Dispose() will + // be called even if we return a failure status right now. + // + ADDREF(this); + + // + // DPC's can be parented by, and optionally serialize with an FxDevice or + // an FxQueue. + // + m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks); + + if (m_DeviceBase == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Configure Serialization for the DPC and callbacks on the supplied object + // + status = _GetEffectiveLock( + ParentObject, + pCallbacks, + Config->AutomaticSerialization, + FALSE, + &m_CallbackLock, + &m_CallbackLockObject + ); + + if (!NT_SUCCESS(status)) { + if (status == STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL) { + + + + + + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "ParentObject %p can not automatically synchronize callbacks " + "with a DPC since it is configured for passive level callback " + "constraints. Set AutomaticSerialization to FALSE. %!STATUS!", + Attributes->ParentObject, status); + } + + return status; + } + + // + // We automatically synchronize with and reference count + // the lifetime of the framework object to prevent any DPC races + // that can access the object while it is going away. + // + + // + // The caller supplied object is the object the caller wants the + // DPC to be associated with, and the framework must ensure this + // object remains live until the DPC object is destroyed. Otherwise, + // it could access either object context memory, or an object API + // on a freed object. + // + // Due to the locking model of the framework, the lock may actually + // be owned by a higher level object as well. This is the lockObject + // returned. As long was we are a child of this object, the lockObject + // does not need to be dereferenced since it will notify us of Cleanup + // before it goes away. + // + + // + // Associate the FxDpc with the object. When this object gets deleted or + // disposed, it will notify our Dispose function as well. + // + + // + // Add a reference to the parent object we are associated with. + // We will be notified of Cleanup to release this reference. + // + ParentObject->ADDREF(this); + + // Save the ptr to the object the DPC is associated with + m_Object = ParentObject; + + // + // Attributes->ParentObject is the same as ParentObject. Since we already + // converted it to an object, use that. + // + status = Commit(Attributes, (WDFOBJECT*)Dpc, ParentObject); + + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +BOOLEAN +FxDpc::Cancel( + __in BOOLEAN Wait + ) +{ + BOOLEAN result; + + result = KeRemoveQueueDpc(GetDpcPtr()); + + // + // If result == FALSE, then the DPC could already be running. + // + // If the caller supplies Wait == TRUE, they want to wait and + // ensure on return the DPC has finished running. + // + // The trick here is to implement this without adding execessive + // overhead to the "normal" path, such as tracking reference counts, + // locking, signaling events to waiting threads, etc. + // + // So we take the expensive approach for the Cancel call in the + // case the caller wants to wait, and misses the DPC window. In + // this case we will just do the system wide FlushQueuedDpc's to + // ensure the DPC has finished running before return. + // + if( Wait && !result ) { + + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + KeFlushQueuedDpcs(); + } + + return result; +} + +VOID +FxDpc::DpcHandler( + __in PKDPC Dpc, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ) +{ + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + FX_TRACK_DRIVER(GetDriverGlobals()); + + if (m_Callback != NULL) { + + FxPerfTraceDpc(&m_Callback); + + if (m_CallbackLock != NULL) { + KIRQL irql = 0; + + m_CallbackLock->Lock(&irql); + m_Callback((WDFDPC)(this->GetObjectHandle())); + m_CallbackLock->Unlock(irql); + } + else { + m_Callback((WDFDPC)(this->GetObjectHandle())); + } + } +} + +VOID +FxDpc::FxDpcThunk( + __in PKDPC Dpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ) + +/*++ + +Routine Description: + + This is the C routine called by the kernels DPC handler + +Arguments: + + Dpc - our DPC object associated with our Timer + DeferredContext - Context for the DPC that we setup in DriverEntry + SystemArgument1 - + SystemArgument2 - + +Return Value: + + Nothing. + +--*/ + +{ + FxDpc* pDpc = (FxDpc*)DeferredContext; + + pDpc->DpcHandler( + Dpc, + SystemArgument1, + SystemArgument2 + ); + + return; +} + +// +// Called when DeleteObject is called, or when the parent +// is being deleted or Disposed. +// +// Also invoked directly by the cleanup list at our request after +// a Dispose occurs and must be deferred if not at passive level. +// +BOOLEAN +FxDpc::Dispose() +{ + // MarkPassiveDispose() in Initialize ensures this + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + m_RunningDown = TRUE; + + FlushAndRundown(); + + return TRUE; +} + +// +// Called by the system work item to finish the rundown +// +VOID +FxDpc::FlushAndRundown() +{ + FxObject* pObject; + + // + // If we have the KeFlushQueuedDpcs function call it + // to ensure the DPC routine is no longer running before + // we release the final reference and memory to the framework objects + // + KeFlushQueuedDpcs(); + + // + // Release our reference count to the associated parent object if present + // + if (m_Object != NULL) { + pObject = m_Object; + m_Object = NULL; + + pObject->RELEASE(this); + } + + // + // Perform our final release to ourselves, destroying the FxDpc + // + RELEASE(this); +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxdpcapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxdpcapi.cpp new file mode 100644 index 00000000000..36cdfe34e0f --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxdpcapi.cpp @@ -0,0 +1,289 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDpcApi.cpp + +Abstract: + + This implements the WDFDPC API's + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#include "fxcorepch.hpp" + +#include "FxDpc.hpp" + +extern "C" { +#include "FxDpcApi.tmh" +} + +// +// extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDpcCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDF_DPC_CONFIG Config, + __in + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFDPC * Dpc + ) + +/*++ + +Routine Description: + + Create a DPC object that will call the supplied function with + context when it fires. It returns a handle to the WDFDPC object. + +Arguments: + + Config - WDF_DPC_CONFIG structure. + + Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object and to request + a context memory allocation, and a DestroyCallback. + + Dpc - Pointer to location to returnt he resulting WDFDPC handle. + +Returns: + + STATUS_SUCCESS - A WDFDPC handle has been created. + +Notes: + + The WDFDPC object is deleted either when the DEVICE or QUEUE it is + associated as its parent with is deleted, or WdfObjectDelete is called. + + If the DPC is used to access WDM objects, a Cleanup callback should + be registered to allow references to be released. + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxObject* pParent; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_REQUIRED); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Config); + FxPointerNotNull(pFxDriverGlobals, Dpc); + + if (Config->Size != sizeof(WDF_DPC_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDF_DPC_CONFIG got Size %d, expected %d, %!STATUS!", + Config->Size, sizeof(WDF_DPC_CONFIG), status); + + return status; + } + + status = FxValidateObjectAttributes( + pFxDriverGlobals, + Attributes + ); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxDpc::_Create(pFxDriverGlobals, Config, Attributes, pParent, Dpc); + + return status; +} + + +__drv_maxIRQL(HIGH_LEVEL) +KDPC* +WDFEXPORT(WdfDpcWdmGetDpc)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDPC Dpc + ) +/*++ + +Routine Description: + + Return the KDPC* object pointer so that it may be linked into + a DPC list. + +Arguments: + + WDFDPC - Handle to WDFDPC object created with WdfDpcCreate. + +Returns: + + KDPC* + +--*/ + +{ + FxDpc* pFxDpc; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Dpc, + FX_TYPE_DPC, + (PVOID*)&pFxDpc); + + return pFxDpc->GetDpcPtr(); +} + + +__drv_maxIRQL(HIGH_LEVEL) +BOOLEAN +WDFEXPORT(WdfDpcEnqueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDPC Dpc + ) + +/*++ + +Routine Description: + + Enqueue the DPC to run at a system determined time + +Arguments: + + WDFDPC - Handle to WDFDPC object created with WdfDpcCreate. + +Returns: + +--*/ + +{ + FxDpc* pFxDpc; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Dpc, + FX_TYPE_DPC, + (PVOID*)&pFxDpc); + + return KeInsertQueueDpc(pFxDpc->GetDpcPtr(), NULL, NULL); +} + + +__drv_when(Wait == __true, __drv_maxIRQL(PASSIVE_LEVEL)) +__drv_when(Wait == __false, __drv_maxIRQL(HIGH_LEVEL)) +BOOLEAN +WDFEXPORT(WdfDpcCancel)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDPC Dpc, + __in + BOOLEAN Wait + ) + +/*++ + +Routine Description: + + Attempt to cancel the DPC and returns status + +Arguments: + + WDFDPC - Handle to WDFDPC object created with WdfDpcCreate. + +Returns: + + TRUE - DPC was cancelled, and was not run + + FALSE - DPC was not cancelled, has run, is running, or will run + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDpc* pFxDpc; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Dpc, + FX_TYPE_DPC, + (PVOID*)&pFxDpc, + &pFxDriverGlobals); + + if (Wait) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return FALSE; + } + } + + return pFxDpc->Cancel(Wait); +} + + + +__drv_maxIRQL(HIGH_LEVEL) +WDFOBJECT +WDFEXPORT(WdfDpcGetParentObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDPC Dpc + ) + +/*++ + +Routine Description: + + Return the parent parent object supplied to WdfDpcCreate. + +Arguments: + + WDFDPC - Handle to WDFDPC object created with WdfDpcCreate. + +Returns: + +--*/ + +{ + FxDpc* pFxDpc; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Dpc, + FX_TYPE_DPC, + (PVOID*)&pFxDpc); + + return pFxDpc->GetObject(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/fxsystemthread.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/fxsystemthread.cpp new file mode 100644 index 00000000000..accdd17aa72 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/fxsystemthread.cpp @@ -0,0 +1,677 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSystemThread.cpp + +Abstract: + + This is the implementation of the FxSystemThread object. + + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#include "fxcorepch.hpp" + +extern "C" { +#include "FxSystemThread.tmh" +} + + +FxSystemThread::FxSystemThread( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_SYSTEMTHREAD, 0, FxDriverGlobals) +{ + + m_Initialized = FALSE; + m_ThreadPtr = NULL; + m_Exit = FALSE; + m_PEThread = NULL; + + //m_Spinup.WorkerRoutine = NULL; // Async-Thread-Spinup + m_Reaper.WorkerRoutine = NULL; + + InitializeListHead(&m_WorkList); + m_InitEvent.Initialize(NotificationEvent, FALSE); + m_WorkEvent.Initialize(NotificationEvent, FALSE); +} + +FxSystemThread::~FxSystemThread() { + +} + +_Must_inspect_result_ +NTSTATUS +FxSystemThread::_CreateAndInit( + __deref_out FxSystemThread** SystemThread, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFDEVICE Device, + __in PDEVICE_OBJECT DeviceObject + ) +{ + NTSTATUS status; + FxSystemThread *pThread = NULL; + + *SystemThread = NULL; + + pThread = new(FxDriverGlobals) FxSystemThread(FxDriverGlobals); + if (pThread == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj %p could not allocate a thread for handling " + "power requests %!STATUS!", + Device, DeviceObject, status); + + return status; + } + + if (pThread->Initialize() == FALSE) { + status = STATUS_UNSUCCESSFUL; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p, !devobj %p, could not initialize power thread, " + "%!STATUS!", + Device, DeviceObject, status); + + pThread->DeleteFromFailedCreate(); + + return status; + } + + *SystemThread = pThread; + + status = STATUS_SUCCESS; + + return status; +} + +// +// Create the system thread in order to be able to service work items +// +// It is recommended this is done from the system process context +// since the threads handle is available to the user mode process +// for a temporary window. XP and later supports OBJ_KERNELHANDLE, but +// DriverFrameworks must support W2K with the same binary. +// +// It is safe to call this at DriverEntry which is in the system process +// to create an initial driver thread, and this driver thread should be +// used for creating any child driver threads on demand. +// +BOOLEAN +FxSystemThread::Initialize() +{ + NTSTATUS status; + KIRQL irql; + + Lock(&irql); + + // Frameworks bug if this is called with a thread already running + ASSERT(m_ThreadPtr == NULL); + + ASSERT(m_Initialized == FALSE); + + m_Initialized = TRUE; + + Unlock(irql); + + status = CreateThread(); + + return NT_SUCCESS(status) ? TRUE : FALSE; +} + +_Must_inspect_result_ +NTSTATUS +FxSystemThread::CreateThread( + VOID + ) +{ + HANDLE threadHandle; + NTSTATUS status; + + // + // Take an extra object reference on ourselves to account + // for the system thread referencing the object while it is running. + // + // The thread itself will release this reference in its exit routine + // + ADDREF(FxSystemThread::StaticThreadThunk); + + status = PsCreateSystemThread( + &threadHandle, + THREAD_ALL_ACCESS, + NULL, // Obja + NULL, // hProcess + NULL, // CLIENT_ID, + FxSystemThread::StaticThreadThunk, + this + ); + + if (!NT_SUCCESS(status)) { + m_Initialized = FALSE; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not create system thread %!STATUS!", status); + // + // Release the reference taken above due to failure + // + RELEASE(FxSystemThread::StaticThreadThunk); + } + else { + status = ObReferenceObjectByHandle( + threadHandle, + THREAD_ALL_ACCESS, + NULL, + KernelMode, + &m_ThreadPtr, + NULL + ); + + ASSERT(NT_SUCCESS(status)); + + // We can now close the thread handle since we have a pointer reference + ZwClose(threadHandle); + } + + return status; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +// +// This is called to tell the thread to exit. +// +// It must be called from thread context such as +// the driver unload routine since it will wait for the +// thread to exit. +// +BOOLEAN +FxSystemThread::ExitThread() +{ + NTSTATUS Status; + KIRQL irql; + + Lock(&irql); + + if( !m_Initialized ) { + Unlock(irql); + return TRUE; + } + + if( m_Exit ) { + ASSERT(FALSE); // This is not race free, so don't allow it + Unlock(irql); + return TRUE; + } + + // Tell the system thread to exit + m_Exit = TRUE; + + // + // The thread could still be spinning up, so we must handle this condition. + // + if( m_ThreadPtr == NULL ) { + + Unlock(irql); + + KeEnterCriticalRegion(); + + // Wait for thread to start + Status = m_InitEvent.WaitFor(Executive, KernelMode, FALSE, NULL); + + KeLeaveCriticalRegion(); + + UNREFERENCED_PARAMETER(Status); + ASSERT(NT_SUCCESS(Status)); + + // + // Now we have a thread, wait for it to go away + // + ASSERT(m_ThreadPtr != NULL); + } + else { + Unlock(irql); + } + + m_WorkEvent.Set(); + + // + // We can't be waiting in our own thread for the thread to exit. + // + ASSERT(IsCurrentThread() == FALSE); + + KeEnterCriticalRegion(); + + // Wait for thread to exit + Status = KeWaitForSingleObject( + m_ThreadPtr, + Executive, + KernelMode, + FALSE, + NULL + ); + + KeLeaveCriticalRegion(); + + UNREFERENCED_PARAMETER(Status); + ASSERT(NT_SUCCESS(Status)); + + ObDereferenceObject(m_ThreadPtr); + + // + // Now safe to unload the driver or object + // the thread worker is pointing to + // + + return TRUE; +} + +BOOLEAN +FxSystemThread::ExitThreadAsync( + __inout FxSystemThread* Reaper + ) +{ + KIRQL irql; + + // + // Without a top level reaper, the frameworks can not ensure + // all worker threads have exited at driver unload in the async + // case. If this is a top level thread, then DriverUnload should + // call the synchronous ExitThread() method. + // + ASSERT(Reaper != NULL); + + Lock(&irql); + + if( !m_Initialized ) { + Unlock(irql); + return TRUE; + } + + if( m_Exit ) { + ASSERT(FALSE); + Unlock(irql); + return TRUE; + } + + // Tell the system thread to exit + m_Exit = TRUE; + + // Add a reference which will be released by the reaper + ADDREF(FxSystemThread::StaticReaperThunk); + + Unlock(irql); + + m_WorkEvent.Set(); + + ASSERT(m_Reaper.WorkerRoutine == NULL); + + // We are the only user of this field protected by setting m_Exit + m_Reaper.WorkerRoutine = FxSystemThread::StaticReaperThunk; + m_Reaper.Parameter = this; + + Reaper->QueueWorkItem(&m_Reaper); + + // + // It is not safe to unload the driver until the reaper + // thread has processed the work item and waited for this + // thread to exit. + // + + return TRUE; +} + +BOOLEAN +FxSystemThread::QueueWorkItem( + __inout PWORK_QUEUE_ITEM WorkItem + ) +{ + KIRQL irql; + BOOLEAN result; + + Lock(&irql); + + if (m_Exit) { + result = FALSE; + } + else { + result = TRUE; + InsertTailList(&m_WorkList, &WorkItem->List); + + m_WorkEvent.Set(); + } + + Unlock(irql); + + return result; +} + +// +// Attempt to cancel the work item. +// +// Returns TRUE if success. +// +// If returns FALSE, the work item +// routine either has been called, is running, +// or is about to be called. +// +BOOLEAN +FxSystemThread::CancelWorkItem( + __inout PWORK_QUEUE_ITEM WorkItem + ) +{ + PLIST_ENTRY Entry; + KIRQL irql; + + Lock(&irql); + + Entry = m_WorkList.Flink; + + while( Entry != &this->m_WorkList ) { + + if( Entry == &WorkItem->List ) { + RemoveEntryList(&WorkItem->List); + Unlock(irql); + return TRUE; + } + + Entry = Entry->Flink; + } + + // Not found + Unlock(irql); + + return FALSE; +} + +VOID +FxSystemThread::Thread() +{ + NTSTATUS status; + LIST_ENTRY head; + PLIST_ENTRY ple; + PWORK_QUEUE_ITEM pItem; + + //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + // "Created, entering work loop"); + + // + // The worker thread will process all list entries before + // checking for exit. This allows the top level FxDriver + // thread to process all deferred cleanup work items at + // driver unload. + // + // CancelWorkItem may be used to remove entries + // before requesting a thread exit if the caller wants to + // interrupt work queue processing. + // + + InitializeListHead(&head); + + // Initialize for IsCurrentThread() + m_PEThread = Mx::GetCurrentEThread(); + + // Set the event that the thread now exists + m_InitEvent.Set(); + + for ( ; ; ) { + KIRQL irql; + + // + // Lock the list so we are in sync with QueueWorkItem + // + Lock(&irql); + + while(!IsListEmpty(&m_WorkList)) { + // + // Instead of popping each LIST_ENTRY off of the old list and + // enqueueing it to the local list head, manipulate the first and + // last entry in the list to point to our new head. + // + head.Flink = m_WorkList.Flink; + head.Blink = m_WorkList.Blink; + + // First link in the list point backwrad to the new head + m_WorkList.Flink->Blink = &head; + + // Last link in the list point fwd to the new head + m_WorkList.Blink->Flink = &head; + + ASSERT(!IsListEmpty(&head)); + + // + // Reinitialize the work list head + // + InitializeListHead(&m_WorkList); + + // + // Process the workitems while unlocked so that the work item can + // requeue itself if needed and work at passive level. + // + Unlock(irql); + + while (!IsListEmpty(&head)) { + ple = RemoveHeadList(&head); + pItem = CONTAINING_RECORD(ple, WORK_QUEUE_ITEM, List); + pItem->WorkerRoutine(pItem->Parameter); + + // + // NOTE: pItem may have been pool released by the called worker + // routine, so it may not be accessed after the callback + // + } + + // + // Relock the list and repeat until the work list is empty + // + Lock(&irql); + } + + // No more items on list, check for exit + if (m_Exit) { + //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + // "Terminating"); + + Unlock(irql); + + // Release the object reference held by the thread + RELEASE(FxSystemThread::StaticThreadThunk); + + status = PsTerminateSystemThread(STATUS_SUCCESS); + UNREFERENCED_PARAMETER(status); + ASSERT(NT_SUCCESS(status)); + + // NOT REACHED + return; + } + + // + // No work to do, clear event under lock to prevent a race with a work + // enqueue + // + m_WorkEvent.Clear(); + + Unlock(irql); + + // We are a system thread, so we do not need KeEnterCriticalRegion() + status = m_WorkEvent.WaitFor( + Executive, KernelMode, FALSE, NULL); + + UNREFERENCED_PARAMETER(status); + ASSERT(NT_SUCCESS(status)); + } + + // NOT REACHED + return; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + +VOID +FxSystemThread::Reaper() +{ + NTSTATUS Status; + KIRQL irql; + + Lock(&irql); + + ASSERT(m_Initialized); + ASSERT(m_Exit); + + // + // The thread could still be spinning up, so we must handle this condition. + // + if( m_ThreadPtr == NULL ) { + + Unlock(irql); + + KeEnterCriticalRegion(); + + // Wait for thread to start + Status = m_InitEvent.WaitFor(Executive, KernelMode, FALSE, NULL); + + KeLeaveCriticalRegion(); + + UNREFERENCED_PARAMETER(Status); + ASSERT(NT_SUCCESS(Status)); + + // + // Now we have a thread, wait for it to go away + // + ASSERT(m_ThreadPtr != NULL); + } + else { + Unlock(irql); + } + + KeEnterCriticalRegion(); + + // Wait for thread to exit + Status = KeWaitForSingleObject( + m_ThreadPtr, + Executive, + KernelMode, + FALSE, + NULL + ); + + KeLeaveCriticalRegion(); + + UNREFERENCED_PARAMETER(Status); + ASSERT(NT_SUCCESS(Status)); + + ObDereferenceObject(m_ThreadPtr); + + RELEASE(FxSystemThread::StaticReaperThunk); + + return; +} + +VOID +FxSystemThread::StaticThreadThunk( + __inout PVOID Context + ) +{ + FxSystemThread* thread = (FxSystemThread*)Context; + + thread->Thread(); +} + + + + + + + + + + + + + + + +VOID +FxSystemThread::StaticReaperThunk( + __inout PVOID Context + ) +{ + FxSystemThread* thread = (FxSystemThread*)Context; + + thread->Reaper(); +} + + diff --git a/sdk/lib/drivers/wdf/kmdf/src/core/tracing.cpp b/sdk/lib/drivers/wdf/kmdf/src/core/tracing.cpp new file mode 100644 index 00000000000..8b1e10c35fe --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/core/tracing.cpp @@ -0,0 +1,530 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + Tracing.cpp + +Abstract: + + This module implements tracing for the driver frameworks + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + + + + +--*/ + +#include "fxcorepch.hpp" + +// We use DoTraceMessage +extern "C" { +#include "tracing.tmh" +} + +#include +#include "fxIFR.h" // shared struct between IFR and debug ext. +#include "fxIFRKm.h" // kernel mode only IFR definitions + + +//============================================================================= +// +//============================================================================= + +_Must_inspect_result_ +NTSTATUS +FxTraceInitialize( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the frameworks tracing. + + It must be called early on in the frameworks DriverEntry + initialization. + +Arguments: + + None + +Returns: + + NTSTATUS code + +--*/ +{ + // + // Initialize the tracing package: Vista or later + // + WPP_INIT_TRACING(NULL, NULL); + + return STATUS_SUCCESS; +} + +VOID +TraceUninitialize( + VOID + ) +/*++ + +Routine Description: + This routine uninitializes the frameworks tracing. It must be called just + before DriverUnload + +Arguments: + None + +Returns: + None + +--*/ +{ + // + // Vista and later + // + WPP_CLEANUP(NULL); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiTraceMessage( + __in TRACEHANDLE LoggerHandle, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + __in ... + ) +{ + NTSTATUS status; + va_list va; + + va_start(va, MessageNumber); + +#pragma prefast(suppress:__WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean"); + status = WmiTraceMessageVa(LoggerHandle, + MessageFlags, + MessageGuid, + MessageNumber, + va); + va_end(va); + + return status; +} + + +//----------------------------------------------------------------------------- +// Subcomponents for the In-Flight Recorder follow. +//----------------------------------------------------------------------------- + +ULONG +FxIFRGetSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + Checks to see if the service has overriden the default number of pages that + are in the IFR. + +Arguments: + RegistryPath - path to the service + +Return Value: + The size of the IFR to create in bytes (not pages!) + + --*/ +{ + FxAutoRegKey service, parameters; + NTSTATUS status; + OBJECT_ATTRIBUTES oa; + ULONG numPages; + + // + // This is the value used in case of any error while retrieving 'LogPages' + // from the registry. + // + numPages = FxIFRMinLogPages; + + // + // External representation of the IFR is the "LogPages", so use that term when + // overriding the size via the registry. + // + DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf"); + DECLARE_CONST_UNICODE_STRING(valueName, L"LogPages"); + + InitializeObjectAttributes(&oa, + (PUNICODE_STRING)RegistryPath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + status = ZwOpenKey(&service.m_Key, KEY_READ, &oa); + if (!NT_SUCCESS(status)) { + goto defaultValues; + } + + InitializeObjectAttributes(&oa, + (PUNICODE_STRING)¶metersPath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + service.m_Key, + NULL); + + status = ZwOpenKey(¶meters.m_Key, KEY_READ, &oa); + + if (!NT_SUCCESS(status)) { + goto defaultValues; + } + + status = FxRegKey::_QueryULong(parameters.m_Key, &valueName, &numPages); + if (!NT_SUCCESS(status)) { + goto defaultValues; + } + + if (numPages == 0) { + numPages = FxIFRMinLogPages; + } + +defaultValues: + // + // Use FxIFRAvgLogPages if user specifies greater than FxIFRMaxLogPages and if + // Verifier flag is on and so is Verbose flag. + // + if (numPages > FxIFRMaxLogPages) { + if (FxDriverGlobals->FxVerifierOn && FxDriverGlobals->FxVerboseOn) { + numPages = FxIFRAvgLogPages; + } + else { + numPages = FxIFRMinLogPages; + } + } + + return numPages * PAGE_SIZE; +} + +VOID +FxIFRStart( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath, + __in MdDriverObject DriverObject + ) +/*++ + +Routine Description: + + This routine initialize the In-Flight Recorder (IFR). + + The default log size is set by WDF_IFR_LOG_SIZE and currently + is 4096 (one x86 page). + This routine should be called very early in driver initialization + to allow the capture of all significant events. + +--*/ +{ + PWDF_IFR_HEADER pHeader; + ULONG size; + + UNREFERENCED_PARAMETER( DriverObject ); + + WDFCASSERT(FxIFRRecordSignature == WDF_IFR_RECORD_SIGNATURE); + + // + // Return early if IFR is disabled. + // + if (FxLibraryGlobals.IfrDisabled) { + ASSERT(FxDriverGlobals->WdfLogHeader == NULL); + return; + } + + if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader != NULL) { + return; + } + + size = FxIFRGetSize(FxDriverGlobals, RegistryPath); + + pHeader = (PWDF_IFR_HEADER) ExAllocatePoolWithTag(NonPagedPool, + size, + WDF_IFR_LOG_TAG ); + if (pHeader == NULL) { + return; + } + + RtlZeroMemory(pHeader, size); + + // + // Initialize the header. + // Base will be where the IFR records are placed. + // WPP_ThisDir_CTLGUID_FrameworksTraceGuid + // + RtlCopyMemory(&pHeader->Guid, (PVOID) &WdfTraceGuid, sizeof(GUID)); + + pHeader->Base = (PUCHAR) &pHeader[1]; + pHeader->Size = size - sizeof(WDF_IFR_HEADER); + + pHeader->Offset.u.s.Current = 0; + pHeader->Offset.u.s.Previous = 0; + RtlStringCchCopyA(pHeader->DriverName, WDF_IFR_HEADER_NAME_LEN, FxDriverGlobals->Public.DriverName); + + FxDriverGlobals->WdfLogHeader = pHeader; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "FxIFR logging started" ); + + if (size > FxIFRMinLogSize) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "FxIFR has been started with a size override: size 0x%x bytes, " + "# Pages %d. An extended IFR size may not be written to a minidump!", + size, size/PAGE_SIZE); + } +} + +VOID +FxIFRStop( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +/*++ + +Routine Description: + + This routine stops the In-Flight Recorder (IFR). + + It should be called as late in the driver teardown as possible + to allow for the capture of all significant events. + +--*/ +{ + // + // Return early if IFR is disabled. + // + if (FxLibraryGlobals.IfrDisabled) { + ASSERT(FxDriverGlobals->WdfLogHeader == NULL); + return; + } + + if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader == NULL) { + return; + } + + // + // Free the Log buffer. + // + ExFreePoolWithTag( FxDriverGlobals->WdfLogHeader, WDF_IFR_LOG_TAG ); + FxDriverGlobals->WdfLogHeader = NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxIFR( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in UCHAR MessageLevel, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + __in ... + ) +/*++ + +Routine Description: + + This routine is the main In-Flight Recorder (IFR) routine. + + It captures a WPP message to the IFR log. + The IFR is always running, e.g. not WPP logger is necessary + to start logging. + +Arguments: + + MessageLevel - The WPP message level for this event + MessageFlags - The WPP message flags for this event (see trace GUID) + MessageGuid - The tracewpp generated guid for module emitting this event. + MessageNumber - The tracewpp generated message number within + the emitting module. + ... - Variable arguments associates with the emitted message. + +Returns: + + NTSTATUS + +--*/ +{ + size_t size; + PWDF_IFR_RECORD record; + PWDF_IFR_HEADER header; + + UNREFERENCED_PARAMETER( MessageLevel ); + UNREFERENCED_PARAMETER( MessageFlags ); + + // + // Return early if IFR is disabled. + // + if (FxLibraryGlobals.IfrDisabled) { + ASSERT(FxDriverGlobals->WdfLogHeader == NULL); + return STATUS_SUCCESS; + } + + if ( FxDriverGlobals->WdfLogHeader == NULL) { + return STATUS_UNSUCCESSFUL; + } + + // + // Determine the number bytes to follow header + // + size = 0; // For Count of Bytes + + // + // Determine how much log space is needed for this + // trace record's data. + // + { + va_list ap; + size_t argLen; + + va_start(ap, MessageNumber); +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean"); + while ((va_arg(ap, PVOID)) != NULL) { + + argLen = va_arg(ap, size_t); + + if (argLen > 0) { + + if (argLen > FxIFRMaxMessageSize) { + goto drop_message; + } + size += (USHORT) argLen; + } + } + + va_end(ap); + + // + // NOTE: The final size must be 32-bit (ULONG) aligned. + // This is necessary for IA64 to prevent Alignment Faults. + // + size += (size % sizeof(ULONG)) ? sizeof(ULONG) - (size % sizeof(ULONG)) : 0; + + if (size > FxIFRMaxMessageSize) { + goto drop_message; + } + } + + size += sizeof(WDF_IFR_RECORD); + + // + // Allocate log space of the calculated size + // + { + WDF_IFR_OFFSET offsetRet; + WDF_IFR_OFFSET offsetCur; + WDF_IFR_OFFSET offsetNew; + USHORT usSize = (USHORT) size; // for a prefast artifact. + + header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader; + + FxVerifyLogHeader(FxDriverGlobals, header); + + offsetRet.u.AsLONG = header->Offset.u.AsLONG; + offsetNew.u.AsLONG = offsetRet.u.s.Current; + + do { + offsetCur.u.AsLONG = offsetRet.u.AsLONG; + + if (&header->Base[header->Size] < &header->Base[offsetCur.u.s.Current+size]) { + + offsetNew.u.s.Current = 0; + offsetNew.u.s.Previous = offsetRet.u.s.Previous; + + offsetRet.u.AsLONG = + InterlockedCompareExchange( &header->Offset.u.AsLONG, + offsetNew.u.AsLONG, + offsetCur.u.AsLONG ); + + if (offsetCur.u.AsLONG != offsetRet.u.AsLONG) { + continue; + } else { + offsetNew.u.s.Current = offsetCur.u.s.Current + usSize; + offsetNew.u.s.Previous = offsetRet.u.s.Current; + } + } else { + + offsetNew.u.s.Current = offsetCur.u.s.Current + usSize; + offsetNew.u.s.Previous = offsetCur.u.s.Current; + } + + offsetRet.u.AsLONG = + InterlockedCompareExchange( &header->Offset.u.AsLONG, + offsetNew.u.AsLONG, + offsetCur.u.AsLONG ); + + } while (offsetCur.u.AsLONG != offsetRet.u.AsLONG); + + record = (PWDF_IFR_RECORD) &header->Base[offsetRet.u.s.Current]; + + // RtlZeroMemory( record, sizeof(WDF_IFR_RECORD) ); + + // + // Build record (fill all fields!) + // + record->Signature = FxIFRRecordSignature; + record->Length = (USHORT) size; + record->PrevOffset = (USHORT) offsetRet.u.s.Previous; + record->MessageNumber = MessageNumber; + record->Sequence = InterlockedIncrement( &header->Sequence ); + record->MessageGuid = *MessageGuid; + } + + // + // Move variable part of data into log. + // + { + va_list ap; + size_t argLen; + PVOID source; + PUCHAR argsData; + + argsData = (UCHAR*) &record[1]; + + va_start(ap, MessageNumber); + + while ((source = va_arg(ap, PVOID)) != NULL) { + + argLen = va_arg(ap, size_t); + + if (argLen > 0) { + + RtlCopyMemory( argsData, source, argLen ); + argsData += argLen; + } + } + + va_end(ap); + } + + FxVerifyLogHeader(FxDriverGlobals, header); + + return STATUS_SUCCESS; + + { + // + // Increment sequence number to indicate dropped message + // +drop_message: + header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader; + InterlockedIncrement( &header->Sequence ); + return STATUS_UNSUCCESSFUL; + } +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxcommonbuffer.cpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxcommonbuffer.cpp new file mode 100644 index 00000000000..db36b0f2fb3 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxcommonbuffer.cpp @@ -0,0 +1,173 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCommonBuffer.cpp + +Abstract: + + WDF CommonBuffer Object + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#include "FxDmaPCH.hpp" + +extern "C" { +#include "FxCommonBuffer.tmh" +} + +FxCommonBuffer::FxCommonBuffer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxDmaEnabler * pDmaEnabler + ) : + FxNonPagedObject(FX_TYPE_COMMON_BUFFER, sizeof(FxCommonBuffer), FxDriverGlobals) +{ + m_DmaEnabler = pDmaEnabler; + m_BufferRawVA = NULL; // allocated buffer base (unaligned) + m_BufferAlignedVA = NULL; // aligned buffer base + m_BufferAlignedLA.QuadPart = NULL; // aligned physical buffer base + m_BufferRawLA.QuadPart = NULL; // allocated buffer phy base (unaligned) + m_Length = 0; + m_RawLength = 0; + + MarkDisposeOverride(ObjectDoNotLock); + + // + // By default use the alignment of the dma enabler. + // + m_Alignment = m_DmaEnabler->GetAlignment(); +} + +BOOLEAN +FxCommonBuffer::Dispose() +{ + FreeCommonBuffer(); + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxCommonBuffer::AllocateCommonBuffer( + __in size_t Length + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + ULONGLONG offset; + ULONG result; + + // + // Must be running at PASIVE_LEVEL + // + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + m_Length = Length; + + // + // If required, add alignment to the length. + // If alignment is <= page-1, we actually don't need to do it b/c + // AllocateCommonBuffer allocates at least a page of memory, regardless + // of the requested Length. If driver version is < v1.11, we still add the + // alignment to the length for compatibility. + // + if (m_Alignment > PAGE_SIZE-1 || + pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) { + + status = RtlSizeTAdd(Length, m_Alignment, &m_RawLength); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMAENABLER %p AllocateCommonBuffer: overflow when adding Length " + "%I64d + Alignment %I64d", GetObjectHandle(), Length, m_Alignment); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + } + else { + m_RawLength = Length; + } + + m_DmaEnabler->AllocateCommonBuffer(m_RawLength, + &m_BufferRawVA, + &m_BufferRawLA); + if (m_BufferRawVA) { + + m_BufferAlignedVA = FX_ALIGN_VIRTUAL_ADDRESS(m_BufferRawVA, m_Alignment); + m_BufferAlignedLA.QuadPart = FX_ALIGN_LOGICAL_ADDRESS(m_BufferRawLA, m_Alignment); + + if (m_Alignment > PAGE_SIZE-1) { + // + // If the alignment mask is over a page-size then the aligned virtual + // and aligned logical could be pointing to different locations + // in memory. So ajdust the VA to match the LA address by adding + // the offset of alignedLA and RawLA to VA. By doing this we + // only guarantee alignment of LA when the page alignment exceeds PAGE_SIZE. + // + status = RtlULongLongSub(m_BufferAlignedLA.QuadPart, + m_BufferRawLA.QuadPart, + &offset); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMAENABLER %p AllocateCommonBuffer: overflow when subtracting " + "RawLA %I64x from AlignedLA %I64x", + GetObjectHandle(), m_BufferRawLA.QuadPart, m_BufferAlignedLA.QuadPart); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + status = RtlULongLongToULong(offset, &result); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMAENABLER %p AllocateCommonBuffer: overflow when " + "converting from ULongLong %I64d to ULong", + GetObjectHandle(), offset); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + m_BufferAlignedVA = WDF_PTR_ADD_OFFSET(m_BufferRawVA, result); + } + else { + ASSERT(m_BufferAlignedVA == m_BufferRawVA); + ASSERT(m_BufferAlignedLA.QuadPart == m_BufferRawLA.QuadPart); + } + } else { + m_Length = 0; + m_RawLength = 0; + m_BufferAlignedVA = NULL; + m_BufferAlignedLA.QuadPart = NULL; + return STATUS_INSUFFICIENT_RESOURCES; + } + + return status; +} + +VOID +FxCommonBuffer::FreeCommonBuffer( + VOID + ) +{ + // + // Free this CommonBuffer per DmaEnabler + // + if (m_BufferRawVA != NULL) { + m_DmaEnabler->FreeCommonBuffer((ULONG) m_RawLength, + m_BufferRawVA, + m_BufferRawLA); + } +} + + diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxcommonbufferapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxcommonbufferapi.cpp new file mode 100644 index 00000000000..58189ec61b1 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxcommonbufferapi.cpp @@ -0,0 +1,303 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCommonBufferAPI.cpp + +Abstract: + + Base for WDF CommonBuffer APIs + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#include "FxDmaPCH.hpp" + +extern "C" { +#include "FxCommonBufferAPI.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfCommonBufferCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in + __drv_when(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + __in_opt + WDF_OBJECT_ATTRIBUTES * Attributes, + __out + WDFCOMMONBUFFER * CommonBufferHandle + ) +{ + FxCommonBuffer * pComBuf; + FxDmaEnabler * pDmaEnabler; + NTSTATUS status; + WDFOBJECT handle; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + // + // Get validate DmaEnabler handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, CommonBufferHandle); + + *CommonBufferHandle = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Basic parameter validation + // + if (Length == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Length is 0, %!STATUS!", status); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED + ); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Create a new CommonBuffer object + // + pComBuf = new(pFxDriverGlobals, Attributes) + FxCommonBuffer(pFxDriverGlobals, pDmaEnabler); + + if (pComBuf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Could not allocate memory for a WDFCOMMONBUFFER, " + "%!STATUS!", status); + return status; + } + + // + // Assign this FxCommonBuffer to its parent FxDmaEnabler object. + // + status = pComBuf->Commit(Attributes, (WDFOBJECT*)&handle, pDmaEnabler); + + if (NT_SUCCESS(status)) { + // + // Ok: now allocate a CommonBuffer via this DmaEnabler + // + status = pComBuf->AllocateCommonBuffer( Length ); + } + + if (NT_SUCCESS(status)) { + // + // Only return a valid handle on success. + // + *CommonBufferHandle = (WDFCOMMONBUFFER) handle; + } + else { + pComBuf->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfCommonBufferCreateWithConfig)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in + __drv_when(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + __in + PWDF_COMMON_BUFFER_CONFIG Config, + __in_opt + WDF_OBJECT_ATTRIBUTES * Attributes, + __out + WDFCOMMONBUFFER * CommonBufferHandle + ) +{ + FxCommonBuffer * pComBuf; + FxDmaEnabler * pDmaEnabler; + NTSTATUS status; + WDFOBJECT handle; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + // + // Get validate DmaEnabler handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + // + // Basic parameter validation + // + FxPointerNotNull(pFxDriverGlobals, Config); + + if (Config->Size != sizeof(WDF_COMMON_BUFFER_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDF_COMMON_BUFFER_CONFIG Size 0x%x, expected 0x%x, %!STATUS!", + Config->Size, sizeof(WDF_COMMON_BUFFER_CONFIG), status); + + return status; + } + + FxPointerNotNull(pFxDriverGlobals, CommonBufferHandle); + + *CommonBufferHandle = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Length == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Length is 0, %!STATUS!", status); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED + ); + if (!NT_SUCCESS(status)) { + return status; + } + + pComBuf = new(pFxDriverGlobals, Attributes) + FxCommonBuffer(pFxDriverGlobals, pDmaEnabler); + + if (pComBuf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Could not allocate memory for a WDFCOMMONBUFFER, " + "%!STATUS!", status); + return status; + } + + // + // Assign this FxCommonBuffer to its parent FxDmaEnabler object. + // + status = pComBuf->Commit(Attributes, (WDFOBJECT*)&handle, pDmaEnabler); + + if (NT_SUCCESS(status)) { + // + // Set the alignment value before calling AllocateCommonBuffer. + // + pComBuf->SetAlignment(Config->AlignmentRequirement); + status = pComBuf->AllocateCommonBuffer( Length ); + } + + if (NT_SUCCESS(status)) { + // + // Only return a valid handle on success. + // + *CommonBufferHandle = (WDFCOMMONBUFFER) handle; + } + else { + pComBuf->DeleteFromFailedCreate(); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PVOID +WDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOMMONBUFFER CommonBuffer + ) +{ + FxCommonBuffer * pComBuf; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + CommonBuffer, + FX_TYPE_COMMON_BUFFER, + (PVOID *) &pComBuf); + + return pComBuf->GetAlignedVirtualAddress(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PHYSICAL_ADDRESS +WDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOMMONBUFFER CommonBuffer + ) +{ + FxCommonBuffer * pComBuf; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + CommonBuffer, + FX_TYPE_COMMON_BUFFER, + (PVOID *) &pComBuf); + + return pComBuf->GetAlignedLogicalAddress(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +size_t +WDFEXPORT(WdfCommonBufferGetLength)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOMMONBUFFER CommonBuffer + ) +{ + FxCommonBuffer * pComBuf; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + CommonBuffer, + FX_TYPE_COMMON_BUFFER, + (PVOID *) &pComBuf); + + return pComBuf->GetLength(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmaenabler.cpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmaenabler.cpp new file mode 100644 index 00000000000..91f9bdc1a85 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmaenabler.cpp @@ -0,0 +1,1125 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaEnabler.cpp + +Abstract: + + Base for WDF DMA Enabler object + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#include "FxDmaPCH.hpp" + +extern "C" { +#include "FxDmaEnabler.tmh" +} + +FxDmaEnabler::FxDmaEnabler( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_DMA_ENABLER, sizeof(FxDmaEnabler), FxDriverGlobals) +{ + RtlZeroMemory(&m_SimplexAdapterInfo, sizeof(FxDmaDescription)); + RtlZeroMemory(&m_DuplexAdapterInfo, sizeof(m_DuplexAdapterInfo)); + + // + // Transaction link into list of FxDmaEnabler pointers maintained by + // FxDevice's pnp package. + // + m_TransactionLink.SetTransactionedObject(this); + + m_FDO = NULL; + m_PDO = NULL; + m_CommonBufferAlignment = 0; + m_MaxSGElements = WDF_DMA_ENABLER_UNLIMITED_FRAGMENTS; + m_IsScatterGather = FALSE; + m_IsDuplexTransfer = FALSE; + m_IsSGListAllocated = FALSE; + m_SGListSize = 0; + + m_IsAdded = FALSE; + + m_EvtDmaEnablerFill.m_Method = NULL; + m_EvtDmaEnablerFlush.m_Method = NULL; + m_EvtDmaEnablerEnable.m_Method = NULL; + m_EvtDmaEnablerDisable.m_Method = NULL; + m_EvtDmaEnablerSelfManagedIoStart.m_Method = NULL; + m_EvtDmaEnablerSelfManagedIoStop.m_Method = NULL; + + m_DmaEnablerFillFailed = FALSE; + m_DmaEnablerEnableFailed = FALSE; + m_DmaEnablerSelfManagedIoStartFailed = FALSE; + + RtlZeroMemory(&m_SGList, sizeof(m_SGList)); + + MarkDisposeOverride(ObjectDoNotLock); +} + +FxDmaEnabler::~FxDmaEnabler() +{ + if (m_IsSGListAllocated) { + if (m_IsScatterGather) { + // + // Scatter Gather profile - cleanup the lookaside list + // + ExDeleteNPagedLookasideList(&m_SGList.ScatterGatherProfile.Lookaside); + + } else if (!m_IsBusMaster) { + // + // System profile (not busmastering) - cleanup the preallocated + // SG list + // + ExFreePool(m_SGList.SystemProfile.List); + + } else { + // + // Packet profile. No special cleanup to do. + // + + } + +#if DBG + RtlZeroMemory(&m_SGList, sizeof(m_SGList)); +#endif + m_IsSGListAllocated = FALSE; + } +} + + +BOOLEAN +FxDmaEnabler::Dispose() +{ + ReleaseResources(); + + if (m_IsAdded) { + ASSERT(m_DeviceBase != NULL); + m_DeviceBase->RemoveDmaEnabler(this); + } + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::Initialize( + __in PWDF_DMA_ENABLER_CONFIG Config, + __inout FxDeviceBase *Device + ) +{ + NTSTATUS status; + DEVICE_DESCRIPTION deviceDescription; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + ULONG mapRegistersAllocated; + + RtlZeroMemory(&deviceDescription, sizeof(DEVICE_DESCRIPTION)); + + // + // Default to version 2 description (except on ARM platforms) + // + +#ifdef _ARM_ + deviceDescription.Version = DEVICE_DESCRIPTION_VERSION3; +#else + deviceDescription.Version = DEVICE_DESCRIPTION_VERSION2; +#endif + + // + // Make sure the device's list of enablers has been created. + // + + status = Device->AllocateDmaEnablerList(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Unable to allocate DmaEnablerList for " + "WDFDEVICE %p, %!STATUS!", + Device->GetHandle(), status); + return status; + } + + // + // Retain parent FxDeviceBase object + // + m_DeviceBase = Device; + + // + // Save the profile. + // + m_Profile = Config->Profile; + + // + // Invariant parameters vis-a-vis kernel-mode bus-mastering DMA APIs + // (overrided below if using system-DMA + // + deviceDescription.Master = TRUE; + deviceDescription.Dma32BitAddresses = TRUE; + deviceDescription.InterfaceType = PCIBus; + + // + // Assume enabler is a bus-master + // + m_IsBusMaster = TRUE; + + // + // Expand the profile into settings. + // + switch (m_Profile) { + // + // Packet based profiles. + // + + case WdfDmaProfilePacket: + deviceDescription.ScatterGather = FALSE; + deviceDescription.Dma64BitAddresses = FALSE; + break; + case WdfDmaProfilePacket64: + deviceDescription.ScatterGather = FALSE; + deviceDescription.Dma64BitAddresses = TRUE; + break; + + // + // Scatter-gather profiles + // + + case WdfDmaProfileScatterGather: + deviceDescription.ScatterGather = TRUE; + deviceDescription.Dma64BitAddresses = FALSE; + m_IsScatterGather = TRUE; + break; + case WdfDmaProfileScatterGatherDuplex: + deviceDescription.ScatterGather = TRUE; + deviceDescription.Dma64BitAddresses = FALSE; + m_IsDuplexTransfer = TRUE; + m_IsScatterGather = TRUE; + break; + case WdfDmaProfileScatterGather64: + deviceDescription.ScatterGather = TRUE; + deviceDescription.Dma64BitAddresses = TRUE; + m_IsScatterGather = TRUE; + break; + case WdfDmaProfileScatterGather64Duplex: + deviceDescription.ScatterGather = TRUE; + deviceDescription.Dma64BitAddresses = TRUE; + m_IsDuplexTransfer = TRUE; + m_IsScatterGather = TRUE; + break; + + // + // Non-PC System-mode (non-bus-mastering) profiles. These + // require DMA v3. + // + + case WdfDmaProfileSystem: + deviceDescription.ScatterGather = FALSE; + deviceDescription.Master = FALSE; + deviceDescription.Dma32BitAddresses = FALSE; + deviceDescription.Dma64BitAddresses = FALSE; + deviceDescription.Version = DEVICE_DESCRIPTION_VERSION3; + m_IsBusMaster = FALSE; + m_DeviceBase->SetDeviceTelemetryInfoFlags(DeviceInfoDmaSystem); + break; + case WdfDmaProfileSystemDuplex: + deviceDescription.ScatterGather = FALSE; + deviceDescription.Master = FALSE; + deviceDescription.Dma32BitAddresses = FALSE; + deviceDescription.Dma64BitAddresses = FALSE; + deviceDescription.Version = DEVICE_DESCRIPTION_VERSION3; + m_IsBusMaster = FALSE; + m_IsDuplexTransfer = TRUE; + m_DeviceBase->SetDeviceTelemetryInfoFlags(DeviceInfoDmaSystemDuplex); + break; + + // + // Unknown profile. + // + + default: + // + // Just do quick exit as no resource have been allocated. + // + return STATUS_INVALID_PARAMETER; + } + + // + // Save the maximum length. + // + m_MaximumLength = (ULONG) Config->MaximumLength; + + // + // An override of address width requires the DMA v3 engine. it also requires + // that we explicitly specify the DMA width the controller can support, but + // we do that down below. + // + if (Config->AddressWidthOverride != 0) { + + // + // Address width override is not supported for system mode DMA, since + // the HAL runs the DMA controller in that case and it knows the + // controller's address limitations better than the driver does. + // + if (m_IsBusMaster == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "AddressWidthOverride set to %d. AddressWidthOverride " + "must be zero when using a system DMA profile " + "(%!WDF_DMA_PROFILE!) - %!STATUS!", + Config->AddressWidthOverride, + Config->Profile, + status + ); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return status; + } + + if ((deviceDescription.Dma64BitAddresses == FALSE) && + (Config->AddressWidthOverride > 32)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "AddressWidthOverride set to %d. AddressWidthOverride " + "must be <= 32 when using a 32-bit DMA profile " + "(%!WDF_DMA_PROFILE!) - %!STATUS!", + Config->AddressWidthOverride, + Config->Profile, + status + ); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return status; + } + + // + // Handle the AddressWidthOverride. For Win8 use DMA v3 and pass the + // value through to the HAL. For Win7 downgrade to the next lower + // address width. + // + if (IsOsVersionGreaterThanOrEqualTo(6, 2)) { + deviceDescription.Version = DEVICE_DESCRIPTION_VERSION3; + deviceDescription.DmaAddressWidth = Config->AddressWidthOverride; + } + else { + + NT_ASSERTMSGW(L"Ensure driver is not doing something earlier that " + L"would require DMA v3 before we downgrade them to " + L"DMA v2", + (deviceDescription.Version == DEVICE_DESCRIPTION_VERSION2)); + + if (Config->AddressWidthOverride < 64) { + deviceDescription.Dma64BitAddresses = FALSE; + } + + if (Config->AddressWidthOverride < 32) { + deviceDescription.Dma32BitAddresses = FALSE; + } + + // + // DMA V2 can't handle an address width restriction smaller than + // 24 bits (ISA DMA). DMA V3 will fail that also - return the same + // error here that DMA V3 would have. + // + if (Config->AddressWidthOverride < 24) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "AddressWidthOverride of less than 24 bits is not supported" + ); + return STATUS_UNSUCCESSFUL; + } + else if ((Config->AddressWidthOverride != 64) && + (Config->AddressWidthOverride != 32)) { + + // + // Log a warning about downgrading DMA if we are actually + // downgrading. if the caller uses a 64-bit DMA + // profile with an override of 64, or 32-bit with an override + // of 32 then silently let it go through. + // + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGDMA, + "DMA AddressWidthOverride requires Windows version 6.2 or " + "higher. Windows cannot support %d bit DMA is falling back to " + "the next lower supported width (%d-bit)", + Config->AddressWidthOverride, + (deviceDescription.Dma32BitAddresses ? 32 : 24) + ); + } + } + } + + // + // Allow for a specific version override (and fail if + // that override is inconsistent with the settings). On Win7 this will + // fail when we get the DMA adapter. + // + if (Config->WdmDmaVersionOverride != 0) { + + if (Config->WdmDmaVersionOverride < deviceDescription.Version) { + status = STATUS_INVALID_PARAMETER; + + // + // Driver is asking for a lower version of the DMA engine than the + // config settings imply it needs. Fail with invalid parameter. + // + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "WdmDmaVersionOverride set to %d, conflicts with required version of %d, " + "%!STATUS!", + Config->WdmDmaVersionOverride, + deviceDescription.Version, + status + ); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return status; + } + + deviceDescription.Version = Config->WdmDmaVersionOverride; + } + + // + // Propagate some settings from the old engine's location to the new ones. + // + if (deviceDescription.Version >= DEVICE_DESCRIPTION_VERSION3) { + + if (deviceDescription.DmaAddressWidth == 0) { + + if (deviceDescription.Dma64BitAddresses) { + deviceDescription.DmaAddressWidth = 64; + } else if (deviceDescription.Dma32BitAddresses) { + deviceDescription.DmaAddressWidth = 32; + } else { + // + // Assume ISA access width. + // + + deviceDescription.DmaAddressWidth = 24; + } + } + } + + // + // Get the FDO + // + m_FDO = m_DeviceBase->GetDeviceObject(); + ASSERT(m_FDO != NULL); + + // + // Get the PDO. PDO may be NULL in the miniport case, but on + // x86 that will still allow for DMA (IoGetDmaAdapter special + // cases that on x86). On amd64 the attempt to get the DMA + // adapter later will fail cleanly. + // + m_PDO = m_DeviceBase->GetPhysicalDevice(); + + mapRegistersAllocated = 0; + + // + // If this device is a bus-master then configure the profile + // right now, since we don't need to wait for PrepareHardware + // to find out the DMA resource. + // + if (m_IsBusMaster) { + status = ConfigureBusMasterAdapters(&deviceDescription, Config); + if (!NT_SUCCESS(status)) { + goto End; + } + } + + // + // Retain the Power event callbacks. + // + m_EvtDmaEnablerFill.m_Method = Config->EvtDmaEnablerFill; + m_EvtDmaEnablerFlush.m_Method = Config->EvtDmaEnablerFlush; + m_EvtDmaEnablerEnable.m_Method = Config->EvtDmaEnablerEnable; + m_EvtDmaEnablerDisable.m_Method = Config->EvtDmaEnablerDisable; + m_EvtDmaEnablerSelfManagedIoStart.m_Method = Config->EvtDmaEnablerSelfManagedIoStart; + m_EvtDmaEnablerSelfManagedIoStop.m_Method = Config->EvtDmaEnablerSelfManagedIoStop; + + // + // Add this DmaEnabler to the parent device's list of dma enablers. + // + m_DeviceBase->AddDmaEnabler(this); + m_IsAdded = TRUE; + + // + // update hardware info for Telemetry + // + if (m_IsBusMaster) { + m_DeviceBase->SetDeviceTelemetryInfoFlags(DeviceInfoDmaBusMaster); + } + + // + // Success: + // + status = STATUS_SUCCESS; + +End: + // + // If errors then clean-up resources accumulated. + // + if (!NT_SUCCESS(status)) { + ReleaseResources(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::ConfigureSystemAdapter( + __in PWDF_DMA_SYSTEM_PROFILE_CONFIG Config, + __in WDF_DMA_DIRECTION ConfigDirection + ) +{ + DEVICE_DESCRIPTION deviceDescription; + + NTSTATUS status; + + // + // Check to make sure this direction isn't currently configured. + // + if (GetDmaDescription(ConfigDirection)->AdapterObject != NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGDMA, + "WDFDMAENABLER %p, profile %!WDF_DMA_PROFILE! " + "Enabler has already been configured for %!WDF_DMA_DIRECTION!, %!STATUS!", + GetHandle(), m_Profile, + ConfigDirection, + status + ); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + return status; + } + + // + // Initialize the adapter info from scratch given the Config structure + // then copy it to the appropriate channel and do the allocation. + // + RtlZeroMemory(&deviceDescription, sizeof(DEVICE_DESCRIPTION)); + + deviceDescription.Version = DEVICE_DESCRIPTION_VERSION3; + deviceDescription.MaximumLength = m_MaximumLength; + + deviceDescription.DemandMode = Config->DemandMode; + deviceDescription.AutoInitialize = Config->LoopedTransfer; + + deviceDescription.DmaWidth = Config->DmaWidth; + + deviceDescription.DeviceAddress = Config->DeviceAddress; + + // + // Pull the remainder of the description from the provided resource. + // + deviceDescription.InterfaceType = Internal; + deviceDescription.DmaChannel = Config->DmaDescriptor->u.Dma.Channel; + deviceDescription.DmaRequestLine = Config->DmaDescriptor->u.Dma.Port; + + + // + // Run the common adapter configuration. + // + status = ConfigureDmaAdapter( + &deviceDescription, + ConfigDirection + ); + + if (!NT_SUCCESS(status)) { + goto End; + } + + // + // Allocate a single SGList to pass to MapTransferEx. Since we + // only run a single system transfer at a time we can use the same + // list for each transfer + // + + { + size_t systemSGListSize = 0; + + if (m_IsDuplexTransfer) { + + systemSGListSize = max(GetReadDmaDescription()->PreallocatedSGListSize, + GetWriteDmaDescription()->PreallocatedSGListSize); + } else { + + systemSGListSize = m_SimplexAdapterInfo.PreallocatedSGListSize; + } + + // + // Allocate the SG list. + // + m_SGList.SystemProfile.List = + (PSCATTER_GATHER_LIST) ExAllocatePoolWithTag(NonPagedPool, + systemSGListSize, + GetDriverGlobals()->Tag); + + if (m_SGList.SystemProfile.List == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "Unable to allocate scatter gather list for system DMA " + "enabler %p, %!STATUS!", + GetHandle(), status + ); + goto End; + } + + m_IsSGListAllocated = TRUE; + m_SGListSize = systemSGListSize; + } + + // + // For a simple enabler, both of these calls will return the same + // DMA description entry. + // + if ((GetDmaDescription( + WdfDmaDirectionReadFromDevice + )->AdapterObject != NULL) && + (GetDmaDescription( + WdfDmaDirectionWriteToDevice + )->AdapterObject != NULL)) { + m_IsConfigured = TRUE; + } + +End: + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::ConfigureBusMasterAdapters( + __in PDEVICE_DESCRIPTION DeviceDescription, + __in PWDF_DMA_ENABLER_CONFIG Config + ) +{ + ULONG alignment; + NTSTATUS status; + + // + // Initialize map register management + // + DeviceDescription->MaximumLength = m_MaximumLength; + + if (m_IsDuplexTransfer) { + status = ConfigureDmaAdapter(DeviceDescription, + WdfDmaDirectionReadFromDevice); + + if (!NT_SUCCESS(status)) { + goto End; + } + + status = ConfigureDmaAdapter(DeviceDescription, + WdfDmaDirectionWriteToDevice); + } else { + // + // Direction is ignored in this case. + // + + status = ConfigureDmaAdapter(DeviceDescription, + WdfDmaDirectionReadFromDevice); + } + + if (!NT_SUCCESS(status)) { + goto End; + } + + // + // Allocate a scatter gather lookaside list if we need one. + // + + if (m_IsScatterGather) { + size_t sgLookasideListSize; + + sgLookasideListSize = 0; + + if (m_IsDuplexTransfer) { + FxDmaDescription *readDmaDesc = GetReadDmaDescription(); + FxDmaDescription *writeDmaDesc = GetWriteDmaDescription(); + + alignment = readDmaDesc->AdapterObject->DmaOperations-> + GetDmaAlignment(readDmaDesc->AdapterObject); + + // + // GetDmaAlignment returns alignment in terms of bytes + // while we treat alignment as a mask (which is how it is set + // in _DEVICE_OBJECT as well. + // For example, for byte alignment GetDmaAlignment returns 1 while + // the alignment mask is 0x00000000 + // + // For < 1.11 drivers we keep the same behaviour as before for + // compatibility. + // + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1, 11) && + alignment > 0) { + alignment -= 1; + } + + m_CommonBufferAlignment = (ULONG) FxSizeTMax(m_FDO->AlignmentRequirement, + alignment); + + // + // We will create a lookaside list based on the larger of the read & + // write SGListSize. It's done this way so that we can allocate + // sglist buffer when the dma-transaction object is created, where + // we don't know the direction of DMA transfer, and make the + // transaction initialize call fail-proof. + // + sgLookasideListSize = FxSizeTMax( + readDmaDesc->PreallocatedSGListSize, + writeDmaDesc->PreallocatedSGListSize + ); + } else { + + FxDmaDescription *simplexDmaDesc = &m_SimplexAdapterInfo; + + alignment = simplexDmaDesc->AdapterObject->DmaOperations-> + GetDmaAlignment(simplexDmaDesc->AdapterObject); + + // + // GetDmaAlignment returns alignment in terms of bytes + // while we treat alignment as a mask (which is how it is set + // in _DEVICE_OBJECT as well. + // For example, for byte alignment GetDmaAlignment returns 1 while + // the alignment mask is 0x00000000 + // + // For < 1.11 drivers we keep the same behaviour as before for + // compatibility. + // + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1, 11) && + alignment > 0) { + alignment -= 1; + } + + m_CommonBufferAlignment = (ULONG) FxSizeTMax(m_FDO->AlignmentRequirement, + alignment); + + sgLookasideListSize = simplexDmaDesc->PreallocatedSGListSize; + } + + // + // Initialize a LookasideList for ScatterGather list + // + if ((Config->Flags & WDF_DMA_ENABLER_CONFIG_NO_SGLIST_PREALLOCATION) == 0) { + ASSERT(m_IsSGListAllocated == FALSE); + + m_SGListSize = sgLookasideListSize; + + ExInitializeNPagedLookasideList( &m_SGList.ScatterGatherProfile.Lookaside, + NULL, // Allocate OPTIONAL + NULL, // Free OPTIONAL + 0, // Flag - Reserved. Must be zero. + m_SGListSize, + GetDriverGlobals()->Tag, + 0 ); // Depth - Reserved. Must be zero. + + m_IsSGListAllocated = TRUE; + } + } + + // + // The DMA enabler is configured now. + // + + m_IsConfigured = TRUE; + +End: + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::ConfigureDmaAdapter( + __in PDEVICE_DESCRIPTION DeviceDescription, + __in WDF_DMA_DIRECTION ConfigDirection + ) +{ + FxDmaDescription *dmaDesc; + NTSTATUS status; + + // + // Select the adapter to configure. + // + + dmaDesc = GetDmaDescription(ConfigDirection); + + // + // Copy the device-description we have built up so far + // into the read and write dma description field. These + // settings are common to both channels. + // + RtlCopyMemory(&dmaDesc->DeviceDescription, + DeviceDescription, + sizeof(DEVICE_DESCRIPTION)); + + // + // Then initialize resources that are private to read and write. + // + + status = InitializeResources(dmaDesc); + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::InitializeResources( + __inout FxDmaDescription *AdapterInfo + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + NT_ASSERTMSG("expected caller to set DMA version", + AdapterInfo->DeviceDescription.Version != 0); + + // + // Submit IoGetDmaAdapter and retain the DmaAdapter pointer. + // + AdapterInfo->AdapterObject = + IoGetDmaAdapter(m_PDO, + &AdapterInfo->DeviceDescription, + (PULONG)&AdapterInfo->NumberOfMapRegisters); + + if (AdapterInfo->AdapterObject == NULL) { + status = STATUS_UNSUCCESSFUL; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Unable to allocate DmaAdapter object for " + "WDFDMAENABLER %p, %!STATUS!", + GetHandle(), status); + return status; + } + + // + // Calculate the size of the SGList. + // + if (m_IsScatterGather) { + + // + // For scatter gather DMA we ask the HAL how many bytes it needs for + // each SGList. The HAL allocates some scratch space of its own in + // each SGList, which BuildScatterGatherList depends on. + // + ULONG mapRegistersCount; + + status = AdapterInfo->AdapterObject->DmaOperations-> + CalculateScatterGatherList( AdapterInfo->AdapterObject, + NULL, // Optional MDL + NULL, // CurrentVa + AdapterInfo->NumberOfMapRegisters * PAGE_SIZE, + (PULONG) &AdapterInfo->PreallocatedSGListSize, + &mapRegistersCount); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "CalculateScatterGatherList failed for " + "WDFDMAENABLER %p, %!STATUS!", GetHandle(), status); + return status; + } + + ASSERT(AdapterInfo->NumberOfMapRegisters == mapRegistersCount); + + } else if (m_IsBusMaster) { + + // + // For packet based DMA we only need a single SGList entry because + // the HAL moves all of the data into a single continguous buffer + // + AdapterInfo->PreallocatedSGListSize = sizeof(SCATTER_GATHER_LIST) + + sizeof(SCATTER_GATHER_ELEMENT); + + } else { + + // + // For system DMA we need a single SGList entry per map-register + // + AdapterInfo->PreallocatedSGListSize = sizeof(SCATTER_GATHER_LIST) + + (sizeof(SCATTER_GATHER_ELEMENT) * + AdapterInfo->NumberOfMapRegisters); + } + + ASSERT(AdapterInfo->NumberOfMapRegisters > 1); + + AdapterInfo->MaximumFragmentLength = FxSizeTMin(m_MaximumLength, + ((size_t) (AdapterInfo->NumberOfMapRegisters - 1)) << PAGE_SHIFT); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "WDFDMAENABLER %p, profile %!WDF_DMA_PROFILE! " + "DmaAdapterObject %p, MapRegisters %d, " + "MaximumFragmentLength %I64d ", GetHandle(), m_Profile, + AdapterInfo->AdapterObject, + AdapterInfo->NumberOfMapRegisters, + AdapterInfo->MaximumFragmentLength); + + if (AdapterInfo->MaximumFragmentLength < m_MaximumLength) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "The maximum transfer length for WDFDMAENABLER %p " + "is reduced to %I64d from %I64d due to mapregisters limit", + GetHandle(), m_MaximumLength, + AdapterInfo->MaximumFragmentLength); + } + + return STATUS_SUCCESS; +} + +VOID +FxDmaEnabler::FreeResources( + __inout FxDmaDescription *AdapterInfo + ) +{ + if (AdapterInfo->AdapterObject != NULL) { + AdapterInfo->AdapterObject->DmaOperations->PutDmaAdapter(AdapterInfo->AdapterObject); + AdapterInfo->AdapterObject = NULL; + } +} + +VOID +FxDmaEnabler::ReleaseResources( + VOID + ) +{ + FreeResources(GetReadDmaDescription()); + FreeResources(GetWriteDmaDescription()); + + m_IsConfigured = FALSE; + +} + +VOID +FxDmaEnabler::RevokeResources( + VOID + ) +{ + // + // Give back any system DMA resources allocated for this device + // + + if (m_IsBusMaster == FALSE) + { + + + + + + } +} + +// ---------------------------------------------------------------------------- +// ------------------------ Pnp/Power notification ----------------------------- +// ---------------------------------------------------------------------------- + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::PowerUp( + VOID + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMAENABLER handle = GetHandle(); + FxDmaEnablerCallbacks tag = FxEvtDmaEnablerInvalid; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "WDFDMAENABLER %p: PowerUp notification", GetHandle()); + + do { + if (m_EvtDmaEnablerFill.m_Method) { + + status = m_EvtDmaEnablerFill.Invoke( handle ); + + if (!NT_SUCCESS(status)) { + m_DmaEnablerFillFailed = TRUE; + tag = FxEvtDmaEnablerFill; + break; + } + } + + if (m_EvtDmaEnablerEnable.m_Method) { + + status = m_EvtDmaEnablerEnable.Invoke( handle ); + + if (!NT_SUCCESS(status)) { + m_DmaEnablerEnableFailed = TRUE; + tag = FxEvtDmaEnablerEnable; + break; + } + } + + if (m_EvtDmaEnablerSelfManagedIoStart.m_Method) { + + status = m_EvtDmaEnablerSelfManagedIoStart.Invoke( handle ); + + if (!NT_SUCCESS(status)) { + m_DmaEnablerSelfManagedIoStartFailed = TRUE; + tag = FxEvtDmaEnablerSelfManagedIoStart; + break; + } + } + + } WHILE (0); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMAENABLER %p: PowerUp: " + "%!WdfDmaEnablerCallback! failed %!STATUS!", + GetHandle(), tag, status); + } + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaEnabler::PowerDown( + VOID + ) +{ + NTSTATUS status = STATUS_SUCCESS; + NTSTATUS localStatus; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMAENABLER handle = GetHandle(); + FxDmaEnablerCallbacks tag = FxEvtDmaEnablerInvalid; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "WDFDMAENABLER %p: PowerDown notification", GetHandle()); + + do { + + if (m_EvtDmaEnablerSelfManagedIoStop.m_Method) { + + localStatus = m_EvtDmaEnablerSelfManagedIoStop.Invoke( handle ); + + if (!NT_SUCCESS(localStatus)) { + tag = FxEvtDmaEnablerSelfManagedIoStop; + status = (NT_SUCCESS(status)) ? localStatus : status; + } + } + + if (m_EvtDmaEnablerDisable.m_Method && + m_DmaEnablerFillFailed == FALSE) + { + localStatus = m_EvtDmaEnablerDisable.Invoke( handle ); + + if (!NT_SUCCESS(localStatus)) { + tag = FxEvtDmaEnablerDisable; + status = (NT_SUCCESS(status)) ? localStatus : status; + } + } + + if (m_EvtDmaEnablerFlush.m_Method && + m_DmaEnablerFillFailed == FALSE && + m_DmaEnablerEnableFailed == FALSE) + { + localStatus = m_EvtDmaEnablerFlush.Invoke( handle ); + + if (!NT_SUCCESS(localStatus)) { + tag = FxEvtDmaEnablerFlush; + status = (NT_SUCCESS(status)) ? localStatus : status; + } + } + + } WHILE (0); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMAENABLER %p: PowerDown: " + "%!WdfDmaEnablerCallback! failed %!STATUS!", + GetHandle(), tag, status); + } + + return status; +} + +// ---------------------------------------------------------------------------- +// ------------------------ COMMON BUFFER SECTION ----------------------------- +// ---------------------------------------------------------------------------- + +VOID +FxDmaEnabler::AllocateCommonBuffer( + __in size_t Length, + __deref_out_opt PVOID * BufferVA, + __out PHYSICAL_ADDRESS * BufferPA + ) +{ + ULONG result; + PDMA_ADAPTER adapterObject; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + *BufferVA = NULL; + BufferPA->QuadPart = 0; + + if (!NT_SUCCESS(RtlSizeTToULong(Length, &result))) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMAENABLER %p AllocateCommonBuffer: could cast value %I64d to a " + "ULONG", GetHandle(), Length); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // It doesn't matter which channel we use for allocating common buffers + // because the addressing capability of all the channels of this DMA enablers + // are same. + // + adapterObject = GetReadDmaDescription()->AdapterObject; + + *BufferVA = adapterObject->DmaOperations-> + AllocateCommonBuffer( adapterObject, + result, + BufferPA, + TRUE /* CacheEnabled */ ); +} + + +VOID +FxDmaEnabler::FreeCommonBuffer( + __in size_t Length, + __in PVOID BufferVA, + __in PHYSICAL_ADDRESS BufferPA + ) +{ + PDMA_ADAPTER adapterObject; + + adapterObject = GetReadDmaDescription()->AdapterObject; + + adapterObject->DmaOperations-> + FreeCommonBuffer( adapterObject, + (ULONG) Length, + BufferPA, + BufferVA, + TRUE /* CacheEnabled */ ); +} + +VOID +FxDmaEnabler::InitializeTransferContext( + __out PVOID Context, + __in WDF_DMA_DIRECTION Direction + ) +{ + PDMA_ADAPTER adapter = GetDmaDescription(Direction)->AdapterObject; + + NT_ASSERTMSG( + "should not call this routine if enabler is not using DMAv3", + UsesDmaV3() + ); + + PDMA_OPERATIONS dmaOperations = + adapter->DmaOperations; + + dmaOperations->InitializeDmaTransferContext(adapter, Context); +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmaenablerapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmaenablerapi.cpp new file mode 100644 index 00000000000..5b75da357b0 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmaenablerapi.cpp @@ -0,0 +1,516 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaEnablerAPI.cpp + +Abstract: + + Base for WDF DMA Enabler object APIs + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#include "FxDmaPCH.hpp" + +extern "C" { +#include "FxDmaEnablerAPI.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaEnablerCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + WDF_DMA_ENABLER_CONFIG * Config, + __in_opt + WDF_OBJECT_ATTRIBUTES * Attributes, + __out + WDFDMAENABLER * DmaEnablerHandle + ) +{ + FxDmaEnabler * pDmaEnabler; + FxDeviceBase * pDevice; + NTSTATUS status; + WDFDMAENABLER handle; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxObject * pParent; + WDF_DMA_ENABLER_CONFIG dmaConfig; + + // + // Validate the Device handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxPointerNotNull(pFxDriverGlobals, DmaEnablerHandle); + FxPointerNotNull(pFxDriverGlobals, Config); + + *DmaEnablerHandle = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + + if (!NT_SUCCESS(status)) { + return status; + } + + if (Attributes != NULL && Attributes->ParentObject != NULL) { + FxObjectHandleGetPtr(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent); + + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + FxDeviceBase * pSearchDevice; + + // + // If a parent object is passed-in it must be descendent of device. + // DmaEnabler stores device and uses it during dispose + // (to remove it from dmaenabler list maintained at device level), + // so DmaEnabler cannot outlive device. + // + + pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL); + + if (pSearchDevice == NULL) { + status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Attributes->ParentObject 0x%p must have WDFDEVICE as an " + "eventual ancestor, %!STATUS!", + Attributes->ParentObject, status); + + return status; + } + else if (pSearchDevice != pDevice) { + status = STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but " + "not the same WDFDEVICE 0x%p passed to WdfDmaEnablerCreate, " + "%!STATUS!", + Attributes->ParentObject, pSearchDevice->GetHandle(), + Device, status); + + return status; + } + } + else { + // + // For < 1.11 drivers we only allow pDevice to be the parent + // since that is what we were blindly setting the parent to. + // + // Using the passed-in parent for such drivers could cause + // side-effects such as earlier deletion of DmaEnabler object. So + // we don't do that. + // + // We cause this verifier breakpoint to warn downlevel drivers + // that the parent they passed in gets ignored. + // + if (pParent != pDevice) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDMA, + "For drivers bound to version <= 1.9 " + "WdfDmaEnablerCreate uses WDFDEVICE as the " + "parent object for the dma enabler object. " + "Attributes->ParentObject 0x%p, which is different from " + "WDFDEVICE 0x%p, gets ignored. Please note that DmaEnabler " + "would be disposed only when device is disposed.", + Attributes->ParentObject, Device); + + if (pFxDriverGlobals->IsDownlevelVerificationEnabled()) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + + pParent = pDevice; + } + } + else { + pParent = pDevice; + } + + { + ULONG expectedSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ? + sizeof(WDF_DMA_ENABLER_CONFIG) : + sizeof(WDF_DMA_ENABLER_CONFIG_V1_9); + + if (Config->Size != expectedSize) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDF_DMA_ENABLER_CONFIG Size 0x%x, expected 0x%x, %!STATUS!", + Config->Size, expectedSize, status); + + return status; + } + + + // + // Normalize DMA config structure if necessary. + // + if (Config->Size < sizeof(WDF_DMA_ENABLER_CONFIG)) { + // + // Init new fields to default values. + // + WDF_DMA_ENABLER_CONFIG_INIT(&dmaConfig, + Config->Profile, + Config->MaximumLength); + // + // Copy over existing fields and readjust the struct size. + // + RtlCopyMemory(&dmaConfig, Config, Config->Size); + dmaConfig.Size = sizeof(dmaConfig); + + // + // Use new config structure from now on. + // + Config = &dmaConfig; + } + } + + switch (Config->Profile) { + case WdfDmaProfilePacket: + case WdfDmaProfileScatterGather: + case WdfDmaProfilePacket64: + case WdfDmaProfileScatterGather64: + case WdfDmaProfileScatterGather64Duplex: + case WdfDmaProfileScatterGatherDuplex: + case WdfDmaProfileSystem: + case WdfDmaProfileSystemDuplex: + break; + default: + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "DMA Profile value %d is unknown, %!STATUS!", + Config->Profile, status); + return status; + } + + if (Config->MaximumLength == 0) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Config MaximumLength of zero is invalid, %!STATUS!", + status); + + return status; + } + + // + // Ok: create a new DmaEnabler + // + pDmaEnabler = new(pFxDriverGlobals, Attributes) + FxDmaEnabler( pFxDriverGlobals ); + + if (pDmaEnabler == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Could not allocate memory for a WDFDMAENABLER, " + "%!STATUS!", status); + + return status; + } + + // + // Assign this FxDmaEnabler to its parent FxDevice object. + // + status = pDmaEnabler->Commit(Attributes, (WDFOBJECT*)&handle, pParent); + + if (NT_SUCCESS(status)) { + // + // Ok: start this DmaEnabler. + // + status = pDmaEnabler->Initialize( Config, pDevice ); + } + + if (NT_SUCCESS(status)) { + // + // Only return a valid handle on success. + // + *DmaEnablerHandle = handle; + } + else { + pDmaEnabler->DeleteFromFailedCreate(); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +size_t +WDFEXPORT(WdfDmaEnablerGetMaximumLength)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler + ) +{ + FxDmaEnabler * pDmaEnabler; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler); + + return pDmaEnabler->GetMaximumLength(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +size_t +WDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler + ) +{ + FxDmaEnabler * pDmaEnabler; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler); + + return pDmaEnabler->GetMaxSGElements(); +} + + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in + __drv_when(MaximumElements == 0, __drv_reportError(MaximumElements cannot be zero)) + size_t MaximumElements + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDmaEnabler * pDmaEnabler; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + if (MaximumElements == 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot set MaximumElements of zero on WDFDMAENABLER %p", + DmaEnabler); + return; + } + + pDmaEnabler->SetMaxSGElements(MaximumElements); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +size_t +WDFEXPORT(WdfDmaEnablerGetFragmentLength)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in + WDF_DMA_DIRECTION DmaDirection + ) +{ + FxDmaEnabler * pDmaEnabler; + size_t length; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + switch (DmaDirection) { + + case WdfDmaDirectionReadFromDevice: + length = pDmaEnabler->GetReadDmaDescription()->MaximumFragmentLength; + break; + + case WdfDmaDirectionWriteToDevice: + length = pDmaEnabler->GetWriteDmaDescription()->MaximumFragmentLength; + break; + + default: + length = 0; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Invalid value for Dma direction %d, %p", + DmaDirection, DmaEnabler); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + break; + } + + return length; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PDMA_ADAPTER +WDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in + WDF_DMA_DIRECTION DmaDirection + ) +{ + PDMA_ADAPTER adapter; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDmaEnabler * pDmaEnabler; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + switch (DmaDirection) { + + case WdfDmaDirectionReadFromDevice: + adapter = pDmaEnabler->GetReadDmaDescription()->AdapterObject; + break; + + case WdfDmaDirectionWriteToDevice: + adapter = pDmaEnabler->GetWriteDmaDescription()->AdapterObject; + break; + + default: + adapter = NULL; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Invalid value for Dma direction %d, %p", + DmaDirection, DmaEnabler); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + break; + } + + return adapter; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaEnablerConfigureSystemProfile)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in + PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig, + __in + WDF_DMA_DIRECTION ConfigDirection + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDmaEnabler * pDmaEnabler; + + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + // + // Verify the DMA config + // + + if (ProfileConfig == NULL) + { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "ProfileConfig must be non-null, %!STATUS!", + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (ProfileConfig->Size != sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG)) + { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDF_DMA_SYSTEM_PROFILE_CONFIG Size 0x%x, expected 0x%x, %!STATUS!", + ProfileConfig->Size, sizeof(WDF_DMA_SYSTEM_PROFILE_CONFIG), status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return status; + } + + if (ProfileConfig->DmaDescriptor == NULL) + { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "ProfileConfig (%p) may not have NULL DmaDescriptor, %!STATUS!", + ProfileConfig, status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return status; + } + + if (ConfigDirection != WdfDmaDirectionReadFromDevice && + ConfigDirection != WdfDmaDirectionWriteToDevice) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "ConfigDirection 0x%x is an invalid value, %!STATUS!", + ConfigDirection, status); + return status; + } + + status = pDmaEnabler->ConfigureSystemAdapter(ProfileConfig, + ConfigDirection); + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmapch.hpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmapch.hpp new file mode 100644 index 00000000000..d95589fbeab --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmapch.hpp @@ -0,0 +1,7 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +extern "C" { +#include +} +#include diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmatransaction.cpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmatransaction.cpp new file mode 100644 index 00000000000..38ee50b51dc --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmatransaction.cpp @@ -0,0 +1,2533 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaTransaction.cpp + +Abstract: + + WDF DMA Transaction Object + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#include "FxDmaPCH.hpp" + +extern "C" { +#include "FxDmaTransaction.tmh" +} + +FxDmaTransactionBase::FxDmaTransactionBase( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ) : + FxNonPagedObject( + FX_TYPE_DMA_TRANSACTION, + ExtraSize == 0 ? ObjectSize : COMPUTE_OBJECT_SIZE(ObjectSize, ExtraSize), + FxDriverGlobals) +{ + m_DmaEnabler = DmaEnabler; + m_EncodedRequest = NULL; + m_MaxFragmentLength = 0; + m_DmaDirection = WdfDmaDirectionReadFromDevice; + m_DmaAcquiredContext = NULL; + m_CurrentFragmentMdl = NULL; + m_CurrentFragmentOffset = 0; + m_StartOffset = NULL; + m_StartMdl = NULL; + m_Remaining = 0; + m_CurrentFragmentLength = 0; + m_TransactionLength = 0; + m_Transferred = 0; + m_Flags = 0; + + m_DmaAcquiredFunction.Method.ProgramDma = NULL; + + m_State = FxDmaTransactionStateCreated; + + if (ExtraSize == 0) { + m_TransferContext = NULL; + } else { + m_TransferContext = WDF_PTR_ADD_OFFSET_TYPE( + this, + COMPUTE_RAW_OBJECT_SIZE(ObjectSize), + PVOID + ); + } + + MarkDisposeOverride(ObjectDoNotLock); +} + +BOOLEAN +FxDmaTransactionBase::Dispose( + VOID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + // + // Must not be in transfer state. + // + if (m_State == FxDmaTransactionStateTransfer) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", GetHandle(), m_State); + + if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) { + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + } + + m_State = FxDmaTransactionStateDeleted; + + // + // Release resources for this Dma Transaction. + // + ReleaseResources(TRUE); + + if (m_EncodedRequest != NULL) { + ClearRequest(); + } + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaTransactionBase::Initialize( + __in PFN_WDF_PROGRAM_DMA ProgramDmaFunction, + __in WDF_DMA_DIRECTION DmaDirection, + __in PMDL Mdl, + __in size_t Offset, + __in ULONG Length + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p", GetHandle()); + // + // Must be in Reserve, Created or Released state. + // + if (m_State != FxDmaTransactionStateCreated && + m_State != FxDmaTransactionStateReserved && + m_State != FxDmaTransactionStateReleased) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", GetHandle(), m_State); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + if (DmaDirection == WdfDmaDirectionReadFromDevice) { + m_AdapterInfo = m_DmaEnabler->GetReadDmaDescription(); + } else { + m_AdapterInfo = m_DmaEnabler->GetWriteDmaDescription(); + } + + // + // Initialize the DmaTransaction object + // + + m_MaxFragmentLength = m_AdapterInfo->MaximumFragmentLength; + m_DmaDirection = DmaDirection; + m_StartMdl = Mdl; + m_StartOffset = Offset; + m_CurrentFragmentMdl = Mdl; + m_CurrentFragmentOffset = Offset; + m_Remaining = Length; + m_TransactionLength = Length; + m_DmaAcquiredFunction.Method.ProgramDma = ProgramDmaFunction; + + // + // If needed, initialize the transfer context. + // + + if (m_DmaEnabler->UsesDmaV3()) { + m_DmaEnabler->InitializeTransferContext(GetTransferContext(), + m_DmaDirection); + } + + status = InitializeResources(); + if (NT_SUCCESS(status)) { + m_State = FxDmaTransactionStateInitialized; + } else { + ReleaseForReuse(FALSE); + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p, %!STATUS!", + GetHandle(), status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaTransactionBase::Execute( + __in PVOID Context + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + // + // Must be in Initialized state. + // + if (m_State != FxDmaTransactionStateInitialized) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", GetHandle(), m_State); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + // + // If this was initialized with a request, then reference the + // request now. + // + if (m_EncodedRequest != NULL) { + ReferenceRequest(); + } + + // + // Set state to Transfer. + // This is necessary because the Execute path complete + // all the way to DmaCompleted before returning to this point. + // + m_State = FxDmaTransactionStateTransfer; + + // + // Save the caller's context + // + m_DmaAcquiredContext = Context; + + ASSERT(m_Transferred == 0); + ASSERT(m_CurrentFragmentLength == 0); + + status = StartTransfer(); + if (!NT_SUCCESS(status)) { + m_State = FxDmaTransactionStateTransferFailed; + m_DmaAcquiredContext = NULL; + + if (m_EncodedRequest != NULL) { + ReleaseButRetainRequest(); + } + } + + // + // StartTransfer results in a call to the EvtProgramDma routine + // where driver could complete and delete the object. So + // don't touch the object beyond this point. + // + + return status; +} + +BOOLEAN +FxDmaTransactionBase::DmaCompleted( + __in size_t TransferredLength, + __out NTSTATUS * ReturnStatus, + __in FxDmaCompletionType CompletionType + ) +{ + BOOLEAN hasTransitioned; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMATRANSACTION dmaTransaction; + + // + // In the case of partial completion, we will start a new transfer + // from with in this function by calling StageTransfer. After that + // call, we lose ownership of the object. Since we need the handle + // for tracing purposes, we will save the value in a local variable and + // use that. + // + dmaTransaction = GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p, length %d", + dmaTransaction, (ULONG)TransferredLength); + } + + // + // Must be in Transfer state. + // + if (m_State != FxDmaTransactionStateTransfer) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", dmaTransaction, m_State); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) dmaTransaction, // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + if (TransferredLength > m_CurrentFragmentLength) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p Transfered Length %I64d can't be more " + "than the length asked to transfer %I64d " + "%!STATUS!", dmaTransaction, TransferredLength, + m_CurrentFragmentLength, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + goto End; + } + + + if (CompletionType == FxDmaCompletionTypePartial || + CompletionType == FxDmaCompletionTypeAbort) { + // + // Tally this DMA tranferred byte count into the accumulator. + // + m_Transferred += TransferredLength; + + // + // Adjust the remaining length to account for the partial transfer. + // + m_Remaining += (m_CurrentFragmentLength - TransferredLength); + + // + // Update CurrentDmaLength to reflect actual transfer because + // we need to FlushAdapterBuffers based on this value in + // TransferCompleted for packet based transfer. + // + m_CurrentFragmentLength = TransferredLength; + + } else { + // + // Tally this DMA tranferred byte count into the accumulator. + // + m_Transferred += m_CurrentFragmentLength; + } + + ASSERT(m_Transferred <= m_TransactionLength); + + // + // Inform the derived object that transfer is completed so it + // can release resources specific to last transfer. + // + status = TransferCompleted(); + if (!NT_SUCCESS(status)) { + goto End; + } + + // + // If remaining DmaTransaction length is zero or if the driver wants + // this to be the last transfer then free the map registers and + // change the state to completed. + // + if (m_Remaining == 0 || CompletionType == FxDmaCompletionTypeAbort) { + status = STATUS_SUCCESS; + goto End; + } + + // + // Stage the next packet for this DmaTransaction... + // + status = StageTransfer(); + + if (NT_SUCCESS(status)) { + // + // StageTransfer results in a call to the EvtProgramDma routine + // where driver could complete and delete the object. So + // don't touch the object beyond this point. + // + status = STATUS_MORE_PROCESSING_REQUIRED; + } + else { + // + // The error will be returned to the caller of + // WdfDmaTransactionDmaComplete*() + // + } + +End: + + if (status != STATUS_MORE_PROCESSING_REQUIRED) { + // + // Failed or succeeded. Either way free + // map registers and release the device. + // + if (NT_SUCCESS(status)) { + m_State = FxDmaTransactionStateTransferCompleted; + } else { + m_State = FxDmaTransactionStateTransferFailed; + } + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "WDFDMATRANSACTION %p completed with status %!STATUS! - " + "releasing DMA resources", + GetHandle(), + status); + } + + ReleaseResources(FALSE); + + if (m_EncodedRequest != NULL) { + ReleaseButRetainRequest(); + } + + m_CurrentFragmentLength = 0; + + hasTransitioned = TRUE; + } else { + hasTransitioned = FALSE; + } + + *ReturnStatus = status; + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p " + "Transitioned(%!BOOLEAN!)", + dmaTransaction, hasTransitioned); + } + + return hasTransitioned; +} + +VOID +FxDmaTransactionBase::ReleaseForReuse( + __in BOOLEAN ForceRelease + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + if (ForceRelease == FALSE) + { + if (m_State == FxDmaTransactionStateReleased) { + + // + // Double release is probably due to cancel during early in transaction + // initialization. DC2 on very slow machines shows this behavior. + // The double release case is rare and benign. + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDMA, + "WDFDMATRANSACTION %p is already released, " + "%!STATUS!", GetHandle(), STATUS_SUCCESS); + + return; // already released. + } + + // + // Must not be in transfer state. + // + if (m_State == FxDmaTransactionStateTransfer) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid (release transaction)", GetHandle(), m_State); + + if (pFxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + } + } + + m_State = FxDmaTransactionStateReleased; + + ReleaseResources(ForceRelease); + + // + // Except DMA enabler field and adapter info everything else should be + // cleared. Adapter info is cleared by ReleaseResources above. + // + m_DmaAcquiredContext = NULL; + + if (m_EncodedRequest != NULL) { + ClearRequest(); + } + + m_StartMdl = NULL; + m_CurrentFragmentMdl = NULL; + m_StartOffset = 0; + m_CurrentFragmentOffset = 0; + m_CurrentFragmentLength = 0; + m_Transferred = 0; + m_Remaining = 0; + m_MaxFragmentLength = 0; + m_TransactionLength = 0; + m_Flags = 0; + + m_DmaAcquiredFunction.Method.ProgramDma = NULL; + +} + +VOID +FxDmaTransactionBase::SetImmediateExecution( + __in BOOLEAN Value + ) +{ + if (m_State != FxDmaTransactionStateCreated && + m_State != FxDmaTransactionStateInitialized && + m_State != FxDmaTransactionStateReleased) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDMA, + "Must set immediate execution flag for WDFDMATRANSACTION " + "%p before calling AllocateResources or Execute (current " + "state is %!FxDmaTransactionState!)", + GetHandle(), + m_State + ); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + if (Value) { + m_Flags |= DMA_SYNCHRONOUS_CALLBACK; + } + else { + m_Flags &= ~DMA_SYNCHRONOUS_CALLBACK; + } +} + +BOOLEAN +FxDmaTransactionBase::CancelResourceAllocation( + VOID + ) +{ + if ((m_State == FxDmaTransactionStateCreated) || + (m_State == FxDmaTransactionStateReleased) || + (m_State == FxDmaTransactionStateDeleted)) { + + DoTraceLevelMessage( + GetDriverGlobals(), + TRACE_LEVEL_ERROR, + TRACINGDMA, + "WDFDMATRANSACTION %p cannot be cancelled in state " + "%!FxDmaTransactionState!", + GetHandle(), + m_State + ); + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_DMA_FATAL_ERROR, + (ULONG_PTR) GetObjectHandle(), + (ULONG_PTR) m_State); + // unreachable code + } + + PDMA_OPERATIONS dmaOperations = + m_AdapterInfo->AdapterObject->DmaOperations; + + BOOLEAN result; + + result = dmaOperations->CancelAdapterChannel( + m_AdapterInfo->AdapterObject, + m_DmaEnabler->m_FDO, + GetTransferContext() + ); + + if (result) { + m_State = FxDmaTransactionStateTransferFailed; + + if (m_EncodedRequest != NULL) { + ReleaseButRetainRequest(); + } + } + + return result; +} + +VOID +FxDmaTransactionBase::_ComputeNextTransferAddress( + __in PMDL CurrentMdl, + __in size_t CurrentOffset, + __in ULONG Transferred, + __deref_out PMDL *NextMdl, + __out size_t *NextOffset + ) +/*++ + +Routine Description: + + This function computes the next mdl and offset given the current MDL, + offset and bytes transfered. + +Arguments: + + CurrentMdl - Mdl where the transfer currently took place. + + CurrentVa - Current virtual address in the buffer + + Transfered - Bytes transfered or to be transfered + + NextMdl - Mdl where the next transfer will take place + + NextVA - Offset within NextMdl where the transfer will start + +--*/ +{ + size_t transfered, mdlSize; + PMDL mdl; + + mdlSize = MmGetMdlByteCount(CurrentMdl) - CurrentOffset; + + if (Transferred < mdlSize) { + // + // We are still in the first MDL + // + *NextMdl = CurrentMdl; + *NextOffset = CurrentOffset + Transferred; + return; + } + + // + // We have transfered the content of the first MDL. + // Move to the next one. + // + transfered = Transferred - mdlSize; + mdl = CurrentMdl->Next; + ASSERT(mdl != NULL); + + while (transfered >= MmGetMdlByteCount(mdl)) { + // + // We have transfered the content of this MDL. + // Move to the next one. + // + transfered -= MmGetMdlByteCount(mdl); + mdl = mdl->Next; + ASSERT(mdl != NULL); + } + + // + // This is the mdl where the last transfer occured. + // + *NextMdl = mdl; + *NextOffset = transfered; + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaTransactionBase::_CalculateRequiredMapRegisters( + __in PMDL Mdl, + __in size_t CurrentOffset, + __in ULONG Length, + __in ULONG AvailableMapRegisters, + __out_opt PULONG PossibleTransferLength, + __out PULONG MapRegistersRequired + ) +/*++ + +Routine Description: + + Used on Windows 2000 to compute number of map registered required + for this transfer. This is derived from HalCalculateScatterGatherListSize. + +Arguments: + + Mdl - Pointer to the MDL that describes the pages of memory that are being + read or written. + + CurrentVa - Current virtual address in the buffer described by the MDL + that the transfer is being done to or from. + + Length - Supplies the length of the transfer. + + AvailableMapRegisters - Map registers available to do the transfer + + PossibleTransferLength - Length that can transfered for the + + MapRegistersRequired - Map registers required to the entire transfer + +Return Value: + + NTSTATUS + +Notes: + +--*/ +{ + PMDL tempMdl; + ULONG requiredMapRegisters; + ULONG transferLength; + ULONG mdlLength; + ULONG pageOffset; + ULONG possTransferLength; + + // + // Calculate the number of required map registers. + // + tempMdl = Mdl; + transferLength = (ULONG) MmGetMdlByteCount(tempMdl) - (ULONG) CurrentOffset; + mdlLength = transferLength; + + pageOffset = BYTE_OFFSET(GetStartVaFromOffset(tempMdl, CurrentOffset)); + requiredMapRegisters = 0; + possTransferLength = 0; + + // + // The virtual address should fit in the first MDL. + // + + ASSERT(CurrentOffset <= tempMdl->ByteCount); + + // + // Loop through chained MDLs, accumulating the required + // number of map registers. + // + + while (transferLength < Length && tempMdl->Next != NULL) { + + // + // With pageOffset and length, calculate number of pages spanned by + // the buffer. + // + requiredMapRegisters += (pageOffset + mdlLength + PAGE_SIZE - 1) >> + PAGE_SHIFT; + + if (requiredMapRegisters <= AvailableMapRegisters) { + possTransferLength = transferLength; + } + + tempMdl = tempMdl->Next; + pageOffset = tempMdl->ByteOffset; + mdlLength = tempMdl->ByteCount; + transferLength += mdlLength; + } + + if ((transferLength + PAGE_SIZE) < (Length + pageOffset )) { + ASSERT(transferLength >= Length); + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Calculate the last number of map registers based on the requested + // length not the length of the last MDL. + // + + ASSERT( transferLength <= mdlLength + Length ); + + requiredMapRegisters += (pageOffset + Length + mdlLength - transferLength + + PAGE_SIZE - 1) >> PAGE_SHIFT; + + if (requiredMapRegisters <= AvailableMapRegisters) { + possTransferLength += (Length + mdlLength - transferLength); + } + + if (PossibleTransferLength != NULL) { + *PossibleTransferLength = possTransferLength; + } + + ASSERT(*PossibleTransferLength); + + *MapRegistersRequired = requiredMapRegisters; + + return STATUS_SUCCESS; +} + +// ---------------------------------------------------------------------------- +// ------------------- Scatter/Gather DMA Section ----------------------------- +// ---------------------------------------------------------------------------- + +FxDmaScatterGatherTransaction::FxDmaScatterGatherTransaction( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ) : + FxDmaTransactionBase(FxDriverGlobals, + sizeof(FxDmaScatterGatherTransaction), + ExtraSize, + DmaEnabler) +{ + m_LookasideBuffer = NULL; + m_SGList = NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaScatterGatherTransaction::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDmaEnabler* DmaEnabler, + __out WDFDMATRANSACTION* Transaction + ) +{ + FxDmaScatterGatherTransaction* pTransaction; + WDFOBJECT hTransaction; + NTSTATUS status; + + pTransaction = new (FxDriverGlobals, Attributes, DmaEnabler->GetTransferContextSize()) + FxDmaScatterGatherTransaction(FxDriverGlobals, + DmaEnabler->GetTransferContextSize(), + DmaEnabler); + + if (pTransaction == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Could not allocate memory for WDFTRANSACTION, %!STATUS!", status); + return status; + } + + // + // Commit and apply the attributes + // + status = pTransaction->Commit(Attributes, &hTransaction, DmaEnabler); + + if (NT_SUCCESS(status) && DmaEnabler->m_IsSGListAllocated) { + + // + // Allocate buffer for SGList from lookaside list. + // + pTransaction->m_LookasideBuffer = (SCATTER_GATHER_LIST *) + FxAllocateFromNPagedLookasideList( + &DmaEnabler->m_SGList.ScatterGatherProfile.Lookaside + ); + + if (pTransaction->m_LookasideBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Unable to allocate memory for SG List, " + "WDFDMATRANSACTION %p, %!STATUS! ", + pTransaction->GetHandle(), status); + } + else { + // + // Take a reference on the enabler to ensure that it remains valid + // if the transaction's disposal is deferred. + // + DmaEnabler->ADDREF(pTransaction); + } + } + + if (NT_SUCCESS(status)) { + *Transaction = (WDFDMATRANSACTION)hTransaction; + } + else { + // + // This will properly clean up the target's state and free it + // + pTransaction->DeleteFromFailedCreate(); + } + + return status; +} + +BOOLEAN +FxDmaScatterGatherTransaction::Dispose( + VOID + ) +{ + BOOLEAN ret; + + ret = __super::Dispose(); + + // + // Free Lookaside Buffer which held SGList + // + if (m_LookasideBuffer != NULL) { + + FxFreeToNPagedLookasideList( + &m_DmaEnabler->m_SGList.ScatterGatherProfile.Lookaside, + m_LookasideBuffer + ); + m_LookasideBuffer = NULL; + m_DmaEnabler->RELEASE(this); + } + + return ret; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaScatterGatherTransaction::InitializeResources( + VOID + ) +{ + NTSTATUS status; + PMDL nextMdl; + size_t nextOffset; + ULONG mapRegistersRequired; + size_t remLength, transferLength, transferred, possibleLength=0; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + status = STATUS_SUCCESS; + + // + // If the caller has specified a limit on the number of scatter-gather + // elements each transfer can support then make sure it's within the + // limit by breaking up the whole transfer into m_MaxFragmentLength and + // computing the number of map-registers required for each fragment. + // This check may not be valid if the driver starts to do partial + // transfers. So driver that do partial transfer with sg-element limit + // should be capable of handling STATUS_WDF_TOO_FRAGMENTED failures during + // dma execution. + // + remLength = m_TransactionLength; + transferred = 0; + nextMdl = m_StartMdl; + nextOffset = m_StartOffset; + transferLength = 0; + + while (remLength != 0) { + + _ComputeNextTransferAddress(nextMdl, + nextOffset, + (ULONG) transferLength, + &nextMdl, + &nextOffset); + + transferLength = FxSizeTMin(remLength, m_MaxFragmentLength); + + status = _CalculateRequiredMapRegisters(nextMdl, + nextOffset, + (ULONG) transferLength, + m_AdapterInfo->NumberOfMapRegisters, + (PULONG) &possibleLength, + &mapRegistersRequired + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "CalculateScatterGatherList failed for " + "WDFDMATRANSACTION %p, %!STATUS!", GetHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (mapRegistersRequired > m_DmaEnabler->m_MaxSGElements) { + status = STATUS_WDF_TOO_FRAGMENTED; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p for MDL %p is more fragmented (%d) " + "than the limit (%I64d) specified by the driver, %!STATUS! ", + GetHandle(), nextMdl, mapRegistersRequired, + m_DmaEnabler->m_MaxSGElements, status); + return status; + } + + transferred += transferLength; + remLength -= transferLength; + } + + return status; +} + +VOID +FxDmaScatterGatherTransaction::ReleaseResources( + __in BOOLEAN /* ForceRelease */ + ) +{ + if (m_SGList != NULL) { + PutScatterGatherList(m_SGList); + m_SGList = NULL; + } + m_AdapterInfo = NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaScatterGatherTransaction::StartTransfer( + VOID + ) +{ + ASSERT(m_CurrentFragmentMdl == m_StartMdl); + ASSERT(m_CurrentFragmentOffset == m_StartOffset); + ASSERT(m_CurrentFragmentLength == 0); + ASSERT(m_Transferred == 0); + + return StageTransfer(); +} + +_Must_inspect_result_ +NTSTATUS +FxDmaScatterGatherTransaction::StageTransfer( + VOID + ) +{ + NTSTATUS status; + ULONG mapRegistersRequired; + WDFDMATRANSACTION dmaTransaction; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + // + // Use an invalid value to make the function fail if the var is not + // updated correctly below. + // + mapRegistersRequired = 0xFFFFFFFF; + + // + // Client driver could complete and delete the object in + // EvtProgramDmaFunction. So, save the handle because we need it + // for tracing after we invoke the callback. + // + dmaTransaction = GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p ", GetHandle()); + } + + // + // Given the first MDL and the bytes transfered, find the next MDL + // and byteoffset within that MDL. + // + _ComputeNextTransferAddress(m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + (ULONG) m_CurrentFragmentLength, + &m_CurrentFragmentMdl, + &m_CurrentFragmentOffset); + + // + // Get the next possible transfer size. + // + m_CurrentFragmentLength = FxSizeTMin(m_Remaining, m_MaxFragmentLength); + + // + // Fix m_CurrentFragmentLength to meet the map registers limit. This is done + // in case the MDL is a chained MDL for an highly fragmented buffer. + // + status = _CalculateRequiredMapRegisters(m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + (ULONG) m_CurrentFragmentLength, + m_AdapterInfo->NumberOfMapRegisters, + (PULONG)&m_CurrentFragmentLength, + &mapRegistersRequired); + // + // We have already validated the entire transfer during initialize + // to see each transfer meets the sglimit. So this call shouldn't fail. + // But, if the driver does partial transfer and changes the fragment + // boundaries then it's possible for the sg-elements to vary. So, check + // one more time to see if we are within the bounds before building + // the sglist and calling into the driver. + // + ASSERT(NT_SUCCESS(status)); + + if (mapRegistersRequired > m_DmaEnabler->m_MaxSGElements) { + status = STATUS_WDF_TOO_FRAGMENTED; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p for MDL %p is more fragmented (%d) " + "than the limit (%I64d) specified by the driver, %!STATUS! ", + dmaTransaction, m_CurrentFragmentMdl, mapRegistersRequired, + m_DmaEnabler->m_MaxSGElements, status); + return status; + } + + + m_Remaining -= m_CurrentFragmentLength; + + if (m_DmaEnabler->m_IsSGListAllocated) { + + ASSERT(m_LookasideBuffer != NULL); + status = BuildScatterGatherList(m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + (ULONG) m_CurrentFragmentLength, +#pragma prefast(suppress: __WARNING_CLASS_MISMATCH_NONE, "This warning requires a wrapper class for the DRIVER_LIST_CONTROL type.") + _AdapterListControl, + this, + m_LookasideBuffer, + (ULONG) m_AdapterInfo->PreallocatedSGListSize); + + } else { + + status = GetScatterGatherList(m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + (ULONG) m_CurrentFragmentLength, +#pragma prefast(suppress: __WARNING_CLASS_MISMATCH_NONE, "This warning requires a wrapper class for the DRIVER_LIST_CONTROL type.") + _AdapterListControl, + this); + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Build or GetScatterGatherList failed for " + "WDFDMATRANSACTION %p, %!STATUS!", + dmaTransaction, status); + // + // Readjust remaining bytes transfered. + // + m_Remaining += m_CurrentFragmentLength; + return status; + } + + // + // Before GetScatterGatherList returns, _AdapterListControl can get called + // on another thread and the driver could delete the transaction object. + // So don't touch the object after this point. + // + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p, " + "%!STATUS!", dmaTransaction, status); + } + + return status; +} + + +VOID +FxDmaScatterGatherTransaction::_AdapterListControl( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp, // UNUSED + __in PSCATTER_GATHER_LIST SgList, + __in PVOID Context + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFDMATRANSACTION dmaTransaction; + FxDmaScatterGatherTransaction * pDmaTransaction; + + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(DeviceObject); + + pDmaTransaction = (FxDmaScatterGatherTransaction*) Context; + pFxDriverGlobals = pDmaTransaction->GetDriverGlobals(); + dmaTransaction = pDmaTransaction->GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p", + dmaTransaction); + } + + ASSERT(pDmaTransaction != NULL); + ASSERT(pDmaTransaction->m_DmaAcquiredFunction.Method.ProgramDma != NULL); + + ASSERT(SgList->NumberOfElements <= pDmaTransaction->m_DmaEnabler->GetMaxSGElements()); + + pDmaTransaction->m_SGList = SgList; + + // + // We ignore the return value. The pattern we want the driver to follow is + // that if it fails to program DMA transfer, it should call DmaCompletedFinal + // to abort the transfer. + // + (VOID) pDmaTransaction->m_DmaAcquiredFunction.InvokeProgramDma( + dmaTransaction, + pDmaTransaction->m_DmaEnabler->m_DeviceBase->GetHandle(), + pDmaTransaction->m_DmaAcquiredContext, + pDmaTransaction->m_DmaDirection, + SgList); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p", + dmaTransaction); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDmaScatterGatherTransaction::TransferCompleted( + VOID + ) +{ + // + // All we have to do is release the scatter-gather list. + // + if (m_SGList != NULL) { + + PutScatterGatherList(m_SGList); + m_SGList = NULL; + } + + return STATUS_SUCCESS; +} + + +// ---------------------------------------------------------------------------- +// ------------------- PACKET DMA SECTION ------------------------------------- +// ---------------------------------------------------------------------------- + +FxDmaPacketTransaction::FxDmaPacketTransaction( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ) : + FxDmaTransactionBase(FxDriverGlobals, ObjectSize, ExtraSize, DmaEnabler) +{ + m_MapRegistersNeeded = 0; + m_MapRegisterBase = NULL; + m_MapRegisterBaseSet = FALSE; + m_DeviceAddressOffset = 0; + m_MapRegistersReserved = 0; + + m_IsCancelled = FALSE; + + m_TransferState.CurrentStagingThread = NULL; + m_TransferState.RerunStaging = FALSE; + m_TransferState.RerunCompletion = FALSE; + m_TransferState.CompletionStatus = UNDEFINED_DMA_COMPLETION_STATUS; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaPacketTransaction::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDmaEnabler* DmaEnabler, + __out WDFDMATRANSACTION* Transaction + ) +{ + FxDmaPacketTransaction* pTransaction; + WDFOBJECT hTransaction; + NTSTATUS status; + + pTransaction = new (FxDriverGlobals, Attributes, DmaEnabler->GetTransferContextSize()) + FxDmaPacketTransaction(FxDriverGlobals, + sizeof(FxDmaPacketTransaction), + DmaEnabler->GetTransferContextSize(), + DmaEnabler); + + if (pTransaction == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Could not allocate memory for WDFTRANSACTION, %!STATUS!", status); + return status; + } + + // + // Commit and apply the attributes + // + status = pTransaction->Commit(Attributes, &hTransaction, DmaEnabler); + if (NT_SUCCESS(status)) { + *Transaction = (WDFDMATRANSACTION)hTransaction; + } + else { + // + // This will properly clean up the target's state and free it + // + pTransaction->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaPacketTransaction::InitializeResources( + VOID + ) +{ + KIRQL oldIrql; + m_DeviceAddressOffset = 0; + LockTransferState(&oldIrql); + m_IsCancelled = FALSE; + UnlockTransferState(oldIrql); + return STATUS_SUCCESS; +} + +VOID +FxDmaPacketTransaction::ReleaseResources( + __in BOOLEAN ForceRelease + ) +{ + // + // If the map register base hasn't been assigned, then just + // skip this. + // + + if (IsMapRegisterBaseSet() == FALSE) { + return; + } + + // + // Map registers are reserved. Unless the caller is forcing + // us to free them, just return. Otherwise updated the + // number of map registers that FreeMapRegistersAndAdapter + // is going to look at. + // + if ((m_MapRegistersReserved > 0) && (ForceRelease == FALSE)) + { + return; + } + + // + // Free the map registers and release the device. + // + FreeMapRegistersAndAdapter(); + + ClearMapRegisterBase(); + + ReleaseDevice(); + + m_AdapterInfo = NULL; + m_MapRegistersReserved = 0; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaPacketTransaction::ReserveAdapter( + __in ULONG NumberOfMapRegisters, + __in WDF_DMA_DIRECTION DmaDirection, + __in PFN_WDF_RESERVE_DMA Callback, + __in_opt PVOID Context + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMATRANSACTION dmaTransaction = GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p", dmaTransaction); + } + + // + // If caller doesn't supply a map register count then we get the count + // out of the transaction. So the transaction must be initialized. + // + // Otherwise the transaction can't be executing. + // + if (NumberOfMapRegisters == 0) { + if (m_State != FxDmaTransactionStateInitialized) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "RequiredMapRegisters cannot be 0 because " + "WDFDMATRANSACTION %p is not initialized (" + "state is %!FxDmaTransactionState!) - %!STATUS!", + GetHandle(), + m_State, + status); + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + } + else if (m_State != FxDmaTransactionStateCreated && + m_State != FxDmaTransactionStateInitialized && + m_State != FxDmaTransactionStateReleased) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", dmaTransaction, m_State); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + // + // Must not already have reserved map registers + // + if (m_MapRegistersReserved != 0) + { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p already has allocated map registers.", + dmaTransaction); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + // + // Get the adapter + // + if (DmaDirection == WdfDmaDirectionReadFromDevice) { + m_AdapterInfo = m_DmaEnabler->GetReadDmaDescription(); + } else { + m_AdapterInfo = m_DmaEnabler->GetWriteDmaDescription(); + } + + // + // Save the number of map registers being reserved. + // + if (NumberOfMapRegisters != 0) { + + // + // Use the number the caller passed us + // + m_MapRegistersReserved = NumberOfMapRegisters; + } + else if (m_DmaEnabler->IsBusMaster() == FALSE) { + + // + // For system DMA use all the map registers we have + // + m_MapRegistersReserved = m_AdapterInfo->NumberOfMapRegisters; + + } else { + + // + // Compute the number of map registers required based on + // the MDL and length passed in + // + status = _CalculateRequiredMapRegisters( + m_StartMdl, + m_StartOffset, + (ULONG) m_TransactionLength, + m_AdapterInfo->NumberOfMapRegisters, + NULL, + &m_MapRegistersReserved + ); + + if (!NT_SUCCESS(status)) { + ReleaseForReuse(TRUE); + goto End; + } + } + + // + // Initialize the DmaTransaction object with enough data to + // trick StartTransfer into allocating the adapter channel for us. + // + m_DmaDirection = DmaDirection; + m_StartMdl = NULL; + m_StartOffset = 0; + m_CurrentFragmentMdl = NULL; + m_CurrentFragmentOffset = 0; + m_Remaining = 0; + m_TransactionLength = 0; + + // + // Save the callback and context + // + m_DmaAcquiredFunction.Method.ReserveDma = Callback; + m_DmaAcquiredContext = Context; + + // + // If needed, initialize the transfer context. + // + if (m_DmaEnabler->UsesDmaV3()) { + m_DmaEnabler->InitializeTransferContext(GetTransferContext(), + m_DmaDirection); + } + + status = InitializeResources(); + if (NT_SUCCESS(status)) { + // + // Set the state to reserved so _AdapterControl knows which + // callback to invoke. + // + m_State = FxDmaTransactionStateReserved; + } else { + ReleaseForReuse(TRUE); + goto End; + } + + // + // Start the adapter channel allocation through StartTransfer + // + status = StartTransfer(); + +End: + if (!NT_SUCCESS(status)) { + m_State = FxDmaTransactionStateTransferFailed; + m_DmaAcquiredFunction.Method.ReserveDma = NULL; + m_DmaAcquiredContext = NULL; + m_MapRegistersReserved = 0; + + if (m_EncodedRequest != NULL) { + ReleaseButRetainRequest(); + } + } + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p, %!STATUS!", + dmaTransaction, status); + } + + return status; +} + +VOID +FxDmaPacketTransaction::ReleaseAdapter( + VOID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMATRANSACTION dmaTransaction = GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p", dmaTransaction); + } + + // + // Must not be in invalid, created, transfer or deleted state + // + if (m_State == FxDmaTransactionStateInvalid || + m_State == FxDmaTransactionStateCreated || + m_State == FxDmaTransactionStateTransfer || + m_State == FxDmaTransactionStateDeleted) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", dmaTransaction, m_State); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + // + // The caller wants to free the reserved map registers, so force their + // release. + // + ReleaseForReuse(TRUE); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p", + dmaTransaction); + } + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaPacketTransaction::StartTransfer( + VOID + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + WDFDMATRANSACTION dmaTransaction; + + // + // Client driver could complete and delete the object in + // EvtProgramDmaFunction. So, save the handle because we need it + // for tracing after we invoke the callback. + // + dmaTransaction = GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p", + dmaTransaction); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Starting WDFDMATRANSACTION %p - MDL %#p, " + "offset %I64x, length %I64x", + dmaTransaction, + m_StartMdl, + m_StartOffset, + m_TransactionLength); + } + + // + // Reference the device when using DMA v2. For DMA v3 we can support + // concurrent attempts to allocate the channel. + // + status = AcquireDevice(); + if (!NT_SUCCESS(status)) { + + NT_ASSERTMSG("AcquireDevice should never fail when DMAv3 is in use", + m_DmaEnabler->UsesDmaV3()); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Only one transaction can be queued " + "at one time on a packet based WDFDMAENABLER %p " + "%!STATUS!", m_DmaEnabler->GetHandle(), + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Calculate the initial DMA transfer length. + // + m_CurrentFragmentLength = FxSizeTMin(m_Remaining, m_MaxFragmentLength); + + m_CurrentFragmentOffset = m_StartOffset; + + if (m_State == FxDmaTransactionStateReserved) { + // + // Caller is simply reserving the DMA adapter for later use. Ask for + // as many map registers as the driver requested. + // + m_MapRegistersNeeded = m_MapRegistersReserved; + + ASSERT(m_MapRegistersNeeded <= m_AdapterInfo->NumberOfMapRegisters); + + status = AllocateAdapterChannel(FALSE); + + } + else { + + if (m_DmaEnabler->IsBusMaster() == FALSE) { + + // + // Use as many map registers as we were granted. + // + m_MapRegistersNeeded = m_AdapterInfo->NumberOfMapRegisters; + } else { + + // + // If the transfer is the size of the transaction then use the offset + // to determine the number of map registers needed. If it's smaller + // then use the worst-case offset to make sure we ask for enough MR's + // to account for a bigger offset in one of the later transfers. + // + // Example: + // Transaction is 8 KB and is page aligned + // if max transfer is >= 8KB then this will be one transfer and only + // requires two map registers. Even if the driver completes a partial + // transfer and we have to do the rest in a second transfer it will + // fit within two map registers becuase the overall transaction does + // (and a partial transfer can't take more map registers than the + // whole transaction would). + // + // If max transfer is 2KB then this nominally requires 4 2KB transfers. + // In this case however, a partial completion of one of those transfers + // would leave us attempting a second 2KB transfer starting on an + // unaligned address. For example, we might transfer 2KB, then 1KB + // then 2KB. Even though the first transfer was page aligned, the + // 3rd transfer isn't and could cross a page boundary, requiring two + // map registers rather than one. + // + // To account for this second case, ignore the actual MDL offset and + // instead compute the maximum number of map registers than an N byte + // transfer could take (with worst-case alignment). + // + // + m_MapRegistersNeeded = + (ULONG) ADDRESS_AND_SIZE_TO_SPAN_PAGES( + ((m_CurrentFragmentLength == m_Remaining) ? + GetStartVaFromOffset(m_CurrentFragmentMdl, + m_CurrentFragmentOffset) : + (PVOID)(ULONG_PTR) (PAGE_SIZE -1)), + m_CurrentFragmentLength + ); + + + ASSERT(m_MapRegistersNeeded <= m_AdapterInfo->NumberOfMapRegisters); + } + + // + // NOTE: the number of map registers needed for this transfer may + // exceed the number that we've reserved. StageTransfer will + // take care of fragmenting the transaction accordingly. + // + status = AllocateAdapterChannel(m_MapRegistersReserved > 0); + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "AllocateAdapterChannel failed for " + "WDFDMATRANSACTION %p, %!STATUS!", + dmaTransaction, status); + ReleaseDevice(); + } + + // + // Before AllocateAdapterChannel returns, _AdapterControl can get called + // on another thread and the driver could delete the transaction object. + // So don't touch the object after this point. + // + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p, " + "%!STATUS!", dmaTransaction, status); + } + + return status; +} + +IO_ALLOCATION_ACTION +FxDmaPacketTransaction::_AdapterControl( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp, + __in PVOID MapRegisterBase, + __in PVOID Context + ) +{ + FxDmaPacketTransaction * pDmaTransaction; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IO_ALLOCATION_ACTION action; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(DeviceObject); + + pDmaTransaction = (FxDmaPacketTransaction*) Context; + ASSERT(pDmaTransaction); + + pFxDriverGlobals = pDmaTransaction->GetDriverGlobals(); + + // + // Cache the return value while we can still touch the transaction + // + action = pDmaTransaction->GetAdapterControlReturnValue(); + + // + // Save the MapRegister base, unless it was previously set + // during a reserve. + // + if (pDmaTransaction->IsMapRegisterBaseSet() == FALSE) { + pDmaTransaction->SetMapRegisterBase(MapRegisterBase); + } + else { + NT_ASSERTMSG("Caller was expected to use existing map register base", + MapRegisterBase == pDmaTransaction->m_MapRegisterBase); + } + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Map registers for WDFDMATRANSACTION %p allocated " + "(base %p)", + pDmaTransaction->GetHandle(), + MapRegisterBase); + } + + // + // NOTE: KMDF used to call KeFlushIoBuffers() here to "ensure the + // data buffers were flushed." However KeFlushIoBuffers did + // nothing on x86 & amd64 (which are cache coherent WRT DMA) + // and calling FlushAdapterBuffers() does any necessary + // flushing anyway. Plus on non-cache-coherent architectures + // (such as ARM) the flush operation has to be cache-line aligned + // to avoid cache line tearing. So the flush is not necessary + // and has been removed. + + // + // Check the state of the transaction. If it's reserve then call the + // reserve callback and return. Otherwise stage the first fragment. + // + if (pDmaTransaction->m_State == FxDmaTransactionStateReserved) + { + FxDmaTransactionProgramOrReserveDma callback; + + // + // Save off and clear the callback before calling it. + // + callback = pDmaTransaction->m_DmaAcquiredFunction; + pDmaTransaction->m_DmaAcquiredFunction.Clear(); + + ASSERTMSG("Mismatch between map register counts", + (pDmaTransaction->m_MapRegistersReserved == + pDmaTransaction->m_MapRegistersNeeded)); + + // + // Invoke the callback. Note that from here the driver may initialize + // and execute the transaction. + // + callback.InvokeReserveDma( + pDmaTransaction->GetHandle(), + pDmaTransaction->m_DmaAcquiredContext + ); + } + else { + + // + // Stage next fragment + // + status = pDmaTransaction->StageTransfer(); + + if (!NT_SUCCESS(status)) { + + DMA_COMPLETION_STATUS dmaStatus = + (status == STATUS_CANCELLED ? DmaCancelled : DmaError); + FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTransaction; + + // + // Map transfer failed. There will be no DMA completion callback + // and no call to EvtProgramDma. And we have no way to hand this + // status back directly to the driver. Fake a DMA completion with + // the appropriate status. + // + // This should only happen for system DMA (and there most likely + // only during cancelation, though we leave the possibility that + // the DMA extension may fail the transfer) + // + ASSERTMSG("Unexpected failure of StageTransfer for packet based " + "DMA", + (pDmaTransaction->GetDmaEnabler()->IsBusMaster() == false)); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Invoking DmaCompleted callback %p (context %p) " + "for WDFDMATRANSACTION %p (status %x) " + "due to staging failure (%!STATUS!)", + systemTransaction->m_TransferCompleteFunction.Method, + systemTransaction->m_TransferCompleteContext, + pDmaTransaction->GetHandle(), + dmaStatus, + status); + } + + pDmaTransaction->CallEvtDmaCompleted( + status == STATUS_CANCELLED ? DmaCancelled : DmaError + ); + } + } + + // + // Indicate that MapRegs are to be kept + // + return action; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaPacketTransaction::StageTransfer( + VOID + ) +{ + PSCATTER_GATHER_LIST sgList; + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + UCHAR_MEMORY_ALIGNED sgListBuffer[sizeof(SCATTER_GATHER_LIST) + + sizeof(SCATTER_GATHER_ELEMENT)]; + WDFDMATRANSACTION dmaTransaction; + + KIRQL oldIrql; + BOOLEAN stagingNeeded; + + NTSTATUS status = STATUS_SUCCESS; + + // + // Client driver could complete and delete the object in + // EvtProgramDmaFunction. So, save the handle because we need it + // for tracing after we invoke the callback. + // + pFxDriverGlobals = GetDriverGlobals(); + dmaTransaction = GetHandle(); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Enter WDFDMATRANSACTION %p ", dmaTransaction); + } + + // + // For packet base DMA, current and startMDL will always be + // same. For V2 DMA we don't support MDL chains. For V3 DMA + // we use the HAL's support for MDL chains and don't walk through + // the MDL chain on our own. + // + ASSERT(m_CurrentFragmentMdl == m_StartMdl); + + LockTransferState(&oldIrql); + + if (m_TransferState.CurrentStagingThread != NULL) { + + // + // Staging in progress. Indicate that another staging will + // be needed. + // + m_TransferState.RerunStaging = TRUE; + + stagingNeeded = FALSE; + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Staging next fragment of WDFDMATRANSACTION %p " + "deferred", + dmaTransaction + ); + } + } + else { + // + // Staging isn't in progress anyplace else. Indicate that it's + // running now so that any parallel attempt is blocked. + // + m_TransferState.CurrentStagingThread = KeGetCurrentThread(); + + ASSERTMSG("The thread which was staging didn't clear " + "RerunStaging", + (m_TransferState.RerunStaging == FALSE)); + + stagingNeeded = TRUE; + } + + UnlockTransferState(oldIrql); + + // + // Take a reference on the transaction so that we can safely + // manipulate the transfer state even after it's destroyed. + // + AddRef(&pFxDriverGlobals); + + // + // Loop for as long as staging is required + // + while (stagingNeeded) { + + // + // Calculate length for this packet. + // + m_CurrentFragmentLength = FxSizeTMin(m_Remaining, m_MaxFragmentLength); + + // + // Calculate address for this packet. + // + m_CurrentFragmentOffset = m_StartOffset + m_Transferred; + + // + // Adjust the fragment length for the number of reserved map registers. + // + if ((m_MapRegistersReserved > 0) && + (m_MapRegistersNeeded > m_MapRegistersReserved)) + { + size_t currentOffset = m_CurrentFragmentOffset; + size_t currentPageOffset; + PMDL mdl; + + for (mdl = m_CurrentFragmentMdl; mdl != NULL; mdl = mdl->Next) + { + // + // For packet/system transfers of chained MDLs, m_CurrentFragmentMdl + // is never adjusted, and m_CurrentFragmentOFfset is the offset + // into the entire chain. + // + // Locate the MDL which contains the current fragment. + // + ULONG mdlBytes = MmGetMdlByteCount(mdl); + if (mdlBytes >= currentOffset) + { + // + // This MDL is larger than the remaining offset, so it + // contains the start address. + // + break; + } + + currentOffset -= mdlBytes; + } + + ASSERT(mdl != NULL); + + // + // Compute page offset from current MDL's initial page offset + // and the offset into that MDL + // + + currentPageOffset = BYTE_OFFSET(MmGetMdlByteOffset(mdl) + + currentOffset); + + // + // Compute the maximum number of bytes we can transfer with + // the number of map registers we have reserved, taking into + // account the offset of the first page. + // + size_t l = ((PAGE_SIZE * (m_MapRegistersReserved - 1)) + + (PAGE_SIZE - currentPageOffset)); + + m_CurrentFragmentLength = FxSizeTMin(m_CurrentFragmentLength, l); + } + + m_Remaining -= m_CurrentFragmentLength; + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Initiating %s transfer for WDFDMATRANSACTION %p. " + "Mdl %p, Offset %I64x, Length %I64x", + m_Transferred == 0 ? "first" : "next", + GetHandle(), + m_CurrentFragmentMdl, + m_Transferred, + m_CurrentFragmentLength); + } + + // + // Check for a pending cancellation. This can happen if the cancel + // occurred between DMA completion and FlushAdapterBuffers - + // FlushAdapterBuffers will clear the canceled bit in the transfer + // context (TC), which would allow MapTransfer to succeed. + // + // An unprotected check of IsCancelled here is safe. A concurrent + // cancel at this point would mark the TC cancelled such that + // MapTransfer will fail. + // + if (m_IsCancelled == TRUE) { + status = STATUS_CANCELLED; + goto End; + } + + // + // Profile specific work before mapping the transfer. if this + // fails consider 'this' invalid. + // + if (PreMapTransfer() == FALSE) { + status = STATUS_SUCCESS; + goto End; + } + + // + // Map this packet for transfer. + // + + // + // For packet based DMA we use a single entry on-stack SGL. This + // allows us to map multiple packet-based requests concurrently and + // we know packet base DMA only requires a single SGL + // + // NOTE: It turns out the HAL doesn't handle chained MDLs in packet + // mode correctly. It makes each MDL continguous, but returns + // a list of SG elements - one for each MDL. That's scatter + // gather DMA, not packet DMA. + // + // So it's actually very important in Win8 that we only use a + // single entry SGL when calling MapTransferEx. This ensures + // we only map the first MDL in the chain and thus get a + // contiguous buffer + // + // For system DMA we use the SystemSGList stored in the DMA enabler + // We can use a shared one in that case because we won't be mapping + // multiple system DMA requests concurrently (HAL doesn't allow it) + // + FxDmaEnabler* enabler = GetDmaEnabler(); + size_t sgListSize; + + if (enabler->IsBusMaster()) { + sgList = (PSCATTER_GATHER_LIST)sgListBuffer; + sgListSize = sizeof(sgListBuffer); + } else { + sgList = enabler->m_SGList.SystemProfile.List; + sgListSize = enabler->m_SGListSize; + } + + ULONG mappedBytes; + + status = MapTransfer(sgList, + (ULONG) sgListSize, + GetTransferCompletionRoutine(), + this, + &mappedBytes); + + NT_ASSERTMSG("Unexpected failure of MapTransfer", + ((NT_SUCCESS(status) == TRUE) || + (status == STATUS_CANCELLED))); + + if (NT_SUCCESS(status)) { + + NT_ASSERTMSG("unexpected number of mapped bytes", + ((mappedBytes > 0) && + (mappedBytes <= m_CurrentFragmentLength))); + + // + // Adjust the remaining byte count if the HAL mapped less data than we + // requested. + // + if (mappedBytes < m_CurrentFragmentLength) { + m_Remaining += m_CurrentFragmentLength - mappedBytes; + m_CurrentFragmentLength = mappedBytes; + } + + // + // Do client PFN_WDF_PROGRAM_DMA callback. + // + if (m_DmaAcquiredFunction.Method.ProgramDma != NULL) { + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Invoking ProgramDma callback %p (context %p) for " + "WDFDMATRANSACTION %p.", + m_DmaAcquiredFunction.Method.ProgramDma, + m_DmaAcquiredContext, + GetHandle() + ); + } + + // + // Call program DMA + // + (VOID) m_DmaAcquiredFunction.InvokeProgramDma( + GetHandle(), + m_DmaEnabler->m_DeviceBase->GetHandle(), + m_DmaAcquiredContext, + m_DmaDirection, + sgList + ); + } + } + +End: + // + // Process any pending completion or nested staging. + // + { + LockTransferState(&oldIrql); + + // + // While staging we could either have deferred a call to the + // completion routine or deferred another call to stage the + // next fragment. We should not ever have to do both - this + // would imply that the driver didn't wait for its DMA completion + // routine to run when calling TransferComplete*. + // + ASSERTMSG("driver called TransferComplete with pending DMA " + "completion callback", + !((m_TransferState.RerunCompletion == TRUE) && + (m_TransferState.RerunStaging == TRUE))); + + // + // Check for pending completion. save the status away and clear it + // before dropping the lock. + // + if (m_TransferState.RerunCompletion == TRUE) { + DMA_COMPLETION_STATUS completionStatus; + FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) this; + + // + // Save the completion status for when we drop the lock. + // + completionStatus = m_TransferState.CompletionStatus; + + ASSERTMSG("completion needed, but status was not set or was " + "already cleared", + completionStatus != UNDEFINED_DMA_COMPLETION_STATUS); + + ASSERTMSG("completion needed, but mapping failed so there shouldn't " + "be any parallel work going on", + NT_SUCCESS(status)); + + // + // Clear the completion needed state. + // + m_TransferState.RerunCompletion = FALSE; + m_TransferState.CompletionStatus = UNDEFINED_DMA_COMPLETION_STATUS; + + // + // Drop the lock, call the completion routine, then take the + // lock again. + // + UnlockTransferState(oldIrql); + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Invoking DmaCompleted callback %p (context %p) " + "for WDFDMATRANSACTION %p (status %x) " + "after deferral", + systemTransaction->m_TransferCompleteFunction.Method, + systemTransaction->m_TransferCompleteContext, + GetHandle(), + completionStatus); + } + CallEvtDmaCompleted(completionStatus); + LockTransferState(&oldIrql); + + // + // Staging is blocked, which means we aren't starting up the + // next transfer. Therefore we cannot have a queued completion. + // + ASSERTMSG("RerunCompletion should not be set on an unstaged " + "transaction", + m_TransferState.RerunCompletion == FALSE); + } + + // + // Capture whether another staging is needed. If none is needed + // then we can clear staging in progress. + // + if (m_TransferState.RerunStaging == TRUE) { + stagingNeeded = TRUE; + m_TransferState.RerunStaging = FALSE; + } + else { + m_TransferState.CurrentStagingThread = NULL; + stagingNeeded = FALSE; + } + + UnlockTransferState(oldIrql); + } + +#if DBG + if (!NT_SUCCESS(status)) { + ASSERTMSG("MapTransfer returned an error - there should not be any " + "deferred work.", + (stagingNeeded == FALSE)); + } +#endif + + } // while(stagingNeeded) + + Release(&pFxDriverGlobals); + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Exit WDFDMATRANSACTION %p, " + "%!STATUS!", dmaTransaction, + status); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaPacketTransaction::TransferCompleted( + VOID + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + // + // Flush the buffers + // + status = FlushAdapterBuffers(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "FlushAdapterBuffers on WDFDMATRANSACTION %p " + "failed, %!STATUS!", + GetHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + + return status; +} + +// ---------------------------------------------------------------------------- +// ------------------- SYSTEM DMA SECTION ------------------------------------- +// ---------------------------------------------------------------------------- + +FxDmaSystemTransaction::FxDmaSystemTransaction( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ExtraSize, + __in FxDmaEnabler *DmaEnabler + ) : + FxDmaPacketTransaction(FxDriverGlobals, sizeof(FxDmaSystemTransaction), ExtraSize, DmaEnabler) +{ + return; +} + +_Must_inspect_result_ +NTSTATUS +FxDmaSystemTransaction::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDmaEnabler* DmaEnabler, + __out WDFDMATRANSACTION* Transaction + ) +{ + FxDmaPacketTransaction* pTransaction; + WDFOBJECT hTransaction; + NTSTATUS status; + + pTransaction = new (FxDriverGlobals, Attributes, DmaEnabler->GetTransferContextSize()) + FxDmaSystemTransaction(FxDriverGlobals, DmaEnabler->GetTransferContextSize(), DmaEnabler); + + if (pTransaction == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Could not allocate memory for WDFTRANSACTION, %!STATUS!", status); + return status; + } + + // + // Commit and apply the attributes + // + status = pTransaction->Commit(Attributes, &hTransaction, DmaEnabler); + if (NT_SUCCESS(status)) { + *Transaction = (WDFDMATRANSACTION)hTransaction; + } + else { + // + // This will properly clean up the target's state and free it + // + pTransaction->DeleteFromFailedCreate(); + } + + return status; +} + +BOOLEAN +FxDmaSystemTransaction::PreMapTransfer( + VOID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + BOOLEAN result = TRUE; + + if (m_ConfigureChannelFunction.Method != NULL) { + // + // Invoke the callback. If it returns false then the driver has + // completed the transaction in the callback and we must abort + // processing. + // + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Invoking ConfigureChannel callback %p (context " + "%p) for WDFDMATRANSACTION %p.", + m_ConfigureChannelFunction.Method, + m_ConfigureChannelContext, + GetHandle()); + } + + result = m_ConfigureChannelFunction.Invoke( + GetHandle(), + m_DmaEnabler->m_DeviceBase->GetHandle(), + m_ConfigureChannelContext, + m_CurrentFragmentMdl, + m_CurrentFragmentOffset, + m_CurrentFragmentLength + ); + } + + return result; +} + + +PDMA_COMPLETION_ROUTINE +FxDmaSystemTransaction::GetTransferCompletionRoutine( + VOID + ) +{ + if (m_TransferCompleteFunction.Method == NULL) { + return NULL; + } + else { + return _SystemDmaCompletion; + } +} + +VOID +FxDmaSystemTransaction::CallEvtDmaCompleted( + __in DMA_COMPLETION_STATUS Status + ) +{ + // + // Call the TransferComplete callback to indicate that the + // transfer was aborted. + // + m_TransferCompleteFunction.Invoke( + GetHandle(), + m_DmaEnabler->m_Device->GetHandle(), + m_TransferCompleteContext, + m_DmaDirection, + Status + ); +} + +VOID +FxDmaTransactionBase::GetTransferInfo( + __out_opt ULONG *MapRegisterCount, + __out_opt ULONG *ScatterGatherElementCount + ) +{ + if (m_State != FxDmaTransactionStateInitialized) { + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p state %!FxDmaTransactionState! " + "is invalid", GetHandle(), m_State); + + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // specific type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + + DMA_TRANSFER_INFO info = {0}; + + + + + + + if (m_DmaEnabler->UsesDmaV3()) { + + // + // Ask the HAL for information about the MDL and how many resources + // it will require to transfer. + // + m_AdapterInfo->AdapterObject->DmaOperations->GetDmaTransferInfo( + m_AdapterInfo->AdapterObject, + m_StartMdl, + m_StartOffset, + (ULONG) this->m_TransactionLength, + this->m_DmaDirection == WDF_DMA_DIRECTION::WdfDmaDirectionWriteToDevice, + &info + ); + } else { + size_t offset = m_StartOffset; + size_t length = m_TransactionLength; + + // + // Walk through the MDL chain and make a worst-case computation of + // the number of scatter gather entries and map registers the + // transaction would require. + // + for(PMDL mdl = m_StartMdl; + mdl != NULL && length != 0; + mdl = mdl->Next) { + + size_t byteCount = MmGetMdlByteCount(mdl); + if (byteCount <= offset) { + offset -= byteCount; + } else { + ULONG_PTR startVa = (ULONG_PTR) MmGetMdlVirtualAddress(mdl); + + startVa += offset; + byteCount -= offset; + + info.V1.MapRegisterCount += + (ULONG) ADDRESS_AND_SIZE_TO_SPAN_PAGES( + startVa, + min(byteCount, length) + ); + + length -= min(byteCount, length); + } + } + + info.V1.ScatterGatherElementCount = info.V1.MapRegisterCount; + } + + if (ARGUMENT_PRESENT(MapRegisterCount)) { + *MapRegisterCount = info.V1.MapRegisterCount; + } + + if (ARGUMENT_PRESENT(ScatterGatherElementCount)) { + *ScatterGatherElementCount = info.V1.ScatterGatherElementCount; + } + + return; +} + +VOID +FxDmaSystemTransaction::_SystemDmaCompletion( + __in PDMA_ADAPTER /* DmaAdapter */, + __in PDEVICE_OBJECT /* DeviceObject */, + __in PVOID CompletionContext, + __in DMA_COMPLETION_STATUS Status + ) +{ + FxDmaSystemTransaction* transaction = (FxDmaSystemTransaction*) CompletionContext; + PFX_DRIVER_GLOBALS pFxDriverGlobals = transaction->GetDriverGlobals(); + KIRQL oldIrql; + BOOLEAN completionDeferred; + + // + // Lock the transfer state so that a staging or cancelling thread + // cannot change it. + // + transaction->LockTransferState(&oldIrql); + + ASSERTMSG("Completion state was already set", + (transaction->m_TransferState.CompletionStatus == + UNDEFINED_DMA_COMPLETION_STATUS)); + ASSERTMSG("Deferred completion is already pending", + (transaction->m_TransferState.RerunCompletion == FALSE)); + + // + // If a staging is in progress then defer the completion. + // + if (transaction->m_TransferState.CurrentStagingThread != NULL) { + transaction->m_TransferState.CompletionStatus = Status; + transaction->m_TransferState.RerunCompletion = TRUE; + completionDeferred = TRUE; + } + else { + completionDeferred = FALSE; + } + + transaction->UnlockTransferState(oldIrql); + + // + // Process the old state. + // + if (completionDeferred == TRUE) { + // + // The staging thread has not moved past EvtProgramDma. The staging thread + // will detect the state change and call the completion routine. + // + // Nothing to do in this case. + // + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Deferring DmaCompleted callback for WDFDMATRANSACTION %p" + "(status %x)", + transaction->GetHandle(), + Status); + } + } + else { + // + // Completion occurred while the transfer was running or + // being cancelled. Call the completion routine. + // + // Note: a cancel when in programming state leaves the + // state as programming. that we're not in programming + // means we don't need to worry about racing with + // EvtProgramDma. + // + + if (pFxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDMA, + "Invoking DmaCompleted callback %p (context %p) " + "for WDFDMATRANSACTION %p (status %x)", + transaction->m_TransferCompleteFunction.Method, + transaction->m_TransferCompleteContext, + transaction->GetHandle(), + Status); + } + transaction->CallEvtDmaCompleted(Status); + } +} + +VOID +FxDmaSystemTransaction::StopTransfer( + VOID + ) +{ + // + // Mark the transfer cancelled so we have a record of it even if + // a racing call to FlushAdapterBuffers clears the TC. + // + m_IsCancelled = TRUE; + + // + // Cancel the system DMA transfer. This arranges for one of two things + // to happen: + // * the next call to MapTransfer will fail + // * the DMA completion routine will run + // + if (CancelMappedTransfer() == FALSE) { + + // + // The cancel failed. Someone has already stopped this transfer. + // That's illegal. + // + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFDMATRANSACTION %p has already been stopped", + GetHandle()); + + if (pFxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierBugCheck(pFxDriverGlobals, // globals + WDF_DMA_FATAL_ERROR, // type + (ULONG_PTR) GetObjectHandle(), // parm 2 + (ULONG_PTR) m_State); // parm 3 + } + } +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmatransactionapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmatransactionapi.cpp new file mode 100644 index 00000000000..7eff523e702 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dma/base/fxdmatransactionapi.cpp @@ -0,0 +1,1251 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaTransactionAPI.cpp + +Abstract: + + Base for WDF DMA Transaction APIs + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#include "FxDmaPCH.hpp" + +extern "C" { +#include "FxDmaTransactionAPI.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaTransactionCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMAENABLER DmaEnabler, + __in_opt + WDF_OBJECT_ATTRIBUTES * Attributes, + __out + WDFDMATRANSACTION * DmaTransactionHandle + ) +{ + NTSTATUS status; + FxDmaEnabler* pDmaEnabler; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaEnabler, + FX_TYPE_DMA_ENABLER, + (PVOID *) &pDmaEnabler, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DmaTransactionHandle); + + *DmaTransactionHandle = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED + ); + if (!NT_SUCCESS(status)) { + return status; + } + + switch (pDmaEnabler->GetProfile()) + { + case WdfDmaProfilePacket: + case WdfDmaProfilePacket64: + status = FxDmaPacketTransaction::_Create(pFxDriverGlobals, + Attributes, + pDmaEnabler, + DmaTransactionHandle); + break; + + case WdfDmaProfileScatterGather: + case WdfDmaProfileScatterGather64: + case WdfDmaProfileScatterGatherDuplex: + case WdfDmaProfileScatterGather64Duplex: + status = FxDmaScatterGatherTransaction::_Create( + pFxDriverGlobals, + Attributes, + pDmaEnabler, + DmaTransactionHandle + ); + break; + + case WdfDmaProfileSystem: + case WdfDmaProfileSystemDuplex: + status = FxDmaSystemTransaction::_Create(pFxDriverGlobals, + Attributes, + pDmaEnabler, + DmaTransactionHandle); + break; + + default: + NT_ASSERTMSG("Unknown profile for DMA enabler", FALSE); + status = STATUS_UNSUCCESSFUL; + break; + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +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; +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaTransactionInitializeUsingOffset)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + __in + WDF_DMA_DIRECTION DmaDirection, + __in + PMDL Mdl, + __in + size_t Offset, + __in + __drv_when(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ) +{ + // + // Stub this out by calling the regular initialize method. Eventually + // the regular initialize method will call this instead. + // + + return WDFEXPORT(WdfDmaTransactionInitialize)( + DriverGlobals, + DmaTransaction, + EvtProgramDmaFunction, + DmaDirection, + Mdl, + (PVOID) (((ULONG_PTR) MmGetMdlVirtualAddress(Mdl)) + Offset), + Length + ); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaTransactionInitialize)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + __in + WDF_DMA_DIRECTION DmaDirection, + __in + PMDL Mdl, + + //__drv_when(DmaDirection == WdfDmaDirectionReadFromDevice, __out_bcount(Length)) + //__drv_when(DmaDirection == WdfDmaDirectionWriteToDevice, __in_bcount(Length)) + __in + PVOID VirtualAddress, + __in + __drv_when(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ) +{ + NTSTATUS status; + FxDmaTransactionBase * pDmaTrans; + PUCHAR pVA; + ULONG mdlLength; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, EvtProgramDmaFunction); + FxPointerNotNull(pFxDriverGlobals, Mdl); + + if (Length == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Can't initialize WDFDMATRANSACTION 0x%p with " + "zero length transfer", DmaTransaction); + return status; + } + + if (DmaDirection != WdfDmaDirectionReadFromDevice && + DmaDirection != WdfDmaDirectionWriteToDevice) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Initialization of WDFDMATRANSACTION 0x%p,DmaDirection 0x%x is an " + "invalid value, %!STATUS!", DmaTransaction, DmaDirection, status); + return status; + } + + // + // Make sure the VirtualAddress is within the first MDL bounds. + // + pVA = (PUCHAR) MmGetMdlVirtualAddress(Mdl); + mdlLength = MmGetMdlByteCount(Mdl); + + if (VirtualAddress < pVA || + VirtualAddress >= WDF_PTR_ADD_OFFSET(pVA, mdlLength)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "VirtualAddress %p is not within the Mdl bounds, StartVA (%p) + " + "ByteCount (0x%x), %!STATUS! ", + VirtualAddress, pVA, mdlLength, status); + + return status; + } + + // + // Get the DmaEnabler + // + FxObjectHandleGetPtr(pFxDriverGlobals, + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + if (pDmaTrans->GetDmaEnabler()->SupportsChainedMdls() == FALSE) { + // + // Make sure the MDL is not a chained MDL by checking + // to see if the virtual address and the length + // are within bounds. + // + if (WDF_PTR_ADD_OFFSET(VirtualAddress, Length) > + WDF_PTR_ADD_OFFSET(pVA, mdlLength)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "VirtualAddress+Length (%p+%I64d) is out of bounds of MDL VA + MDL " + "Byte count (max address is %p). " + "Possibly a chained MDL, %!STATUS!", + VirtualAddress, Length, + WDF_PTR_ADD_OFFSET(pVA, mdlLength), status); + + return status; + } + } + + status = pDmaTrans->Initialize(EvtProgramDmaFunction, + DmaDirection, + Mdl, + WDF_PTR_GET_OFFSET( + MmGetMdlVirtualAddress(Mdl), + VirtualAddress + ), + (ULONG) Length); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "WDFTANSACTION 0x%p initialization failed: " + "%!STATUS!", DmaTransaction, status); + } + + return status; +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaTransactionExecute)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in_opt + WDFCONTEXT Context + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + return pDmaTrans->Execute(Context); +} + +__success(TRUE) +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaTransactionRelease)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + // + // Release map registers allocated for this specific transaction, + // but not map registers which were allocated through + // AllocateResources. + // + pDmaTrans->ReleaseForReuse(FALSE); + return STATUS_SUCCESS; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfDmaTransactionDmaCompleted)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __out + NTSTATUS * pStatus + ) +{ + FxDmaTransactionBase * pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + FxPointerNotNull(pDmaTrans->GetDriverGlobals(), pStatus); + + + // + // Indicate this DMA has been completed. + // + return pDmaTrans->DmaCompleted(0, pStatus, FxDmaCompletionTypeFull); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfDmaTransactionDmaCompletedWithLength)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + size_t TransferredLength, + __out + NTSTATUS * pStatus + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + FxPointerNotNull(pDmaTrans->GetDriverGlobals(), pStatus); + + // + // Indicate this DMA transfer has been completed. + // + return pDmaTrans->DmaCompleted(TransferredLength, + pStatus, + FxDmaCompletionTypePartial); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfDmaTransactionDmaCompletedFinal)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + size_t FinalTransferredLength, + __out + NTSTATUS * pStatus + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + FxPointerNotNull(pDmaTrans->GetDriverGlobals(), pStatus); + + // + // Indicate this DMA FinalLength has completed. + // + return pDmaTrans->DmaCompleted(FinalTransferredLength, + pStatus, + FxDmaCompletionTypeAbort); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +size_t +WDFEXPORT(WdfDmaTransactionGetBytesTransferred)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + return pDmaTrans->GetBytesTransferred(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionSetMaximumLength)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + size_t MaximumLength + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + pDmaTrans->SetMaximumFragmentLength(MaximumLength); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFREQUEST +WDFEXPORT(WdfDmaTransactionGetRequest)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + FxRequest* pRequest; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + pRequest = pDmaTrans->GetRequest(); + + if (pRequest != NULL) { + return pRequest->GetHandle(); + } + else { + return NULL; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +size_t +WDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + return pDmaTrans->GetCurrentFragmentLength(); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfDmaTransactionGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans); + + return pDmaTrans->GetDmaEnabler()->GetDeviceHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in_opt + PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL ConfigureRoutine, + __in_opt + PVOID ConfigureContext + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Verify that the transaction belongs to a system profile enabler. + // + + WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile(); + if ((profile != WdfDmaProfileSystem) && + (profile != WdfDmaProfileSystemDuplex)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on non-system-profile " + "WDFDMATRANSACTION (%p) (transaction profile " + "is %!WDF_DMA_PROFILE!).", + DmaTransaction, + profile); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Cast the transaction to the right sub-type now that we've verified the + // profile. + // + + FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans; + systemTransaction->SetConfigureChannelCallback(ConfigureRoutine, + ConfigureContext); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in_opt + PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE DmaCompletionRoutine, + __in_opt + PVOID DmaCompletionContext + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Verify that the transaction belongs to a system profile enabler. + // + + WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile(); + if ((profile != WdfDmaProfileSystem) && + (profile != WdfDmaProfileSystemDuplex)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on non-system-profile " + "WDFDMATRANSACTION (%p) (transaction profile " + "is %!WDF_DMA_PROFILE!).", + DmaTransaction, + profile); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Cast the transaction to the right sub-type now that we've verified the + // profile. + // + + FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans; + systemTransaction->SetTransferCompleteCallback(DmaCompletionRoutine, + DmaCompletionContext); + +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + ULONG Offset + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Verify that the transaction belongs to a system profile enabler. + // + + WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile(); + if ((profile != WdfDmaProfileSystem) && + (profile != WdfDmaProfileSystemDuplex)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on non-system-profile " + "WDFDMATRANSACTION (%p) (transaction profile " + "is %!WDF_DMA_PROFILE!).", + DmaTransaction, + profile); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Cast the transaction to the right sub-type now that we've verified the + // profile. + // + + FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans; + systemTransaction->SetDeviceAddressOffset(Offset); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PVOID +WDFEXPORT(WdfDmaTransactionWdmGetTransferContext)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! for WDFDMATRANSACTION %p " + "because the parent WDFDMAENABLER (%p) is not " + "configured to use DMA version 3.", + DmaTransaction, + pDmaTrans->GetDmaEnabler()->GetHandle()); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + + FxDmaTransactionState state = pDmaTrans->GetTransactionState(); + + if ((state == FxDmaTransactionStateInvalid) || + (state == FxDmaTransactionStateCreated) || + (state == FxDmaTransactionStateReleased) || + (state == FxDmaTransactionStateDeleted)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on WDFDMATRANSACTION %p " + "becuase it is uninitialized, reused, deleted " + "(state is %!FxDmaTransactionState!).", + DmaTransaction, + state + ); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + + return pDmaTrans->GetTransferContext(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionGetTransferInfo)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __out_opt + ULONG* MapRegisterCount, + __out_opt + ULONG* ScatterGatherElementCount + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + pDmaTrans->GetTransferInfo(MapRegisterCount, ScatterGatherElementCount); +} + +// +// Stubbed WDF 1.11 DMA DDIs start here. +// + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionSetImmediateExecution)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + BOOLEAN UseImmediateExecution + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) + { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! for WDFDMATRANSACTION %p " + "because the parent WDFDMAENABLER (%p) is not " + "configured to use DMA version 3.", + DmaTransaction, + pDmaTrans->GetDmaEnabler()->GetHandle()); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pDmaTrans->SetImmediateExecution(UseImmediateExecution); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDmaTransactionAllocateResources)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction, + __in + WDF_DMA_DIRECTION DmaDirection, + __in + ULONG RequiredMapRegisters, + __in + PFN_WDF_RESERVE_DMA EvtReserveDmaFunction, + __in + PVOID EvtReserveDmaContext + ) +{ + FxDmaPacketTransaction* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Only valid if DMA V3 is enabled. + // + + if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) + { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on WDFDMATRANSACTION %p " + "because WDFDMAENABLER %p was not configured " + "for DMA version 3 - %!STATUS!.", + DmaTransaction, + pDmaTrans->GetDmaEnabler()->GetHandle(), + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Only valid for packet or system profile transactions. + // + WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile(); + if ((profile != WdfDmaProfilePacket) && + (profile != WdfDmaProfilePacket64) && + (profile != WdfDmaProfileSystem) && + (profile != WdfDmaProfileSystemDuplex)) { + + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on non packet or system " + "profile WDFDMATRANSACTION (%p) (transaction " + "profile is %!WDF_DMA_PROFILE!) - %!STATUS!.", + DmaTransaction, + profile, + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Validate the direction value. + // + if (DmaDirection != WdfDmaDirectionReadFromDevice && + DmaDirection != WdfDmaDirectionWriteToDevice) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Allocation of DMA adapter for WDFDMATRANSACTION 0x%p, " + "DmaDirection 0x%x is an invalid value, %!STATUS!", + DmaTransaction, DmaDirection, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + FxPointerNotNull(pFxDriverGlobals, EvtReserveDmaFunction); + + status = pDmaTrans->ReserveAdapter(RequiredMapRegisters, + DmaDirection, + EvtReserveDmaFunction, + EvtReserveDmaContext); + + return status; +} +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionFreeResources)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaPacketTransaction* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Only valid for packet or system profile transactions. + // + WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile(); + if ((profile != WdfDmaProfilePacket) && + (profile != WdfDmaProfilePacket64) && + (profile != WdfDmaProfileSystem) && + (profile != WdfDmaProfileSystemDuplex)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on non packet or system " + "profile WDFDMATRANSACTION (%p) (transaction " + "profile is %!WDF_DMA_PROFILE!).", + DmaTransaction, + profile); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Only valid if DMA V3 is enabled. + // + + if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) + { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on WDFDMATRANSACTION %p " + "because WDFDMAENABLER %p was not configured " + "for DMA version 3", + DmaTransaction, + pDmaTrans->GetDmaEnabler()->GetHandle()); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pDmaTrans->ReleaseAdapter(); + + return; +} +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfDmaTransactionCancel)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Only valid if the enabler uses DMA v3 + // + + if (pDmaTrans->GetDmaEnabler()->UsesDmaV3() == FALSE) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! WDFDMATRANSACTION (%p) " + "because enabler is not using DMA version 3", + DmaTransaction); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return FALSE; + } + + return pDmaTrans->CancelResourceAllocation(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDmaTransactionStopSystemTransfer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDMATRANSACTION DmaTransaction + ) +{ + FxDmaTransactionBase* pDmaTrans; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + DmaTransaction, + FX_TYPE_DMA_TRANSACTION, + (PVOID *) &pDmaTrans, + &pFxDriverGlobals); + + // + // Verify that the transaction belongs to a system profile enabler. + // + + WDF_DMA_PROFILE profile = pDmaTrans->GetDmaEnabler()->GetProfile(); + if ((profile != WdfDmaProfileSystem) && + (profile != WdfDmaProfileSystemDuplex)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDMA, + "Cannot call %!FUNC! on non-system-profile " + "WDFDMATRANSACTION (%p) (transaction profile " + "is %!WDF_DMA_PROFILE!).", + DmaTransaction, + profile); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Cast the transaction to the right sub-type now that we've verified the + // profile. + // + + FxDmaSystemTransaction* systemTransaction = (FxDmaSystemTransaction*) pDmaTrans; + systemTransaction->StopTransfer(); + return; +} + + + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/dynamic/version/version.cpp b/sdk/lib/drivers/wdf/kmdf/src/dynamic/version/version.cpp new file mode 100644 index 00000000000..73a03befd65 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/dynamic/version/version.cpp @@ -0,0 +1,760 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + Version.cpp + +Abstract: + + This module forms a loadable library from the WDF core libs + +Revision History: + +--*/ + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +} + +#define FX_DYNAMICS_GENERATE_TABLE 1 + +#include "fx.hpp" + +#include +#include "fxbugcheck.h" +#include "wdfversionlog.h" + +#define DRIVER_OBJECT_EXTENSION_IDENTIFIER DriverEntry +#define DRIVER_PARAMETERS L"Parameters" +#define REGISTRY_KMDF_MAJOR_VERSION L"MajorVersion" +#define REGISTRY_KMDF_MINOR_VERSION L"MinorVersion" +#define REGISTRY_KMDF_BUILD_NUMBER L"BuildNumber" + +//----------------------------------------------------------------------------- +// These header files are referenced in order to make internal structures +// available in public symbols. Various WDFKD debug commands use these +// internal structures to provide information about WDF. +//----------------------------------------------------------------------------- +#include "FxIFR.h" + +extern "C" { + +// +// This is the collection of all structure/types to be make public. +// This union forces the structure type-info into the PDB file. +// +union { + + WDF_IFR_HEADER * typeWDF_IFR_HEADER; + WDF_IFR_RECORD * typeWDF_IFR_RECORD; + WDF_IFR_OFFSET * typeWDF_IFR_OFFSET; + WDF_BIND_INFO * typeWDF_BIND_INFO; + WDF_OBJECT_CONTEXT_TYPE_INFO * typeWDF_OBJECT_CONTEXT_TYPE_INFO; + WDF_POWER_ROUTINE_TIMED_OUT_DATA * typeWDF_POWER_ROUTINE_TIMED_OUT_DATA; + WDF_BUGCHECK_CODES * typeWDF_BUGCHECK_CODES; + WDF_REQUEST_FATAL_ERROR_CODES * typeWDF_REQUEST_FATAL_ERROR_CODES; + FX_OBJECT_INFO * typeFX_OBJECT_INFO; + FX_POOL_HEADER * typeFX_POOL_HEADER; + FX_POOL * typeFX_POOL; + FxObject * typeFxObject; + FxContextHeader * typeFxContextHeader; + FX_DUMP_DRIVER_INFO_ENTRY * typeFX_DUMP_DRIVER_INFO_ENTRY; + FxTargetSubmitSyncParams * typeFxTargetSubmitSyncParams; + +} uAllPublicTypes; + +} // extern "C" end + +//----------------------------------------- ------------------------------------ + +extern "C" { + +#include "FxDynamics.h" + +#include "FxLibraryCommon.h" + +#define KMDF_DEFAULT_NAME "Wdf" ## \ + LITERAL(__WDF_MAJOR_VERSION_STRING) ## \ + "000" //minor version + +//----------------------------------------------------------------------------- +// local prototype definitions +//----------------------------------------------------------------------------- +extern "C" +DRIVER_UNLOAD DriverUnload; + +extern "C" +DRIVER_INITIALIZE DriverEntry; + +extern "C" +__drv_dispatchType(IRP_MJ_CREATE) +__drv_dispatchType(IRP_MJ_CLEANUP) +__drv_dispatchType(IRP_MJ_CLOSE) +DRIVER_DISPATCH FxLibraryDispatch; + +RTL_OSVERSIONINFOW gOsVersion = { sizeof(RTL_OSVERSIONINFOW) }; + +ULONG WdfLdrDbgPrintOn = 0; + +PCHAR WdfLdrType = KMDF_DEFAULT_NAME; + +} // extern "C" + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_COMMISSION( + VOID + ); + +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_DECOMMISSION( + VOID + ); + +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_REGISTER_CLIENT( + __inout PWDF_BIND_INFO Info, + __deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + __deref_inout PVOID * Context + ); + +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_UNREGISTER_CLIENT( + __in PWDF_BIND_INFO Info, + __in PWDF_DRIVER_GLOBALS WdfDriverGlobals + ); + +extern "C" +VOID +FxLibraryDeleteDevice( + VOID + ); + +VOID +FxLibraryCleanup( + VOID + ); + +VOID +WdfWriteKmdfVersionToRegistry( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath + ); + +VOID +WdfDeleteKmdfVersionFromRegistry( + __in PDRIVER_OBJECT DriverObject + ); + +typedef struct _DRV_EXTENSION { + UNICODE_STRING ParametersRegistryPath; +} DRV_EXTENSION, *PDRV_EXTENSION; + +//----------------------------------------------------------------------------- +// Library registeration information +//----------------------------------------------------------------------------- +extern "C" { +#pragma prefast(suppress:__WARNING_ENCODE_MEMBER_FUNCTION_POINTER, "kernel component."); +WDF_LIBRARY_INFO WdfLibraryInfo = { + sizeof(WDF_LIBRARY_INFO), + (PFNLIBRARYCOMMISSION) WDF_LIBRARY_COMMISSION, + (PFNLIBRARYDECOMMISSION) WDF_LIBRARY_DECOMMISSION, + (PFNLIBRARYREGISTERCLIENT) WDF_LIBRARY_REGISTER_CLIENT, + (PFNLIBRARYUNREGISTERCLIENT) WDF_LIBRARY_UNREGISTER_CLIENT, + { __WDF_MAJOR_VERSION, __WDF_MINOR_VERSION, __WDF_BUILD_NUMBER } +}; + +} // extern "C" end + +extern "C" +NTSTATUS +FxLibraryDispatch ( + __in struct _DEVICE_OBJECT * DeviceObject, + __in PIRP Irp + ) +{ + NTSTATUS status; + + UNREFERENCED_PARAMETER(DeviceObject); + ASSERT(FxLibraryGlobals.LibraryDeviceObject == DeviceObject); + + status = STATUS_INVALID_DEVICE_REQUEST; + + switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction) { + case IRP_MJ_CREATE: + // + // To limit our exposure for this device object, only allow kernel mode + // creates. + // + if (Irp->RequestorMode == KernelMode) { + status = STATUS_SUCCESS; + } + break; + + case IRP_MJ_CLEANUP: + case IRP_MJ_CLOSE: + // + // Since we allowed a create to succeed, succeed the cleanup and close + // + status = STATUS_SUCCESS; + break; + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = 0x0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- + +#define KMDF_DEVICE_NAME L"\\Device\\KMDF" + +_Must_inspect_result_ +NTSTATUS +FxLibraryCreateDevice( + __in PUNICODE_STRING DeviceName + ) +{ + NTSTATUS status; + ULONG i; + + i = 0; + + // + // Repeatedly try to create a named device object until we run out of buffer + // space or we succeed. + // + do { + status = RtlUnicodeStringPrintf(DeviceName, L"%s%d", KMDF_DEVICE_NAME, i++); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Create a device with no device extension + // + status = IoCreateDevice( + FxLibraryGlobals.DriverObject, + 0, + DeviceName, + FILE_DEVICE_UNKNOWN, + 0, + FALSE, + &FxLibraryGlobals.LibraryDeviceObject + ); + } while (STATUS_OBJECT_NAME_COLLISION == status); + + if (NT_SUCCESS(status)) { + // + // Clear the initializing bit now because the loader will attempt to + // open the device before we return from DriverEntry + // + ASSERT(FxLibraryGlobals.LibraryDeviceObject != NULL); + FxLibraryGlobals.LibraryDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + } + + return status; +} + +extern "C" +VOID +FxLibraryDeleteDevice( + VOID + ) +{ + FxLibraryCleanup(); +} + +VOID +FxLibraryCleanup( + VOID + ) +{ + if (FxLibraryGlobals.LibraryDeviceObject != NULL) { + IoDeleteDevice(FxLibraryGlobals.LibraryDeviceObject); + FxLibraryGlobals.LibraryDeviceObject = NULL; + } +} + +extern "C" +NTSTATUS +DriverEntry( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath + ) +{ + UNICODE_STRING name; + UNICODE_STRING string; + NTSTATUS status; + + // + // This creates a local buffer which is big enough to hold a copy of the + // constant string assigned to it. It does not point to the constant + // string. As such, it is a writeable buffer. + // + // NOTE: KMDF_DEVICE_NAME L"XXXX" creates a concatenated string of + // KMDF_DEVICE_NAME + L"XXXX". This is done to give us room for + // appending a number up to 4 digits long after KMDF_DEVICE_NAME if + // you want a null terminated string, 5 digits long if the string is + // not null terminated (as is the case for a UNICODE_STRING) + // + WCHAR buffer[] = KMDF_DEVICE_NAME L"XXXX"; + + // + // Initialize global to make NonPagedPool be treated as NxPool on Win8 + // and NonPagedPool on down-level + // + ExInitializeDriverRuntime(DrvRtPoolNxOptIn); + + RtlInitUnicodeString(&string, WDF_REGISTRY_DBGPRINT_ON); + + // + // Determine if debug prints are on. + // + (void) WdfLdrDiagnosticsValueByNameAsULONG(&string, &WdfLdrDbgPrintOn); + + __Print(("DriverEntry\n")); + + DriverObject->DriverUnload = DriverUnload; + + FxLibraryGlobals.DriverObject = DriverObject; + + DriverObject->MajorFunction[IRP_MJ_CREATE] = FxLibraryDispatch; + DriverObject->MajorFunction[IRP_MJ_CLEANUP] = FxLibraryDispatch; + DriverObject->MajorFunction[IRP_MJ_CLOSE] = FxLibraryDispatch; + + RtlZeroMemory(&name, sizeof(name)); + name.Buffer = buffer; + name.Length = 0x0; + name.MaximumLength = sizeof(buffer); + + // + // We use the string when we declare the buffer to get the right sized + // buffer. Now we want to make sure there are no contents before we + // use it to create a device object. + // + RtlZeroMemory(buffer, sizeof(buffer)); + + status = FxLibraryCreateDevice(&name); + if (!NT_SUCCESS(status)) { + __Print(("ERROR: FxLibraryCreateDevice failed with Status 0x%x\n", status)); + return status; + } + + // + // Register this library with WdfLdr + // + // NOTE: Once WdfRegisterLibrary returns NT_SUCCESS() we must return + // NT_SUCCESS from DriverEntry! + // + status = WdfRegisterLibrary( &WdfLibraryInfo, RegistryPath, &name ); + if (!NT_SUCCESS(status)) { + __Print(("ERROR: WdfRegisterLibrary failed with Status 0x%x\n", status)); + FxLibraryCleanup(); + return status; + } + + // + // Write KMDF version to registry + // + WdfWriteKmdfVersionToRegistry(DriverObject, RegistryPath); + + return STATUS_SUCCESS; +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +VOID +DriverUnload( + __in PDRIVER_OBJECT DriverObject + ) +{ + __Print(("DriverUnload\n")); + + // + // Delete KMDF version from registry before destroying the Driver Object + // + WdfDeleteKmdfVersionFromRegistry(DriverObject); + + // + // Make sure everything is deleted. Since the driver is considered a legacy + // driver, it can be unloaded while there are still outstanding device objects. + // + FxLibraryCleanup(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_COMMISSION( + VOID + ) +{ + return FxLibraryCommonCommission(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_DECOMMISSION( + VOID + ) +{ + return FxLibraryCommonDecommission(); +} + +#define EVTLOG_MESSAGE_SIZE 70 +#define RAW_DATA_SIZE 4 + +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_REGISTER_CLIENT( + __in PWDF_BIND_INFO Info, + __deref_out PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + __deref_inout PVOID * Context + ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WCHAR insertString[EVTLOG_MESSAGE_SIZE]; + ULONG rawData[RAW_DATA_SIZE]; + PCLIENT_INFO clientInfo = NULL; + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n")); + + clientInfo = (PCLIENT_INFO)*Context; + *Context = NULL; + + ASSERT(Info->Version.Major == WdfLibraryInfo.Version.Major); + + // + // NOTE: If the currently loaded library < drivers minor version fail the load + // instead of binding to a lower minor version. The reason for that if there + // is a newer API or new contract change made the driver shouldn't be using older + // API than it was compiled with. + // + + if (Info->Version.Minor > WdfLibraryInfo.Version.Minor) { + status = RtlStringCchPrintfW(insertString, + RTL_NUMBER_OF(insertString), + L"Driver Version: %d.%d Kmdf Lib. Version: %d.%d", + Info->Version.Major, + Info->Version.Minor, + WdfLibraryInfo.Version.Major, + WdfLibraryInfo.Version.Minor); + if (!NT_SUCCESS(status)) { + __Print(("ERROR: RtlStringCchPrintfW failed with Status 0x%x\n", status)); + return status; + } + rawData[0] = Info->Version.Major; + rawData[1] = Info->Version.Minor; + rawData[2] = WdfLibraryInfo.Version.Major; + rawData[3] = WdfLibraryInfo.Version.Minor; + + LibraryLogEvent(FxLibraryGlobals.DriverObject, + WDFVER_MINOR_VERSION_NOT_SUPPORTED, + STATUS_OBJECT_TYPE_MISMATCH, + insertString, + rawData, + sizeof(rawData) ); + // + // this looks like the best status to return + // + return STATUS_OBJECT_TYPE_MISMATCH; + + } + + status = FxLibraryCommonRegisterClient(Info, + WdfDriverGlobals, + clientInfo); + + if (NT_SUCCESS(status)) { + // + // The context will be a pointer to FX_DRIVER_GLOBALS + // + *Context = GetFxDriverGlobals(*WdfDriverGlobals); + + // + // Set the WDF_BIND_INFO structure pointer in FxDriverGlobals + // + pFxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals); + pFxDriverGlobals->WdfBindInfo = Info; + } + + return status; +} + + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +_Must_inspect_result_ +NTSTATUS +WDF_LIBRARY_UNREGISTER_CLIENT( + __in PWDF_BIND_INFO Info, + __in PWDF_DRIVER_GLOBALS WdfDriverGlobals + ) +{ + return FxLibraryCommonUnregisterClient(Info, WdfDriverGlobals); +} + +VOID +WdfWriteKmdfVersionToRegistry( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath + ) +{ + NTSTATUS status; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE driverKey; + HANDLE parametersKey; + UNICODE_STRING valueName; + UNICODE_STRING parametersPath; + PDRV_EXTENSION driverExtension; + + driverKey = NULL; + parametersKey = NULL; + driverExtension = NULL; + + RtlInitUnicodeString(¶metersPath, DRIVER_PARAMETERS); + + InitializeObjectAttributes(&objectAttributes, + RegistryPath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + status = ZwOpenKey(&driverKey, KEY_CREATE_SUB_KEY, &objectAttributes); + if (!NT_SUCCESS(status)) { + __Print(("WdfWriteKmdfVersionToRegistry: Failed to open HKLM\\%S\n", + RegistryPath->Buffer)); + goto out; + } + + InitializeObjectAttributes(&objectAttributes, + ¶metersPath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + driverKey, + NULL); + + // + // Open or create key and get a handle + // + status = ZwCreateKey(¶metersKey, + KEY_SET_VALUE, + &objectAttributes, + 0, + (PUNICODE_STRING) NULL, + REG_OPTION_VOLATILE, + NULL); + + if (!NT_SUCCESS(status)) { + __Print(("WdfWriteKmdfVersionToRegistry: Failed to open HKLM\\%S\\%S\n", + RegistryPath->Buffer, parametersPath.Buffer)); + goto out; + } + + // + // Set Major Version + // + RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MAJOR_VERSION); + + status = ZwSetValueKey(parametersKey, + &valueName, + 0, + REG_DWORD, + &WdfLibraryInfo.Version.Major, + sizeof(WdfLibraryInfo.Version.Major)); + + if (!NT_SUCCESS(status)) { + __Print(("WdfWriteKmdfVersionToRegistry: Failed to set Major Version\n")); + goto out; + } + + // + // Set Minor Version + // + RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MINOR_VERSION); + + status = ZwSetValueKey(parametersKey, + &valueName, + 0, + REG_DWORD, + &WdfLibraryInfo.Version.Minor, + sizeof(WdfLibraryInfo.Version.Minor)); + + if (!NT_SUCCESS(status)) { + __Print(("WdfWriteKmdfVersionToRegistry: Failed to set Minor Version\n")); + goto out; + } + + + // + // Set Build Number + // + RtlInitUnicodeString(&valueName, REGISTRY_KMDF_BUILD_NUMBER); + + status = ZwSetValueKey(parametersKey, + &valueName, + 0, + REG_DWORD, + &WdfLibraryInfo.Version.Build, + sizeof(WdfLibraryInfo.Version.Build)); + + if (!NT_SUCCESS(status)) { + __Print(("WdfWriteKmdfVersionToRegistry: Failed to set Build Number\n")); + goto out; + } + + // + // Create a Driver Extension to store the registry path, where we write the + // version of the wdf01000.sys that's loaded in memory + // + status = IoAllocateDriverObjectExtension(DriverObject, + (PVOID) DRIVER_OBJECT_EXTENSION_IDENTIFIER, + sizeof(DRV_EXTENSION), + (PVOID *)&driverExtension); + + if (!NT_SUCCESS(status) || driverExtension == NULL) { + goto out; + } + + driverExtension->ParametersRegistryPath.Buffer = (PWCHAR) ExAllocatePoolWithTag( + PagedPool, + RegistryPath->MaximumLength, + FX_TAG); + if (driverExtension->ParametersRegistryPath.Buffer == NULL) { + goto out; + } + + driverExtension->ParametersRegistryPath.MaximumLength = RegistryPath->MaximumLength; + RtlCopyUnicodeString(&(driverExtension->ParametersRegistryPath), RegistryPath); + +out: + if (driverKey != NULL) { + ZwClose(driverKey); + } + + if (parametersKey != NULL) { + ZwClose(parametersKey); + } + + return; +} + +VOID +WdfDeleteKmdfVersionFromRegistry( + __in PDRIVER_OBJECT DriverObject + ) +{ + PUNICODE_STRING registryPath; + OBJECT_ATTRIBUTES objectAttributes; + HANDLE driverKey; + HANDLE parametersKey; + UNICODE_STRING valueName; + NTSTATUS status; + UNICODE_STRING parametersPath; + PDRV_EXTENSION driverExtension; + + RtlInitUnicodeString(¶metersPath, DRIVER_PARAMETERS); + + driverKey = NULL; + parametersKey = NULL; + + driverExtension = (PDRV_EXTENSION)IoGetDriverObjectExtension(DriverObject, + DRIVER_OBJECT_EXTENSION_IDENTIFIER); + + if (driverExtension == NULL || driverExtension->ParametersRegistryPath.Buffer == NULL) { + return; + } + + registryPath = &driverExtension->ParametersRegistryPath; + + InitializeObjectAttributes(&objectAttributes, + registryPath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + status = ZwOpenKey(&driverKey, KEY_SET_VALUE, &objectAttributes); + if (!NT_SUCCESS(status)) { + goto out; + } + + InitializeObjectAttributes(&objectAttributes, + ¶metersPath, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + driverKey, + NULL); + // + // Open the key for deletion + // + status = ZwOpenKey(¶metersKey, + DELETE, + &objectAttributes); + + if (!NT_SUCCESS(status)) { + goto out; + } + + RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MAJOR_VERSION); + ZwDeleteValueKey(parametersKey, &valueName); + + RtlInitUnicodeString(&valueName, REGISTRY_KMDF_MINOR_VERSION); + ZwDeleteValueKey(parametersKey, &valueName); + + RtlInitUnicodeString(&valueName, REGISTRY_KMDF_BUILD_NUMBER); + ZwDeleteValueKey(parametersKey, &valueName); + + ZwDeleteKey(parametersKey); + +out: + if (driverExtension->ParametersRegistryPath.Buffer != NULL) { + ExFreePool(driverExtension->ParametersRegistryPath.Buffer); + } + + if (driverKey != NULL) { + ZwClose(driverKey); + } + + if (parametersKey != NULL) { + ZwClose(parametersKey); + } + + return; +} + diff --git a/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/fxobjectinfokm.cpp b/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/fxobjectinfokm.cpp new file mode 100644 index 00000000000..bc1a90afbfb --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/fxobjectinfokm.cpp @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObjectInfoKm.cpp + +Abstract: + + This file contains object info split from globals.cpp + + This is because objects incorporated in KMDF and UMDF will differ + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "fxobjectpch.hpp" + +#include "FxMemoryBufferPreallocated.hpp" +#include "FxUserObject.hpp" +#include "FxUsbDevice.hpp" +#include "FxUsbPipe.hpp" +#include "FxUsbInterface.hpp" + +extern "C" +{ + +// +// Assumes sorted (by type) order! +// +FX_OBJECT_INFO FxObjectsInfo[] = { + FX_INTERNAL_OBJECT_INFO_ENTRY(FxObject, FX_TYPE_OBJECT), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDriver, FX_TYPE_DRIVER, WDFDRIVER), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDevice, FX_TYPE_DEVICE, WDFDEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoQueue, FX_TYPE_QUEUE, WDFQUEUE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWmiProvider, FX_TYPE_WMI_PROVIDER, WDFWMIPROVIDER), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRegKey, FX_TYPE_REG_KEY, WDFKEY), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxString, FX_TYPE_STRING, WDFSTRING), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRequest, FX_TYPE_REQUEST, WDFREQUEST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxLookasideList, FX_TYPE_LOOKASIDE, WDFLOOKASIDE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMemoryObject, IFX_TYPE_MEMORY, WDFMEMORY), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxIrpQueue, FX_TYPE_IRPQUEUE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUserObject, FX_TYPE_USEROBJECT, WDFOBJECT), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCollection, FX_TYPE_COLLECTION, WDFCOLLECTION), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxVerifierLock, FX_TYPE_VERIFIERLOCK), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxSystemThread, FX_TYPE_SYSTEMTHREAD), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMpDevice, FX_TYPE_MP_DEVICE, WDFDEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDpc, FX_TYPE_DPC, WDFDPC), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxResourceIo, FX_TYPE_RESOURCE_IO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxResourceCm, FX_TYPE_RESOURCE_CM), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxFileObject, FX_TYPE_FILEOBJECT, WDFFILEOBJECT), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxRelatedDevice, FX_TYPE_RELATED_DEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMemoryBufferPreallocated, FX_TYPE_MEMORY_PREALLOCATED, WDFMEMORY), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWaitLock, FX_TYPE_WAIT_LOCK, WDFWAITLOCK), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxSpinLock, FX_TYPE_SPIN_LOCK, WDFSPINLOCK), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWorkItem, FX_TYPE_WORKITEM, WDFWORKITEM), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxInterrupt, FX_TYPE_INTERRUPT, WDFINTERRUPT), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxTimer, FX_TYPE_TIMER, WDFTIMER), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxChildList, FX_TYPE_CHILD_LIST, WDFCHILDLIST), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxSystemWorkItem, FX_TYPE_SYSTEMWORKITEM), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRequestMemory, FX_TYPE_REQUEST_MEMORY, WDFMEMORY), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxDisposeList, FX_TYPE_DISPOSELIST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWmiInstanceExternal, FX_TYPE_WMI_INSTANCE, WDFWMIINSTANCE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoResList, FX_TYPE_IO_RES_LIST, WDFIORESLIST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCmResList, FX_TYPE_CM_RES_LIST, WDFCMRESLIST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoResReqList, FX_TYPE_IO_RES_REQ_LIST, WDFIORESREQLIST), + + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgIo, FX_TYPE_PACKAGE_IO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgFdo, FX_TYPE_PACKAGE_FDO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgPdo, FX_TYPE_PACKAGE_PDO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxWmiIrpHandler, FX_TYPE_WMI_IRP_HANDLER), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgGeneral, FX_TYPE_PACKAGE_GENERAL), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxDefaultIrpHandler, FX_TYPE_DEFAULT_IRP_HANDLER), + + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoTarget, FX_TYPE_IO_TARGET, WDFIOTARGET), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbDevice, FX_TYPE_IO_TARGET_USB_DEVICE, WDFUSBDEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbPipe, FX_TYPE_IO_TARGET_USB_PIPE, WDFUSBPIPE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbInterface, FX_TYPE_USB_INTERFACE, WDFUSBINTERFACE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoTargetSelf, FX_TYPE_IO_TARGET_SELF, WDFIOTARGET), + + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDmaEnabler, FX_TYPE_DMA_ENABLER, WDFDMAENABLER ), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDmaTransactionBase, FX_TYPE_DMA_TRANSACTION, WDFDMATRANSACTION ), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCommonBuffer, FX_TYPE_COMMON_BUFFER, WDFCOMMONBUFFER ), +}; + +ULONG FxObjectsInfoCount = sizeof(FxObjectsInfo)/sizeof(FX_OBJECT_INFO); + +} //extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/fxobjectpch.hpp b/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/fxobjectpch.hpp new file mode 100644 index 00000000000..573fdab61a1 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/fxobjectpch.hpp @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxcorepch.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in FxToSharedInterface\FxObject + +Author: + +Environment: + Kernel mode only + +Revision History: + +--*/ + +#ifndef __FX_CORE_PCH_H__ +#define __FX_CORE_PCH_H__ + +#include "objectpriv.hpp" +#include + +#endif // __FX_CORE_PCH_H__ diff --git a/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/objectpriv.hpp b/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/objectpriv.hpp new file mode 100644 index 00000000000..d65aa9cc6e9 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/fxtosharedinterface/fxobject/objectpriv.hpp @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + corepriv.hpp + +Abstract: + + Private header file for FxToSharedInterface\FxObject directory + It is then included in objectpch.hpp + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + + +extern "C" { +#include +#include "wdf.h" +} + +#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf" + diff --git a/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiapi.cpp new file mode 100644 index 00000000000..566249d2cf1 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiapi.cpp @@ -0,0 +1,439 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiApi.cpp + +Abstract: + + This module implements the C interface to the WMI package + for the driver frameworks. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + + +--*/ + +#include "fxwmipch.hpp" + +// +// Extern "C" the tmh file and all external APIs +// +extern "C" { +#include "FxWmiAPI.tmh" + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfWmiProviderCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + __in_opt + PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + __out + WDFWMIPROVIDER* WmiProvider + ) +{ + FxDevice* pDevice; + FxPowerPolicyOwnerSettings* ownerSettings; + FxWmiProvider* pProvider; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), WmiProviderConfig); + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), WmiProvider); + + // + // If the Device is a power policy owner then do not allow client drivers + // to register for GUID_POWER_DEVICE_ENABLE or GUID_POWER_DEVICE_WAKE_ENABLE + // if the framework has already register a provider for those guids. + // + if (pDevice->m_PkgPnp->IsPowerPolicyOwner()) { + ownerSettings = pDevice->m_PkgPnp->m_PowerPolicyMachine.m_Owner; + + if ((FxIsEqualGuid(&WmiProviderConfig->Guid, + &GUID_POWER_DEVICE_ENABLE) && + ownerSettings->m_IdleSettings.WmiInstance != NULL) || + + (FxIsEqualGuid(&WmiProviderConfig->Guid, + &GUID_POWER_DEVICE_WAKE_ENABLE) && + ownerSettings->m_WakeSettings.WmiInstance != NULL)) { + + DoTraceLevelMessage(GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_ERROR, + TRACINGDEVICE, "WMI Guid already registered by " + "framework"); + return STATUS_WMI_GUID_DISCONNECTED; + } + } + + return FxWmiProvider::_Create(GetFxDriverGlobals(DriverGlobals), + Device, + ProviderAttributes, + WmiProviderConfig, + WmiProvider, + &pProvider); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfWmiInstanceCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_WMI_INSTANCE_CONFIG InstanceConfig, + __in_opt + PWDF_OBJECT_ATTRIBUTES InstanceAttributes, + __out_opt + WDFWMIINSTANCE* Instance + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxWmiProvider* pProvider; + FxWmiInstanceExternal* pInstance; + WDFWMIINSTANCE hInstance; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + pInstance = NULL; + + FxPointerNotNull(pFxDriverGlobals, InstanceConfig); + + if (InstanceConfig->Size != sizeof(WDF_WMI_INSTANCE_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Expected InstanceConfig Size %d, got %d, %!STATUS!", + InstanceConfig->Size, sizeof(*InstanceConfig), + status); + return status; + } + + if (InstanceConfig->Provider == NULL && + InstanceConfig->ProviderConfig == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "InstanceConfig %p Provider and ProviderConfig are both NULL, only " + "one can be, %!STATUS!", InstanceConfig, status); + + return status; + } + else if (InstanceConfig->Provider != NULL && + InstanceConfig->ProviderConfig != NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "InstanceConfig %p Provider %p and ProviderConfig %p are both not " + "NULL, only one can be, %!STATUS!", InstanceConfig, + InstanceConfig->Provider, InstanceConfig->ProviderConfig, status); + + return status; + } + + if (InstanceConfig->Provider != NULL) { + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + InstanceConfig->Provider, + FX_TYPE_WMI_PROVIDER, + (PVOID*) &pProvider, + &pFxDriverGlobals); + } + else { + FxDevice* pDevice; + FxPowerPolicyOwnerSettings* ownerSettings; + WDFWMIPROVIDER hProvider; + + hProvider = NULL; + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + // + // If the Device is a power policy owner then do not allow client drivers + // to register for GUID_POWER_DEVICE_ENABLE or GUID_POWER_DEVICE_WAKE_ENABLE + // if the framework has already register a provider for those guids. + // + if (pDevice->m_PkgPnp->IsPowerPolicyOwner()) { + ownerSettings = pDevice->m_PkgPnp->m_PowerPolicyMachine.m_Owner; + + if ((FxIsEqualGuid(&InstanceConfig->ProviderConfig->Guid, + &GUID_POWER_DEVICE_ENABLE) && + ownerSettings->m_IdleSettings.WmiInstance != NULL) || + + (FxIsEqualGuid(&InstanceConfig->ProviderConfig->Guid, + &GUID_POWER_DEVICE_WAKE_ENABLE) && + ownerSettings->m_WakeSettings.WmiInstance != NULL)) { + + status = STATUS_WMI_GUID_DISCONNECTED; + DoTraceLevelMessage(GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_ERROR, + TRACINGDEVICE, "WMI Guid already registered by " + "framework"); + return status; + } + } + + status = FxWmiProvider::_Create(pFxDriverGlobals, + Device, + NULL, + InstanceConfig->ProviderConfig, + &hProvider, + &pProvider); + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Use the object's globals and not the caller's + // + pFxDriverGlobals = pProvider->GetDriverGlobals(); + } + + status = FxWmiInstanceExternal::_Create(pFxDriverGlobals, + pProvider, + InstanceConfig, + InstanceAttributes, + &hInstance, + &pInstance); + + if (NT_SUCCESS(status) && InstanceConfig->Register) { + status = pProvider->AddInstance(pInstance); + } + + if (NT_SUCCESS(status)) { + if (Instance != NULL) { + *Instance = hInstance; + } + } + else { + // + // Something went wrong, cleanup + // + if (pInstance != NULL) { + // + // This will remove the instance from the provider's list as well. + // + pInstance->DeleteFromFailedCreate(); + } + + // + // Only remove the provider if we created it in this function + // + if (InstanceConfig->ProviderConfig != NULL) { + pProvider->DeleteFromFailedCreate(); + } + } + + return status; +} + +WDFAPI +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfWmiProviderGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIPROVIDER WmiProvider + ) +{ + FxWmiProvider *pProvider; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiProvider, + FX_TYPE_WMI_PROVIDER, + (PVOID*) &pProvider); + + return pProvider->GetDevice()->GetHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfWmiProviderIsEnabled)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIPROVIDER WmiProvider, + __in + WDF_WMI_PROVIDER_CONTROL ProviderControl + ) +{ + FxWmiProvider *pProvider; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiProvider, + FX_TYPE_WMI_PROVIDER, + (PVOID*) &pProvider); + + return pProvider->IsEnabled(ProviderControl); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONGLONG +WDFEXPORT(WdfWmiProviderGetTracingHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIPROVIDER WmiProvider + ) +{ + FxWmiProvider *pProvider; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiProvider, + FX_TYPE_WMI_PROVIDER, + (PVOID*) &pProvider); + + return pProvider->GetTracingHandle(); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfWmiInstanceRegister)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIINSTANCE WmiInstance + ) +{ + FxWmiInstanceExternal* pInstance; + FxWmiProvider* pProvider; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiInstance, + FX_TYPE_WMI_INSTANCE, + (PVOID*) &pInstance); + + pProvider = pInstance->GetProvider(); + + return pProvider->AddInstance(pInstance); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfWmiInstanceDeregister)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIINSTANCE WmiInstance + ) +{ + FxWmiInstanceExternal* pInstance; + FxWmiProvider* pProvider; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiInstance, + FX_TYPE_WMI_INSTANCE, + (PVOID*) &pInstance); + + pProvider = pInstance->GetProvider(); + pProvider->RemoveInstance(pInstance); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfWmiInstanceGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIINSTANCE WmiInstance + ) +{ + FxWmiInstanceExternal* pInstance; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiInstance, + FX_TYPE_WMI_INSTANCE, + (PVOID*) &pInstance); + + return pInstance->GetDevice()->GetHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFWMIPROVIDER +WDFEXPORT(WdfWmiInstanceGetProvider)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIINSTANCE WmiInstance + ) +{ + FxWmiInstanceExternal *pInstance; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiInstance, + FX_TYPE_WMI_INSTANCE, + (PVOID*) &pInstance); + + return pInstance->GetProvider()->GetHandle(); +} + + +_Must_inspect_result_ +__drv_maxIRQL(APC_LEVEL) +NTSTATUS +WDFEXPORT(WdfWmiInstanceFireEvent)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWMIINSTANCE WmiInstance, + __in_opt + ULONG EventDataSize, + __in_bcount_opt(EventDataSize) + PVOID EventData + ) +/*++ + +Routine Description: + Fires an event based on the instance handle. + +Arguments: + WmiInstance - instance which the event is associated with + EventDataSize - size of EventData in bytes + EventData - buffer associated with the event + +Return Value: + NTSTATUS + + --*/ +{ + FxWmiInstanceExternal* pInstance; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WmiInstance, + FX_TYPE_WMI_INSTANCE, + (PVOID*) &pInstance); + + status = FxVerifierCheckIrqlLevel(pInstance->GetDriverGlobals(), APC_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + return pInstance->FireEvent(EventData, EventDataSize); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiinstance.cpp b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiinstance.cpp new file mode 100644 index 00000000000..2c79fe9a214 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiinstance.cpp @@ -0,0 +1,684 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiInstance.cpp + +Abstract: + + This module implements the FxWmiInstance object and its derivations + +Author: + + + +Revision History: + + +--*/ + +#include "fxwmipch.hpp" + +extern "C" { +#include "FxWmiInstance.tmh" +} + +FxWmiInstance::FxWmiInstance( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in FxWmiProvider* Provider + ) : + FxNonPagedObject(FX_TYPE_WMI_INSTANCE, ObjectSize, FxDriverGlobals) +{ + InitializeListHead(&m_ListEntry); + m_Provider = Provider; + m_Provider->ADDREF(this); + MarkDisposeOverride(ObjectDoNotLock); +} + +FxWmiInstance::~FxWmiInstance() +{ + ASSERT(IsListEmpty(&m_ListEntry)); +} + +BOOLEAN +FxWmiInstance::Dispose( + VOID + ) +{ + m_Provider->RemoveInstance(this); + m_Provider->RELEASE(this); + + // + // Object is being deleted, remove this object from the provider's list + // of instances. If we don't do this, the provider will have a list which + // contains entries which have been freed. + // + return __super::Dispose(); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiInstance::FireEvent( + __in_bcount_opt(EventBufferSize) PVOID EventBuffer, + __inout ULONG EventBufferSize + ) +{ + ULONG sizeNeeded; + PWNODE_SINGLE_INSTANCE pNode; + NTSTATUS status; + + if (EventBuffer == NULL) { + EventBufferSize = 0; + } + + sizeNeeded = sizeof(WNODE_SINGLE_INSTANCE) + EventBufferSize; + + // + // IoWMIWriteEvent will free the memory by calling ExFreePool. This means + // we cannot use a framework allocate function. + // + pNode = (PWNODE_SINGLE_INSTANCE) + ExAllocatePoolWithTag(NonPagedPool, sizeNeeded, GetDriverGlobals()->Tag); + + if (pNode != NULL) { + RtlCopyMemory(&pNode->WnodeHeader.Guid, + m_Provider->GetGUID(), + sizeof(GUID)); + + pNode->WnodeHeader.ProviderId = IoWMIDeviceObjectToProviderId( + GetDevice()->GetDeviceObject()); + pNode->WnodeHeader.BufferSize = sizeNeeded; + pNode->WnodeHeader.Flags = WNODE_FLAG_SINGLE_INSTANCE | + WNODE_FLAG_EVENT_ITEM | + WNODE_FLAG_STATIC_INSTANCE_NAMES; + KeQuerySystemTime(&pNode->WnodeHeader.TimeStamp); + + pNode->InstanceIndex = m_Provider->GetInstanceIndex(this); + pNode->SizeDataBlock = EventBufferSize; + pNode->DataBlockOffset = sizeof(WNODE_SINGLE_INSTANCE); + + if (EventBuffer != NULL) { + RtlCopyMemory(&pNode->VariableData, EventBuffer, EventBufferSize); + } + + // + // Upon success, IoWMIWriteEvent will free pNode. + // + status = IoWMIWriteEvent(pNode); + + if (!NT_SUCCESS(status)) { + ExFreePool(pNode); + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFWMIINSTANCE %p insufficient resources to fire event,%!STATUS!", + GetHandle(), status); + } + + return status; +} + +FxWmiInstanceExternal::FxWmiInstanceExternal( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WMI_INSTANCE_CONFIG Config, + __in FxWmiProvider* Provider + ) : + FxWmiInstance(FxDriverGlobals, sizeof(FxWmiInstanceExternal), Provider), + m_QueryInstanceCallback(FxDriverGlobals), + m_SetInstanceCallback(FxDriverGlobals), + m_SetItemCallback(FxDriverGlobals), + m_ExecuteMethodCallback(FxDriverGlobals) +{ + m_ContextLength = 0; + m_UseContextForQuery = Config->UseContextForQuery; + + if (m_UseContextForQuery == FALSE) { + m_QueryInstanceCallback.m_Method = Config->EvtWmiInstanceQueryInstance; + } + m_SetInstanceCallback.m_Method = Config->EvtWmiInstanceSetInstance; + m_SetItemCallback.m_Method = Config->EvtWmiInstanceSetItem; + + m_ExecuteMethodCallback.m_Method = Config->EvtWmiInstanceExecuteMethod; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiInstanceExternal::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxWmiProvider* Provider, + __in PWDF_WMI_INSTANCE_CONFIG WmiInstanceConfig, + __in_opt PWDF_OBJECT_ATTRIBUTES InstanceAttributes, + __out WDFWMIINSTANCE* WmiInstance, + __out FxWmiInstanceExternal** Instance + ) +{ + FxWmiInstanceExternal* pInstance; + WDFWMIINSTANCE hInstance; + NTSTATUS status; + size_t contextSize; + + contextSize = 0; + *Instance = 0; + + *WmiInstance = NULL; + + // + // For event only providers, you cannot specify any callbacks or context + // usage. + // + if (Provider->IsEventOnly() && + (WmiInstanceConfig->UseContextForQuery || + WmiInstanceConfig->EvtWmiInstanceQueryInstance != NULL || + WmiInstanceConfig->EvtWmiInstanceSetInstance != NULL || + WmiInstanceConfig->EvtWmiInstanceSetItem != NULL || + WmiInstanceConfig->EvtWmiInstanceExecuteMethod != NULL)) { + + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFWMIPROVIDER %p is event only and UseContextForQuery (%d) is TRUE," + " or a callback (query instance %p, set instance %p, set item %p, " + "executue method %p) is not NULL, %!STATUS!", + Provider->GetHandle(), WmiInstanceConfig->UseContextForQuery, + WmiInstanceConfig->EvtWmiInstanceQueryInstance, + WmiInstanceConfig->EvtWmiInstanceSetInstance, + WmiInstanceConfig->EvtWmiInstanceSetItem, + WmiInstanceConfig->EvtWmiInstanceExecuteMethod, status); + + return status; + } + + status = FxValidateObjectAttributes(FxDriverGlobals, + InstanceAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + if (WmiInstanceConfig->UseContextForQuery) { + // + // UseContextForQuery only supported for read only instances. + // ExecuteMethod has undefined side affects, so we allow it. + // + if (WmiInstanceConfig->EvtWmiInstanceSetInstance != NULL || + WmiInstanceConfig->EvtWmiInstanceSetItem != NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "UseContextForQuery set, i.e. a read only instance, but " + "EvtWmiInstanceSetInstance %p or EvtWmiInstanceSetItem %p is " + "set, %!STATUS!", + WmiInstanceConfig->EvtWmiInstanceSetInstance, + WmiInstanceConfig->EvtWmiInstanceSetItem, status); + + return status; + } + + // + // We must have a context to use for the query + // + if (InstanceAttributes == NULL || + InstanceAttributes->ContextTypeInfo == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "UseContextForQuery set, but InstanceAttributes %p is null or " + "there is no associated type, %!STATUS!", + InstanceAttributes, status); + + return status; + } + + contextSize = InstanceAttributes->ContextTypeInfo->ContextSize; + + if (InstanceAttributes->ContextSizeOverride != 0) { + status = RtlSizeTAdd(contextSize, + InstanceAttributes->ContextSizeOverride, + &contextSize); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Overlfow adding contextSize %I64d with size override %I64d, " + "%!STATUS!", contextSize, + InstanceAttributes->ContextSizeOverride, status); + + return status; + } + } + + if (contextSize > ULONG_MAX) { + // + // Since we are casting to a ULONG below, detect loss of data here + // (only really applicable on 64 bit machines where sizeof(size_t) != + // sizeof(ULONG) + // + status = STATUS_INTEGER_OVERFLOW; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "context size %I64d can be %d large, %!STATUS!", + contextSize, ULONG_MAX, status); + + return status; + } + + // + // Make sure the context is the minimum the buffer size. + // + if (contextSize < Provider->GetMinInstanceBufferSize()) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "context size %I64d is less then the WDFWMIPROVIDER %p min size " + "of %d, %!STATUS!", + contextSize, Provider->GetHandle(), + Provider->GetMinInstanceBufferSize(), status); + + return status; + } + } + + pInstance = new(FxDriverGlobals, InstanceAttributes) + FxWmiInstanceExternal(FxDriverGlobals, WmiInstanceConfig, Provider); + + if (pInstance == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "could not allocate memory for WDFWMIINSTANCE, %!STATUS!", + status); + + return status; + } + + if (contextSize > 0) { + pInstance->SetContextForQueryLength((ULONG) contextSize); + } + + if (NT_SUCCESS(status)) { + status = pInstance->Commit( + InstanceAttributes, (PWDFOBJECT) &hInstance, Provider); + + if (NT_SUCCESS(status)) { + // + // Assign the handle back to the caller. + // + *WmiInstance = hInstance; + } + else { + // + // On failure, DeleteFromFailedCreate will delete the object and + // the Dispose callback will remove the instance from the provider's + // list. + // + DO_NOTHING(); + } + } + + if (NT_SUCCESS(status)) { + *Instance = pInstance; + } + else { + pInstance->DeleteFromFailedCreate(); + } + + return status; +} + +BOOLEAN +FxWmiInstanceExternal::IsQueryInstanceSupported( + VOID + ) +{ + // + // If we have a function pointer to call or we are using the context + // as the buffer, query instance is supported. + // + // Also, if neither of the first 2 are true, we need to support query + // instance if the device has an execute method callback b/c WMI will + // send a query instance to this instance which much succeed for the + // execute method irp to be sent. + // + return (m_UseContextForQuery || + m_QueryInstanceCallback.m_Method != NULL || + m_ExecuteMethodCallback.m_Method != NULL) ? TRUE + : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceExternal::QueryInstance( + __inout ULONG OutBufferSize, + __out_bcount(OutBufferSize) PVOID OutBuffer, + __out PULONG BufferUsed + ) +{ + NTSTATUS status; + + if (m_UseContextForQuery) { + // + // No matter what, we are reporting the length of the context. If the + // buffer is too small, it is used to report the desired buffer length. + // Otherwise, it is the amount of data we copied to the query buffer. + // + *BufferUsed = m_ContextLength; + + if (OutBufferSize < m_ContextLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFWMIINSTANCE %p query instance using context for query, " + "query buffer length %d, context length %d, %!STATUS!", + GetHandle(), OutBufferSize, m_ContextLength, status); + } + else { + status = STATUS_SUCCESS; + + RtlCopyMemory(OutBuffer, + &GetContextHeader()->Context[0], + m_ContextLength); + } + } + else if (m_QueryInstanceCallback.m_Method != NULL) { + BYTE dummy; + + if (OutBufferSize == 0) { + ASSERT(m_Provider->GetMinInstanceBufferSize() == 0); + OutBuffer = (PVOID) &dummy; + OutBufferSize = sizeof(dummy); + } + + status = m_QueryInstanceCallback.Invoke( + GetDevice()->GetHandle(), + GetHandle(), + OutBufferSize, + OutBuffer, + BufferUsed + ); + + if (status == STATUS_PENDING) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIINSTANCE %p was queried and returned %!STATUS!, which is " + "not an allowed return value", GetHandle(), status); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + status = STATUS_UNSUCCESSFUL; + *BufferUsed = 0; + } + else if (NT_SUCCESS(status)) { + if (*BufferUsed > OutBufferSize) { + // + // Caller error, they returned more bytes in *BufferUsed then + // was passed in via OutBufferSize, yet returned NT_SUCCESS + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIINSTANCE %p was queried with buffer size %d, " + " but returned %d bytes and %!STATUS!, should return " + "!NT_SUCCESS in this case", + GetHandle(), OutBufferSize, *BufferUsed, status); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + status = STATUS_UNSUCCESSFUL; + *BufferUsed = 0; + } + else if (OutBuffer == &dummy && *BufferUsed > 0) { + // + // Convert success back to an error where we can report the + // required size back to the caller. + // + status = STATUS_BUFFER_TOO_SMALL; + } + } + else if (status == STATUS_BUFFER_TOO_SMALL) { + if (m_Provider->GetMinInstanceBufferSize()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIINSTANCE %p returned %!STATUS!, but it specified " + "a minimum instance size %d in its WDFWMIPROVIDER %p", + GetHandle(), status, m_Provider->GetMinInstanceBufferSize(), + m_Provider->GetHandle()); + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "This is a break in the contract. Minimum instance size " + "should only be used for fixed sized instances"); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + } + else { + ASSERT(m_ExecuteMethodCallback.m_Method != NULL); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIINSTANCE %p was queried with no query callback and supports " + "execute method (%p), zero bytes returned", GetHandle(), + m_ExecuteMethodCallback.m_Method); + + status = STATUS_SUCCESS; + *BufferUsed = 0; + } + + return status; +} + +BOOLEAN +FxWmiInstanceExternal::IsSetInstanceSupported( + VOID + ) +{ + return m_SetInstanceCallback.m_Method != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceExternal::SetInstance( + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) +{ + return m_SetInstanceCallback.Invoke( + GetDevice()->GetHandle(), + GetHandle(), + InBufferSize, + InBuffer + ); +} + +BOOLEAN +FxWmiInstanceExternal::IsSetItemSupported( + VOID + ) +{ + return m_SetItemCallback.m_Method != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceExternal::SetItem( + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) +{ + return m_SetItemCallback.Invoke( + GetDevice()->GetHandle(), + GetHandle(), + DataItemId, + InBufferSize, + InBuffer + ); +} + +BOOLEAN +FxWmiInstanceExternal::IsExecuteMethodSupported( + VOID + ) +{ + return m_ExecuteMethodCallback.m_Method != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceExternal::ExecuteMethod( + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ) +{ + return m_ExecuteMethodCallback.Invoke( + GetDevice()->GetHandle(), + GetHandle(), + MethodId, + InBufferSize, + OutBufferSize, + Buffer, + BufferUsed + ); +} + +FxWmiInstanceInternal::FxWmiInstanceInternal( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxWmiInstanceInternalCallbacks* Callbacks, + __in FxWmiProvider* Provider + ) : FxWmiInstance(FxDriverGlobals, sizeof(FxWmiInstanceInternal), Provider) +{ + m_QueryInstance = Callbacks->QueryInstance; + m_SetInstance = Callbacks->SetInstance; + m_SetItem = Callbacks->SetItem; + m_ExecuteMethod = Callbacks->ExecuteMethod; +} + +BOOLEAN +FxWmiInstanceInternal::IsQueryInstanceSupported( + VOID + ) +{ + return m_QueryInstance != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceInternal::QueryInstance( + __inout ULONG OutBufferSize, + __out_bcount(OutBufferSize) PVOID OutBuffer, + __out PULONG BufferUsed + ) +{ + return m_QueryInstance(GetDevice(), + this, + OutBufferSize, + OutBuffer, + BufferUsed); +} + +BOOLEAN +FxWmiInstanceInternal::IsSetInstanceSupported( + VOID + ) +{ + return m_SetInstance != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceInternal::SetInstance( + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) +{ + return m_SetInstance(GetDevice(), + this, + InBufferSize, + InBuffer); +} + +BOOLEAN +FxWmiInstanceInternal::IsSetItemSupported( + VOID + ) +{ + return m_SetItem != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceInternal::SetItem( + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) +{ + return m_SetItem(GetDevice(), + this, + DataItemId, + InBufferSize, + InBuffer); +} + +BOOLEAN +FxWmiInstanceInternal::IsExecuteMethodSupported( + VOID + ) + +{ + return m_ExecuteMethod != NULL ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxWmiInstanceInternal::ExecuteMethod( + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ) +{ + return m_ExecuteMethod(GetDevice(), + this, + MethodId, + InBufferSize, + OutBufferSize, + Buffer, + BufferUsed); +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiirphandler.cpp b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiirphandler.cpp new file mode 100644 index 00000000000..02d00aec89d --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiirphandler.cpp @@ -0,0 +1,1960 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiIrpHandler.cpp + +Abstract: + + This module implements the wmi irp handler for the driver frameworks. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "fxwmipch.hpp" + +extern "C" { +#include "FxWmiIrpHandler.tmh" +} + +#ifndef WppDebug +#define WppDebug(a, b) +#endif + +const FxWmiMinorEntry FxWmiIrpHandler::m_WmiDispatchTable[] = +{ + // IRP_MN_QUERY_ALL_DATA + { _QueryAllData, FALSE }, + + // IRP_MN_QUERY_SINGLE_INSTANCE + { _QuerySingleInstance, TRUE }, + + // IRP_MN_CHANGE_SINGLE_INSTANCE + { _ChangeSingleInstance, TRUE }, + + // IRP_MN_CHANGE_SINGLE_ITEM + { _ChangeSingleItem, TRUE }, + + // IRP_MN_ENABLE_EVENTS + { _EnableDisableEventsAndCollection, FALSE }, + + // IRP_MN_DISABLE_EVENTS + { _EnableDisableEventsAndCollection, FALSE }, + + // IRP_MN_ENABLE_COLLECTION + { _EnableDisableEventsAndCollection, FALSE }, + + // IRP_MN_DISABLE_COLLECTION + { _EnableDisableEventsAndCollection, FALSE }, + + // IRP_MN_REGINFO + { _RegInfo, FALSE }, + + // IRP_MN_EXECUTE_METHOD + { _ExecuteMethod, TRUE }, + + // 0xA is reseverved + { NULL, FALSE }, + + // IRP_MN_REGINFO_EX + { _RegInfo, FALSE }, +}; + +VOID +FxWmiIrpHandler::CheckAssumptions( + VOID + ) +{ + WDFCASSERT(sizeof(m_WmiDispatchTable)/sizeof(m_WmiDispatchTable[0]) == + IRP_MN_REGINFO_EX + 1); +} + +FxWmiIrpHandler::FxWmiIrpHandler( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxDevice *Device, + __in WDFTYPE Type + ) : + FxPackage(FxDriverGlobals, Device, Type), + m_NumProviders(0), m_RegisteredState(WmiUnregistered), + m_WorkItem(NULL), m_WorkItemEvent(NULL), m_WorkItemQueued(FALSE), + m_UpdateCount(1) // bias m_UpdateCount to 1, Deregister routine will + // decrement this. +{ + InitializeListHead(&m_ProvidersListHead); +} + +FxWmiIrpHandler::~FxWmiIrpHandler() +{ + // + // If the device could not get past AddDevice or failed the initial start + // device, we will be unregistered. Otherwise we should be cleaned up. + // + ASSERT(m_RegisteredState != WmiRegistered); + + ASSERT(IsListEmpty(&m_ProvidersListHead)); + + if (m_WorkItem != NULL) { + IoFreeWorkItem(m_WorkItem); + } +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::PostCreateDeviceInitialize( + VOID + ) +{ + m_WorkItem = IoAllocateWorkItem(GetDevice()->GetDeviceObject()); + if (m_WorkItem == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::Register( + VOID + ) +{ + NTSTATUS status; + KIRQL irql; + + // + // We rely on the PnP state machine to manage our state transitions properly + // so that we don't have to do any state checking here. + // + Lock(&irql); + ASSERT(m_RegisteredState == WmiUnregistered || + m_RegisteredState == WmiDeregistered); + m_RegisteredState = WmiRegistered; + Unlock(irql); + + status = IoWMIRegistrationControl(GetDevice()->GetDeviceObject(), + WMIREG_ACTION_REGISTER); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "could not register WMI with OS, %!STATUS!", status); + + Lock(&irql); + m_RegisteredState = WmiUnregistered; + Unlock(irql); + } + + return status; +} + +VOID +FxWmiIrpHandler::Deregister( + VOID + ) +{ + FxCREvent event; + KIRQL irql; + BOOLEAN call; + + call = FALSE; + + Lock(&irql); + if (m_RegisteredState == WmiRegistered) { + m_RegisteredState = WmiDeregistered; + + if (m_WorkItemQueued) { + + + + + + m_WorkItemEvent = (PKEVENT)event.GetEvent(); + } + + call = TRUE; + } + Unlock(irql); + + if (m_WorkItemEvent != NULL) { + event.EnterCRAndWaitAndLeave(); + } + + if (call) { + NTSTATUS status; + + // + // Per WMI rules, there should not be any call to update WMI + // registration after we have deregistered because that can lead to + // deadlock in Pnp, so before we go ahead to deregister, let's ensure + // that. This will wait for any pending updates to happen. + // + DecrementUpdateCountAndWait(); + + status = IoWMIRegistrationControl(GetDevice()->GetDeviceObject(), + WMIREG_ACTION_DEREGISTER); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "failure deregistering WMI with OS, %!STATUS!", status); + } + } +} + +VOID +FxWmiIrpHandler::Cleanup( + VOID + ) +{ + KIRQL irql; + + Lock(&irql); + m_RegisteredState = WmiCleanedUp; + Unlock(irql); +} + +VOID +FxWmiIrpHandler::ResetStateForPdoRestart( + VOID + ) +{ + KIRQL irql; + + Lock(&irql); + + // + // We can reach this state in 2 ways: + // 1. PDO went through Init->Started->Removed->Started transition + // 2. PDO went through Init->->Started state (e.g. + // Init->Ejected->EjectFailed->Started) transition. + // + // So, WMI registration state would either be Deregistered due to #1 + // or, Unregistered due to #2. Also, update count would be 0 in case of #1 + // and 1 in case of #2. + // + ASSERT(m_RegisteredState == WmiUnregistered || + m_RegisteredState == WmiDeregistered); + ASSERT(m_UpdateCount == 0 || m_UpdateCount == 1); + + // + // Update count is biased to 1 when created so do the same here. + // + m_UpdateCount = 1; + m_UpdateEvent.Initialize(); + Unlock(irql); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::AddProviderLocked( + __in FxWmiProvider* Provider, + __in KIRQL OldIrql, + __out_opt PBOOLEAN Update + ) +{ + BOOLEAN update; + + update = FALSE; + + switch (m_RegisteredState) { + case WmiRegistered: + if (Provider->m_Flags & WdfWmiProviderTracing) { + update = TRUE; + } + case WmiUnregistered: + break; + + case WmiDeregistered: + return STATUS_INVALID_DEVICE_STATE; + } + + // + // Didn't find it in the list, add it + // + m_NumProviders++; + InsertTailList(&m_ProvidersListHead, &Provider->m_ListEntry); + + if (update) { + update = DeferUpdateLocked(OldIrql); + + if (Update != NULL) { + *Update = update; + } + } + + return STATUS_SUCCESS; +} + +BOOLEAN +FxWmiIrpHandler::DeferUpdateLocked( + __in KIRQL OldIrql + ) +{ + BOOLEAN checkQueue; + + checkQueue = FALSE; + + // + // Check to see if the caller is going to return to something > PASSIVE_LEVEL. + // If so, then always defer to the workitem. + // + if (OldIrql > PASSIVE_LEVEL) { + checkQueue = TRUE; + } + else { + // + // At passive level and updates are allowed, indicate to the caller to + // update. The caller will do registration update outside of lock but + // update count needs to be incremented under lock, so this is done here. + // + IncrementUpdateCount(); + return TRUE; + } + + if (checkQueue && m_WorkItemQueued == FALSE) { + // + // we are going to queue a workitem which will do registration update, + // so increment the update count. Note that one work item may correspond + // to multiple requests to update (since if the workitem is already + // queued, it's not queued again). + // + IncrementUpdateCount(); + + m_WorkItemQueued = TRUE; + IoQueueWorkItem(m_WorkItem, + _UpdateGuids, + DelayedWorkQueue, + this); + } + + return FALSE; +} + +VOID +FxWmiIrpHandler::_UpdateGuids( + __in PDEVICE_OBJECT DeviceObject, + __in PVOID Context + ) +{ + FxWmiIrpHandler* pThis; + KIRQL irql; + + UNREFERENCED_PARAMETER(DeviceObject); + + pThis = (FxWmiIrpHandler*)Context; + + pThis->UpdateGuids(); + + pThis->Lock(&irql); + pThis->m_WorkItemQueued = FALSE; + + if (pThis->m_WorkItemEvent != NULL) { + KeSetEvent(pThis->m_WorkItemEvent, FALSE, IO_NO_INCREMENT); + } + pThis->Unlock(irql); +} + +VOID +FxWmiIrpHandler::UpdateGuids( + VOID + ) +{ + NTSTATUS status; + + status = IoWMIRegistrationControl(GetDevice()->GetDeviceObject(), + WMIREG_ACTION_UPDATE_GUIDS); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "IoWMIRegistrationControl DevObj %p, for UpdateGuids failed, %!STATUS!", + GetDevice()->GetDeviceObject(), status); + + // + // Just drop the error + // + } + + // + // The caller incremented the update count when it decided to do the update. + // Decrement the count now that we have completed registration update. + // + DecrementUpdateCount(); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::AddProvider( + __in FxWmiProvider* Provider, + __out_opt PBOOLEAN Update + ) +{ + NTSTATUS status; + KIRQL irql; + + Lock(&irql); + + if (IsListEmpty(&Provider->m_ListEntry) == FALSE || + FindProviderLocked(Provider->GetGUID()) != NULL) { + status = STATUS_OBJECT_NAME_EXISTS; + } + else { + status = AddProviderLocked(Provider, irql, Update); + } + Unlock(irql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::AddPowerPolicyProviderAndInstance( + __in PWDF_WMI_PROVIDER_CONFIG ProviderConfig, + __in FxWmiInstanceInternalCallbacks* InstanceCallbacks, + __inout FxWmiInstanceInternal** Instance + ) +{ + FxWmiProvider* pProvider; + FxWmiInstanceInternal* pInstance; + NTSTATUS status; + KIRQL irql; + BOOLEAN providerAllocated, providerAdded, update; + + providerAllocated = FALSE; + providerAdded = FALSE; + update = FALSE; + + pInstance = NULL; + + status = STATUS_SUCCESS; + + Lock(&irql); + + pProvider = FindProviderLocked(&ProviderConfig->Guid); + + if (pProvider == NULL) { + pProvider = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) + FxWmiProvider(GetDriverGlobals(), ProviderConfig, GetDevice()); + + if (pProvider == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + providerAllocated = TRUE; + + status = AddProviderLocked(pProvider, irql); + if (!NT_SUCCESS(status)) { + goto Done; + } + + providerAdded = TRUE; + + status = pProvider->AssignParentObject(GetDevice()); + if (!NT_SUCCESS(status)) { + goto Done; + } + } + else if (pProvider->m_NumInstances > 0 && + (FxIsEqualGuid(pProvider->GetGUID(), &GUID_POWER_DEVICE_ENABLE) || + FxIsEqualGuid(pProvider->GetGUID(), &GUID_POWER_DEVICE_WAKE_ENABLE))) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "WMI Guid already registered by client driver"); + status = STATUS_WMI_GUID_DISCONNECTED; + } + + if (NT_SUCCESS(status)) { + pInstance = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) + FxWmiInstanceInternal(GetDriverGlobals(), InstanceCallbacks, pProvider); + + if (pInstance != NULL) { + status = pInstance->AssignParentObject(pProvider); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status) && + InterlockedCompareExchangePointer((PVOID*) Instance, + pInstance, + NULL) != NULL) { + // + // Some other thread got here first and created an instance, just + // bail out. the caller will handle this specific return value + // gracefully. + // + status = STATUS_OBJECT_NAME_COLLISION; + } + else { + // + // We are the first one to set the value, good for us. + // + DO_NOTHING(); + } + } + + // + // Add the instance only if we are successful to this point + // + if (NT_SUCCESS(status)) { + // + // Passing FALSE indicates that this instance cannot be in the list + // when added. + // + status = pProvider->AddInstanceLocked( + pInstance, + FALSE, + &update, + FxWmiProvider::AddInstanceToHead + ); + } + +Done: + if (NT_SUCCESS(status)) { + if (update) { + update = DeferUpdateLocked(irql); + } + } + else if (providerAdded) { + RemoveProviderLocked(pProvider); + } + + Unlock(irql); + + if (NT_SUCCESS(status)) { + if (update) { + UpdateGuids(); + } + } + else { + if (pInstance != NULL) { + pInstance->DeleteObject(); + } + + if (providerAllocated) { + pProvider->DeleteObject(); + } + } + + return status; +} + +VOID +FxWmiIrpHandler::RemoveProvider( + __in FxWmiProvider* Provider + ) +{ + KIRQL irql; + + // + // No need to update via IoWMIRegistrationControl because this is only + // called in the error path of creating a provider. + // + Lock(&irql); + RemoveProviderLocked(Provider); + Unlock(irql); +} + +VOID +FxWmiIrpHandler::RemoveProviderLocked( + __in FxWmiProvider* Provider + ) +{ + m_NumProviders--; + RemoveEntryList(&Provider->m_ListEntry); + InitializeListHead(&Provider->m_ListEntry); +} + +_Must_inspect_result_ +FxWmiProvider* +FxWmiIrpHandler::FindProviderLocked( + __in LPGUID Guid + ) +{ + FxWmiProvider* pFound; + PLIST_ENTRY ple; + + pFound = NULL; + + for (ple = m_ProvidersListHead.Flink; + ple != &m_ProvidersListHead; + ple = ple->Flink) { + + FxWmiProvider* pProvider; + + pProvider = CONTAINING_RECORD(ple, FxWmiProvider, m_ListEntry); + + if (RtlCompareMemory(&pProvider->m_Guid, + Guid, + sizeof(GUID)) == sizeof(GUID)) { + pFound = pProvider; + break; + } + } + + return pFound; +} + +_Must_inspect_result_ +FxWmiProvider* +FxWmiIrpHandler::FindProviderReferenced( + __in LPGUID Guid, + __in PVOID Tag + ) +{ + FxWmiProvider* pProvider; + KIRQL irql; + + Lock(&irql); + pProvider = FindProviderLocked(Guid); + if (pProvider != NULL) { + pProvider->ADDREF(Tag); + } + Unlock(irql); + + return pProvider; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::Dispatch( + __in PIRP Irp + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxWmiProvider* pProvider; + FxWmiInstance* pInstance; + PIO_STACK_LOCATION stack; + PDEVICE_OBJECT pAttached; + NTSTATUS status; + PVOID pTag; + ULONG instanceIndex; + KIRQL irql; + BOOLEAN handled, completeNow; + UCHAR minor; + + pFxDriverGlobals = GetDriverGlobals(); + + FX_TRACK_DRIVER(pFxDriverGlobals); + + stack = IoGetCurrentIrpStackLocation(Irp); + minor = stack->MinorFunction; + pTag = UlongToPtr(minor); + status = Irp->IoStatus.Status; + + pProvider = NULL; + pInstance = NULL; + + handled = FALSE; + completeNow = FALSE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_SYSTEM_CONTROL, %!sysctrl! IRP 0x%p", + m_Device->GetHandle(), m_Device->GetDeviceObject(), minor, Irp); + + // + // Verify the minor code is within range, there is hole in the table at 0xA. + // This check works around the hole in the table. + // + if (minor > IRP_MN_EXECUTE_METHOD && minor != IRP_MN_REGINFO_EX) { + goto Done; + } + + // + // If the irp is not targetted at this device, send it down the stack + // + if (stack->Parameters.WMI.ProviderId != (UINT_PTR) m_Device->GetDeviceObject()) { + goto Done; + } + + if (minor == IRP_MN_REGINFO || minor == IRP_MN_REGINFO_EX) { + status = STATUS_SUCCESS; + } + else { + Lock(&irql); + + pProvider = FindProviderLocked((LPGUID)stack->Parameters.WMI.DataPath); + + if (pProvider != NULL) { + status = STATUS_SUCCESS; + } + else { + // + // check for WMI tracing (no pProvider) + // + status = STATUS_WMI_GUID_NOT_FOUND; + } + + if (NT_SUCCESS(status) && m_WmiDispatchTable[minor].CheckInstance) { + PWNODE_SINGLE_INSTANCE pSingle; + + pSingle = (PWNODE_SINGLE_INSTANCE) stack->Parameters.WMI.Buffer; + + instanceIndex = pSingle->InstanceIndex; + + // + // Also possible bits set in Flags related to instance names + // WNODE_FLAG_PDO_INSTANCE_NAMES + // + if (pSingle->WnodeHeader.Flags & WNODE_FLAG_STATIC_INSTANCE_NAMES) { + // + // Try to get the instance + // + pInstance = pProvider->GetInstanceReferencedLocked( + instanceIndex, pTag); + + if (pInstance == NULL) { + status = STATUS_WMI_INSTANCE_NOT_FOUND; + } + } + else { + + + + + + + status = STATUS_WMI_INSTANCE_NOT_FOUND; + } + } + + if (NT_SUCCESS(status)) { + pProvider->ADDREF(pTag); + } + else { + // + // NULL out the provider so we don't deref it later. We could not + // use if (pProvider != NULL && NT_SUCCESS(status) in the Done: block + // because we could have success here, but the dispatch function + // returns error. + // + pProvider = NULL; + } + + Unlock(irql); + + if (!NT_SUCCESS(status)) { + Irp->IoStatus.Status = status; + completeNow = TRUE; + } + } + + if (NT_SUCCESS(status) && m_WmiDispatchTable[minor].Handler != NULL) { + status = m_WmiDispatchTable[minor].Handler(this, + Irp, + pProvider, + pInstance); + handled = TRUE; + } + +Done: + if (pInstance != NULL) { + pInstance->RELEASE(pTag); + pInstance = NULL; + } + + if (pProvider != NULL) { + pProvider->RELEASE(pTag); + pProvider = NULL; + } + + if (handled == FALSE) { + pAttached = m_Device->GetAttachedDevice(); + if (completeNow || pAttached == NULL) { + // + // Sent to a PDO, error in the FDO handling, or controller devobj + // style devobj, complete it here + // + status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + } + else { + // + // Request sent to PNP device object that is not a PDO, send down + // the stack + // + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(pAttached, Irp); + } + } + + // + // Only release the remove lock *after* we have removed the thread entry + // from the list because the list lifetime is tied to the FxDevice lifetime + // and the remlock controls the lifetime of FxDevice. + // + // Since we never pend the wmi request, we can release the remove lock in + // this Dispatch routine. If we ever pended the IRPs, this would have to + // have some more logic involved. + // + IoReleaseRemoveLock( + &FxDevice::_GetFxWdmExtension(m_Device->GetDeviceObject())->IoRemoveLock, + Irp + ); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_QueryAllData( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in_opt FxWmiInstance* Instance + ) +/*++ + +Routine Description: + Handles querying all instances for data. In the case where there is not + enough space in the buffer, we query each instance for the required amount + of buffer space and report that. + +Arguments: + This - device instance + + Irp - WMI request for query all data + + Providre - the provider being queried + + Instance - ignored, NULL + +Return Value: + STATUS_BUFFER_TOO_SMALL in case the buffer is not large enough + STATUS_SUCCESS on a successful query + or other values depending on the client driver + + --*/ +{ + POFFSETINSTANCEDATAANDLENGTH pOffsets; + PWNODE_ALL_DATA pNodeData; + PIO_STACK_LOCATION stack; + PUCHAR pData; + NTSTATUS status, addStatus; + ULONG instanceCount, dataBlockOffset, lengthArraySize, i, sizeRemaining, + lastAdjustment, bufferUsed, tempOffset; + KIRQL irql; + BOOLEAN tooSmall; + + UNREFERENCED_PARAMETER(Instance); + + status = STATUS_SUCCESS; + + stack = IoGetCurrentIrpStackLocation(Irp); + pNodeData = (PWNODE_ALL_DATA) stack->Parameters.WMI.Buffer; + + lastAdjustment = 0; + pData = NULL; + dataBlockOffset = 0; + + // + // This either the amount of buffer used on successful queries or the + // amount of buffer required if the buffer is not big enough. + // + bufferUsed = 0; + + tooSmall = FALSE; + + if (stack->Parameters.WMI.BufferSize < sizeof(WNODE_ALL_DATA)) { + status = STATUS_UNSUCCESSFUL; + goto Done; + } + + + + + + + + // + // All of the provider's access is guarded by the irp handler's lock + // + This->Lock(&irql); + instanceCount = Provider->m_NumInstances; + This->Unlock(irql); + + + + + + + + + + + + if (instanceCount == 0) { + status = STATUS_WMI_INSTANCE_NOT_FOUND; + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Failing QueryAllData since no instances found for " + "WDFWMIPROVIDER %p, %!STATUS!", + Provider->GetHandle(), status); + bufferUsed = 0; + goto Done; + } + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFWMIPROVIDER %p QueryAllData, num instances %d", + Provider->GetHandle(), instanceCount); + + pNodeData->InstanceCount = instanceCount; + + + + + + + pNodeData->WnodeHeader.Flags &= ~WNODE_FLAG_FIXED_INSTANCE_SIZE; + + // + // Since value of instanceCount is not limited, do overflow-safe addition + // and multiplication + // + // lengthArraySize = instanceCount * sizeof(OFFSETINSTANCEDATAANDLENGTH); + status = RtlULongMult(instanceCount, + sizeof(OFFSETINSTANCEDATAANDLENGTH), + &lengthArraySize); + + if (NT_SUCCESS(status)) { + // dataBlockOffset = + // FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength) + lengthArraySize; + status = RtlULongAdd( + FIELD_OFFSET(WNODE_ALL_DATA, OffsetInstanceDataAndLength), + lengthArraySize, + &tempOffset); + + if (NT_SUCCESS(status)) { + dataBlockOffset = (ULONG) WDF_ALIGN_SIZE_UP( + tempOffset, MEMORY_ALLOCATION_ALIGNMENT); + + if (dataBlockOffset < tempOffset) { + status = STATUS_INTEGER_OVERFLOW; + } + } + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failing QueryAllData since integer overflow occured using" + " provider instance count %d for WDFWMIPROVIDER %p, %!STATUS!", + instanceCount, Provider->GetHandle(), status); + bufferUsed = 0; + goto Done; + } + + pNodeData->DataBlockOffset = dataBlockOffset; + + if (dataBlockOffset <= stack->Parameters.WMI.BufferSize) { + pOffsets = &pNodeData->OffsetInstanceDataAndLength[0]; + sizeRemaining = stack->Parameters.WMI.BufferSize - dataBlockOffset; + pData = (PUCHAR) WDF_PTR_ADD_OFFSET(pNodeData, dataBlockOffset); + } + else { + // + // There is not enough room in the WNODE to complete the query, but + // we still want to query all the instances to see how big a buffer the + // caller should resend. + // + pOffsets = NULL; + pData = NULL; + sizeRemaining = 0; + + // + // We are in the too small case + // + tooSmall = TRUE; + status = STATUS_BUFFER_TOO_SMALL; + } + + if (instanceCount > 0 && Provider->GetMinInstanceBufferSize() != 0) { + ULONG size, minSizeAdjusted; + + size = 0; + + minSizeAdjusted = (ULONG) WDF_ALIGN_SIZE_UP( + Provider->GetMinInstanceBufferSize(), + MEMORY_ALLOCATION_ALIGNMENT + ); + + // + // Quick size check to make sure there is enough buffer for all of the + // instances. We round up all but the last instance's minimum size so + // that we can make sure we have enough room for an aligned bufer for + // each instance. + // + // All but the last instance are using the adjusted size. In the end, + // we will have: + // + // size = minSizeAdjusted * (instanceCount-1) + + // Provider->GetMinInstanceBufferSize(); + // + // NOTE: we do not care about instances which do not support query + // data. We don't care b/c by computing the total size of all + // instances we compute the maximum sized buffer needed, and if + // a few instances do no support query data, then the buffer + // will just be too large, never too small. + // + status = RtlULongMult(minSizeAdjusted, instanceCount - 1, &size); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = RtlULongAdd(size, Provider->GetMinInstanceBufferSize(), &size); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Since the client indicated that that each block as a minimum instance + // size (which in reality is the fixed size, variable sized instnaces + // should report a minimum instance size of zero), we can compute the + // required buffer size w/out querying each instance for the required + // size. + // + if (sizeRemaining < size) { + // + // bufferUsed in the buffer too small case indicates how many bytes + // we want the caller to allocate. + // + bufferUsed = size; + status = STATUS_BUFFER_TOO_SMALL; + goto Done; + } + } + + for (i = 0; i < instanceCount; i++) { + FxWmiInstance* pInstance; + + // + // In the case where we have a minimum instance size, we should have + // verified correctly above to have enough buffer. + // + ASSERT(sizeRemaining >= Provider->GetMinInstanceBufferSize()); + + pInstance = Provider->GetInstanceReferenced(i, Irp); + + if (pInstance == NULL) { + break; + } + + if (pInstance->IsQueryInstanceSupported()) { + ULONG tmpSize; + + tmpSize = 0; + + status = pInstance->QueryInstance(sizeRemaining, pData, &tmpSize); + + if (NT_SUCCESS(status) || status == STATUS_BUFFER_TOO_SMALL) { + ULONG adjustedSize; + + // + // We calculate the size in both cases. In the NT_SUCCESS case, + // it is the amount of buffer used. In the too small case, it is + // the amount of buffer required for a subsequent query. + // + adjustedSize = (ULONG) WDF_ALIGN_SIZE_UP( + tmpSize, MEMORY_ALLOCATION_ALIGNMENT + ); + + if (adjustedSize < tmpSize) { + // + // Overflow, adjustedSize will be >= tmpSize in the normal + // case. + // + status = STATUS_INTEGER_OVERFLOW; + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIINSTNACE %p queried, returned a buffer size of %d," + "but it could not be rounded up, %!STATUS!", + pInstance->GetHandle(), tmpSize, status); + goto QueryError; + } + + // + // Keep track of how much we adjusted up the size on the last + // instance so that when compute the total buffer used, we + // do not include the final size adjustment. + // + lastAdjustment = adjustedSize - tmpSize; + + // + // We only write the offset and data if we have not yet + // encountered an instance where the buffer size was too small. + // + if (NT_SUCCESS(status) && tooSmall == FALSE) { + // + // dataBlockOffset is where we are currently at in the buffer + // + pOffsets[i].LengthInstanceData = tmpSize; + pOffsets[i].OffsetInstanceData = dataBlockOffset; + + pData += adjustedSize; + } + else { + tooSmall = TRUE; + } + + // + // Compute how much buffer we have left and our offset into it. + // + if (adjustedSize <= sizeRemaining) { + sizeRemaining -= adjustedSize; + + // + // dataBlockOffset += adjustedSize; + // + addStatus = RtlULongAdd(dataBlockOffset, + adjustedSize, + &dataBlockOffset); + } + else { + // + // dataBlockOffset += sizeRemaining; + // + addStatus = RtlULongAdd(dataBlockOffset, + sizeRemaining, + &dataBlockOffset); + sizeRemaining = 0; + } + + if (!NT_SUCCESS(addStatus)) { + status = addStatus; + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIPROVIDER %p, arithmetic overflow in computing " + "block offset, %!STATUS!", Provider->GetHandle(), + status); + goto QueryError; + } + + // + // Compute how much buffer space we have used or require the + // caller to provide. This is just the count of bytes for the + // data queried, it does not yet include the array size required + // to report offset & lengths. + // + // bufferUsed += adjustedSize; + // + addStatus = RtlULongAdd(bufferUsed, adjustedSize, &bufferUsed); + + if (!NT_SUCCESS(addStatus)) { + status = addStatus; + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIPROVIDER %p, arithmetic overflow in computing " + "buffer consumed(%d+%d), %!STATUS!", + Provider->GetHandle(), bufferUsed, adjustedSize, status); + goto QueryError; + } + } + } + else if (pOffsets != NULL) { + // + // Indicate no buffer and the current offset. If there any + // other instances after this one, they will share the same + // offset. + // + pOffsets[i].LengthInstanceData = 0; + pOffsets[i].OffsetInstanceData = dataBlockOffset; + } + +QueryError: + pInstance->RELEASE(Irp); + + // + // We continue on STATUS_BUFFER_TOO_SMALL so that we can ask each + // instance the amount of buffer it needs. + // + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { + break; + } + } + + // + // We can have STATUS_BUFFER_TOO_SMALL if the last instance could not fit + // its data into the buffer or have success if the last instance could write + // its data, but a previous instance could not. + // + if (status == STATUS_BUFFER_TOO_SMALL || (NT_SUCCESS(status) && tooSmall)) { + // + // Since we align up the size of each block to MEMORY_ALLOCATION_ALIGNMENT, + // the total buffer size is possibly adjusted up too high. Subtract the + // last adjustment made for alignment when computing the instance size + // so that our total size is not rounded up. + // + // CompleteWmiQueryAllDataRequest will take care of adding enough space + // to the requested size to account for the array of instance offsets + // and lengths. + // + bufferUsed -=lastAdjustment; + + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFWMIPROVIDER %p QueryAllData returning %!STATUS!, requesting " + "buffer size of 0x%x", Provider->GetHandle(), status, bufferUsed); + } + else if (NT_SUCCESS(status)) { + // + // Compute the total amount of buffer used. dataBlockOffset is the + // offset of the next instance, which is one past the end, so just + // compute the distance from the start. + // + // Since align up the size of each block to MEMORY_ALLOCATION_ALIGNMENT, + // the total buffer size is possibly adjusted up too high. Subtract the + // last adjustment made for alignment when computing the instance size + // so that our total size is not rounded up. + // + ASSERT(dataBlockOffset >= pNodeData->DataBlockOffset); + ASSERT(dataBlockOffset - pNodeData->DataBlockOffset >= lastAdjustment); + bufferUsed = dataBlockOffset - pNodeData->DataBlockOffset - lastAdjustment; + } + else { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFWMIPROVIDER %p QueryAllData returning %!STATUS!", + Provider->GetHandle(), status); + + bufferUsed = 0; + } + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFWMIPROVIDER %p QueryAllData returning %!STATUS!, buffer used 0x%x", + Provider->GetHandle(), status, bufferUsed); + +Done: + status = This->CompleteWmiRequest(Irp, status, bufferUsed); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_QuerySingleInstance( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ) +{ + PWNODE_SINGLE_INSTANCE pSingle; + PIO_STACK_LOCATION stack; + NTSTATUS status; + ULONG size, bufferSize; + + size = 0; + + stack = IoGetCurrentIrpStackLocation(Irp); + pSingle = (PWNODE_SINGLE_INSTANCE) stack->Parameters.WMI.Buffer; + bufferSize = stack->Parameters.WMI.BufferSize - pSingle->DataBlockOffset; + + if (Instance->IsQueryInstanceSupported() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + } + else if (bufferSize < Provider->GetMinInstanceBufferSize()) { + size = Provider->GetMinInstanceBufferSize(); + status = STATUS_BUFFER_TOO_SMALL; + } + else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + status = Instance->QueryInstance( + bufferSize, + WDF_PTR_ADD_OFFSET(pSingle, pSingle->DataBlockOffset), + &size + ); + + pSingle->SizeDataBlock = size; + } + + status = This->CompleteWmiRequest(Irp, status, size); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_ChangeSingleInstance( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ) +{ + PWNODE_SINGLE_INSTANCE pSingle; + PIO_STACK_LOCATION stack; + NTSTATUS status; + ULONG size; + + size = 0; + + stack = IoGetCurrentIrpStackLocation(Irp); + pSingle = (PWNODE_SINGLE_INSTANCE) stack->Parameters.WMI.Buffer; + + if (Instance->IsSetInstanceSupported() == FALSE) { + status = STATUS_WMI_READ_ONLY; + } + else if (pSingle->SizeDataBlock < Provider->m_MinInstanceBufferSize) { + size = Provider->m_MinInstanceBufferSize; + status = STATUS_BUFFER_TOO_SMALL; + } + else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + size = pSingle->SizeDataBlock; + + status = Instance->SetInstance( + pSingle->SizeDataBlock, + size == 0 ? + NULL : WDF_PTR_ADD_OFFSET(pSingle, pSingle->DataBlockOffset) + ); + + ASSERT(status != STATUS_PENDING); + if (status == STATUS_PENDING) { + status = STATUS_UNSUCCESSFUL; + size = 0; + } + } + + status = This->CompleteWmiRequest(Irp, status, size); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_ChangeSingleItem( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ) +{ + PWNODE_SINGLE_ITEM pSingle; + NTSTATUS status; + ULONG size; + + UNREFERENCED_PARAMETER(Provider); + + size = 0; + + pSingle = (PWNODE_SINGLE_ITEM) IoGetCurrentIrpStackLocation(Irp)-> + Parameters.WMI.Buffer; + + if (Instance->IsSetItemSupported() == FALSE) { + status = STATUS_WMI_READ_ONLY; + } + else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + status = Instance->SetItem( + pSingle->ItemId, + pSingle->SizeDataItem, + pSingle->SizeDataItem == 0 ? + NULL : WDF_PTR_ADD_OFFSET(pSingle, pSingle->DataBlockOffset) + ); + + ASSERT(status != STATUS_PENDING); + if (status == STATUS_PENDING) { + status = STATUS_UNSUCCESSFUL; + size = 0; + } + } + + status = This->CompleteWmiRequest(Irp, status, size); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_EnableDisableEventsAndCollection( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ) +{ + NTSTATUS status; + BOOLEAN enable; + WDF_WMI_PROVIDER_CONTROL control; + PIO_STACK_LOCATION stack; + + UNREFERENCED_PARAMETER(This); + UNREFERENCED_PARAMETER(Instance); + + Irp->IoStatus.Information = 0; + + stack = IoGetCurrentIrpStackLocation(Irp); + + if (stack->Parameters.WMI.BufferSize < sizeof(WNODE_HEADER)) { + status = STATUS_INVALID_PARAMETER; + goto Done; + } + + switch (stack->MinorFunction) { + case IRP_MN_ENABLE_EVENTS: + enable = TRUE; + control = WdfWmiEventControl; + break; + + case IRP_MN_DISABLE_EVENTS: + enable = FALSE; + control = WdfWmiEventControl; + break; + + case IRP_MN_ENABLE_COLLECTION: + enable = TRUE; + control = WdfWmiInstanceControl; + break; + + case IRP_MN_DISABLE_COLLECTION: + enable = FALSE; + control = WdfWmiInstanceControl; + break; + + default: + status = Irp->IoStatus.Status; + goto Done; + } + + if (control == WdfWmiEventControl) { + Provider->m_EventControlEnabled = enable; + + // + // Capture the tracing information before making the callback + // + if (Provider->m_Flags & WdfWmiProviderTracing) { + Provider->SetTracingHandle( + ((PWNODE_HEADER) stack->Parameters.WMI.Buffer)->HistoricalContext + ); + } + } + else { + Provider->m_DataBlockControlEnabled = enable; + } + + if (Provider->IsFunctionControlSupported()) { + status = Provider->FunctionControl(control, enable); + } + else { + status = STATUS_SUCCESS; + } + + ASSERT(status != STATUS_PENDING); + if (status == STATUS_PENDING) { + status = STATUS_UNSUCCESSFUL; + } + + // + // Undo the previous capture on error + // + if (!NT_SUCCESS(status)) { + if (control == WdfWmiEventControl) { + Provider->m_EventControlEnabled = FALSE; + + if (Provider->m_Flags & WdfWmiProviderTracing) { + Provider->SetTracingHandle(NULL); + } + } + else { + Provider->m_DataBlockControlEnabled = FALSE; + } + + } + +Done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_ExecuteMethod( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ) +{ + PWNODE_METHOD_ITEM pMethod; + PIO_STACK_LOCATION stack; + NTSTATUS status; + ULONG size, inBufferSize, outBufferSize; + + UNREFERENCED_PARAMETER(This); + UNREFERENCED_PARAMETER(Provider); + + size = 0; + + stack = IoGetCurrentIrpStackLocation(Irp); + pMethod = (PWNODE_METHOD_ITEM) stack->Parameters.WMI.Buffer; + inBufferSize = pMethod->SizeDataBlock; + outBufferSize = stack->Parameters.WMI.BufferSize - pMethod->DataBlockOffset; + + + + + + + + + + + + if (Instance->IsExecuteMethodSupported() == FALSE) { + // + // WmiLib returns this value when there is no execute method function + // pointer specified to it. + // + status = STATUS_INVALID_DEVICE_REQUEST; + } + else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + status = Instance->ExecuteMethod( + pMethod->MethodId, + inBufferSize, + outBufferSize, + (inBufferSize == 0 && outBufferSize == 0) ? + NULL : WDF_PTR_ADD_OFFSET(pMethod, pMethod->DataBlockOffset), + &size + ); + + ASSERT(status != STATUS_PENDING); + if (status == STATUS_PENDING) { + status = STATUS_UNSUCCESSFUL; + size = 0; + } + } + + status = This->CompleteWmiRequest(Irp, status, size); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::_RegInfo( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in_opt FxWmiProvider* Provider, + __in_opt FxWmiInstance* Instance + ) +{ + PIO_STACK_LOCATION stack; + PUNICODE_STRING pRegPath; + PWMIREGINFO pWmiRegInfo; + PUCHAR pBuffer; + PUNICODE_STRING pMofString; + FxDevice* pDevice; + NTSTATUS status; + ULONG registryPathOffset, mofResourceOffset, bufferNeeded, information, + bufferSize; + KIRQL irql; + + UNREFERENCED_PARAMETER(Provider); + UNREFERENCED_PARAMETER(Instance); + + information = 0; + + stack = IoGetCurrentIrpStackLocation(Irp); + pBuffer = (PUCHAR) stack->Parameters.WMI.Buffer; + bufferSize = stack->Parameters.WMI.BufferSize; + + pDevice = This->m_Device; + + This->Lock(&irql); + + mofResourceOffset = sizeof(WMIREGINFO) + + This->m_NumProviders * sizeof(WMIREGGUIDW); + + pMofString = NULL; + + if (pDevice->m_MofResourceName.Buffer != NULL) { + pMofString = &pDevice->m_MofResourceName; + } + else { + // + // Start with the parent and iterate up until we hit a device without + // a parent. + // + pDevice = pDevice->m_ParentDevice; + + while (pDevice != NULL) { + if (pDevice->m_MofResourceName.Buffer != NULL) { + pMofString = &pDevice->m_MofResourceName; + break; + } + + // + // Advance to the next ancestor + // + pDevice = pDevice->m_ParentDevice; + } + + // + // Restore pDevice back to this device + // + pDevice = This->m_Device; + } + + pRegPath = pDevice->GetDriver()->GetRegistryPathUnicodeString(); + + // + // if there is a mof string, add its length. We always need to at least + // add the USHORT to indicate a string of size 0. + // + registryPathOffset = mofResourceOffset + sizeof(USHORT); + if (pMofString != NULL) { + registryPathOffset += pMofString->Length; + } + + // + // eventually bufferNeeded = registryPathOffset + pRegPath->Length + + // sizeof(USHORT) + // + status = RtlULongAdd(registryPathOffset, pRegPath->Length, &bufferNeeded); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = RtlULongAdd(bufferNeeded, sizeof(USHORT), &bufferNeeded); + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (bufferNeeded <= bufferSize) { + PLIST_ENTRY ple; + ULONG i; + BOOLEAN addref; + + information = bufferNeeded; + + pWmiRegInfo = (PWMIREGINFO) pBuffer; + pWmiRegInfo->BufferSize = bufferNeeded; + pWmiRegInfo->NextWmiRegInfo = 0; + pWmiRegInfo->MofResourceName = mofResourceOffset; + pWmiRegInfo->RegistryPath = registryPathOffset; + pWmiRegInfo->GuidCount = This->m_NumProviders; + + addref = IoGetCurrentIrpStackLocation(Irp)->MinorFunction == IRP_MN_REGINFO_EX + ? TRUE : FALSE; + + for (ple = This->m_ProvidersListHead.Flink, i = 0; + i < This->m_NumProviders; + ple = ple->Flink, i++) { + + PWMIREGGUIDW pWmiRegGuid; + PDEVICE_OBJECT pdo; + FxWmiProvider* pProvider; + + pProvider = CONTAINING_RECORD(ple, FxWmiProvider, m_ListEntry); + + pWmiRegGuid = &pWmiRegInfo->WmiRegGuid[i]; + + RtlCopyMemory(&pWmiRegGuid->Guid, + &pProvider->m_Guid, + sizeof(GUID)); + + pWmiRegGuid->InstanceCount = pProvider->m_NumInstances; + + pWmiRegGuid->Flags = pProvider->GetRegistrationFlagsLocked(); + + pdo = pDevice->GetPhysicalDevice(); + pWmiRegGuid->Pdo = (ULONG_PTR) pdo; + + if (addref) { + ObReferenceObject(pdo); + } + } + } + else { + *((PULONG) pBuffer) = bufferNeeded; + information = sizeof(ULONG); + } + + This->Unlock(irql); + + // + // Must copy the strings outside of any lock since they are in paged pool + // + if (bufferNeeded <= bufferSize) { + PUSHORT pLength; + + pLength = WDF_PTR_ADD_OFFSET_TYPE(pBuffer, mofResourceOffset, PUSHORT); + + if (pMofString != NULL) { + *pLength = pMofString->Length; + + RtlCopyMemory(pLength + 1, + pMofString->Buffer, + pMofString->Length); + } + else { + *pLength = 0; + } + + pLength = WDF_PTR_ADD_OFFSET_TYPE(pBuffer, registryPathOffset, PUSHORT); + + *pLength = pRegPath->Length; + RtlCopyMemory(pLength + 1, + pRegPath->Buffer, + pRegPath->Length); + } + + status = STATUS_SUCCESS; + +Done: + if (!NT_SUCCESS(status)) { + This->Unlock(irql); + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = information; + + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +VOID +FxWmiIrpHandler::CompleteWmiQueryAllDataRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ) +{ + PWNODE_ALL_DATA pNodeAllData; + ULONG bufferNeeded, information; + PIO_STACK_LOCATION stack; + + stack = IoGetCurrentIrpStackLocation(Irp); + + pNodeAllData = (PWNODE_ALL_DATA) stack->Parameters.WMI.Buffer; + bufferNeeded = pNodeAllData->DataBlockOffset + BufferUsed; + + if (NT_SUCCESS(Status) && bufferNeeded > stack->Parameters.WMI.BufferSize) { + Status = STATUS_BUFFER_TOO_SMALL; + } + + if (NT_SUCCESS(Status)) { + KeQuerySystemTime(&pNodeAllData->WnodeHeader.TimeStamp); + + pNodeAllData->WnodeHeader.BufferSize = bufferNeeded; + information = bufferNeeded; + } + else if (Status == STATUS_BUFFER_TOO_SMALL) { + PWNODE_TOO_SMALL pNodeTooSmall; + + pNodeTooSmall = (PWNODE_TOO_SMALL) stack->Parameters.WMI.Buffer; + + pNodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL); + pNodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL; + pNodeTooSmall->SizeNeeded = bufferNeeded; + + information = sizeof(WNODE_TOO_SMALL); + Status = STATUS_SUCCESS; + } + else { + information = 0; + } + + Irp->IoStatus.Information = information; + Irp->IoStatus.Status = Status; +} + +VOID +FxWmiIrpHandler::CompleteWmiQuerySingleInstanceRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ) +{ + PWNODE_SINGLE_INSTANCE pNodeSingle; + ULONG bufferNeeded, information; + + pNodeSingle = (PWNODE_SINGLE_INSTANCE) + IoGetCurrentIrpStackLocation(Irp)->Parameters.WMI.Buffer; + + bufferNeeded = pNodeSingle->DataBlockOffset + BufferUsed; + + if (NT_SUCCESS(Status)) { + pNodeSingle->WnodeHeader.BufferSize = bufferNeeded; + KeQuerySystemTime(&pNodeSingle->WnodeHeader.TimeStamp); + + ASSERT(pNodeSingle->SizeDataBlock <= BufferUsed); + information = bufferNeeded; + } + else if (Status == STATUS_BUFFER_TOO_SMALL) { + PWNODE_TOO_SMALL pNodeTooSmall; + + pNodeTooSmall = (PWNODE_TOO_SMALL) pNodeSingle; + + pNodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL); + pNodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL; + pNodeTooSmall->SizeNeeded = bufferNeeded; + + information = sizeof(WNODE_TOO_SMALL); + Status = STATUS_SUCCESS; + } + else { + information = 0; + } + + Irp->IoStatus.Information = information; + Irp->IoStatus.Status = Status; +} + +VOID +FxWmiIrpHandler::CompleteWmiExecuteMethodRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ) +{ + PWNODE_METHOD_ITEM pNodeMethod; + ULONG bufferNeeded, information; + + pNodeMethod = (PWNODE_METHOD_ITEM) + IoGetCurrentIrpStackLocation(Irp)->Parameters.WMI.Buffer; + + bufferNeeded = pNodeMethod->DataBlockOffset + BufferUsed; + + if (NT_SUCCESS(Status)) { + pNodeMethod->WnodeHeader.BufferSize = bufferNeeded; + pNodeMethod->SizeDataBlock = BufferUsed; + KeQuerySystemTime(&pNodeMethod->WnodeHeader.TimeStamp); + + information = bufferNeeded; + } + else if (Status == STATUS_BUFFER_TOO_SMALL) { + PWNODE_TOO_SMALL pNodeTooSmall; + + pNodeTooSmall = (PWNODE_TOO_SMALL) pNodeMethod; + + pNodeTooSmall->WnodeHeader.BufferSize = sizeof(WNODE_TOO_SMALL); + pNodeTooSmall->WnodeHeader.Flags = WNODE_FLAG_TOO_SMALL; + pNodeTooSmall->SizeNeeded = bufferNeeded; + + information = sizeof(WNODE_TOO_SMALL); + Status = STATUS_SUCCESS; + } + else { + information = 0; + } + + Irp->IoStatus.Information = information; + Irp->IoStatus.Status = Status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::CompleteWmiRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ) +/*++ + +Routine Description: + This routine will do the work of completing a WMI irp. Depending upon the + the WMI request this routine will fixup the returned WNODE appropriately. + + This may be called at DPC level + +Arguments: + + Irp - Supplies the Irp making the request. + + Status has the return status code for the IRP + + BufferUsed has the number of bytes needed by the device to return the + data requested in any query. In the case that the buffer passed to + the device is too small this has the number of bytes needed for the + return data. If the buffer passed is large enough then this has the + number of bytes actually used by the device. + +Return Value: + + status + +--*/ +{ + switch (IoGetCurrentIrpStackLocation(Irp)->MinorFunction) { + case IRP_MN_QUERY_ALL_DATA: + CompleteWmiQueryAllDataRequest(Irp, Status, BufferUsed); + break; + + case IRP_MN_QUERY_SINGLE_INSTANCE: + CompleteWmiQuerySingleInstanceRequest(Irp, Status, BufferUsed); + break; + + case IRP_MN_EXECUTE_METHOD: + CompleteWmiExecuteMethodRequest(Irp, Status, BufferUsed); + break; + + case IRP_MN_CHANGE_SINGLE_INSTANCE: + case IRP_MN_CHANGE_SINGLE_ITEM: + // + // Lot's of drivers return STATUS_BUFFER_TOO_SMALL for an invalid buffer + // size. WMI expects STATUS_WMI_SET_FAILURE in this case. Change the + // Status to the expected value. No way to return any size in + // Information, the buffer is input only. + // + if (Status == STATUS_BUFFER_TOO_SMALL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Converting %!STATUS! to %!STATUS!", + Status, STATUS_WMI_SET_FAILURE); + Status = STATUS_WMI_SET_FAILURE; + } + // || || Fall through || || + // \/ \/ \/ \/ + + default: + // + // All other requests don't return any data + // + Irp->IoStatus.Status = Status; + Irp->IoStatus.Information = 0; + break; + } + + // + // One of the complete functions may have morphed the status value + // + Status = Irp->IoStatus.Status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return Status; +} + diff --git a/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmipch.hpp b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmipch.hpp new file mode 100644 index 00000000000..16bec659f9c --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmipch.hpp @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxwmipch.hpp + +Abstract: + + This module contains header definitions and include files needed by all + modules in this directory. + +Author: + +Environment: + Kernel mode only + +Revision History: + +--*/ + +#ifndef __FX_WMI_PCH_HPP__ +#define __FX_WMI_PCH_HPP__ + +extern "C" { +#include +} + +#include + +#endif // __FX_WMI_PCH_HPP__ diff --git a/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiprovider.cpp b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiprovider.cpp new file mode 100644 index 00000000000..a542c2d3dea --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/irphandlers/wmi/fxwmiprovider.cpp @@ -0,0 +1,563 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiProvider.cpp + +Abstract: + + This module implements the FxWmiProvider object + +Author: + + + +Revision History: + + +--*/ + +#include "fxwmipch.hpp" + +extern "C" { +#include "FxWmiProvider.tmh" +} + +FxWmiProvider::FxWmiProvider( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WMI_PROVIDER_CONFIG Config, + __in FxDevice* Device + ) : + FxNonPagedObject(FX_TYPE_WMI_PROVIDER, + sizeof(FxWmiProvider), + FxDriverGlobals), + m_FunctionControl(FxDriverGlobals) +{ + InitializeListHead(&m_ListEntry); + InitializeListHead(&m_InstanceListHead); + m_NumInstances = 0; + + m_Parent = Device->m_PkgWmi; + + m_EventControlEnabled = FALSE; + m_DataBlockControlEnabled = FALSE; + m_RemoveGuid = FALSE; + + m_TracingHandle = 0; + + m_Flags = Config->Flags; + m_MinInstanceBufferSize = Config->MinInstanceBufferSize; + RtlCopyMemory(&m_Guid, &Config->Guid, sizeof(GUID)); + + if (Config->EvtWmiProviderFunctionControl != NULL) { + m_FunctionControl.m_Method = Config->EvtWmiProviderFunctionControl; + } + + // + // Driver cannot call WdfObjectDelete on this handle + // + MarkNoDeleteDDI(); + + MarkDisposeOverride(ObjectDoNotLock); +} + +FxWmiProvider::~FxWmiProvider() +{ + ASSERT(IsListEmpty(&m_ListEntry)); +} + +BOOLEAN +FxWmiProvider::Dispose( + VOID + ) +{ + // + // Object is being deleted, remove this object from the irp handler's list + // of providers. If we don't do this, the irp handler will have a list + // which contains entries which have been freed. + // + m_Parent->RemoveProvider(this); + + return __super::Dispose(); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::_Create( + __in PFX_DRIVER_GLOBALS CallersGlobals, + __in WDFDEVICE Device, + __in_opt PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + __in PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + __out WDFWMIPROVIDER* WmiProvider, + __out FxWmiProvider** Provider + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + FxWmiProvider* pProvider; + NTSTATUS status; + WDFOBJECT hProvider; + GUID zeroGuid; + BOOLEAN update; + + FxObjectHandleGetPtrAndGlobals(CallersGlobals, + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals); + + *Provider = NULL; + update = FALSE; + + *WmiProvider = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, + ProviderAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + if (WmiProviderConfig->Size != sizeof(WDF_WMI_PROVIDER_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WmiProviderConfig Size 0x%x, expected size 0x%x, %!STATUS!", + WmiProviderConfig->Size, sizeof(WDF_WMI_PROVIDER_CONFIG), + status); + + return status; + } + + if ((WmiProviderConfig->Flags & ~WdfWmiProviderValidFlags) != 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid flag(s) set, Flags 0x%x, valid mask 0x%x, %!STATUS!", + WmiProviderConfig->Flags, WdfWmiProviderValidFlags, + status); + return status; + } + + if ((WmiProviderConfig->Flags & WdfWmiProviderTracing) && + (WmiProviderConfig->Flags & ~WdfWmiProviderTracing)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WdfWmiProviderTracing must be the only flag set, %!STATUS!", + status); + + return status; + } + + // + // Function control makes sense if it is expensive. Otherwise you will + // not be called back on it. + // + // The opposite, marking yourself as expensive but providing no callback is + // OK b/c the provider marks the enabled state and the driver can retrieve + // it at runtime. + // + // Function control also applies to tracing GUIDs since the tracing subsystem + // will call enable/disable events to start/stop tracing. + // + if (WmiProviderConfig->EvtWmiProviderFunctionControl != NULL && + ((WmiProviderConfig->Flags & (WdfWmiProviderTracing | WdfWmiProviderExpensive)) == 0)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtWmiProviderFunctionControl can only be set if Flags 0x%x has " + "WdfWmiProviderTracing (%d) or WdfWmiProviderExpensive (%d) bit " + "values set, %!STATUS!", + WmiProviderConfig->Flags, WdfWmiProviderTracing, + WdfWmiProviderExpensive, status); + + return status; + } + + RtlZeroMemory(&zeroGuid, sizeof(zeroGuid)); + + if (RtlCompareMemory(&WmiProviderConfig->Guid, + &zeroGuid, + sizeof(GUID)) == sizeof(GUID)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WmiProvider Guid filed is all zeros, %!STATUS!", + status); + + return status; + } + + pProvider = NULL; + + pProvider = new(pFxDriverGlobals, ProviderAttributes) + FxWmiProvider(pFxDriverGlobals, WmiProviderConfig, pDevice); + + if (pProvider == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate memory for a WDFWMIPROVIDER, %!STATUS!", + status); + + return status; + } + + status = pDevice->m_PkgWmi->AddProvider(pProvider, &update); + + if (NT_SUCCESS(status)) { + status = pProvider->Commit(ProviderAttributes, &hProvider, pDevice); + + if (!NT_SUCCESS(status)) { + pDevice->m_PkgWmi->RemoveProvider(pProvider); + } + else { + // + // NT_SUCCES(status) case + // + *WmiProvider = (WDFWMIPROVIDER) hProvider; + } + } + + if (NT_SUCCESS(status)) { + *Provider = pProvider; + + if (update) { + pDevice->m_PkgWmi->UpdateGuids(); + } + } + else { + // + // AddProvider incremented update count on success however since we + // are not going to update registration due to this failure, decrement + // the count. + // + if (update) { + pDevice->m_PkgWmi->DecrementUpdateCount(); + } + + pProvider->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::AddInstanceLocked( + __in FxWmiInstance* Instance, + __in BOOLEAN NoErrorIfPresent, + __out PBOOLEAN Update, + __in AddInstanceAction Action + ) +{ + NTSTATUS status; + + *Update = FALSE; + + if (!IsListEmpty(&Instance->m_ListEntry)) { + if (NoErrorIfPresent) { + return STATUS_SUCCESS; + } + else { + // + // Entry is already on a list, bad caller! + // + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFWMIINSTANCE %p already added, %!STATUS!", + Instance->GetHandle(), status); + + return status; + } + } + + // + // Check to see if we are in the process of + // + switch (m_Parent->m_RegisteredState) { + case FxWmiIrpHandler::WmiUnregistered: + // + // The GUID will be reported when we do the initial registration + // + break; + + case FxWmiIrpHandler::WmiDeregistered: + // + // Either the GUID will be reported when we do the re-registration or + // we will clean it up when we goto the cleanup state. + // + break; + + case FxWmiIrpHandler::WmiRegistered: + // + // Since we already registered we need to tell WMI the change in the + // number of instances on this provider. + // + *Update = TRUE; + break; + + case FxWmiIrpHandler::WmiCleanedUp: + // + // Device is going away, registration is not allowed for the device + // anymore. + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGDEVICE, + "WMI is being cleanedup, WDFWMIINSTANCE %p add failing, %!STATUS!", + Instance->GetHandle(), status); + + return status; + + default: + ASSERT(FALSE); + break; + } + + if (Action == AddInstanceToTail) { + InsertTailList(&m_InstanceListHead, &Instance->m_ListEntry); + } + else { + InsertHeadList(&m_InstanceListHead, &Instance->m_ListEntry); + } + + // + // Since the count is increasing to at least one, we are not going to + // need to report this GUID as missing. We could check the + // m_Parent->m_RegisteredState and only set it when we are registered, but + // it does us no harm to always clear this value regardless of state. + // + m_RemoveGuid = FALSE; + + m_NumInstances++; + status = STATUS_SUCCESS; + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::AddInstance( + __in FxWmiInstance* Instance, + __in BOOLEAN NoErrorIfPresent + ) +{ + NTSTATUS status; + KIRQL irql; + BOOLEAN update; + + if (m_Flags & WdfWmiProviderTracing) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFWMIINSTANCE %p cannot be added to tracing WDFWMIPROVIDER %p, " + "%!STATUS!", Instance->GetHandle(), GetHandle(), status); + + return status; + } + + m_Parent->Lock(&irql); + status = AddInstanceLocked(Instance, NoErrorIfPresent, &update); + + if (update) { + update = m_Parent->DeferUpdateLocked(irql); + } + m_Parent->Unlock(irql); + + if (update) { + m_Parent->UpdateGuids(); + } + + return status; +} + +VOID +FxWmiProvider::RemoveInstance( + __in FxWmiInstance* Instance + ) +{ + KIRQL irql; + BOOLEAN update; + + update = FALSE; + + m_Parent->Lock(&irql); + + if (!IsListEmpty(&Instance->m_ListEntry)) { + // + // Instance is in the list of instances on this provider. Remove it. + // + RemoveEntryList(&Instance->m_ListEntry); + InitializeListHead(&Instance->m_ListEntry); + m_NumInstances--; + + if (m_Parent->m_RegisteredState == FxWmiIrpHandler::WmiRegistered) { + update = TRUE; + + // + // When the count goes to zero, inform WMI that the GUID should be + // removed when we get requeried. We only need to do this once we have + // been registered. In all other states, we ignore this value. + // + if (m_NumInstances == 0 && + (m_Flags & WdfWmiProviderExpensive) == 0) { + m_RemoveGuid = TRUE; + } + } + } + else { + // + // The instance was explicitly removed and now the instance is trying + // to remove itself during dispose. Nothing to do. + // + DO_NOTHING(); + } + + if (update) { + update = m_Parent->DeferUpdateLocked(irql); + } + + m_Parent->Unlock(irql); + + if (update) { + m_Parent->UpdateGuids(); + } +} + +ULONG +FxWmiProvider::GetInstanceIndex( + __in FxWmiInstance* Instance + ) +{ + PLIST_ENTRY ple; + ULONG index; + KIRQL irql; + + m_Parent->Lock(&irql); + for (index = 0, ple = m_InstanceListHead.Flink; + index < m_NumInstances; + index++, ple = ple->Flink) { + if (CONTAINING_RECORD(ple, FxWmiInstance, m_ListEntry) == Instance) { + break; + } + } + m_Parent->Unlock(irql); + + return index; +} + +_Must_inspect_result_ +FxWmiInstance* +FxWmiProvider::GetInstanceReferenced( + __in ULONG Index, + __in PVOID Tag + ) +{ + FxWmiInstance* pInstance; + KIRQL irql; + + m_Parent->Lock(&irql); + pInstance = GetInstanceReferencedLocked(Index, Tag); + m_Parent->Unlock(irql); + + return pInstance; +} + +_Must_inspect_result_ +FxWmiInstance* +FxWmiProvider::GetInstanceReferencedLocked( + __in ULONG Index, + __in PVOID Tag + ) +{ + FxWmiInstance* pFound; + PLIST_ENTRY ple; + ULONG i; + + pFound = NULL; + + for (i = 0, ple = m_InstanceListHead.Flink; + i < m_NumInstances; + ple = ple->Flink, i++) { + + if (i == Index) { + pFound = CONTAINING_RECORD(ple, FxWmiInstance, m_ListEntry); + pFound->ADDREF(Tag); + break; + } + } + + return pFound; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::FunctionControl( + __in WDF_WMI_PROVIDER_CONTROL Control, + __in BOOLEAN Enable + ) +{ + return m_FunctionControl.Invoke(m_Parent->GetDevice()->GetHandle(), + GetHandle(), + Control, + Enable); +} + +ULONG +FxWmiProvider::GetRegistrationFlagsLocked( + VOID + ) +{ + ULONG flags; + + if (m_Flags & WdfWmiProviderTracing) { + flags = WMIREG_FLAG_TRACED_GUID | WMIREG_FLAG_TRACE_CONTROL_GUID; + + // + // Once tracing GUID is registered, we do not allow it to be unregistered + // + ASSERT(m_RemoveGuid == FALSE); + } + else { + flags = WMIREG_FLAG_INSTANCE_PDO; + + if (m_Flags & WdfWmiProviderExpensive) { + flags |= WMIREG_FLAG_EXPENSIVE; + } + + if (m_Flags & WdfWmiProviderEventOnly) { + flags |= WMIREG_FLAG_EVENT_ONLY_GUID; + } + } + + if (m_RemoveGuid) { + // + // We have gone down to zero instances of this provider, report it as + // gone to WMI. + // + ASSERT(m_NumInstances == 0); + flags |= WMIREG_FLAG_REMOVE_GUID; + + // + // Once reported as removed, we do not have not have to report ourselves + // as removed again. + // + m_RemoveGuid = FALSE; + } + + return flags; +} + diff --git a/sdk/lib/drivers/wdf/kmdf/src/librarycommon/fxlibrarycommon.cpp b/sdk/lib/drivers/wdf/kmdf/src/librarycommon/fxlibrarycommon.cpp new file mode 100644 index 00000000000..6fe2cd2e886 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/librarycommon/fxlibrarycommon.cpp @@ -0,0 +1,717 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +extern "C" { +#include +} + +// +// This will cause inclusion of VfWdfFunctions table implementation from header +// +#define VF_FX_DYNAMICS_GENERATE_TABLE 1 + +// +// Compute the length based on the max. service name length and the rest of the +// error string as seen in ReportDdiFunctionCountMismatch +// +#define EVTLOG_DDI_COUNT_ERROR_MAX_LEN (53 + MAX_PATH) + +#include "fx.hpp" +#include "fxldr.h" +#include "FxLibraryCommon.h" +#include "FxTelemetry.hpp" +#include "WdfVersionLog.h" +#include "minwindef.h" + +extern "C" { +// +// Global triage Info for dbgeng and 0x9F work +// +static WDFOBJECT_TRIAGE_INFO _WdfObjectTriageInfo = {0}; +static WDFCONTEXT_TRIAGE_INFO _WdfContextTriageInfo = {0}; +static WDFCONTEXTTYPE_TRIAGE_INFO _WdfContextTypeTriageInfo = {0}; +static WDFQUEUE_TRIAGE_INFO _WdfQueueTriageInfo = {0}; +static WDFIRPQUEUE_TRIAGE_INFO _WdfIrpQueueTriageInfo = {0}; +static WDFREQUEST_TRIAGE_INFO _WdfRequestTriageInfo = {0}; +static WDFDEVICE_TRIAGE_INFO _WdfDeviceTriageInfo = {0}; +static WDFIRP_TRIAGE_INFO _WdfIrpTriageInfo = {0}; +static WDFFWDPROGRESS_TRIAGE_INFO _WdfFwdProgressTriageInfo = {0}; + +WDF_TRIAGE_INFO g_WdfTriageInfo = { + // + // KMDF Version. + // + __WDF_MAJOR_VERSION, + __WDF_MINOR_VERSION, + + // + // Table Version. + // + WDF_01_TRIAGE_INFO_MAJOR_VERSION, + WDF_01_TRIAGE_INFO_MINOR_VERSION, + + // + // Reserved ptr (set to NULL). + // + NULL, + + // + // WDF objects triage info. + // + &_WdfObjectTriageInfo, + &_WdfContextTriageInfo, + &_WdfContextTypeTriageInfo, + &_WdfQueueTriageInfo, + &_WdfFwdProgressTriageInfo, + &_WdfIrpQueueTriageInfo, + &_WdfRequestTriageInfo, + &_WdfDeviceTriageInfo, + &_WdfIrpTriageInfo, +}; +} // extern "C" + +VOID +GetTriageInfo( + VOID + ) +{ + // Object + _WdfObjectTriageInfo.RawObjectSize = sizeof(FxObject); + _WdfObjectTriageInfo.ObjectType = FIELD_OFFSET(FxObject, m_Type); + _WdfObjectTriageInfo.TotalObjectSize = FIELD_OFFSET(FxObject, m_ObjectSize); + _WdfObjectTriageInfo.ChildListHead = FIELD_OFFSET(FxObject, m_ChildListHead); + _WdfObjectTriageInfo.ChildEntry = FIELD_OFFSET(FxObject, m_ChildEntry); + _WdfObjectTriageInfo.Globals = FIELD_OFFSET(FxObject, m_Globals); + _WdfObjectTriageInfo.ParentObject = FIELD_OFFSET(FxObject, m_ParentObject); + + // Context Triage Info + _WdfContextTriageInfo.HeaderSize = sizeof(FxContextHeader); + _WdfContextTriageInfo.NextHeader = FIELD_OFFSET(FxContextHeader, NextHeader); + _WdfContextTriageInfo.Object = FIELD_OFFSET(FxContextHeader, Object); + _WdfContextTriageInfo.TypeInfoPtr = FIELD_OFFSET(FxContextHeader, ContextTypeInfo); + _WdfContextTriageInfo.Context = FIELD_OFFSET(FxContextHeader, Context); + + // Context type Triage info + _WdfContextTypeTriageInfo.TypeInfoSize = sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO); + _WdfContextTypeTriageInfo.ContextSize = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextSize); + _WdfContextTypeTriageInfo.ContextName = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextName); + + // WdfRequest Queue + _WdfQueueTriageInfo.QueueSize = sizeof(FxIoQueue); + _WdfQueueTriageInfo.IrpQueue1 = FIELD_OFFSET(FxIoQueue, m_Queue); + _WdfQueueTriageInfo.IrpQueue2 = FIELD_OFFSET(FxIoQueue, m_DriverCancelable); + _WdfQueueTriageInfo.RequestList1 = FIELD_OFFSET(FxIoQueue, m_Cancelled); + _WdfQueueTriageInfo.RequestList2 = FIELD_OFFSET(FxIoQueue, m_CanceledOnQueueList); + _WdfQueueTriageInfo.FwdProgressContext = FIELD_OFFSET(FxIoQueue, m_FwdProgContext); + _WdfQueueTriageInfo.PkgIo = FIELD_OFFSET(FxIoQueue, m_PkgIo); + + // Forward Progress + _WdfFwdProgressTriageInfo.ReservedRequestList = + FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestList); + _WdfFwdProgressTriageInfo.ReservedRequestInUseList = + FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestInUseList); + _WdfFwdProgressTriageInfo.PendedIrpList = + FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_PendedIrpList); + + // Irp Queue + _WdfIrpQueueTriageInfo.IrpQueueSize = sizeof(FxIrpQueue); + _WdfIrpQueueTriageInfo.IrpListHeader = FIELD_OFFSET(FxIrpQueue, m_Queue); + _WdfIrpQueueTriageInfo.IrpListEntry = FIELD_OFFSET(IRP, Tail.Overlay.ListEntry); + _WdfIrpQueueTriageInfo.IrpContext = FIELD_OFFSET(IRP, + Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY]); + + // WdfRequest + _WdfRequestTriageInfo.RequestSize = sizeof(FxRequest); + _WdfRequestTriageInfo.CsqContext = FIELD_OFFSET(FxRequest, m_CsqContext); + _WdfRequestTriageInfo.FxIrp = FIELD_OFFSET(FxRequest, m_Irp); + _WdfRequestTriageInfo.ListEntryQueueOwned = + FIELD_OFFSET(FxRequest, m_OwnerListEntry); + _WdfRequestTriageInfo.ListEntryQueueOwned2 = + FIELD_OFFSET(FxRequest, m_OwnerListEntry2); + _WdfRequestTriageInfo.RequestListEntry = + FIELD_OFFSET(FxRequest, m_ListEntry); + _WdfRequestTriageInfo.FwdProgressList = + FIELD_OFFSET(FxRequest, m_ForwardProgressList); + + // WdfDevice + _WdfDeviceTriageInfo.DeviceInitSize = sizeof(WDFDEVICE_INIT); + _WdfDeviceTriageInfo.DeviceDriver = FIELD_OFFSET(FxDevice, m_Driver); + + // FxIrp + _WdfIrpTriageInfo.FxIrpSize = sizeof(FxIrp); + _WdfIrpTriageInfo.IrpPtr = FIELD_OFFSET(FxIrp, m_Irp); +} + +BOOLEAN +IsClientInfoValid( + _In_ PCLIENT_INFO ClientInfo + ) +{ + if (ClientInfo == NULL || + ClientInfo->Size != sizeof(CLIENT_INFO) || + ClientInfo->RegistryPath == NULL || + ClientInfo->RegistryPath->Length == 0 || + ClientInfo->RegistryPath->Buffer == NULL) { + return FALSE; + } + return TRUE; +} + +VOID +ReportDdiFunctionCountMismatch( + _In_ PCUNICODE_STRING ServiceName, + _In_ ULONG ActualFunctionCount, + _In_ ULONG ExpectedFunctionCount + ) +{ + WCHAR insertString[EVTLOG_DDI_COUNT_ERROR_MAX_LEN] = { 0 }; + NTSTATUS status; + + // + // NOTE: Any single call to DbgPrintEx will only transmit 512 bytes of + // information. + // + DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, + "\n\n************************* \n" + "* DDI function table mismatch detected in KMDF driver. The \n" + "* driver will not load until it is re-compiled using a \n" + "* newer version of the Windows Driver Kit (WDK). \n" + ); + + DbgPrintEx(DPFLTR_DEFAULT_ID, DPFLTR_ERROR_LEVEL, + "* Service name : %wZ\n" + "* Actual function table count : %d \n" + "* Expected function table count: %d \n" + "*************************** \n\n", + ServiceName, + ActualFunctionCount, + ExpectedFunctionCount + ); + + // + // Report a warning level ETW event to the system event log. "Wdf01000" is + // the listed event provider. + // + status = RtlStringCchPrintfW(insertString, + RTL_NUMBER_OF(insertString), + L"Service:%wZ Count:Actual %d Expected %d", + ServiceName, + ActualFunctionCount, + ExpectedFunctionCount); + if (NT_SUCCESS(status)) { + LibraryLogEvent(FxLibraryGlobals.DriverObject, + WDFVER_CLIENT_INVALID_DDI_COUNT, + STATUS_INVALID_PARAMETER, + insertString, + NULL, + 0); + } + + // + // Report a telemetry event that can be used to proactively fix drivers + // + TraceLoggingWrite(g_TelemetryProvider, + "KmdfClientFunctionCountMismatch", + WDF_TELEMETRY_EVT_KEYWORDS, + TraceLoggingUnicodeString(ServiceName, "ServiceName"), + TraceLoggingUInt32(ActualFunctionCount, "FunctionCount"), + TraceLoggingUInt32(ExpectedFunctionCount, "ExpectedCount")); +} + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonCommission( + VOID + ) +{ + DECLARE_CONST_UNICODE_STRING(usName, L"RtlGetVersion"); + PFN_RTL_GET_VERSION pRtlGetVersion = NULL; + NTSTATUS status; + + __Print((LITERAL(WDF_LIBRARY_COMMISSION) "\n")); + + // + // Commission this version's DLL globals. + // + status = FxLibraryGlobalsCommission(); + + if (!NT_SUCCESS(status)) { + __Print(("FxLibraryGlobalsCommission failed %X\n", status)); + return status; + } + + // + // register telemetry provider. + // + RegisterTelemetryProvider(); + + // + // Initialize internal WPP tracing. + // + status = FxTraceInitialize(); + if (NT_SUCCESS(status)) { + FxLibraryGlobals.InternalTracingInitialized = TRUE; + } + else { + __Print(("Failed to initialize tracing for WDF\n")); + + // + // Failure to initialize is not critical enough to fail driver load. + // + status = STATUS_SUCCESS; + } + + // + // Attempt to load RtlGetVersion (works for > w2k). + // + pRtlGetVersion = (PFN_RTL_GET_VERSION) MmGetSystemRoutineAddress( + (PUNICODE_STRING) &usName + ); + + // + // Now attempt to get this OS's version. + // + if (pRtlGetVersion != NULL) { + pRtlGetVersion(&gOsVersion); + } + + __Print(("OsVersion(%d.%d)\n", + gOsVersion.dwMajorVersion, + gOsVersion.dwMinorVersion )); + + // + // Init triage info for 9f bugcheck analysis. + // + GetTriageInfo(); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonDecommission( + VOID + ) +{ + __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": enter\n")); + + // + // Uninitialize WPP tracing. + // + if (FxLibraryGlobals.InternalTracingInitialized) { + TraceUninitialize(); + FxLibraryGlobals.InternalTracingInitialized = FALSE; + } + + // + // Unregister telemetry provider. + // + UnregisterTelemetryProvider(); + + EventUnregisterMicrosoft_Windows_DriverFrameworks_KernelMode_Performance(); + + // + // Decommission this version's DLL globals. + // + FxLibraryGlobalsDecommission(); + + // + // Note: This is the absolute last action from WDF library (dynamic or static). + // The image is likely to be deleted after returning. + // + __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": exit\n")); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonRegisterClient( + __inout PWDF_BIND_INFO Info, + __deref_out PWDF_DRIVER_GLOBALS *WdfDriverGlobals, + __in_opt PCLIENT_INFO ClientInfo + ) +{ + NTSTATUS status; + UNICODE_STRING serviceName = { 0 }; + + status = STATUS_INVALID_PARAMETER; + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n")); + + if (Info == NULL || WdfDriverGlobals == NULL || Info->FuncTable == NULL) { + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": NULL parameter -- %s\n", + (Info == NULL) ? "PWDF_BIND_INFO" : + (WdfDriverGlobals == NULL) ? "PWDF_DRIVER_GLOBALS *" : + (Info->FuncTable == NULL) ? "PWDF_BIND_INFO->FuncTable" : + "unknown" )); + goto Done; + } + + ASSERT(Info->FuncCount); + + + *WdfDriverGlobals = NULL; + + // + // WdfVersion.Count is initialized in FxDynamics.h and is never changed. + // Prefast is unable to make that determination. + // + __assume(WdfVersion.FuncCount == sizeof(WDFFUNCTIONS)/sizeof(PVOID)); + + if (Info->FuncCount > WdfVersion.FuncCount) { + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": version mismatch detected in function table count: client" + "has 0x%x, library has 0x%x\n", + Info->FuncCount, WdfVersion.FuncCount)); + goto Done; + } + + if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_15) { + // + // Make sure table count matches exactly with previously + // released framework version table sizes. + // + switch (Info->FuncCount) { + + case WdfFunctionTableNumEntries_V1_15: + case WdfFunctionTableNumEntries_V1_13: + case WdfFunctionTableNumEntries_V1_11: + case WdfFunctionTableNumEntries_V1_9: + // case WdfFunctionTableNumEntries_V1_7: // both 1.7 and 1.5 have 387 functions + case WdfFunctionTableNumEntries_V1_5: + case WdfFunctionTableNumEntries_V1_1: + case WdfFunctionTableNumEntries_V1_0: + break; + + default: + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": Function table count 0x%x doesn't match any previously " + "released framework version table size\n", + Info->FuncCount)); + goto Done; + } + } + else { + + + + + + + + + // Client version is same as framework version. Make + // sure table count is exact. + if (Info->FuncCount != WdfFunctionTableNumEntries) { + RtlZeroMemory(&serviceName, sizeof(UNICODE_STRING)); + + if (IsClientInfoValid(ClientInfo)) { + GetNameFromPath(ClientInfo->RegistryPath, &serviceName); + } + else { + RtlInitUnicodeString(&serviceName, L"Unknown"); + } + + // + // Report a DbgPrint message, telemetry event and an ETW event that + // will serve as diagnostic aid. + // + ReportDdiFunctionCountMismatch((PCUNICODE_STRING)&serviceName, + Info->FuncCount, + WdfFunctionTableNumEntries); + + // + // If loader diagnostics are enabled and KD is connected, break-in + // + if (WdfLdrDbgPrintOn && KD_DEBUGGER_ENABLED && + !KD_DEBUGGER_NOT_PRESENT) { + DbgBreakPoint(); + } + goto Done; + } + } + + // + // Allocate an new FxDriverGlobals area for this driver. + // + *WdfDriverGlobals = FxAllocateDriverGlobals(); + + if (*WdfDriverGlobals) { + BOOLEAN isFunctinTableHookingOn = FALSE; + BOOLEAN isPerformanceAnalysisOn = FALSE; + PFX_DRIVER_GLOBALS fxDriverGlobals = NULL; + + // + // Check the registry to see if Enhanced verifier is on for this driver. + // if registry read fails, options value remains unchanged. + // store enhanced verifier options in driver globals + // + fxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals); + GetEnhancedVerifierOptions(ClientInfo, &fxDriverGlobals->FxEnhancedVerifierOptions); + isFunctinTableHookingOn = IsFxVerifierFunctionTableHooking(fxDriverGlobals); + isPerformanceAnalysisOn = IsFxPerformanceAnalysis(fxDriverGlobals); + + // + // Set-up the function table. Enhanced verifier and Performance analysis is off by default. + // + if (isFunctinTableHookingOn == FALSE && isPerformanceAnalysisOn == FALSE) { + + // + // Starting in 1.15 we reference a copy of the DDI table in WDF01000, + // prior to that we copy the entire table to local memory. + // + if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_13) { + RtlCopyMemory( Info->FuncTable, + &WdfVersion.Functions, + Info->FuncCount * sizeof(PVOID) ); + } + else { + // + // FuncTable arrives with a ptr to &WdfFunctions, so we update + // what WdfFunctions points to. + // + *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &WdfVersion.Functions; + } + } + else { + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": Enhanced Verification is ON \n")); + + LockVerifierSection(fxDriverGlobals, ClientInfo->RegistryPath); + + if (Microsoft_Windows_DriverFrameworks_KernelMode_PerformanceHandle == NULL) { + EventRegisterMicrosoft_Windows_DriverFrameworks_KernelMode_Performance(); + } + + // + // Enhanced verification is on. Return verifier function table + // + // Starting in 1.15 we reference a copy of the DDI table in WDF01000, + // prior to that we copy the entire table to local memory. + // + if (Info->FuncCount <= WdfFunctionTableNumEntries_V1_13) { + RtlCopyMemory( Info->FuncTable, + &VfWdfVersion.Functions, + Info->FuncCount * sizeof(PVOID) ); + } + else { + // + // FuncTable arrives with a ptr to &WdfFunctions, so we update + // what WdfFunctions points to. + // + *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &VfWdfVersion.Functions; + } + } + + status = STATUS_SUCCESS; + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": WdfFunctions %p\n", Info->FuncTable)); + } + +Done: + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": exit: status %X\n", status)); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxLibraryCommonUnregisterClient( + __in PWDF_BIND_INFO Info, + __in PWDF_DRIVER_GLOBALS WdfDriverGlobals + ) +{ + NTSTATUS status; + + __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) ": enter\n")); + + ASSERT(Info); + ASSERT(WdfDriverGlobals); + + if (Info != NULL && WdfDriverGlobals != NULL) { + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + status = STATUS_SUCCESS; + + pFxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals); + + // + // Destroy this FxDriver instance, if its still indicated. + // + if (pFxDriverGlobals->Driver != NULL) { + // + // Association support, we are a root with no parent + // + pFxDriverGlobals->Driver->DeleteObject(); + + FxDestroy(pFxDriverGlobals); + } + + // + // Stop IFR logging + // + FxIFRStop(pFxDriverGlobals); + + // + // unlock enhanced-verifier image sections + // + if (IsFxVerifierFunctionTableHooking(pFxDriverGlobals)) { + UnlockVerifierSection(pFxDriverGlobals); + } + + // + // This will free the client's FxDriverGlobals area + // + FxFreeDriverGlobals(WdfDriverGlobals); + } + else { + status = STATUS_UNSUCCESSFUL; + } + + __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) + ": exit: status %X\n", status)); + + return status; +} + +VOID +GetEnhancedVerifierOptions( + __in PCLIENT_INFO ClientInfo, + __out PULONG Options + ) +{ + NTSTATUS status; + ULONG value; + FxAutoRegKey hKey, hWdf; + DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf"); + DECLARE_CONST_UNICODE_STRING(valueName, WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME); + + *Options = 0; + if (!IsClientInfoValid(ClientInfo) || + Options == NULL) { + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": Invalid ClientInfo received from wdfldr \n")); + return; + } + + status = FxRegKey::_OpenKey(NULL, + ClientInfo->RegistryPath, + &hWdf.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + return; + } + + status = FxRegKey::_OpenKey(hWdf.m_Key, + ¶metersPath, + &hKey.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + return; + } + + status = FxRegKey::_QueryULong( + hKey.m_Key, &valueName, &value); + + // + // Examine key values and set Options only on success. + // + if (NT_SUCCESS(status)) { + if (value) { + *Options = value; + } + } +} + +VOID +LibraryLogEvent( + __in PDRIVER_OBJECT DriverObject, + __in NTSTATUS ErrorCode, + __in NTSTATUS FinalStatus, + __in PWSTR ErrorInsertionString, + __in_bcount(RawDataLen) PVOID RawDataBuf, + __in USHORT RawDataLen + ) +/*++ + + +Routine Description: + + Logs an error to the system event log. + + Arguments: + + DriverObject - Pointer to driver object reporting the error. + + ErrorCode - Indicates the type of error, system or driver-defined. + + ErrorInsertionString - Null-terminated Unicode string inserted into error + description, as defined by error code. + +Return Value: + +None. + +--*/ +{ + PIO_ERROR_LOG_PACKET errorLogEntry; + size_t errorLogEntrySize; // [including null] + size_t errorInsertionStringByteSize = 0; + + if (ErrorInsertionString) { + errorInsertionStringByteSize = wcslen(ErrorInsertionString) * sizeof(WCHAR); + errorInsertionStringByteSize += sizeof(UNICODE_NULL); + } + + errorLogEntrySize = sizeof(IO_ERROR_LOG_PACKET) + RawDataLen + errorInsertionStringByteSize; + + // + // Log an error. + // + // + // prefast complains about comparison of constant with constant here + // +#pragma prefast(suppress:__WARNING_CONST_CONST_COMP, "If ErrorInsertionString is not null then this is not a constant") + if (errorLogEntrySize <= ERROR_LOG_MAXIMUM_SIZE) { + + errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DriverObject, + (UCHAR)errorLogEntrySize); + + if (errorLogEntry != NULL) { + + RtlZeroMemory(errorLogEntry, errorLogEntrySize); + + errorLogEntry->ErrorCode = ErrorCode; + errorLogEntry->FinalStatus = FinalStatus; + errorLogEntry->NumberOfStrings = (ErrorInsertionString) ? 1 : 0; + errorLogEntry->DumpDataSize = RawDataLen; + errorLogEntry->StringOffset = (FIELD_OFFSET(IO_ERROR_LOG_PACKET, DumpData)) + errorLogEntry->DumpDataSize; + + // + // Insertion strings follow dumpdata and since there is no dumpdata we place the + // insertion string at the start offset of the dumpdata. + // + if (RawDataBuf) { + RtlCopyMemory(errorLogEntry->DumpData, + RawDataBuf, + RawDataLen); + } + + if (ErrorInsertionString) { + RtlCopyMemory(((PCHAR)errorLogEntry->DumpData) + RawDataLen, + ErrorInsertionString, + errorInsertionStringByteSize); + } + + IoWriteErrorLogEntry(errorLogEntry); + } + } + + return; +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/support/fxqueryinterface.cpp b/sdk/lib/drivers/wdf/kmdf/src/support/fxqueryinterface.cpp new file mode 100644 index 00000000000..2b6a6f8f2f7 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/support/fxqueryinterface.cpp @@ -0,0 +1,182 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxQueryInterface.cpp + +Abstract: + + This module implements the device interface object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxQueryInterface.tmh" +} + +FxQueryInterface::FxQueryInterface( + __in FxDevice* Device, + __in PWDF_QUERY_INTERFACE_CONFIG Config + ) : + m_Device(Device), + m_Interface(NULL) +{ + m_Entry.Next = NULL; + + m_EmbeddedInterface = FALSE; + + if (Config != NULL) { + m_SendQueryToParentStack = Config->SendQueryToParentStack; + m_ImportInterface = Config->ImportInterface; + m_ProcessRequest.m_Method = Config->EvtDeviceProcessQueryInterfaceRequest; + RtlCopyMemory(&m_InterfaceType, Config->InterfaceType, sizeof(GUID)); + } +} + +FxQueryInterface::~FxQueryInterface() +{ + // + // Should not in any list + // + ASSERT(m_Entry.Next == NULL); + + if (m_Interface != NULL && m_EmbeddedInterface == FALSE) { + FxPoolFree(m_Interface); + } +} + +VOID +FxQueryInterface::_FormatIrp( + __in PIRP Irp, + __in const GUID* InterfaceGuid, + __out PINTERFACE Interface, + __in USHORT InterfaceSize, + __in USHORT InterfaceVersion, + __in_opt PVOID InterfaceSpecificData + ) +{ + PIO_STACK_LOCATION stack; + + Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; + + stack = IoGetNextIrpStackLocation(Irp); + + stack->MajorFunction = IRP_MJ_PNP; + stack->MinorFunction = IRP_MN_QUERY_INTERFACE; + + stack->Parameters.QueryInterface.Interface = Interface; + stack->Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData; + stack->Parameters.QueryInterface.Size = InterfaceSize; + stack->Parameters.QueryInterface.Version = InterfaceVersion; + stack->Parameters.QueryInterface.InterfaceType = InterfaceGuid; +} + +_Must_inspect_result_ +NTSTATUS +FxQueryInterface::_QueryForInterface( + __in PDEVICE_OBJECT TopOfStack, + __in const GUID* InterfaceType, + __out PINTERFACE Interface, + __in USHORT Size, + __in USHORT Version, + __in_opt PVOID InterfaceSpecificData + ) +/*++ + +Routine Description: + Send an IRP_MJPNP/IRP_MN_QUERY_INTERFACE irp to a device object and its + attached stack. + +Arguments: + TargetDevice - device to send the query to. + + InterfaceType - The type of interface to query for + + Interface - The interface to fill out + + Size - Size of Interface in bytes + + Version - Version of the interface to be queried + + InterfaceSpecificData - Addtional interface data to be queried + + +Return Value: + NTSTATUS as indicated by the handler of the QI with in the device stack, + STATUS_NOT_SUPPORTED if the QI is not handled. + + --*/ +{ + PIRP pIrp; + NTSTATUS status; + + pIrp = IoAllocateIrp(TopOfStack->StackSize, FALSE); + + if (pIrp != NULL) { + FxAutoIrp irp(pIrp); + + _FormatIrp( + pIrp, + InterfaceType, + Interface, + Size, + Version, + InterfaceSpecificData + ); + + status = irp.SendIrpSynchronously(TopOfStack); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + return status; +} + +VOID +FxQueryInterface::SetEmbedded( + __in PWDF_QUERY_INTERFACE_CONFIG Config, + __in PINTERFACE Interface + ) +/*++ + +Routine Description: + Marks the structure as embedded and sets the configuration. This is used + for FxQueryInterface structs which are embedded in other structures because + at contruction time the Config is not available yet. + + By marking as embedded, FxPkgPnp will not free the structure when it deletes + the query interface chain. + +Arguments: + Config - how the interface behaves + + Interface - the interface that is exported + +Return Value: + None + + --*/ +{ + m_EmbeddedInterface = TRUE; + m_Interface = Interface; + + m_SendQueryToParentStack = Config->SendQueryToParentStack; + m_ImportInterface = Config->ImportInterface; + m_ProcessRequest.m_Method = Config->EvtDeviceProcessQueryInterfaceRequest; + RtlCopyMemory(&m_InterfaceType, Config->InterfaceType, sizeof(GUID)); +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/support/fxqueryinterfaceapi.cpp b/sdk/lib/drivers/wdf/kmdf/src/support/fxqueryinterfaceapi.cpp new file mode 100644 index 00000000000..183a33ccc4f --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/support/fxqueryinterfaceapi.cpp @@ -0,0 +1,222 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxQueryInterfaceAPI.cpp + +Abstract: + + This module implements the device interface object. + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxQueryInterfaceAPI.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAddQueryInterface)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_QUERY_INTERFACE_CONFIG InterfaceConfig + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxQueryInterface *pQueryInterface; + FxDevice *pDevice; + PINTERFACE pInterface; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals ); + + pQueryInterface = NULL; + + FxPointerNotNull(pFxDriverGlobals, Device); + FxPointerNotNull(pFxDriverGlobals, InterfaceConfig); + FxPointerNotNull(pFxDriverGlobals, InterfaceConfig->InterfaceType); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + pInterface = InterfaceConfig->Interface; + + if (InterfaceConfig->Size != sizeof(WDF_QUERY_INTERFACE_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, WDF_QUERY_INTERFACE_CONFIG Size %d, expected %d, " + "%!STATUS!", Device, InterfaceConfig->Size, + sizeof(WDF_QUERY_INTERFACE_CONFIG), status); + + goto Done; + } + + // + // A pass through interface is only associated with PDOs + // + if (InterfaceConfig->SendQueryToParentStack && pDevice->IsPdo() == FALSE) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "SendQueryToParentStack TRUE, but WDFDEVICE %p not a PDO, %!STATUS!", + Device, status); + + goto Done; + } + + // + // The only time we can have a NULL Interface is if the interface is + // passthrough or it is an import interface (since on import interfaces + // the callback must do the copying). + // + if (pInterface == NULL) { + if (InterfaceConfig->SendQueryToParentStack || InterfaceConfig->ImportInterface) { + // + // A NULL interface is valid for this config + // + DO_NOTHING(); + } + else { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, SendQueryToParentStack is FALSE and " + "InterfaceConfig->ImportInterface is FALSE, %!STATUS!", + Device, status); + + goto Done; + } + } + + // + // If it is an import interface, we need a callback so that the driver can + // modify the interface being returned. + // + if (InterfaceConfig->ImportInterface && + InterfaceConfig->EvtDeviceProcessQueryInterfaceRequest == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, ImportInterface is TRUE and " + "EvtDeviceProcessQueryInterfaceRequest is NULL, %!STATUS!", + Device, status); + + goto Done; + } + + if (pInterface != NULL) { + // + // Make sure we are exposing the minimum size + // + if (pInterface->Size < sizeof(INTERFACE)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, Interface size %d < sizeof(INTERFACE) (%d), " + "%!STATUS!", Device, pInterface->Size, sizeof(INTERFACE), status); + + goto Done; + } + } + + // + // Since the QI irp is only allowed to be sent at passive level and + // the list of FxQueryInterface's is locked by a lock which does not + // raise IRQL, we can allocate the structure out paged pool. + // + pQueryInterface = new (pFxDriverGlobals, PagedPool) + FxQueryInterface(pDevice, InterfaceConfig); + + if (pQueryInterface == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, object creation failed, %!STATUS!", Device, status); + + goto Done; + } + + if (pInterface != NULL) { + // + // Try to allocate memory for the interface. + // + pQueryInterface->m_Interface = (PINTERFACE) + FxPoolAllocate(pFxDriverGlobals, PagedPool, pInterface->Size); + + if (pQueryInterface->m_Interface == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, interface allocation failed, %!STATUS!", + Device, status); + + goto Done; + } + + RtlCopyMemory(pQueryInterface->m_Interface, + pInterface, + pInterface->Size); + + if (pInterface->InterfaceReference == NULL) { + pQueryInterface->m_Interface->InterfaceReference = + FxDevice::_InterfaceReferenceNoOp; + } + if (pInterface->InterfaceDereference == NULL) { + pQueryInterface->m_Interface->InterfaceDereference = + FxDevice::_InterfaceDereferenceNoOp; + } + } + + status = STATUS_SUCCESS; + + pDevice->m_PkgPnp->AddQueryInterface(pQueryInterface, TRUE); + +Done: + // + // Delete the query interface structure if there is an error. + // + if (!NT_SUCCESS(status) && pQueryInterface != NULL) { + delete pQueryInterface; + pQueryInterface = NULL; + } + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/kmdf/src/support/fxrelateddevice.cpp b/sdk/lib/drivers/wdf/kmdf/src/support/fxrelateddevice.cpp new file mode 100644 index 00000000000..fb93c1ca397 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/support/fxrelateddevice.cpp @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRelatedDevice.cpp + +Abstract: + + This module implements the FxRelatedDevice class which is used in usage + notification propagation + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +FxRelatedDevice::FxRelatedDevice( + __in PDEVICE_OBJECT DeviceObject, + __in PFX_DRIVER_GLOBALS Globals + ) : FxObject(FX_TYPE_RELATED_DEVICE, 0, Globals), + m_DeviceObject(DeviceObject), + m_State(RelatedDeviceStateNeedsReportPresent) +{ + m_TransactionedEntry.SetTransactionedObject(this); + ObReferenceObject(m_DeviceObject); +} + +FxRelatedDevice::~FxRelatedDevice( + VOID + ) +{ + ObDereferenceObject(m_DeviceObject); +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/support/fxrelateddevicelist.cpp b/sdk/lib/drivers/wdf/kmdf/src/support/fxrelateddevicelist.cpp new file mode 100644 index 00000000000..80be7033b3c --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/support/fxrelateddevicelist.cpp @@ -0,0 +1,150 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxDependentList.cpp + +Abstract: + This object derives from the transactioned list and provides a unique + object check during the addition of an item. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +_Must_inspect_result_ +NTSTATUS +FxRelatedDeviceList::Add( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxRelatedDevice* Entry + ) +{ + return FxSpinLockTransactionedList::Add(FxDriverGlobals, + &Entry->m_TransactionedEntry); +} + +VOID +FxRelatedDeviceList::Remove( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PDEVICE_OBJECT Device + ) +{ + SearchForAndRemove(FxDriverGlobals, (PVOID) Device); +} + +_Must_inspect_result_ +FxRelatedDevice* +FxRelatedDeviceList::GetNextEntry( + __in_opt FxRelatedDevice* Entry + ) +{ + FxTransactionedEntry *pReturn, *pEntry; + + if (Entry == NULL) { + pEntry = NULL; + } + else { + pEntry = &Entry->m_TransactionedEntry; + } + + pReturn = FxSpinLockTransactionedList::GetNextEntry(pEntry); + + if (pReturn != NULL) { + return CONTAINING_RECORD(pReturn, FxRelatedDevice, m_TransactionedEntry); + } + else { + return NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxRelatedDeviceList::ProcessAdd( + __in FxTransactionedEntry *NewEntry + ) +{ + FxRelatedDevice* pNew, *pInList; + FxTransactionedEntry *pEntry; + PLIST_ENTRY ple; + + pNew = CONTAINING_RECORD(NewEntry, FxRelatedDevice, m_TransactionedEntry); + + pEntry = NULL; + + // + // Go over the transactions first because the device could be in the real + // list with a transaction to remove it, so we catch first here instead + // of adding complexity to the iteration of the already inserted list. + // + for (ple = m_TransactionHead.Flink; + ple != &m_TransactionHead; + ple = ple->Flink) { + pEntry = FxTransactionedEntry::_FromEntry(ple); + pInList = CONTAINING_RECORD(pEntry, FxRelatedDevice, m_TransactionedEntry); + + if (pInList->m_DeviceObject == pNew->m_DeviceObject) { + if (pEntry->GetTransactionAction() == FxTransactionActionAdd) { + // + // An additional add, failure + // + return STATUS_DUPLICATE_OBJECTID; + } + + + // Removal is OK b/c our add will be right behind it + // + ASSERT(pEntry->GetTransactionAction() == FxTransactionActionRemove); + return STATUS_SUCCESS; + } + } + + pEntry = NULL; + while ((pEntry = __super::GetNextEntryLocked(pEntry)) != NULL) { + pInList = CONTAINING_RECORD(pEntry, FxRelatedDevice, m_TransactionedEntry); + + if (pInList->m_DeviceObject == pNew->m_DeviceObject) { + return STATUS_DUPLICATE_OBJECTID; + } + } + + return STATUS_SUCCESS; +} + +BOOLEAN +FxRelatedDeviceList::Compare( + __in FxTransactionedEntry* Entry, + __in PVOID Data + ) +{ + FxRelatedDevice *pRelated; + + pRelated = CONTAINING_RECORD(Entry, FxRelatedDevice, m_TransactionedEntry); + + return pRelated->GetDevice() == (PDEVICE_OBJECT) Data ? TRUE : FALSE; +} + +VOID +FxRelatedDeviceList::EntryRemoved( + __in FxTransactionedEntry* Entry + ) +{ + FxRelatedDevice *pRelated; + + pRelated = CONTAINING_RECORD(Entry, FxRelatedDevice, m_TransactionedEntry); + + if (pRelated->m_State == RelatedDeviceStateReportedPresent) { + m_NeedReportMissing++; + } +} diff --git a/sdk/lib/drivers/wdf/kmdf/src/support/fxsupportpch.hpp b/sdk/lib/drivers/wdf/kmdf/src/support/fxsupportpch.hpp new file mode 100644 index 00000000000..a4ebb6d37c3 --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/support/fxsupportpch.hpp @@ -0,0 +1,32 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxsupportpch.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in fx\support + +Author: + +Environment: + Kernel mode only + +Revision History: + +--*/ + +#ifndef __FX_SUPPORT_PCH_HPP__ +#define __FX_SUPPORT_PCH_HPP__ + +extern "C" { +#include +} + +#include + +#endif // __FX_SUPPORT_PCH_HPP__ diff --git a/sdk/lib/drivers/wdf/kmdf/src/support/probeandlock.c b/sdk/lib/drivers/wdf/kmdf/src/support/probeandlock.c new file mode 100644 index 00000000000..bf4ab8caaca --- /dev/null +++ b/sdk/lib/drivers/wdf/kmdf/src/support/probeandlock.c @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + ProbeAndLock.c + +Abstract: + + This module contains C routines for probing and locking + down memory buffers. + + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +// +// These routines must be implemented in a C file to avoid problems +// with C++ exception handling errors. +// + +#include + +NTSTATUS +FxProbeAndLockForRead( + __in PMDL Mdl, + __in KPROCESSOR_MODE AccessMode + ) +{ + try { + MmProbeAndLockPages(Mdl, AccessMode, IoReadAccess); + } except(EXCEPTION_EXECUTE_HANDLER) { + return GetExceptionCode(); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +FxProbeAndLockForWrite( + __in PMDL Mdl, + __in KPROCESSOR_MODE AccessMode + ) +{ + try { + MmProbeAndLockPages(Mdl, AccessMode, IoWriteAccess); + } except(EXCEPTION_EXECUTE_HANDLER) { + return GetExceptionCode(); + } + return STATUS_SUCCESS; +} + +NTSTATUS +FxProbeAndLockWithAccess( + __in PMDL Mdl, + __in KPROCESSOR_MODE AccessMode, + __in LOCK_OPERATION Operation + ) +{ + try { + MmProbeAndLockPages(Mdl, AccessMode, Operation); + } except(EXCEPTION_EXECUTE_HANDLER) { + return GetExceptionCode(); + } + + return STATUS_SUCCESS; +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/coreprivshared.hpp b/sdk/lib/drivers/wdf/shared/core/coreprivshared.hpp new file mode 100644 index 00000000000..897bb1bd50b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/coreprivshared.hpp @@ -0,0 +1,388 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + corepriv.hpp + +Abstract: + + This is the main driver framework. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#pragma once + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#define FX_IS_USER_MODE (TRUE) +#define FX_IS_KERNEL_MODE (FALSE) +#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#define FX_IS_USER_MODE (FALSE) +#define FX_IS_KERNEL_MODE (TRUE) +#endif + +/* +extern "C" { +#include +#include "wdf.h" +} + +#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf" + +*/ + +extern "C" { +#include "mx.h" +} + +#include "FxMin.hpp" + +#include "wdfmemory.h" +#include "wdfrequest.h" +#include "wdfdevice.h" +#include "wdfdevicepri.h" +#include "wdfiotargetpri.h" +#include "wdfwmi.h" +#include "wdfChildList.h" +#include "wdfpdo.h" +#include "wdffdo.h" +#include "wdfiotarget.h" +#include "wdfcontrol.h" +#include "wdfcx.h" +#include "wdfio.h" +#include "wdfqueryinterface.h" +#include "wdftriage.h" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "FxIrpUm.hpp" +#else +#include "FxIrpKm.hpp" +#endif + +// +typedef +VOID +(*PFN_WDF_SYSTEMWORKITEM) ( + IN PVOID Parameter + ); + +#include "FxIrpQueue.hpp" + + +// + + +#include "FxProbeAndLock.h" +#include "FxPackage.hpp" +#include "FxCollection.hpp" +#include "FxDeviceInitShared.hpp" + +#include "IfxMemory.hpp" +#include "FxCallback.hpp" +#include "FxRequestContext.hpp" +#include "FxRequestContextTypes.h" +#include "FxRequestBase.hpp" +#include "FxMemoryObject.hpp" +#include "FxMemoryBuffer.hpp" + +#include "FxMemoryBufferFromPool.hpp" + +#include "FxMemoryBufferPreallocated.hpp" + +#include "FxTransactionedList.hpp" + +// +// MERGE temp: We may not need these include files here, +// temporarily including them to verify they compile in shared code +// +#include "FxRequestValidateFunctions.hpp" +#include "FxRequestCallbacks.hpp" + +// support +#include "StringUtil.hpp" +#include "FxAutoString.hpp" +#include "FxString.hpp" +#include "FxDeviceText.hpp" +#include "FxCallback.hpp" +#include "FxDisposeList.hpp" +#include "FxSystemThread.hpp" + +#include "FxIrpPreprocessInfo.hpp" +#include "FxPnpCallbacks.hpp" + +// device init +#include "FxCxDeviceInit.hpp" +#include "FxCxDeviceInfo.hpp" +#include "FxDeviceInit.hpp" + +#include "FxDeviceToMxInterface.hpp" + +// request +#include "FxRequestMemory.hpp" +#include "FxRequest.hpp" +#include "FxRequestBuffer.hpp" +#include "FxSyncRequest.hpp" + +// io target +#include "FxIoTarget.hpp" +#include "FxIoTargetSelf.hpp" + +#include "FxSystemWorkItem.hpp" +#include "FxCallbackMutexLock.hpp" +#include "FxDriver.hpp" + +#include "FxDeviceInterface.hpp" +#include "FxQueryInterface.hpp" + +#include "FxCallbackSpinLock.hpp" +#include "FxDefaultIrpHandler.hpp" +#include "FxWmiIrpHandler.hpp" + +// packages +#include "FxPkgIo.hpp" +#include "FxPkgPnp.hpp" +#include "FxPkgFdo.hpp" +#include "FxPkgPdo.hpp" +#include "FxPkgGeneral.hpp" +#include "FxFileObject.hpp" +#include "FxIoQueue.hpp" +#include "FxDevice.hpp" +#include "FxTelemetry.hpp" + +#include "FxChildList.hpp" + +#include "FxLookasideList.hpp" + +/*#if FX_IS_KERNEL_MODE +#include "wdfrequest.h" +#endif*/ + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + +} WDF_DRIVER_CONFIG_V1_0, *PWDF_DRIVER_CONFIG_V1_0; + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V1_1 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + +} WDF_DRIVER_CONFIG_V1_1, *PWDF_DRIVER_CONFIG_V1_1; + + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5; + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V1_7 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + LONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_TIMER_CONFIG_V1_7, *PWDF_TIMER_CONFIG_V1_7; + +typedef struct _WDF_TIMER_CONFIG_V1_11 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + +} WDF_TIMER_CONFIG_V1_11, *PWDF_TIMER_CONFIG_V1_11; + diff --git a/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinit.cpp b/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinit.cpp new file mode 100644 index 00000000000..5fbd10d660f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinit.cpp @@ -0,0 +1,78 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCxDeviceInit.cpp + +Abstract: + Internals for WDFCXDEVICE_INIT + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxCxDeviceInit.tmh" +} + +WDFCXDEVICE_INIT::WDFCXDEVICE_INIT() +{ + InitializeListHead(&ListEntry); + + ClientDriverGlobals = NULL; + CxDriverGlobals = NULL; + PreprocessInfo = NULL; + IoInCallerContextCallback = NULL; + RtlZeroMemory(&RequestAttributes, sizeof(RequestAttributes)); + RtlZeroMemory(&FileObject, sizeof(FileObject)); + FileObject.AutoForwardCleanupClose = WdfUseDefault; + CxDeviceInfo = NULL; +} + +WDFCXDEVICE_INIT::~WDFCXDEVICE_INIT() +{ + ASSERT(IsListEmpty(&ListEntry)); + + if (PreprocessInfo != NULL) { + delete PreprocessInfo; + } +} + +_Must_inspect_result_ +PWDFCXDEVICE_INIT +WDFCXDEVICE_INIT::_AllocateCxDeviceInit( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + PFX_DRIVER_GLOBALS fxDriverGlobals; + PWDFCXDEVICE_INIT init; + + fxDriverGlobals = DeviceInit->DriverGlobals; + + init = new(fxDriverGlobals) WDFCXDEVICE_INIT(); + if (init == NULL) { + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDRIVER 0x%p couldn't allocate WDFCXDEVICE_INIT", + DeviceInit->Driver); + return NULL; + } + + DeviceInit->AddCxDeviceInit(init); + + return init; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinitapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinitapi.cpp new file mode 100644 index 00000000000..ecc9d93c460 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxcxdeviceinitapi.cpp @@ -0,0 +1,501 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCxDeviceInitApi.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object + for the class extensions. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxCxDeviceInitApi.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +__inline +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; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFCXDEVICE_INIT CxDeviceInit, + __in + PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess, + __in + UCHAR MajorFunction, + __drv_when(NumMinorFunctions > 0, __in_bcount(NumMinorFunctions)) + __drv_when(NumMinorFunctions == 0, __in_opt) + PUCHAR MinorFunctions, + __in + ULONG NumMinorFunctions + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals; + PFX_DRIVER_GLOBALS cxDriverGlobals; + NTSTATUS status; + + cxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + FxPointerNotNull(cxDriverGlobals, CxDeviceInit); + fxDriverGlobals = CxDeviceInit->ClientDriverGlobals; + + // + // Caller must be a class extension driver. + // + status = FxValiateCx(fxDriverGlobals, cxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + FxPointerNotNull(fxDriverGlobals, EvtCxDeviceWdmIrpPreprocess); + + if (NumMinorFunctions > 0) { + FxPointerNotNull(fxDriverGlobals, MinorFunctions); + } + + // + // ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch) just returns a + // constant size, it does not actually deref PreprocessInfo (which could + // be NULL) + // + if (MajorFunction >= ARRAY_SIZE(CxDeviceInit->PreprocessInfo->Dispatch)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "MajorFunction %x is invalid, %!STATUS!", + (ULONG)MajorFunction, status); + + goto Done; + } + + // + // CX must call this API multiple times if it wants to register preprocess callbacks for + // multiple IRP major codes. + // + if (CxDeviceInit->PreprocessInfo == NULL) { + CxDeviceInit->PreprocessInfo = new(fxDriverGlobals) FxIrpPreprocessInfo(); + if (CxDeviceInit->PreprocessInfo == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object PreprocessInfo, " + "%!STATUS!", status); + + goto Done; + } + CxDeviceInit->PreprocessInfo->ClassExtension = TRUE; + } + + ASSERT(CxDeviceInit->PreprocessInfo->ClassExtension); + + if (NumMinorFunctions > 0) { + if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions != 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Already assigned Minorfunctions, %!STATUS!", + status); + goto Done; + } + + CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions = + (PUCHAR) FxPoolAllocate(fxDriverGlobals, + NonPagedPool, + sizeof(UCHAR) * NumMinorFunctions); + + if (CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object MinorFunctions, " + "%!STATUS!", status); + goto Done; + } + + RtlCopyMemory( + &CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions[0], + &MinorFunctions[0], + NumMinorFunctions + ); + + CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions = + NumMinorFunctions; + } + + CxDeviceInit->PreprocessInfo->Dispatch[MajorFunction].EvtCxDevicePreprocess = + EvtCxDeviceWdmIrpPreprocess; + + status = STATUS_SUCCESS; + +Done: + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFCXDEVICE_INIT CxDeviceInit, + __in + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ) + +/*++ + +Routine Description: + + Registers an I/O pre-processing callback for the class extension device. + + If registered, any I/O for the device is first presented to this + callback function before being placed in any I/O Queue's. + + The callback is invoked in the thread and/or DPC context of the + original WDM caller as presented to the I/O package. No framework + threading, locking, synchronization, or queuing occurs, and + responsibility for synchronization is up to the device driver. + + This API is intended to support METHOD_NEITHER IRP_MJ_DEVICE_CONTROL's + which must access the user buffer in the original callers context. The + driver would probe and lock the buffer pages from within this event + handler using the functions supplied on the WDFREQUEST object, storing + any required mapped buffers and/or pointers on the WDFREQUEST context + whose size is set by the RequestContextSize of the WDF_DRIVER_CONFIG structure. + + It is the responsibility of this routine to either complete the request, or + pass it on to the I/O package through WdfDeviceEnqueueRequest(Device, Request). + +Arguments: + + CxDeviceInit - Class Extension Device initialization structure + + EvtIoInCallerContext - Pointer to driver supplied callback function + +Return Value: + + None + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals; + PFX_DRIVER_GLOBALS cxDriverGlobals; + NTSTATUS status; + + cxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + FxPointerNotNull(cxDriverGlobals, CxDeviceInit); + fxDriverGlobals = CxDeviceInit->ClientDriverGlobals; + + // + // Caller must be a class extension driver. + // + status = FxValiateCx(fxDriverGlobals, cxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + FxPointerNotNull(fxDriverGlobals, EvtIoInCallerContext); + + CxDeviceInit->IoInCallerContextCallback = EvtIoInCallerContext; + +Done: + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFCXDEVICE_INIT CxDeviceInit, + __in + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals; + PFX_DRIVER_GLOBALS cxDriverGlobals; + NTSTATUS status; + + cxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + FxPointerNotNull(cxDriverGlobals, CxDeviceInit); + fxDriverGlobals = CxDeviceInit->ClientDriverGlobals; + + // + // Caller must be a class extension driver. + // + status = FxValiateCx(fxDriverGlobals, cxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + FxPointerNotNull(fxDriverGlobals, RequestAttributes); + + // + // Parent of all requests created from WDFDEVICE are parented by the WDFDEVICE. + // + status = FxValidateObjectAttributes(fxDriverGlobals, + RequestAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(fxDriverGlobals); + return; + } + + RtlCopyMemory(&CxDeviceInit->RequestAttributes, + RequestAttributes, + sizeof(WDF_OBJECT_ATTRIBUTES)); + +Done: + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFCXDEVICE_INIT CxDeviceInit, + __in + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + __in_opt + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ) + +/*++ + +Routine Description: + + Registers file object callbacks for class extensions. + + Defaults to WdfFileObjectNotRequired if no file obj config set. + +Arguments: + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals; + PFX_DRIVER_GLOBALS cxDriverGlobals; + NTSTATUS status; + WDF_FILEOBJECT_CLASS normalizedFileClass; + + cxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + FxPointerNotNull(cxDriverGlobals, CxDeviceInit); + fxDriverGlobals = CxDeviceInit->ClientDriverGlobals; + + // + // Caller must be a class extension driver. + // + status = FxValiateCx(fxDriverGlobals, cxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + FxPointerNotNull(fxDriverGlobals, CxFileObjectConfig); + + if (CxFileObjectConfig->Size != sizeof(WDFCX_FILEOBJECT_CONFIG)) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid CxFileObjectConfig Size %d, expected %d", + CxFileObjectConfig->Size, sizeof(WDFCX_FILEOBJECT_CONFIG)); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + status = FxValidateObjectAttributes( + fxDriverGlobals, + FileObjectAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED | + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | + FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED + ); + + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Validate AutoForwardCleanupClose. + // + switch (CxFileObjectConfig->AutoForwardCleanupClose) { + case WdfTrue: + case WdfFalse: + case WdfUseDefault: + break; + + default: + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid CxFileObjectConfig->AutoForwardCleanupClose value 0x%x, " + "expected WDF_TRI_STATE value", + CxFileObjectConfig->AutoForwardCleanupClose); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + CxDeviceInit->FileObject.Set = TRUE; + + CxDeviceInit->FileObject.AutoForwardCleanupClose = + CxFileObjectConfig->AutoForwardCleanupClose; + + // + // Remove bit flags and validate file object class value. + // + normalizedFileClass = FxFileObjectClassNormalize( + CxFileObjectConfig->FileObjectClass); + + if (normalizedFileClass == WdfFileObjectInvalid || + normalizedFileClass > WdfFileObjectWdfCannotUseFsContexts) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Out of range CxFileObjectConfig->FileObjectClass %d", + CxFileObjectConfig->FileObjectClass); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // The optional flag can only be combined with a subset of values. + // + if (FxIsFileObjectOptional(CxFileObjectConfig->FileObjectClass)) { + switch(normalizedFileClass) { + case WdfFileObjectWdfCanUseFsContext: + case WdfFileObjectWdfCanUseFsContext2: + case WdfFileObjectWdfCannotUseFsContexts: + break; + + default: + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid CxFileObjectConfig->FileObjectClass %d", + CxFileObjectConfig->FileObjectClass); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + break; // just in case static verification tools complain. + } + } + + CxDeviceInit->FileObject.Class = CxFileObjectConfig->FileObjectClass; + + RtlCopyMemory(&CxDeviceInit->FileObject.Callbacks, + CxFileObjectConfig, + sizeof(CxDeviceInit->FileObject.Callbacks)); + + if (FileObjectAttributes != NULL) { + RtlCopyMemory(&CxDeviceInit->FileObject.Attributes, + FileObjectAttributes, + sizeof(CxDeviceInit->FileObject.Attributes)); + } + +Done: + return; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +PWDFCXDEVICE_INIT +WDFEXPORT(WdfCxDeviceInitAllocate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS cxDriverGlobals; + PFX_DRIVER_GLOBALS fxDriverGlobals; + PWDFCXDEVICE_INIT cxDeviceInit; + NTSTATUS status; + + cxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + FxPointerNotNull(cxDriverGlobals, DeviceInit); + fxDriverGlobals = DeviceInit->DriverGlobals; + cxDeviceInit = NULL; + + // + // Caller must be a class extension driver. + // + status = FxValiateCx(fxDriverGlobals, cxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = FxVerifierCheckIrqlLevel(fxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + goto Done; + } + + cxDeviceInit = WDFCXDEVICE_INIT::_AllocateCxDeviceInit(DeviceInit); + if (NULL == cxDeviceInit) { + goto Done; + } + + cxDeviceInit->ClientDriverGlobals = fxDriverGlobals; + cxDeviceInit->CxDriverGlobals = cxDriverGlobals; + +Done: + return cxDeviceInit; +} + +} // extern "C" + diff --git a/sdk/lib/drivers/wdf/shared/core/fxdevice.cpp b/sdk/lib/drivers/wdf/shared/core/fxdevice.cpp new file mode 100644 index 00000000000..be5739a1008 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdevice.cpp @@ -0,0 +1,2177 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDevice.cpp + +Abstract: + + This is the class implementation for the base Device class. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDevice.tmh" +} + +// +// This table contains the mapping between device type and the +// default priority boost used by the the framework when +// an I/O request is completed. The DeviceObject->DeviceType +// is used as an index into this table. +// +const CHAR FxDevice::m_PriorityBoosts[] = { + IO_NO_INCREMENT, // FILE_DEVICE_UNDEFINED 0x00000000 + IO_NO_INCREMENT, // FILE_DEVICE_BEEP 0x00000001 + IO_CD_ROM_INCREMENT, // FILE_DEVICE_CD_ROM 0x00000002 + IO_CD_ROM_INCREMENT, // FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003 + IO_NO_INCREMENT, // FILE_DEVICE_CONTROLLER 0x00000004 + IO_NO_INCREMENT, // FILE_DEVICE_DATALINK 0x00000005 + IO_NO_INCREMENT, // FILE_DEVICE_DFS 0x00000006 + IO_DISK_INCREMENT, // FILE_DEVICE_DISK 0x00000007 + IO_DISK_INCREMENT, // FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008 + IO_NO_INCREMENT, // FILE_DEVICE_FILE_SYSTEM 0x00000009 + IO_NO_INCREMENT, // FILE_DEVICE_INPORT_PORT 0x0000000a + IO_KEYBOARD_INCREMENT, // FILE_DEVICE_KEYBOARD 0x0000000b + IO_MAILSLOT_INCREMENT, // FILE_DEVICE_MAILSLOT 0x0000000c + IO_SOUND_INCREMENT, // FILE_DEVICE_MIDI_IN 0x0000000d + IO_SOUND_INCREMENT, // FILE_DEVICE_MIDI_OUT 0x0000000e + IO_MOUSE_INCREMENT, // FILE_DEVICE_MOUSE 0x0000000f + IO_NO_INCREMENT, // FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010 + IO_NAMED_PIPE_INCREMENT,// FILE_DEVICE_NAMED_PIPE 0x00000011 + IO_NETWORK_INCREMENT, // FILE_DEVICE_NETWORK 0x00000012 + IO_NETWORK_INCREMENT, // FILE_DEVICE_NETWORK_BROWSER 0x00000013 + IO_NETWORK_INCREMENT, // FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014 + IO_NO_INCREMENT, // FILE_DEVICE_NULL 0x00000015 + IO_PARALLEL_INCREMENT, // FILE_DEVICE_PARALLEL_PORT 0x00000016 + IO_NETWORK_INCREMENT, // FILE_DEVICE_PHYSICAL_NETCARD 0x00000017 + IO_NO_INCREMENT, // FILE_DEVICE_PRINTER 0x00000018 + IO_NO_INCREMENT, // FILE_DEVICE_SCANNER 0x00000019 + IO_SERIAL_INCREMENT, // FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a + IO_SERIAL_INCREMENT, // FILE_DEVICE_SERIAL_PORT 0x0000001b + IO_VIDEO_INCREMENT, // FILE_DEVICE_SCREEN 0x0000001c + IO_SOUND_INCREMENT, // FILE_DEVICE_SOUND 0x0000001d + IO_SOUND_INCREMENT, // FILE_DEVICE_STREAMS 0x0000001e + IO_NO_INCREMENT, // FILE_DEVICE_TAPE 0x0000001f + IO_NO_INCREMENT, // FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020 + IO_NO_INCREMENT, // FILE_DEVICE_TRANSPORT 0x00000021 + IO_NO_INCREMENT, // FILE_DEVICE_UNKNOWN 0x00000022 + IO_VIDEO_INCREMENT, // FILE_DEVICE_VIDEO 0x00000023 + IO_DISK_INCREMENT, // FILE_DEVICE_VIRTUAL_DISK 0x00000024 + IO_SOUND_INCREMENT, // FILE_DEVICE_WAVE_IN 0x00000025 + IO_SOUND_INCREMENT, // FILE_DEVICE_WAVE_OUT 0x00000026 + IO_KEYBOARD_INCREMENT, // FILE_DEVICE_8042_PORT 0x00000027 + IO_NETWORK_INCREMENT, // FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028 + IO_NO_INCREMENT, // FILE_DEVICE_BATTERY 0x00000029 + IO_NO_INCREMENT, // FILE_DEVICE_BUS_EXTENDER 0x0000002a + IO_SERIAL_INCREMENT, // FILE_DEVICE_MODEM 0x0000002b + IO_NO_INCREMENT, // FILE_DEVICE_VDM 0x0000002c + IO_DISK_INCREMENT, // FILE_DEVICE_MASS_STORAGE 0x0000002d + IO_NETWORK_INCREMENT, // FILE_DEVICE_SMB 0x0000002e + IO_SOUND_INCREMENT, // FILE_DEVICE_KS 0x0000002f + IO_NO_INCREMENT, // FILE_DEVICE_CHANGER 0x00000030 + IO_NO_INCREMENT, // FILE_DEVICE_SMARTCARD 0x00000031 + IO_NO_INCREMENT, // FILE_DEVICE_ACPI 0x00000032 + IO_NO_INCREMENT, // FILE_DEVICE_DVD 0x00000033 + IO_VIDEO_INCREMENT, // FILE_DEVICE_FULLSCREEN_VIDEO 0x00000034 + IO_NO_INCREMENT, // FILE_DEVICE_DFS_FILE_SYSTEM 0x00000035 + IO_NO_INCREMENT, // FILE_DEVICE_DFS_VOLUME 0x00000036 + IO_SERIAL_INCREMENT, // FILE_DEVICE_SERENUM 0x00000037 + IO_NO_INCREMENT, // FILE_DEVICE_TERMSRV 0x00000038 + IO_NO_INCREMENT, // FILE_DEVICE_KSEC 0x00000039 + IO_NO_INCREMENT, // FILE_DEVICE_FIPS 0x0000003A + IO_NO_INCREMENT, // FILE_DEVICE_INFINIBAND 0x0000003B +}; + +NTSTATUS +FxDevice::_CompletionRoutineForRemlockMaintenance( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp, + __in PVOID Context + ) +/*++ + +Routine Description: + + A completion routine for the IRPs for which we acquired opt-in remove lock. + +Arguments: + DeviceObject - Pointer to deviceobject + Irp - Pointer to the Irp for which we acquired opt-in remove lock. + Context - NULL +Return Value: + + NT Status is returned. + +--*/ + +{ + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER(Context); + + // + // Let the irp continue on its way. + // + irp.PropagatePendingReturned(); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + Mx::MxReleaseRemoveLock(&((FxDevice::_GetFxWdmExtension( + DeviceObject))->IoRemoveLock), Irp); +#else + UNREFERENCED_PARAMETER(DeviceObject); +#endif + + return STATUS_CONTINUE_COMPLETION; +} + + +FxDevice::FxDevice( + __in FxDriver *ArgDriver + ) : + FxDeviceBase(ArgDriver->GetDriverGlobals(), ArgDriver, FX_TYPE_DEVICE, sizeof(FxDevice)), + m_ParentDevice(NULL) +{ + SetInitialState(); +} + +VOID +FxDevice::SetInitialState( + VOID + ) +{ + // + // Set the initial device state + // + m_CurrentPnpState = WdfDevStatePnpObjectCreated; + m_CurrentPowerState = WdfDevStatePowerObjectCreated; + m_CurrentPowerPolicyState = WdfDevStatePwrPolObjectCreated; + + // + // Set the default IO type to "buffered" + // + m_ReadWriteIoType = WdfDeviceIoBuffered; + + RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName)); + RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName)); + RtlZeroMemory(&m_MofResourceName, sizeof(m_MofResourceName)); + + m_Filter = FALSE; + m_Exclusive = FALSE; + m_PowerPageableCapable = FALSE; + m_ParentWaitingOnChild = FALSE; + m_Legacy = FALSE; + m_DeviceObjectDeleted = FALSE; + m_PdoKnown = FALSE; + m_Legacy = FALSE; + m_AutoForwardCleanupClose = FALSE; + m_SelfIoTargetNeeded = FALSE; + m_DeviceTelemetryInfoFlags = 0; + + // + // Clear all packages by default + // + + m_PkgIo = NULL; + m_PkgPnp = NULL; + m_PkgGeneral = NULL; + m_PkgWmi = NULL; + m_PkgDefault = NULL; + + InitializeListHead(&m_PreprocessInfoListHead); + InitializeListHead(&m_CxDeviceInfoListHead); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_FileObjectClass = WdfFileObjectNotRequired; +#else // UMDF + // + // In UMDF file object is always required. So indicate that now. + // + m_FileObjectClass = WdfFileObjectWdfCannotUseFsContexts; +#endif + + m_DefaultPriorityBoost = IO_NO_INCREMENT; + + InitializeListHead(&m_FileObjectListHead); + + m_RequestLookasideListElementSize = 0; + RtlZeroMemory(&m_RequestLookasideList, sizeof(m_RequestLookasideList)); + RtlZeroMemory(&m_RequestAttributes, sizeof(m_RequestAttributes)); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // Init UMDF specific members + // + m_CleanupFromFailedCreate = FALSE; + m_Dispatcher = NULL; + m_DevStack = NULL; + m_PdoDevKey = NULL; + m_DeviceKeyPath = NULL; + m_KernelDeviceName = NULL; + m_DeviceInstanceId = NULL; + + m_RetrievalMode = UMINT::WdfDeviceIoBufferRetrievalDeferred; + m_IoctlIoType = WdfDeviceIoBuffered; + m_DirectTransferThreshold = 0; + + m_DirectHardwareAccess = FX_DIRECT_HARDWARE_ACCESS_DEFAULT; + m_RegisterAccessMode = FX_REGISTER_ACCESS_MODE_DEFAULT; + m_FileObjectPolicy = FX_FILE_OBJECT_POLICY_DEFAULT; + m_FsContextUsePolicy = FX_FS_CONTEXT_USE_POLICY_DEFAULT; + m_InteruptThreadpool = NULL; +#endif +} + +FxDevice::~FxDevice() +{ + PLIST_ENTRY next; + + // Make it always present right now even on free builds + if (IsDisposed() == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDEVICE, + "FxDevice 0x%p not disposed: this maybe a driver reference count " + "problem with WDFDEVICE %p", this, GetObjectHandleUnchecked()); + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_OBJECT_ERROR, + (ULONG_PTR) GetObjectHandleUnchecked(), + (ULONG_PTR) this); + } + + // + // Execute mode-specific destructor. Noop for KMDF, but does + // does detach and delete of UM device object for UMDF. Therefore + // can be done before other cleanup. + // + DestructorInternal(); + + // + // If the device has been initialized but hasn't yet been + // destroyed, destroy it now. + // + + + + + + + + ASSERT(m_DeviceObject.GetObject() == NULL); + + ASSERT(m_DeviceName.Buffer == NULL); + +#if FX_CORE_MODE == FX_CORE_KERNEL_MODE + // + // Assert only applicable to KM because FxDevice can get destroyed in UMDF + // without going through normal pnp remove path, for example, when an + // AddDevice failure is done in reflector, after all um drivers have + // succeeded AddDevice. KMDF and host use fake remove irp to handle + // AddDevice failure in KMDF and host respectively, but reflector does not + // do that for AddDevice failure that happens in reflector. + // Note that symbolicName buffer will anyway be deleted in this destructor + // later on so the symbolic link buffer doesn't leak out. + // + ASSERT(m_SymbolicLinkName.Buffer == NULL); +#endif + + ASSERT(m_MofResourceName.Buffer == NULL); + + if (m_PkgIo != NULL) { + m_PkgIo->RELEASE(NULL); + m_PkgIo = NULL; + } + + if (m_PkgPnp != NULL) { + m_PkgPnp->RELEASE(NULL); + m_PkgPnp = NULL; + } + + if (m_PkgGeneral != NULL) { + m_PkgGeneral->RELEASE(NULL); + m_PkgGeneral = NULL; + } + + if (m_PkgWmi != NULL) { + m_PkgWmi->RELEASE(NULL); + m_PkgWmi = NULL; + } + + if (m_PkgDefault != NULL) { + m_PkgDefault->RELEASE(NULL); + m_PkgDefault = NULL; + } + + while (!IsListEmpty(&m_PreprocessInfoListHead)) { + next = RemoveHeadList(&m_PreprocessInfoListHead); + FxIrpPreprocessInfo* info; + info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry); + InitializeListHead(next); + delete info; + } + + while (!IsListEmpty(&m_CxDeviceInfoListHead)) { + next = RemoveHeadList(&m_CxDeviceInfoListHead); + FxCxDeviceInfo* info; + info = CONTAINING_RECORD(next, FxCxDeviceInfo, ListEntry); + InitializeListHead(next); + delete info; + } + + // + // Clean up any referenced objects + // + if (m_DeviceName.Buffer != NULL) { + FxPoolFree(m_DeviceName.Buffer); + RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName)); + } + + DeleteSymbolicLink(); + + if (m_MofResourceName.Buffer != NULL) { + FxPoolFree(m_MofResourceName.Buffer); + RtlZeroMemory(&m_MofResourceName, sizeof(m_DeviceName)); + } + + // + // m_RequestLookasideListElementSize will be set to non zero if we have + // initialized the request lookaside list. + // + if (m_RequestLookasideListElementSize != 0) { + Mx::MxDeleteNPagedLookasideList(&m_RequestLookasideList); + m_RequestLookasideListElementSize = 0; + } + + if (m_ParentDevice != NULL) { + m_ParentDevice->RELEASE(this); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDFDEVICE_INIT* DeviceInit, + __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + __out FxDevice** Device + ) +{ + PWDFDEVICE_INIT pInit; + FxDevice* pDevice; + NTSTATUS status; + WDFOBJECT object; + PLIST_ENTRY pNext; + PWDFCXDEVICE_INIT pCxInit; + FxWdmDeviceExtension* wdmDeviceExtension; + + *Device = NULL; + pInit = *DeviceInit; + + pDevice = new (FxDriverGlobals, DeviceAttributes) + FxDevice(pInit->Driver); + + if (pDevice == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + status = pDevice->Initialize(pInit, DeviceAttributes); + if (!NT_SUCCESS(status)) { + goto Done; + } + + switch (pInit->InitType) { + case FxDeviceInitTypeFdo: + status = pDevice->FdoInitialize(pInit); + break; + + case FxDeviceInitTypePdo: + status = pDevice->PdoInitialize(pInit); + break; + + case FxDeviceInitTypeControlDevice: + status = pDevice->ControlDeviceInitialize(pInit); + break; + + default: + // + // Should not drop here + // + ASSERT(FALSE); + break; + } + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Ok, we have created the device. Now lets create a handle for it. + // + status = pDevice->PostInitialize(); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Can't use the PDO's FxDevice m_Parent as the object hierarchy parent + // because the Fx object hierarchy lifetime rules do not match the + // rules for a pnp PDO lifetime vs its FDO. + // + status = pDevice->Commit(DeviceAttributes, + &object, + pDevice->GetDriver()); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // NOTE: ---> DO NOT FAIL FROM HERE FORWARD <--- + // + + // + // Up until now we have not reassigned any of the allocations in pInit + // and assigned them to the underlying objects. We are now at the point + // of "no return", ie we cannot fail. If we reassigned the allocations + // before this point and the driver retried to create the device (let's + // say with a different name), we would have freed those allocations + // and the driver writer would have thought that particular settings + // we valid, but were not b/c we freed them on error. So, to avoid a + // huge tracking mess, we only grab the allocations once we know for + // *sure* we are going to return success. + // + if (pInit->DeviceName != NULL) { + pInit->DeviceName->ReleaseString(&pDevice->m_DeviceName); + } + + // + // Check for driver preprocess requirements. + // + if (pInit->PreprocessInfo != NULL) { + ASSERT( pInit->PreprocessInfo->ClassExtension == FALSE); + ASSERT(IsListEmpty(&pDevice->m_PreprocessInfoListHead)); + InsertTailList(&pDevice->m_PreprocessInfoListHead, + &pInit->PreprocessInfo->ListEntry); + pInit->PreprocessInfo = NULL; + + // + // If the driver is preprocessing requests on this device, they need + // their own stack location so that they can set their own completion + // routine. + // + pDevice->SetStackSize(pDevice->GetStackSize()+1); + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + wdmDeviceExtension = _GetFxWdmExtension(pDevice->GetDeviceObject()); + if (wdmDeviceExtension->RemoveLockOptionFlags & + WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) { + // + // We will use a completion routine for remlock maintenance + // + pDevice->SetStackSize(pDevice->GetStackSize()+1); + } + + // + // Note: In case of UMDF StackSize is incremented prior to attaching + // the device to stack. See the comment in FxDeviceUm.cpp + // + if (pDevice->m_SelfIoTargetNeeded) { + pDevice->SetStackSize(pDevice->GetStackSize()+1); + } + +#else + UNREFERENCED_PARAMETER(wdmDeviceExtension); +#endif + + // + // Check for any class-extensions' preprocess requirements. + // + for (pNext = pInit->CxDeviceInitListHead.Flink; + pNext != &pInit->CxDeviceInitListHead; + pNext = pNext->Flink) { + + pCxInit = CONTAINING_RECORD(pNext, WDFCXDEVICE_INIT, ListEntry); + + if (pCxInit->PreprocessInfo != NULL) { + ASSERT(pCxInit->PreprocessInfo->ClassExtension); + InsertTailList(&pDevice->m_PreprocessInfoListHead, + &pCxInit->PreprocessInfo->ListEntry); + pCxInit->PreprocessInfo = NULL; + + // + // If the class extension is preprocessing requests on this + // device, it needs its own stack location so that it can + // set its own completion routine. + // + pDevice->SetStackSize(pDevice->GetStackSize()+1); + } + } + + if (pDevice->IsPnp()) { + // + // Take all of the allocations out of pInit related to pnp. This + // will also transition the pnp state machine into the added state. + // + pDevice->m_PkgPnp->FinishInitialize(pInit); + } + + pInit->CreatedDevice = pDevice; + + // + // Clear out the pointer, we freed it on behalf of the caller + // + *DeviceInit = NULL; + + if (pInit->CreatedOnStack == FALSE) { + delete pInit; + } + +Done: + if (!NT_SUCCESS(status) && pDevice != NULL) { + // + // We want to propagate the original error code + // + (void) pDevice->DeleteDeviceFromFailedCreate(status, FALSE); + pDevice = NULL; + } + + *Device = pDevice; + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::DeleteDeviceFromFailedCreateNoDelete( + __in NTSTATUS FailedStatus, + __in BOOLEAN UseStateMachine + ) +{ + // + // Cleanup the device, the driver may have allocated resources + // associated with the WDFDEVICE + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p created, but EvtDriverDeviceAdd returned " + "status %!STATUS! or failure in creation", + GetObjectHandleUnchecked(), GetDeviceObject(), FailedStatus); + + // + // We do not let filters affect the building of the rest of the stack. + // If they return error, we convert it to STATUS_SUCCESS, remove the + // attached device from the stack, and cleanup. + // + if (IsFilter()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p is a filter, converting %!STATUS! to" + " STATUS_SUCCESS", GetObjectHandleUnchecked(), GetDeviceObject(), + FailedStatus); + FailedStatus = STATUS_SUCCESS; + } + + if (UseStateMachine) { + MxEvent waitEvent; + + // + // See comments for m_CleanupFromFailedCreate in class definition file + // for use of this statement. + // + SetCleanupFromFailedCreate(TRUE); + + + + + + waitEvent.Initialize(SynchronizationEvent, FALSE); + m_PkgPnp->CleanupDeviceFromFailedCreate(waitEvent.GetSelfPointer()); + } + else { + // + // Upon certain types of failure, like STATUS_OBJECT_NAME_COLLISION, we + // could keep the pDevice around and the caller retry after changing + // a property, but the simpler route for now is to just recreate + // everything from scratch on the retry. + // + // Usually the pnp state machine will do this and the FxDevice destructor + // relies on it running b/c it does some cleanup. + // + EarlyDispose(); + DestroyChildren(); + + // + // Wait for all children to drain out and cleanup. + // + if (m_DisposeList != NULL) { + m_DisposeList->WaitForEmpty(); + } + + // + // We keep a reference on m_PkgPnp which is released in the destructor + // so we can safely touch m_PkgPnp after destroying all of the child + // objects. + // + if (m_PkgPnp != NULL) { + m_PkgPnp->CleanupStateMachines(TRUE); + } + } + + // + // This will detach and delete the device object + // + Destroy(); + + return FailedStatus; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::DeleteDeviceFromFailedCreate( + __in NTSTATUS FailedStatus, + __in BOOLEAN UseStateMachine + ) +{ + NTSTATUS status; + + status = DeleteDeviceFromFailedCreateNoDelete(FailedStatus, UseStateMachine); + + // + // Delete the Fx object now + // + DeleteObject(); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::Initialize( + __in PWDFDEVICE_INIT DeviceInit, + __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes + ) +/*++ + +Routine Description: + Generic initialization for an FxDevice regardless of role (pdo, fdo, control). + +Arguments: + + +Return Value: + + + --*/ + +{ + PFX_DRIVER_GLOBALS pGlobals; + PLIST_ENTRY next; + NTSTATUS status; + BOOLEAN wmiTracing; + size_t reqCtxSize; + PWDFCXDEVICE_INIT cxInit; + CCHAR cxIndex; + FxCxDeviceInfo* cxDeviceInfo; + + pGlobals = GetDriverGlobals(); + wmiTracing = FALSE; + m_Exclusive = DeviceInit->Exclusive; + cxIndex = 0; + + MarkDisposeOverride(ObjectDoNotLock); + + // + // Configure device constraints. + // + status = ConfigureConstraints(DeviceAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Generic catch all + // + m_PkgDefault = new (pGlobals) FxDefaultIrpHandler(pGlobals, (CfxDevice*)this); + if (m_PkgDefault == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + InstallPackage(m_PkgDefault); + + if (DeviceInit->InitType == FxDeviceInitTypeControlDevice) { + m_Legacy = TRUE; + } + + // + // Size will be set to a non zero if the driver wants request attributes + // associated with each created request. + // + if (DeviceInit->RequestAttributes.Size != 0) { + ASSERT(DeviceInit->RequestAttributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES)); + RtlCopyMemory(&m_RequestAttributes, + &DeviceInit->RequestAttributes, + sizeof(DeviceInit->RequestAttributes)); + } + + reqCtxSize = FxGetContextSize(&m_RequestAttributes); + + // + // If present, setup a I/O class extensions info chain. + // + for (next = DeviceInit->CxDeviceInitListHead.Flink; + next != &DeviceInit->CxDeviceInitListHead; + next = next->Flink) { + + cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry); + + cxDeviceInfo = new(pGlobals) FxCxDeviceInfo(pGlobals); + if (NULL == cxDeviceInfo) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + cxDeviceInfo->Index = ++cxIndex; // 1-based. + cxDeviceInfo->Driver = cxInit->CxDriverGlobals->Driver; + cxDeviceInfo->IoInCallerContextCallback.m_Method = + cxInit->IoInCallerContextCallback; + cxDeviceInfo->RequestAttributes = cxInit->RequestAttributes; + + InsertTailList(&m_CxDeviceInfoListHead, &cxDeviceInfo->ListEntry); + + // + // Set weak ref to this run-time cx struct to help file-object logic later on. + // + cxInit->CxDeviceInfo = cxDeviceInfo; + + // + // Find the max size for the request context. Used below. + // + ASSERT(cxInit->RequestAttributes.Size == 0 || + cxInit->RequestAttributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES)); + + reqCtxSize = MAX(FxGetContextSize(&cxInit->RequestAttributes), + reqCtxSize); + } + + // + // Memory layout for memory backing FxRequest which is allocated from the + // lookaside list: + // + // If we are tracking memory, the allocation layout is + // 0x0 - FX_POOL_TRACKER + // 0x0 + sizeof(FX_POOL_TRACKER) - FX_POOL_HEADER + // 0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest + // + // if no tracking is occuring, the allocation layout is + // 0x0 - FX_POOL_HEADER + // 0x0 + FX_POOL_HEADER_SIZE - start of FxRequest + // + // NOTE: If the computation of m_RequestLookasideListElementSize changes, + // FxDevice::AllocateRequestMemory and FxDevice::FreeRequestMemory will also + // need to be updated to reflect the changes made. + // + status = FxCalculateObjectTotalSize2(pGlobals, + sizeof(FxRequest), + 0, + reqCtxSize, + &m_RequestLookasideListElementSize); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxPoolAddHeaderSize(pGlobals, + m_RequestLookasideListElementSize, + &m_RequestLookasideListElementSize); + + if (!NT_SUCCESS(status)) { + // + // FxPoolAddHeaderSize will log to the IFR on error + // + return status; + } + + Mx::MxInitializeNPagedLookasideList(&m_RequestLookasideList, + NULL, + NULL, + 0, + m_RequestLookasideListElementSize, + pGlobals->Tag, + 0); + // + // Init device's auto_forward_cleanup_close. + // + ConfigureAutoForwardCleanupClose(DeviceInit); + + // + // Create, close, cleanup, shutdown + // + m_PkgGeneral = new(pGlobals) FxPkgGeneral(pGlobals, this); + if (m_PkgGeneral == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + InstallPackage(m_PkgGeneral); + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + + + + + + + m_PkgWmi = new(pGlobals) FxWmiIrpHandler(pGlobals, this); + if (m_PkgWmi == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + InstallPackage(m_PkgWmi); +#endif + + // + // IO package handles reads, writes, internal and external IOCTLs + // + m_PkgIo = new(pGlobals) FxPkgIo(pGlobals, (CfxDevice*) this); + + if (m_PkgIo == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + InstallPackage(m_PkgIo); + + // + // Configure I/O package. + // + m_PkgIo->SetIoInCallerContextCallback(DeviceInit->IoInCallerContextCallback); + + if (DeviceInit->RequiresSelfIoTarget) { + m_SelfIoTargetNeeded = TRUE; + } + + return STATUS_SUCCESS; +} + +VOID +FxDevice::ConfigureAutoForwardCleanupClose( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + WDF_TRI_STATE autoForwardCleanupClose; + PLIST_ENTRY next; + BOOLEAN checkClientDriver; + + autoForwardCleanupClose = WdfUseDefault; + checkClientDriver = TRUE; + + // + // Device-wide configuration for auto forwarding cleanup and close requests: + // . Use WdfFalse if one of the devices in the chain use this setting with a create + // callback (this means it will complete all create IRPs). + // . Else use lowest driver's setting in the chain (order of cx chain: lower to higher). + // . If no settings are present, use default. + // + for (next = DeviceInit->CxDeviceInitListHead.Blink; + next != &DeviceInit->CxDeviceInitListHead; + next = next->Blink) { + + PWDFCXDEVICE_INIT cxInit; + + cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry); + + if (cxInit->FileObject.Set) { + autoForwardCleanupClose = cxInit->FileObject.AutoForwardCleanupClose; + + if (autoForwardCleanupClose == WdfFalse && + cxInit->FileObject.Callbacks.EvtCxDeviceFileCreate != NULL) { + + checkClientDriver = FALSE; + break; + } + } + } + + if (checkClientDriver && DeviceInit->FileObject.Set) { + autoForwardCleanupClose = DeviceInit->FileObject.AutoForwardCleanupClose; + } + + switch (autoForwardCleanupClose) { + case WdfTrue: + + m_AutoForwardCleanupClose = TRUE; + // + // If the device is legacy then set it to false because you can't forward + // requests. + // + if(m_Legacy) { + m_AutoForwardCleanupClose = FALSE; + } + break; + + case WdfFalse: + m_AutoForwardCleanupClose = FALSE; + break; + + case WdfUseDefault: + // + // For filters (which must be FDOs), we default to TRUE. All other + // device roles (FDO, PDO, control) default to FALSE. We cannot check + // m_Filter yet because it is set in FdoInitialize which occurs later. + // + if (DeviceInit->IsFdoInit() && DeviceInit->Fdo.Filter) { + m_AutoForwardCleanupClose = TRUE; + } + else { + m_AutoForwardCleanupClose = FALSE; + } + } +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::PostInitialize( + VOID + ) +{ + NTSTATUS status; + + status = FxDisposeList::_Create(GetDriverGlobals(), + m_DeviceObject.GetObject(), + &m_DisposeList); + + return status; +} + + + + + + + + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + +_Must_inspect_result_ +NTSTATUS +FxDevice::CreateDevice( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + MdDeviceObject pNewDeviceObject; + ULONG characteristics; + NTSTATUS status; + DEVICE_TYPE devType; + + status = m_PkgGeneral->Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + devType = DeviceInit->DeviceType; + if (devType < ARRAY_SIZE(m_PriorityBoosts)) { + m_DefaultPriorityBoost= m_PriorityBoosts[devType]; + } + + characteristics = DeviceInit->Characteristics; + + // + // You can only create secure device objects which have a name. All other + // device objects rely on the PDO's security + // + if (DeviceInit->ShouldCreateSecure()) { + PUNICODE_STRING pName, pSddl; + LPGUID pGuid; + + if (DeviceInit->DeviceName != NULL) { + pName = DeviceInit->DeviceName->GetUnicodeString(); + } + else { + pName = NULL; + } + + if (DeviceInit->Security.DeviceClassSet) { + pGuid = &DeviceInit->Security.DeviceClass; + } + else { + pGuid = NULL; + } + + if (DeviceInit->Security.Sddl != NULL) { + pSddl = DeviceInit->Security.Sddl->GetUnicodeString(); + } + else { + // + // Always provide an SDDL if one is not supplied. + // + // SDDL_DEVOBJ_SYS_ALL_ADM_ALL = "D:P(A;;GA;;;SY)(A;;GA;;;BA)" + // + // SDDL_DEVOBJ_SYS_ALL_ADM_ALL allows the kernel, system, and + // administrator complete control over the device. No other users + // may access the device. + // + pSddl = (PUNICODE_STRING) &SDDL_DEVOBJ_SYS_ALL_ADM_ALL; + } + + status = Mx::MxCreateDeviceSecure( + m_Driver->m_DriverObject.GetObject(), + sizeof(FxWdmDeviceExtension), + pName, + devType, + characteristics, + m_Exclusive, + pSddl, + pGuid, + &pNewDeviceObject); + } + else { + status = Mx::MxCreateDevice( + m_Driver->m_DriverObject.GetObject(), + sizeof(FxWdmDeviceExtension), + NULL, + devType, + characteristics, + m_Exclusive, + &pNewDeviceObject); + } + + if (NT_SUCCESS(status)) { + FxWdmDeviceExtension* pWdmExt; + + pWdmExt = _GetFxWdmExtension(pNewDeviceObject); + + // + // We reassign DeviceExtension below and then use the knowledge that + // we can always retrieve DeviceExtension by adding sizeof(DEVICE_OBJECT) + // to pNewDeviceObject. ASSERT that this assumption is correct. + // + MxDeviceObject newDeviceObject(pNewDeviceObject); + ASSERT(pWdmExt == newDeviceObject.GetDeviceExtension()); + + Mx::MxInitializeRemoveLock(&pWdmExt->IoRemoveLock, + GetDriverGlobals()->Tag, + 0, // max min + 0 // highwater mark + ); + + // + // Option for remove lock is stored in device extension + // since this option may be examined after FxDevice is destroyed + // (if an Irp is sent after removal of device). + // We combine the flags from DeviceInit with what's set through registry + // + pWdmExt->RemoveLockOptionFlags = DeviceInit->RemoveLockOptionFlags | + GetDriverGlobals()->RemoveLockOptionFlags; + + // + // We assign the first context assigned to this object as the + // DeviceExtension for compatibility reasons. This allows existing + // WDM extensions to work as well as any stack which exports a known + // structure for the extension (ie the FDO knows the extension of its + // PDO and casts it and accesses it directly). + // + newDeviceObject.SetDeviceExtension(&GetContextHeader()->Context[0]); + m_DeviceObject.SetObject(pNewDeviceObject); + + // + // Set some device object flags based on properties of DeviceInit. + // + // If we are a filter, we will set these flags later + // (in FxDevice::FdoInitialize) based on the device we are attached to. + // + if (m_Filter == FALSE) { + if (DeviceInit->ReadWriteIoType == WdfDeviceIoBuffered) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_BUFFERED_IO); + } + else if (DeviceInit->ReadWriteIoType == WdfDeviceIoDirect) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_DIRECT_IO); + } + + m_ReadWriteIoType = DeviceInit->ReadWriteIoType; + m_PowerPageableCapable = DeviceInit->PowerPageable; + } + } + + return status; +} + +#endif // (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + +VOID +FxDevice::FinishInitializing( + VOID + ) + +/*++ + +Routine Description: + + This routine is called when the device is completely initialized. + +Arguments: + + none. + +Returns: + + none. + +--*/ + +{ + + m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~DO_DEVICE_INITIALIZING); +} + +VOID +FxDevice::DeleteObject( + VOID + ) +/*++ + +Routine Description: + Virtual override of an FxObject::DeleteObject. For PDOs which are created + statically and then deleted before being reported to WDF, we must simulate + a pnp remove event to trigger cleanup. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (IsPnp() && IsPdo()) { + FxPkgPdo* pPkgPdo; + KIRQL irql; + BOOLEAN remove; + + remove = FALSE; + + pPkgPdo = GetPdoPkg(); + + pPkgPdo->Lock(&irql); + + if (pPkgPdo->m_Static && pPkgPdo->m_AddedToStaticList == FALSE) { + // + // Since no pnp action has been taken since the child was created, we + // should be in the initial state. + // + if (m_CurrentPnpState == WdfDevStatePnpInit) { + // + // A PDO in this state should be deletable + // + ASSERT(IsNoDeleteDDI() == FALSE); + + remove = TRUE; + } + else { + // + // If we are not in the init state, we should be in the created + // state. This means we are failing from FxDevice::CreateDevice. + // + ASSERT(m_CurrentPnpState == WdfDevStatePnpObjectCreated); + } + } + + pPkgPdo->Unlock(irql); + + if (remove) { + // + // Cleanup the device and then let the super class delete the object. + // + (void) DeleteDeviceFromFailedCreateNoDelete( + STATUS_UNSUCCESSFUL, TRUE); + } + } + else if (IsLegacy() && m_PkgGeneral != NULL && m_DeviceObject.GetObject() != NULL) { + // + // We allow tracing devices to go through a normal DeleteObject() path + // where we do not prematurely delete the device object. + // + (void) FxVerifierCheckIrqlLevel(GetDriverGlobals(), PASSIVE_LEVEL); + + m_DeviceObjectDeleted = TRUE; + + // + // This reference will be released in Destroy(). + // + Mx::MxReferenceObject(m_DeviceObject.GetObject()); + + if (m_PkgWmi != NULL) { + // + // Since a legacy NT4 driver does not have an explicit WMI + // deregistration DDI, we do it for them on deletion. + // + // This is done in DeleteObject because we need to deregister before + // we delete the device object, otherwise we can bugcheck when + // running under driver verifier. + // + m_PkgWmi->Deregister(); + } + + // + // By deleting the device object now, we prevent any new creates from + // being sent to the device (the io manager enforces this). + // + Mx::MxDeleteDevice(m_DeviceObject.GetObject()); + + if (m_PkgGeneral->CanDestroyControlDevice() == FALSE) { + // + // Delay the actual destruction of the device until the last open + // handle has been closed. ControlDeviceDelete() will perform the + // destruction later. + // + return; + } + } + + __super::DeleteObject(); +} + +BOOLEAN +FxDevice::Dispose( + VOID + ) +{ + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + if (m_Legacy) { + if (m_PkgWmi != NULL) { + // + // We deregister in Dispose() (as well as DeleteObject()) for + // control devices which are implicitly destroyed when the driver + // unloads and FxDriver is being deleted. + // + // Since a legacy NT4 driver does not have an explicit WMI + // deregistration DDI, we do it for them on destruction. + // + // This is done in Dispose because we are guaranteed to be at + // passive level here. Even though m_PkgWmi was already + // Dispose()'ed (because it is a child of this object), it is still + // valid to reference the pointer because there is an explicit + // reference on the object that was taken when we created this object. + // + m_PkgWmi->Deregister(); + } + + // + // Important that the cleanup routine be called while the PDEVICE_OBJECT + // is valid! + // + CallCleanup(); + + // + // Manually destroy the children now so that by the time we wait on the + // dispose empty out, all of the children will have been added to it. + // + DestroyChildren(); + + if (m_DisposeList != NULL) { + m_DisposeList->WaitForEmpty(); + } + + // + // Now delete the device object + // + Destroy(); + + return FALSE; + } + + return __super::Dispose(); +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_AcquireOptinRemoveLock( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp + ) +{ + NTSTATUS status; + FxIrp irp(Irp); + + FxWdmDeviceExtension * wdmDeviceExtension = + FxDevice::_GetFxWdmExtension(DeviceObject); + + if (wdmDeviceExtension->RemoveLockOptionFlags & + WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) { + + status = Mx::MxAcquireRemoveLock(&(wdmDeviceExtension->IoRemoveLock), Irp); + + if (!NT_SUCCESS(status)) { + return status; + } + + irp.CopyCurrentIrpStackLocationToNext(); + + irp.SetCompletionRoutineEx( + DeviceObject, + _CompletionRoutineForRemlockMaintenance, + DeviceObject, + TRUE, + TRUE, + TRUE + ); + + irp.SetNextIrpStackLocation(); + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::DispatchWithLock( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp + ) +{ + NTSTATUS status; + FxIrp irp(Irp); + + switch (_RequiresRemLock(irp.GetMajorFunction(), + irp.GetMinorFunction())) { + + case FxDeviceRemLockRequired: + status = Mx::MxAcquireRemoveLock( + &_GetFxWdmExtension(DeviceObject)->IoRemoveLock, + Irp + ); + + if (!NT_SUCCESS(status)) { + irp.SetStatus(status); + irp.CompleteRequest(IO_NO_INCREMENT); + + return status; + } + + break; + + case FxDeviceRemLockOptIn: + status = _AcquireOptinRemoveLock( + DeviceObject, + Irp + ); + + if (!NT_SUCCESS(status)) { + irp.SetStatus(status); + irp.CompleteRequest(IO_NO_INCREMENT); + + return status; + } + + break; + + case FxDeviceRemLockTestValid: + // + // Try to Acquire and Release the RemLock. If acquiring the lock + // fails then it is not safe to process the IRP and the IRP should + // be completed immediately. + // + status = Mx::MxAcquireRemoveLock( + &_GetFxWdmExtension(DeviceObject)->IoRemoveLock, + Irp + ); + + if (!NT_SUCCESS(status)) { + irp.SetStatus(status); + irp.CompleteRequest(IO_NO_INCREMENT); + + return status; + } + + Mx::MxReleaseRemoveLock( + &_GetFxWdmExtension(DeviceObject)->IoRemoveLock, + Irp + ); + break; + } + + return Dispatch(DeviceObject, Irp); +} + +_Must_inspect_result_ +__inline +BOOLEAN +IsPreprocessIrp( + __in MdIrp Irp, + __in FxIrpPreprocessInfo* Info + ) +{ + UCHAR major, minor; + BOOLEAN preprocess; + FxIrp irp(Irp); + + major = irp.GetMajorFunction(); + minor = irp.GetMinorFunction(); + + preprocess = FALSE; + + if (Info->Dispatch[major].EvtDevicePreprocess != NULL) { + if (Info->Dispatch[major].NumMinorFunctions == 0) { + // + // If the driver is not interested in particular minor codes, + // just give the irp to it. + // + preprocess = TRUE; + } + else { + ULONG i; + + // + // Try to match up to a minor code. + // + for (i = 0; i < Info->Dispatch[major].NumMinorFunctions; i++) { + if (Info->Dispatch[major].MinorFunctions[i] == minor) { + preprocess = TRUE; + break; + } + } + } + } + + return preprocess; +} + +_Must_inspect_result_ +__inline +NTSTATUS +PreprocessIrp( + __in FxDevice* Device, + __in MdIrp Irp, + __in FxIrpPreprocessInfo* Info, + __in PVOID DispatchContext + ) +{ + NTSTATUS status; + MdDeviceObject devObj; + UCHAR major, minor; + FxIrp irp(Irp); + + major = irp.GetMajorFunction(); + minor = irp.GetMinorFunction(); + + // + // If this is a pnp remove irp, this object could be deleted by the time + // EvtDevicePreprocess returns. To not touch freed pool, capture all + // values we will need before preprocessing. + // + devObj = Device->GetDeviceObject(); + + if (Info->ClassExtension == FALSE) { + status = Info->Dispatch[major].EvtDevicePreprocess( Device->GetHandle(), + Irp); + } + else { + status = Info->Dispatch[major].EvtCxDevicePreprocess( + Device->GetHandle(), + Irp, + DispatchContext); + } + + // + // If we got this far, we handed the irp off to EvtDevicePreprocess, so we + // must now do our remlock maintainance if necessary. + // + if (FxDevice::_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) { + // + // Keep the remove lock active until after we call into the driver. + // If the driver redispatches the irp to the framework, we will + // reacquire the remove lock at that point in time. + // + // Touching pDevObj after sending the pnp remove irp to the framework + // is OK b/c we have acquired the remlock previously and that will + // prevent this irp's processing racing with the pnp remove irp + // processing. + // + Mx::MxReleaseRemoveLock(Device->GetRemoveLock(), + Irp); + } + + return status; +} + +_Must_inspect_result_ +__inline +NTSTATUS +DispatchWorker( + __in FxDevice* Device, + __in MdIrp Irp, + __in WDFCONTEXT DispatchContext + ) +{ + PLIST_ENTRY next; + FxIrp irp(Irp); + + next = (PLIST_ENTRY)DispatchContext; + + ASSERT(NULL != DispatchContext && + ((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) == 0); + + // + // Check for any driver/class-extensions' preprocess requirements. + // + while (next != &Device->m_PreprocessInfoListHead) { + FxIrpPreprocessInfo* info; + + info = CONTAINING_RECORD(next, FxIrpPreprocessInfo, ListEntry); + + // + // Advance to next node. + // + next = next->Flink; + + if (IsPreprocessIrp(Irp, info)) { + return PreprocessIrp(Device, Irp, info, next); + } + } + + // + // No preprocess requirements, directly dispatch the IRP. + // + return Device->GetDispatchPackage( + irp.GetMajorFunction() + )->Dispatch(Irp); +} + + +_Must_inspect_result_ +NTSTATUS +FxDevice::Dispatch( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp + ) +{ + FxDevice* device = FxDevice::GetFxDevice(DeviceObject); + return DispatchWorker(device, + Irp, + device->m_PreprocessInfoListHead.Flink); +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::DispatchPreprocessedIrp( + __in MdIrp Irp, + __in WDFCONTEXT DispatchContext + ) +{ + NTSTATUS status; + UCHAR major, minor; + FxIrp irp(Irp); + + // + // 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. + // + irp.SetNextIrpStackLocation(); + + major = irp.GetMajorFunction(); + minor = irp.GetMinorFunction(); + + // + // FxPkgPnp and FxWmiIrpHandler expect that there will be a remove lock + // acquired for all power irps. We release the remlock when we called + // Evt(Ext)DevicePreprocessIrp. + // + if (_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) { + status = Mx::MxAcquireRemoveLock( + GetRemoveLock(), + Irp + ); + + if (!NT_SUCCESS(status)) { + goto Done; + } + } + + return DispatchWorker(this, Irp, DispatchContext); + +Done: + irp.SetStatus(status); + irp.SetInformation(0); + irp.CompleteRequest(IO_NO_INCREMENT); + + return status; +} + +VOID +FxDevice::InstallPackage( + __inout FxPackage *Package + ) + +{ + // + // Add this package as an association on FxDevice + // so its children get Dispose notifications. + // + // Note: This assumes a transfer of the controlling reference + // count which it will dereference on FxDevice teardown. + // We need to add an extra one here since packages have + // an existing reference count model. + // + Package->AddRef(); + Package->AssignParentObject(this); +} + +PVOID +FxDevice::AllocateRequestMemory( + __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +/*++ + +Routine Description: + Allocates enough memory for an FxRequest* plus any additonal memory required + for the device's specific context memory. + + If we are tracking memory, the allocation layout is + 0x0 - FX_POOL_TRACKER + 0x0 + sizeof(FX_POOL_TRACKER) - FX_POOL_HEADER + 0x0 + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE - start of FxRequest + + if no tracking is occuring, the allocation layout is + 0x0 - FX_POOL_HEADER + 0x0 + FX_POOL_HEADER_SIZE - start of FxRequest + + the total size is precomputed in m_RequestLookasideListElementSize during + FxDevice::Initialize + +Arguments: + RequestAttributes - Attributes setting for the request. + +Return Value: + valid ptr or NULL + + --*/ + +{ + PFX_DRIVER_GLOBALS pGlobals; + PFX_POOL_TRACKER pTracker; + PFX_POOL_HEADER pHeader; + PVOID ptr, pTrueBase; + + pGlobals = GetDriverGlobals(); + ptr = NULL; + + if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) { + pTrueBase = FxAllocateFromNPagedLookasideListNoTracking(&m_RequestLookasideList); + } + else { + pTrueBase = FxAllocateFromNPagedLookasideList(&m_RequestLookasideList, + m_RequestLookasideListElementSize); + } + + if (pTrueBase != NULL) { + if (pGlobals->IsPoolTrackingOn()) { + pTracker = (PFX_POOL_TRACKER) pTrueBase; + pHeader = WDF_PTR_ADD_OFFSET_TYPE(pTrueBase, + sizeof(FX_POOL_TRACKER), + PFX_POOL_HEADER); + + // + // Format and insert the Tracker in the NonPagedHeader list. + // + FxPoolInsertNonPagedAllocateTracker(&pGlobals->FxPoolFrameworks, + pTracker, + m_RequestLookasideListElementSize, + pGlobals->Tag, + _ReturnAddress()); + } + else { + pHeader = (PFX_POOL_HEADER) pTrueBase; + } + + // + // Common init + // + pHeader->Base = pTrueBase; + pHeader->FxDriverGlobals = pGlobals; + + ptr = &pHeader->AllocationStart[0]; + + if (RequestAttributes == NULL) { + RequestAttributes = &m_RequestAttributes; + } + + ptr = FxObjectAndHandleHeaderInit( + pGlobals, + ptr, + COMPUTE_OBJECT_SIZE(sizeof(FxRequest), 0), + RequestAttributes, + FxObjectTypeExternal + ); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Allocating FxRequest* %p, WDFREQUEST %p", + ptr, _ToHandle((FxObject*) ptr)); +#endif + return ptr; + } + + return NULL; +} + +VOID +FxDevice::FreeRequestMemory( + __in FxRequest* Request + ) +{ + PFX_POOL_HEADER pHeader; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Free FxRequest* %p memory", Request); +#endif + + // + // Remove the request from the list of outstanding requests against this + // driver. + // + pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), Request); + if (IsPdo() && GetPdoPkg()->IsForwardRequestToParentEnabled()) { + FxFreeToNPagedLookasideListNoTracking(&m_RequestLookasideList, pHeader->Base); + } + else { + FxFreeToNPagedLookasideList(&m_RequestLookasideList, pHeader->Base); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::QueryInterface( + __inout FxQueryInterfaceParams* Params + ) +{ + switch (Params->Type) { + case FX_TYPE_DEVICE: + *Params->Object = (FxDevice*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::AddIoTarget( + __inout FxIoTarget* IoTarget + ) +{ + NTSTATUS status; + + status = m_IoTargetsList.Add(GetDriverGlobals(), + &IoTarget->m_TransactionedEntry); + + if (NT_SUCCESS(status)) { + IoTarget->m_AddedToDeviceList = TRUE; + IoTarget->ADDREF(this); + } + + return status; +} + +VOID +FxDevice::RemoveIoTarget( + __inout FxIoTarget* IoTarget + ) +{ + m_IoTargetsList.Remove(GetDriverGlobals(), + &IoTarget->m_TransactionedEntry); + + // + // Assumes that the caller has its own reference on the IoTarget + // + IoTarget->RELEASE(this); +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::AllocateEnumInfo( + VOID + ) +{ + if (IsPnp()) { + return m_PkgPnp->AllocateEnumInfo(); + } + else { + return STATUS_SUCCESS; + } +} + +FxIoTarget* +FxDevice::GetDefaultIoTarget( + VOID + ) +{ + if (IsPnp() && IsFdo()) { + return GetFdoPkg()->m_DefaultTarget; + } + else { + return NULL; + } +} + +FxIoTargetSelf* +FxDevice::GetSelfIoTarget( + VOID + ) +/*++ +Routine Description: + Returns the Self IO target for this FxDevice. + Currently Self IO Target is supported only for a Pnp FDO. + If the Self IO Target has not been established, it returns NULL. +--*/ +{ + if (IsPnp() && IsFdo()) { + return GetFdoPkg()->m_SelfTarget; + } + else { + return NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::SetFilter( + __in BOOLEAN Value + ) +{ + NTSTATUS status; + + ASSERT(IsFdo()); + + status = m_PkgIo->SetFilter(Value); + + if (NT_SUCCESS(status) && m_PkgPnp != NULL) { + status = GetFdoPkg()->SetFilter(Value); + } + + if (NT_SUCCESS(status)) { + m_Filter = Value; + } + + return status; +} + +VOID +FxDevice::SetFilterIoType( + VOID + ) +{ + FxIoTarget * ioTarget; + FxTransactionedEntry * targetsList = NULL; + + ASSERT(IsFilter()); + + m_DeviceObject.SetFlags( m_DeviceObject.GetFlags() & ~(DO_BUFFERED_IO | DO_DIRECT_IO)); + + // + // m_AttachedDevice can be NULL for UMDF, so check for NULL + // + if (m_AttachedDevice.GetObject() != NULL) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | + (m_AttachedDevice.GetFlags() & (DO_BUFFERED_IO | DO_DIRECT_IO))); + } + + if (m_DeviceObject.GetFlags() & DO_BUFFERED_IO) { + m_ReadWriteIoType = WdfDeviceIoBuffered; + } + else if (m_DeviceObject.GetFlags() & DO_DIRECT_IO) { + m_ReadWriteIoType = WdfDeviceIoDirect; + } + else { + m_ReadWriteIoType = WdfDeviceIoNeither; + } + + // + // We also need to propagate these settings to any io targets that + // have already been created + // + + m_IoTargetsList.LockForEnum(GetDriverGlobals()); + + targetsList = m_IoTargetsList.GetNextEntry(targetsList); + + while (targetsList != NULL) { + + ioTarget = (FxIoTarget *) targetsList->GetTransactionedObject(); + + if (ioTarget->GetTargetPDO() == GetPhysicalDevice()) { + ioTarget->UpdateTargetIoType(); + } + + targetsList = m_IoTargetsList.GetNextEntry(targetsList); + } + + m_IoTargetsList.UnlockFromEnum(GetDriverGlobals()); +} + +BOOLEAN +FxDevice::IsInterfaceRegistered( + _In_ const GUID* InterfaceClassGUID, + _In_opt_ PCUNICODE_STRING RefString + ) +{ + PSINGLE_LIST_ENTRY ple; + BOOLEAN found = FALSE; + + m_PkgPnp->m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals()); + + // + // Iterate over the interfaces and see if we have a match + // + for (ple = m_PkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { + FxDeviceInterface *pDI; + + pDI = FxDeviceInterface::_FromEntry(ple); + + if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) { + if (RefString != NULL) { + if ((RefString->Length == pDI->m_ReferenceString.Length) + && + (RtlCompareMemory(RefString->Buffer, + pDI->m_ReferenceString.Buffer, + RefString->Length) == RefString->Length)) { + // + // They match, carry on + // + DO_NOTHING(); + } + else { + // + // The ref strings do not match, continue on in the search + // of the collection. + // + continue; + } + } + else if (pDI->m_ReferenceString.Length > 0) { + // + // Caller didn't specify a ref string but this interface has + // one, continue on in the search through the collection. + // + continue; + } + + // + // Set the state and break out of the loop because we found our + // interface. + // + found = TRUE; + break; + } + } + + m_PkgPnp->m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals()); + + return found; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_AllocAndQueryProperty( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_opt_ MdDeviceObject RemotePdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ POOL_TYPE PoolType, + _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ WDFMEMORY* PropertyMemory + ) +{ + FxMemoryObject* pMemory; + NTSTATUS status; + ULONG length = 0; + + status = FxDevice::_QueryProperty(Globals, + DeviceInit, + Device, + RemotePdo, + DeviceProperty, + 0, + NULL, + &length); + if (status != STATUS_BUFFER_TOO_SMALL) { + DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not retrieve property %d length, %!STATUS!", + DeviceProperty, status); + _Analysis_assume_(!NT_SUCCESS(status)); + return status; + } + + status = FxMemoryObject::_Create(Globals, + PropertyMemoryAttributes, + PoolType, + Globals->Tag, + length, + &pMemory); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not allocate WDFMEMORY, %!STATUS!", status); + return status; + } + + status = FxDevice::_QueryProperty(Globals, + DeviceInit, + Device, + RemotePdo, + DeviceProperty, + length, + pMemory->GetBuffer(), + &length); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not query for full buffer, size %d, for " + "property %d, %!STATUS!", + length, DeviceProperty, status); + pMemory->DeleteObject(); + return status; + } + + status = pMemory->Commit(PropertyMemoryAttributes, + (WDFOBJECT*)PropertyMemory); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(Globals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not commit memory object, %!STATUS!", + status); + pMemory->DeleteObject(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_AllocAndQueryPropertyEx( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ POOL_TYPE PoolType, + _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ WDFMEMORY* PropertyMemory, + _Out_ PDEVPROPTYPE PropertyType + ) +{ + FxMemoryObject* pMemory; + NTSTATUS status; + ULONG length = 0; + DEVPROPTYPE propType; + ULONG requiredLength; + + status = FxDevice::_QueryPropertyEx(DriverGlobals, + DeviceInit, + Device, + PropertyData, + FxPropertyType, + 0, + NULL, + &requiredLength, + &propType); + if (status != STATUS_BUFFER_TOO_SMALL) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not retrieve property, %!STATUS!", + status); + _Analysis_assume_(!NT_SUCCESS(status)); + return status; + } + + *PropertyMemory = NULL; + *PropertyType = 0; + + length = requiredLength; + status = FxMemoryObject::_Create(DriverGlobals, + PropertyMemoryAttributes, + PoolType, + DriverGlobals->Tag, + length, + &pMemory); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate WDFMEMORY, %!STATUS!", status); + return status; + } + + status = FxDevice::_QueryPropertyEx(DriverGlobals, + DeviceInit, + Device, + PropertyData, + FxPropertyType, + length, + pMemory->GetBuffer(), + &requiredLength, + &propType); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not query for full buffer, size %d, for " + "property, %!STATUS!", + length, status); + pMemory->DeleteObject(); + return status; + } + + status = pMemory->Commit(PropertyMemoryAttributes, + (WDFOBJECT*)PropertyMemory); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not commit memory object, %!STATUS!", + status); + pMemory->DeleteObject(); + } + else { + *PropertyMemory = pMemory->GetHandle(); + *PropertyType = propType; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_ValidateOpenKeyParams( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + // + // This function should be called with exactly one valid WDFDEVICE_INIT + // or one valid FxDevice object. Supplying neither or both is an error. + // + if ((DeviceInit == NULL && Device == NULL) || + (DeviceInit != NULL && Device != NULL)) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Device OpenKey/QueryProperty was called with invalid " + "DeviceInit and Device parameters, %!STATUS!", status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/fxdeviceapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxdeviceapi.cpp new file mode 100644 index 00000000000..b057ed4ae38 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdeviceapi.cpp @@ -0,0 +1,2702 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceApi.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "fxiotarget.hpp" + +extern "C" { +#include "FxDeviceApi.tmh" +} + +struct FxOffsetAndName { + __nullterminated PCHAR Name; + UCHAR Offset; +}; + +#define OFFSET_AND_NAME(type, offset) { #offset, FIELD_OFFSET(type, offset) } + +// +// extern "C" the entire file +// +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDRIVER +WDFEXPORT(WdfDeviceGetDriver)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +/*++ + +Routine Description: + + Given a Device Handle, return a Handle to the Driver object + containing this device. + +Arguments: + Device - WDF Device handle. + +Returns: + WDF Driver handle. + +--*/ + +{ + DDI_ENTRY(); + + FxDevice* pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + // + // No need to ref count the driver handle b/c it will be around as long + // as the device handle is. + // + return pDevice->GetDriver()->GetHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFIOTARGET +WDFEXPORT(WdfDeviceGetIoTarget)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + FxIoTarget* pTarget; + FxDeviceBase *pDeviceBase; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*) &pDeviceBase); + + pTarget = pDeviceBase->GetDefaultIoTarget(); + + if (pTarget != NULL) { + return pTarget->GetHandle(); + } + + return NULL; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFIOTARGET +WDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) + +/*++ + +Routine Description: + + Return the handle to the Self IO target for the device. A Self + IO target is only created if the client opted for it by calling + WdfDeviceInitAllowSelfTarget + +Arguments: + + Device - Handle to the Device Object for which Self IO target is needed + +Returns: + + WDFIOTARGET handle to the Self IO Target. NULL is returned in case the + device does not have an Self IO target. + +--*/ + +{ + DDI_ENTRY(); + + FxIoTargetSelf* pTarget; + FxDevice *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + pTarget = pDevice->GetSelfIoTarget(); + + if (pTarget != NULL) { + return pTarget->GetHandle(); + } + + return NULL; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceRetrieveDeviceName)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + WDFSTRING String + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + FxString* pString; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + String, + FX_TYPE_STRING, + (PVOID*) &pString); + + if (pDevice->m_DeviceName.Buffer != NULL) { + status = pString->Assign(&pDevice->m_DeviceName); + } + else { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Device name for WDFDEVICE 0x%p is NULL. Possibly incorrect " + "device handle was passed, %!STATUS!", Device, status); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetCharacteristics)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + ULONG DeviceCharacteristics + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + MxDeviceObject deviceObject; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + deviceObject.SetObject(pDevice->GetDeviceObject()); + deviceObject.SetCharacteristics(DeviceCharacteristics | + FILE_DEVICE_SECURE_OPEN); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfDeviceGetCharacteristics)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + MxDeviceObject deviceObject; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + deviceObject.SetObject(pDevice->GetDeviceObject()); + + return deviceObject.GetCharacteristics(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfDeviceGetAlignmentRequirement)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + FxDeviceBase* pDeviceBase; + MxDeviceObject deviceObject; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*) &pDeviceBase); + + deviceObject.SetObject(pDeviceBase->GetDeviceObject()); + + return deviceObject.GetAlignmentRequirement(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetAlignmentRequirement)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + ULONG AlignmentRequirement + ) +{ + DDI_ENTRY(); + + FxDeviceBase* pDeviceBase; + MxDeviceObject deviceObject; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*) &pDeviceBase); + + deviceObject.SetObject(pDeviceBase->GetDeviceObject()); + + deviceObject.SetAlignmentRequirement(AlignmentRequirement); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDF_DEVICE_PNP_STATE +WDFEXPORT(WdfDeviceGetDevicePnpState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + return pDevice->GetDevicePnpState(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDF_DEVICE_POWER_STATE +WDFEXPORT(WdfDeviceGetDevicePowerState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + return pDevice->GetDevicePowerState(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDF_DEVICE_POWER_POLICY_STATE +WDFEXPORT(WdfDeviceGetDevicePowerPolicyState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + return pDevice->GetDevicePowerPolicyState(); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAssignS0IdleSettings)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDevice* pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Settings); + + if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Device 0x%p is not the power policy owner, caller cannot set S0" + " idle settings %!STATUS!", Device, status); + + return status; + } + + // + // Validate the Settings parameter + // + if (Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS) && + Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9) && + Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Expected Settings Size %d, got %d, %!STATUS!", + sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS), Settings->Size, + status); + return status; + } + else if (Settings->DxState < PowerDeviceD1 || + Settings->DxState > PowerDeviceMaximum || + Settings->IdleCaps < IdleCannotWakeFromS0 || + Settings->IdleCaps > IdleUsbSelectiveSuspend || + Settings->UserControlOfIdleSettings < IdleDoNotAllowUserControl || + Settings->UserControlOfIdleSettings > IdleAllowUserControl || + Settings->Enabled < WdfFalse || + Settings->Enabled > WdfUseDefault) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "a field (DxState, IdleCaps, Enabled, or UserControlOfIdleSettings)" + " is out range, %!STATUS!", status); + return status; + } + + // + // PowerUpIdleDeviceOnSystemWake is available only on > 1.7 and can be set to true + // only when IdleCaps is IdleCannotWakeFromS0 + // + if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) { + if (Settings->PowerUpIdleDeviceOnSystemWake < WdfFalse || + Settings->PowerUpIdleDeviceOnSystemWake > WdfUseDefault) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "value of field PowerUpIdleDeviceOnSystemWake is out of range," + " %!STATUS!", status); + return status; + } + else if (Settings->IdleCaps != IdleCannotWakeFromS0 && + Settings->PowerUpIdleDeviceOnSystemWake != WdfUseDefault) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "value of field PowerUpIdleDeviceOnSystemWake should be set only when" + " IdleCaps is IdleCannotWakeFromS0, %!STATUS!", status); + return status; + } + } + + // + // IdleTimeoutType is available only on > 1.9 + // + if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) { + if (Settings->IdleTimeoutType > SystemManagedIdleTimeoutWithHint) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p, value of field IdleTimeoutType is out of range," + " %!STATUS!", Device, status); + return status; + } + } + + return pDevice->m_PkgPnp->PowerPolicySetS0IdleSettings(Settings); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAssignSxWakeSettings)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + FxDevice* pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + BOOLEAN armForWakeIfChildrenAreArmedForWake; + BOOLEAN indicateChildWakeOnParentWake; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Settings); + + if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Device 0x%p is not the power policy owner, caller cannot set Sx" + " wake settings %!STATUS!", Device, status); + + return status; + } + + // + // Validate the Settings parameter + // + if (Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS) && + Settings->Size != sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Expected Settings Size %x, got %x, %!STATUS!", + sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS), + Settings->Size, + status); + return status; + } + else if (Settings->DxState < PowerDeviceD1 || + Settings->DxState > PowerDeviceMaximum || + Settings->UserControlOfWakeSettings < WakeDoNotAllowUserControl || + Settings->UserControlOfWakeSettings > WakeAllowUserControl || + Settings->Enabled < WdfFalse || + Settings->Enabled > WdfUseDefault) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "a field (DxState, Enabled, or UserControlOfIdleSettings) is out " + "range, %!STATUS!", status); + return status; + } + + // + // Extract the values from the structure for all the parameters that were + // added after v1.5. Since the size of the structure can only grow, get + // the values only if we are using a version of the struct after v1.5 + // + + // + // ArmForWakeIfChildrenAreArmedForWake added after v1.5 + // + armForWakeIfChildrenAreArmedForWake = + (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5)) ? + Settings->ArmForWakeIfChildrenAreArmedForWake : + FALSE; + + // + // IndicateChildWakeOnParentWake added after v1.5 + // + indicateChildWakeOnParentWake = + (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V1_5)) ? + Settings->IndicateChildWakeOnParentWake : + FALSE; + + return pDevice->m_PkgPnp->PowerPolicySetSxWakeSettings( + Settings, + armForWakeIfChildrenAreArmedForWake, + indicateChildWakeOnParentWake); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceOpenRegistryKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + ULONG DeviceInstanceKeyType, + __in + ACCESS_MASK DesiredAccess, + __in_opt + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + __out + WDFKEY* Key + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + FxDevice* pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + + return status; + } + + return FxDevice::_OpenKey(pDevice->GetDriverGlobals(), + NULL, + pDevice, + DeviceInstanceKeyType, + DesiredAccess, + KeyAttributes, + Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceOpenDevicemapKey) ( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + FxDevice* pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey = NULL; + WDFKEY keyHandle; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + + status = FxValidateUnicodeString(pFxDriverGlobals, KeyName); + if (!NT_SUCCESS(status)) { + return status; + } + + if (KeyName->Length == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "The subkey cannot be of length zero, %!STATUS!", status); + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + pKey = new(pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals); + + if (pKey == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Unable to allocate memory for WDFKEY object, %!STATUS!", status); + return status; + } + + pKey->SetDeviceBase(pDevice); + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + if (NT_SUCCESS(status)) { + + status = pDevice->OpenDevicemapKeyWorker(pFxDriverGlobals, + KeyName, + DesiredAccess, + pKey); + if (NT_SUCCESS(status)) { + *Key = keyHandle; + } + } + + if (!NT_SUCCESS(status)) { + pKey->DeleteFromFailedCreate(); + pKey = NULL; + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceGetDeviceState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __out + PWDF_DEVICE_STATE DeviceState + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceState); + + if (DeviceState->Size != sizeof(WDF_DEVICE_STATE)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p DeviceState Size %d, expected %d", + Device, DeviceState->Size, sizeof(WDF_DEVICE_STATE)); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INFO_LENGTH_MISMATCH; + } + + pDevice->m_PkgPnp->GetPnpState(DeviceState); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetDeviceState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_DEVICE_STATE DeviceState + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + ULONG i; + + const static FxOffsetAndName offsets[] = { + OFFSET_AND_NAME(WDF_DEVICE_STATE, Disabled), + OFFSET_AND_NAME(WDF_DEVICE_STATE, DontDisplayInUI), + OFFSET_AND_NAME(WDF_DEVICE_STATE, Failed), + OFFSET_AND_NAME(WDF_DEVICE_STATE, NotDisableable), + OFFSET_AND_NAME(WDF_DEVICE_STATE, Removed), + OFFSET_AND_NAME(WDF_DEVICE_STATE, ResourcesChanged), + }; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceState); + + if (DeviceState->Size != sizeof(WDF_DEVICE_STATE)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p, DeviceState Size %d, expected %d", + Device, DeviceState->Size, sizeof(WDF_DEVICE_STATE)); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; // STATUS_INFO_LENGTH_MISMATCH; + } + + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + WDF_TRI_STATE value; + + // + // This check makes prefast happy + // + if (offsets[i].Offset + sizeof(WDF_TRI_STATE) > sizeof(*DeviceState)) { + return; + } + + value = *(WDF_TRI_STATE*) WDF_PTR_ADD_OFFSET(DeviceState, + offsets[i].Offset); + + switch (value) { + case WdfFalse: + case WdfTrue: + case WdfUseDefault: + break; + + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p DeviceState WDF_TRI_STATE %s value out of range, " + "value is %d", Device, offsets[i].Name, value); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER + } + } + + pDevice->m_PkgPnp->SetPnpState(DeviceState); + + pDevice->InvalidateDeviceState(); +} + + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + + + __inout + + PWDFDEVICE_INIT* DeviceInit, + __in_opt + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + __out + WDFDEVICE* Device + ) +{ + DDI_ENTRY(); + + FxDevice* pDevice; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceInit); + FxPointerNotNull(pFxDriverGlobals, *DeviceInit); + FxPointerNotNull(pFxDriverGlobals, Device); + + // + // Use the object's globals, not the caller's globals + // + pFxDriverGlobals = (*DeviceInit)->DriverGlobals; + + *Device = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Make sure the device attributes is initialized properly if passed in + // + status = FxValidateObjectAttributes(pFxDriverGlobals, + DeviceAttributes, + (FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED | + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | + FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED)); + + if (!NT_SUCCESS(status)) { + return status; + } + + if ((*DeviceInit)->CreatedDevice != NULL) { + // + // Already created the device! + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p already created" + "STATUS_INVALID_DEVICE_STATE", + Device); + + return STATUS_INVALID_DEVICE_STATE; + } + + // + // If security is specified, then the device being created *must* have a + // name to apply that security too. + // + if ((*DeviceInit)->Security.Sddl != NULL || (*DeviceInit)->Security.DeviceClassSet) { + if ((*DeviceInit)->HasName()) { + // + // Driver writer specified a name, all is good + // + DO_NOTHING(); + } + else { + status = STATUS_INVALID_SECURITY_DESCR; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Device init: has device class or SDDL set, but does not have " + "a name, %!STATUS!", status); + + return status; + } + } + + if ((*DeviceInit)->RequiresSelfIoTarget) { + if ((*DeviceInit)->InitType != FxDeviceInitTypeFdo) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Client called WdfDeviceInitAllowSelfTarget. Self " + "IO Targets are supported only for FDOs, %!STATUS!", status); + return status; + } + } + + status = FxDevice::_Create(pFxDriverGlobals, + DeviceInit, + DeviceAttributes, + &pDevice); + if (NT_SUCCESS(status)) { + *Device = pDevice->GetHandle(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceCreateSymbolicLink)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PCUNICODE_STRING SymbolicLinkName + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PUNICODE_STRING pName; + FxAutoString pdoName; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + pName = NULL; + + FxPointerNotNull(pFxDriverGlobals, SymbolicLinkName); + + if (SymbolicLinkName->Length == 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p, SymbolicLinkName has no length, %!STATUS!", + Device, status); + + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, SymbolicLinkName); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pDevice->m_SymbolicLinkName.Buffer != NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p already has a symbolic link associated with it, %!STATUS!", + Device, status); + + return status; + } + + status = pDevice->CreateSymbolicLink(pFxDriverGlobals, SymbolicLinkName); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceQueryProperty)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + DEVICE_REGISTRY_PROPERTY DeviceProperty, + __in + ULONG BufferLength, + __out_bcount_full(BufferLength) + PVOID PropertyBuffer, + __out + PULONG ResultLength + ) +/*++ + +Routine Description: + Retrieves the requested device property for the given device + +Arguments: + Device - the device whose PDO whose will be queried + + DeviceProperty - the property being queried + + BufferLength - length of PropertyBuffer in bytes + + PropertyBuffer - Buffer which will receive the property being queried + + ResultLength - if STATUS_BUFFER_TOO_SMALL is returned, then this will contain + the required length + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ResultLength); + if (BufferLength > 0) { + FxPointerNotNull(pFxDriverGlobals, PropertyBuffer); + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pDevice->IsLegacy()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p is not a PnP device %!STATUS!", + Device, status); + + return status; + } + + status = FxDevice::_QueryProperty(pFxDriverGlobals, + NULL, + pDevice, + NULL, + DeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE, + "exit WDFDEVICE %p, Property %d, %!STATUS!", + Device, DeviceProperty, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryProperty)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + DEVICE_REGISTRY_PROPERTY DeviceProperty, + __in + __drv_strictTypeMatch(__drv_typeExpr) + POOL_TYPE PoolType, + __in_opt + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + __out + WDFMEMORY* PropertyMemory + ) +/*++ + +Routine Description: + Allocates and retrieves the requested device property for the given device + +Arguments: + Device - the pnp device whose PDO whose will be queried + + DeviceProperty - the property being queried + + PoolType - what type of pool to allocate + + PropertyMemoryAttributes - attributes to associate with PropertyMemory + + PropertyMemory - handle which will receive the property buffer + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PropertyMemory); + + *PropertyMemory = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag); + + status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pDevice->IsLegacy()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not a PnP device, %!STATUS!", + Device, status); + + return status; + } + + status = FxDevice::_AllocAndQueryProperty(pFxDriverGlobals, + NULL, + pDevice, + NULL, + DeviceProperty, + PoolType, + PropertyMemoryAttributes, + PropertyMemory); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE, + "exit WDFDEVICE %p, Property %d, %!STATUS!", + Device, DeviceProperty, status); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetStaticStopRemove)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + BOOLEAN Stoppable + ) +{ + DDI_ENTRY(); + + FxDevice *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + if (Stoppable) { + // + // Stoppable means that query stop / query remove can succeed. + // This means m_DeviceStopCount == 0 (eventually if there are nested + // calls to this function). + // + ASSERT(pDevice->m_PkgPnp->m_DeviceStopCount > 0); + InterlockedDecrement((PLONG) &pDevice->m_PkgPnp->m_DeviceStopCount); + } + else { + InterlockedIncrement((PLONG) &pDevice->m_PkgPnp->m_DeviceStopCount); + } + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetFailed)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + WDF_DEVICE_FAILED_ACTION FailedAction + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + if (FailedAction < WdfDeviceFailedAttemptRestart || + FailedAction > WdfDeviceFailedNoRestart) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid FailedAction %d", FailedAction); + FxVerifierDbgBreakPoint(pDevice->GetDriverGlobals()); + return; + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDEVICE, + "WDFDEVICE %p, !devobj %p SetFailed %!WDF_DEVICE_FAILED_ACTION!", + Device, pDevice->GetDeviceObject(), FailedAction); + + pDevice->m_PkgPnp->SetDeviceFailed(FailedAction); +} + +__inline +NTSTATUS +StopIdleWorker( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + BOOLEAN WaitForD0, + __in + PVOID Tag, + __in + LONG Line, + __in + PSTR File + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDevice *pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + if (WaitForD0) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + } + + + if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p WdfDeviceStopIdle does nothing if you are not the power " + "policy owner for the stack, %!STATUS!", Device, status); + return status; + } + + status = pDevice->m_PkgPnp->PowerReference(WaitForD0, Tag, Line, File); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE, + "WDFDEVICE %p WdfDeviceStopIdle, WaitForD0 %d %!STATUS!", + Device, WaitForD0, status); + + return status; +} + +__inline +VOID +ResumeIdleWorker( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PVOID Tag, + __in + LONG Line, + __in + PSTR File + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WdfDeviceResumeIdle does nothing if you are not the power " + "policy owner for the stack"); + return; + } + + pDevice->m_PkgPnp->PowerDereference(Tag, Line, File); +} + +_Must_inspect_result_ +__drv_when(WaitForD0 == 0, __drv_maxIRQL(DISPATCH_LEVEL)) +__drv_when(WaitForD0 != 0, __drv_maxIRQL(PASSIVE_LEVEL)) +NTSTATUS +WDFEXPORT(WdfDeviceStopIdleNoTrack)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + BOOLEAN WaitForD0 + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + + status = StopIdleWorker(DriverGlobals, + Device, + WaitForD0, + NULL, + 0, + NULL); + + return status; +} + +_Must_inspect_result_ +__drv_when(WaitForD0 == 0, __drv_maxIRQL(DISPATCH_LEVEL)) +__drv_when(WaitForD0 != 0, __drv_maxIRQL(PASSIVE_LEVEL)) +NTSTATUS +WDFEXPORT(WdfDeviceStopIdleActual)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + BOOLEAN WaitForD0, + __in_opt + PVOID Tag, + __in + LONG Line, + __in + PSTR File + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + + status = StopIdleWorker(DriverGlobals, + Device, + WaitForD0, + Tag, + Line, + File); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceResumeIdleNoTrack)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + DDI_ENTRY(); + + ResumeIdleWorker(DriverGlobals, + Device, + NULL, + 0, + NULL); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceResumeIdleActual)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in_opt + PVOID Tag, + __in + LONG Line, + __in + PSTR File + ) +{ + DDI_ENTRY(); + + ResumeIdleWorker(DriverGlobals, + Device, + Tag, + Line, + File); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetPnpCapabilities)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ) +/*++ + +Routine Description: + Sets the pnp capabilities of the device. This function is usually called + during AddDevice or EvtDevicePrepareHardware since these values are queried + by the stack and pnp during start device processing or immediately afterwards. + +Arguments: + Device - Device being set + + PnpCapabilities - Caps being set + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + ULONG i; + + const static FxOffsetAndName offsets[] = { + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, LockSupported), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, EjectSupported), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, Removable), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, DockDevice), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, UniqueID), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, SilentInstall), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, SurpriseRemovalOK), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, HardwareDisabled), + OFFSET_AND_NAME(WDF_DEVICE_PNP_CAPABILITIES, NoDisplayInUI), + }; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PnpCapabilities); + + if (PnpCapabilities->Size != sizeof(WDF_DEVICE_PNP_CAPABILITIES)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PnpCapabilities Size %d, expected %d", + Device, PnpCapabilities->Size, sizeof(WDF_DEVICE_PNP_CAPABILITIES)); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INFO_LENGTH_MISMATCH; + } + else { + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + WDF_TRI_STATE value; + + // + // This check makes prefast happy + // + if (offsets[i].Offset + sizeof(WDF_TRI_STATE) > + sizeof(*PnpCapabilities)) { + return; + } + + value = *(WDF_TRI_STATE*) WDF_PTR_ADD_OFFSET(PnpCapabilities, + offsets[i].Offset); + switch (value) { + case WdfFalse: + case WdfTrue: + case WdfUseDefault: + break; + + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PnpCapabilities WDF_TRI_STATE %s value out " + "of range, value is %d", Device, offsets[i].Name, value); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER + } + } + } + + pDevice->m_PkgPnp->SetPnpCaps(PnpCapabilities); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetPowerCapabilities)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ) +/*++ + +Routine Description: + Sets the power capabilities of the device. This function is usually called + during AddDevice or EvtDevicePrepareHardware since these values are queried + by the stack and power during start device processing or immediately afterwards. + +Arguments: + Device - Device being set + + PowerCapabilities - Caps being set + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + FxDevice* pDevice; + ULONG i; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + const static FxOffsetAndName offsets[] = { + OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, DeviceD1), + OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, DeviceD2), + OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD0), + OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD1), + OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD2), + OFFSET_AND_NAME(WDF_DEVICE_POWER_CAPABILITIES, WakeFromD3), + }; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PowerCapabilities); + + if (PowerCapabilities->Size != sizeof(WDF_DEVICE_POWER_CAPABILITIES)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities Size %d, expected %d", + Device, PowerCapabilities->Size, + sizeof(WDF_DEVICE_POWER_CAPABILITIES)); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INFO_LENGTH_MISMATCH; + } + else { + for (i = 0; i < ARRAY_SIZE(offsets); i++) { + WDF_TRI_STATE value; + + // + // This check makes prefast happy + // + if (offsets[i].Offset + sizeof(WDF_TRI_STATE) > + sizeof(*PowerCapabilities)) { + return; + } + + value = *(WDF_TRI_STATE*) WDF_PTR_ADD_OFFSET(PowerCapabilities, + offsets[i].Offset); + switch (value) { + case WdfFalse: + case WdfTrue: + case WdfUseDefault: + break; + + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities WDF_TRI_STATE %s value out " + "of range, value is %d", + Device, offsets[i].Name, value); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER + } + } + + for (i = 0; i < ARRAY_SIZE(PowerCapabilities->DeviceState); i++) { + if (PowerCapabilities->DeviceState[i] < PowerDeviceUnspecified || + PowerCapabilities->DeviceState[i] > PowerDeviceMaximum) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities DeviceState is invalid", + Device); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER; + } + } + + if (PowerCapabilities->DeviceWake < PowerDeviceUnspecified || + PowerCapabilities->DeviceWake > PowerDeviceMaximum) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities DeviceWake %d is out of range", + Device, PowerCapabilities->DeviceWake); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER; + } + + if (PowerCapabilities->SystemWake < PowerSystemUnspecified || + PowerCapabilities->SystemWake > PowerSystemMaximum) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities SystemWake %d is out of range", + Device, PowerCapabilities->SystemWake); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER; + } + + if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE && + PowerCapabilities->IdealDxStateForSx != PowerDeviceMaximum) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities IdealDxStateForSx %d can only" + " be set by the power policy owner", + Device, PowerCapabilities->IdealDxStateForSx); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER; + } + + // + // D0 is not allowed as an ideal Dx state + // + if (PowerCapabilities->IdealDxStateForSx < PowerDeviceD1 || + PowerCapabilities->IdealDxStateForSx > PowerDeviceMaximum) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p PowerCapabilities IdealDxStateForSx %d is out " + "of range", Device, PowerCapabilities->IdealDxStateForSx); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; // STATUS_INVALID_PARAMETER; + } + } + + + pDevice->m_PkgPnp->SetPowerCaps(PowerCapabilities); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceConfigureRequestDispatching)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + WDFQUEUE Queue, + __in + __drv_strictTypeMatch(__drv_typeCond) + WDF_REQUEST_TYPE RequestType + ) + +/*++ + +Routine Description: + + Configure which IRP_MJ_* requests are automatically + forwarded by the I/O package to the specified Queue. + + By default the I/O package sends all requests to the + devices default queue. This API allows certain requests + to be specified to their own queues under driver control. + +Arguments: + + Device - The device which is handling the IO. + + Queue - I/O Queue object to forward specified request to. + + RequestType - WDF Request type to be forwarded to the queue + +Returns: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDevice* pDevice; + FxIoQueue* pFxIoQueue; + + pDevice = NULL; + pFxIoQueue = NULL; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + if (RequestType != WdfRequestTypeCreate && + RequestType != WdfRequestTypeRead && + RequestType != WdfRequestTypeWrite && + RequestType != WdfRequestTypeDeviceControl && + RequestType != WdfRequestTypeDeviceControlInternal) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Invalid RequestType %!WDF_REQUEST_TYPE!, %!STATUS!", + RequestType, status); + return status; + } + + // + // Validate the Queue handle + // + FxObjectHandleGetPtr(pFxDriverGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pFxIoQueue); + + if (pDevice != pFxIoQueue->GetDevice()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Input WDFQUEUE 0x%p doesn't belong to the WDFDEVICE 0x%p, %!STATUS!", + Queue, Device, status); + + return status; + } + + if (pDevice->IsLegacy()) { + // + // This is a controldevice. Make sure the create is called after the device + // is initialized and ready to accept I/O. + // + MxDeviceObject deviceObject(pDevice->GetDeviceObject()); + if ((deviceObject.GetFlags() & DO_DEVICE_INITIALIZING) == 0x0) { + + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Queue cannot be configured for automatic dispatching" + " after WdfControlDeviceFinishInitializing" + "is called on the WDFDEVICE %p is called %!STATUS!", + Device, + status); + return status; + } + } + else { + // + // This is either FDO or PDO. Make sure it's not started yet. + // + if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Queue cannot be configured for automatic dispatching" + "after the WDFDEVICE %p is started, %!STATUS!", + Device, status); + return status; + } + } + + if (RequestType == WdfRequestTypeCreate) { + status = pDevice->m_PkgGeneral->ConfigureForwarding(pFxIoQueue); + } + else { + status = pDevice->m_PkgIo->ConfigureForwarding(pFxIoQueue, RequestType); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFQUEUE +WDFEXPORT(WdfDeviceGetDefaultQueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) + +/*++ + +Routine Description: + + Return the handle to the default queue for the device. + +Arguments: + + Device - Handle to the Device Object + +Returns: + + WDFQUEUE + +--*/ + +{ + DDI_ENTRY(); + + FxPkgIo* pPkgIo;; + FxIoQueue* pFxIoQueue;; + FxDevice * pFxDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pPkgIo = NULL; + pFxIoQueue = NULL; + + // + // Validate the I/O Package handle, and get the FxPkgIo* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pFxDevice, + &pFxDriverGlobals); + + pPkgIo = (FxPkgIo *) pFxDevice->m_PkgIo; + pFxIoQueue = pPkgIo->GetDefaultQueue(); + + // + // A default queue is optional + // + if (pFxIoQueue == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO, + "No default Queue configured " + "for Device 0x%p", Device); + return NULL; + } + + return (WDFQUEUE)pFxIoQueue->GetObjectHandle();; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceEnqueueRequest)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Inserts a request into the I/O Package processing pipeline. + + The given request is processed by the I/O package, forwarding + it to its configured destination or the default queue. + + If an EvtIoInCallerContext is callback is registered, it is not called. + +Arguments: + + Device - Handle to the Device Object + + Request - Request to insert in the processing pipeline + +Return Value: + + STATUS_SUCCESS - Request has been inserted into the I/O processing pipeline + + !NT_SUCCESS(status) + STATUS_WDF_BUSY - Device is not accepting requests, the driver still owns the + the request and must complete it, or correct the conditions. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + FxRequest* pRequest; + + // + // Validate the device object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + // + // Validate Device object handle + // + FxObjectHandleGetPtr(pFxDriverGlobals, + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice); + + // + // Validate the request object handle + // + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID *) &pRequest); + + // + // Dispatch it to the Io Package object + // + return pDevice->m_PkgIo->EnqueueRequest(pDevice, pRequest); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +POWER_ACTION +WDFEXPORT(WdfDeviceGetSystemPowerAction)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) + +/*++ + +Routine Description: + + This DDI returns the System power action. + + If the DDI is called in the power down path of a device, it will return the + current system power transition type because of which the device is powering + down. If the DDI is called in the power up path of a device, it will return + the system power transition type which initially put the device into a lower + power state. If the DDI is called during the normal functioning of a device + that is not undergoing a power state transition, or if the device is powering + up as part of the system start up, the DDI will return the PowerActionNone + value. + +Arguments: + + Device - Handle to the Device Object + +Return Value: + + Returns a POWER_ACTION enum value that represents the current system power + action with regards to any system power transition underway. + +--*/ + +{ + DDI_ENTRY(); + + FxDevice *pDevice; + + // + // Validate Device object handle + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + return pDevice->m_PkgPnp->GetSystemPowerAction(); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ) +/*++ + +Routine Description: + + This routine queries interface property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + DeviceProperty - A pointer to WDF_DEVICE_PROPERTY_ DATA structure. + + BufferLength - The size, in bytes, of the buffer that is pointed to by + PropertyBuffer. + + PropertyBuffer - A caller-supplied pointer to a caller-allocated buffer that + receives the requested information. The pointer can be NULL + if the BufferLength parameter is zero. + + ResultLength - A caller-supplied location that, on return, contains the + size, in bytes, of the information that the method stored in + PropertyBuffer. If the function's return value is + STATUS_BUFFER_TOO_SMALL, this location receives the required + buffer size. + + Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves + the property data, the routine writes the property type value + to this variable. This value indicates the type of property + data that is in the Data buffer. + +Return Value: + + Method returns an NTSTATUS value. This routine might return one of the + following values. + + STATUS_BUFFER_TOO_SMALL - The supplied buffer is too small to receive the + information. The ResultLength member receives the + size of buffer required. + STATUS_SUCCESS - The operation succeeded. + STATUS_INVALID_PARAMETER - One of the parameters is incorrect. + + The method might return other NTSTATUS values. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceProperty); + + // + // Validate PropertyData + // + if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "PropertyData size (%d) incorrect, expected %d, %!STATUS!", + DeviceProperty->Size, + sizeof(WDF_DEVICE_PROPERTY_DATA), status); + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, APC_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + FxPointerNotNull(pFxDriverGlobals, RequiredSize); + FxPointerNotNull(pFxDriverGlobals, Type); + + if (BufferLength != 0 && PropertyBuffer == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Property buffer size is non-zero, while the buffer is NULL" + ", %!STATUS!", status); + return status; + } + + if (BufferLength == 0 && PropertyBuffer != NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Property buffer size is zero, while the buffer is non-NULL" + ", %!STATUS!", status); + return status; + } + + status = FxDevice::_QueryPropertyEx(pFxDriverGlobals, + NULL, + pDevice, + DeviceProperty, + FxDeviceProperty, + BufferLength, + PropertyBuffer, + RequiredSize, + Type); + return status; +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +/*++ + +Routine Description: + + This routine queries device property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PropertyData - A pointer to WDF_DEVICE_PROPERTY_ DATA structure. + + PoolType - A POOL_TYPE-typed enumerator that specifies the type of memory + to be allocated. + + PropertyMemoryAttributes - optional, A pointer to a caller-allocated + WDF_OBJECT_ATTRIBUTES structure that describes object attributes + for the memory object that the function will allocate. This + parameter is optional and can be WDF_NO_OBJECT_ATTRIBUTES. + + PropertyMemory - A pointer to a WDFMEMORY-typed location that receives a + handle to a framework memory object. + + Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves + the property data, the routine writes the property type value to + this variable. This value indicates the type of property data + that is in the Data buffer. + +Return Value: + + Method returns an NTSTATUS value. This routine might return one of the + following values. It might return other NTSTATUS-codes as well. + + STATUS_SUCCESS The operation succeeded. + STATUS_INVALID_PARAMETER One of the parameters is incorrect. + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceProperty); + + // + // Validate PropertyData + // + if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "PropertyData size (%d) incorrect, expected %d, %!STATUS!", + DeviceProperty->Size, + sizeof(WDF_DEVICE_PROPERTY_DATA), status); + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, APC_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag); + + FxPointerNotNull(pFxDriverGlobals, PropertyMemory); + FxPointerNotNull(pFxDriverGlobals, Type); + + *PropertyMemory = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxDevice::_AllocAndQueryPropertyEx(pFxDriverGlobals, + NULL, + pDevice, + DeviceProperty, + FxDeviceProperty, + PoolType, + PropertyMemoryAttributes, + PropertyMemory, + Type); + return status; +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG BufferLength, + _In_opt_ + PVOID PropertyBuffer + ) +/*++ + +Routine Description: + + This routine assigns interface property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PropertyData - A pointer to WDF_DEVICE_PROPERTY_ DATA structure. + + Type - Set this parameter to the DEVPROPTYPE value that specifies the type + of the data that is supplied in the Data buffer. + + BufferLength - Specifies the length, in bytes, of the buffer that + PropertyBuffer points to. + + PropertyBuffer - optional, A pointer to the device interface property data. + Set this parameter to NULL to delete the specified property. + +Return Value: + + Mthod returns an NTSTATUS value. This routine might return one of the + following values. It might return other NTSTATUS-codes as well. + + STATUS_SUCCESS - The operation succeeded. + STATUS_INVALID_PARAMETER - One of the parameters is incorrect. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + NTSTATUS status; + + // + // 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, DeviceProperty); + + // + // Validate PropertyData + // + if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "PropertyData size (%d) incorrect, expected %d, %!STATUS!", + DeviceProperty->Size, + sizeof(WDF_DEVICE_PROPERTY_DATA), status); + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, APC_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (BufferLength == 0 && PropertyBuffer != NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Property buffer size is zero, while the buffer is non-NULL" + ", %!STATUS!", status); + return status; + } + + status = pDevice->AssignProperty(DeviceProperty, + FxDeviceProperty, + Type, + BufferLength, + PropertyBuffer + ); + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch, + _In_opt_ + WDFCONTEXT DriverContext + ) + +/*++ + + Routine Description: + + Configure callbacks for IRP_MJ_READ, IRP_MJ_WRITE, IRP_MJ_DEVICE_CONTROL, and + IRP_MJ_INTERNAL_DEVICE_CONTROL (KMDF only). By default the I/O package sends all requests to + a device's default queue, or to the queues configured with + WdfDeviceConfigureRequestDisaptching. This DDI allows a driver specified + callback to select a different queue dynamically during runtime. + + Arguments: + + Device - The device which is handling the I/O. + + Driver - An optional driver handle. Used to associate the + callback with a specific class extension. + + MajorFunction - IRP major function type to be forwarded to the callback + + EvtDeviceWdmIrpDispatch - Callback invoked when encountering the given major function. + + DriverContext - An optional untyped driver specified context. + + Returns: + + STATUS_SUCCESS on success + STATUS_INVALID_PARAMETER if an incorrect MajorFunction was provided + STATUS_INSUFFICIENT_RESOURCES if insufficient memory was available + STATUS_INVALID_DEVICE_STATE if this DDI was called at an improper time + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDevice* pDevice; + FxCxDeviceInfo* pCxDeviceInfo; + ULONG deviceFlags; + + pDevice = NULL; + pCxDeviceInfo = NULL; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + // + // Validate the MajorFunction provided. Note that + // IRP_MJ_INTERNAL_DEVICE_CONTROL is KMDF only. + // + switch (MajorFunction) { + case IRP_MJ_WRITE: + case IRP_MJ_READ: + case IRP_MJ_DEVICE_CONTROL: +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + case IRP_MJ_INTERNAL_DEVICE_CONTROL: +#endif + break; + default: + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid MajorFunction provided %!IRPMJ!, %!STATUS!", + MajorFunction, status); + goto exit; + } + + // + // Validate the driver handle and get (if present) the associated cx info. + // + if (Driver != NULL) { + FxDriver* pDriver; + + FxObjectHandleGetPtr(pFxDriverGlobals, + Driver, + FX_TYPE_DRIVER, + (PVOID*)&pDriver); + + // + // Find the driver's cx info if it's not the main driver for this device. + // cx struct info can be NULL if cx acts as client driver. + // + pCxDeviceInfo = pDevice->GetCxDeviceInfo(pDriver); + } + + // + // Make sure callback is not null. + // + FxPointerNotNull(pFxDriverGlobals, EvtDeviceWdmIrpDispatch); + + // + // This callback can only be called during initialization. + // + if (pDevice->IsLegacy()) { + + // + // Extract the device flags from the device object + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + deviceFlags = pDevice->GetDeviceObject()->Flags; +#else + deviceFlags = pDevice->GetDeviceObject()->GetDeviceObjectWdmFlags(); +#endif + + // + // This is a controldevice. Make sure the create is called after the device + // is initialized and ready to accept I/O. + // + if ((deviceFlags & DO_DEVICE_INITIALIZING) == 0x0) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot set IRP dispatch callback " + "after WdfControlDeviceFinishInitializing " + "is called on the WDFDEVICE %p, %!STATUS!", + pDevice, status); + goto exit; + } + } else { + // + // This is either FDO or PDO. Make sure it's not started yet. + // + if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot set IRP dispatch callback " + "after the WDFDEVICE %p is started, %!STATUS!", + pDevice, status); + goto exit; + } + } + + // + // Let I/O package do the rest. + // + status = pDevice->m_PkgIo->ConfigureDynamicDispatching(MajorFunction, + pCxDeviceInfo, + EvtDeviceWdmIrpDispatch, + DriverContext); +exit: + return status; +} + +_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; + UCHAR majorFunction, minorFunction; + FxIrp fxIrp(Irp); + + PAGED_CODE_LOCKED(); + + majorFunction = fxIrp.GetMajorFunction(); + minorFunction = fxIrp.GetMinorFunction(); + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ!, IRP_MN %x, IRP 0x%p", + device->GetHandle(), device->GetDeviceObject(), + majorFunction, minorFunction, Irp); + + // + // Validate Flags. For UMDF, this field is reserved and must be zero. + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (Flags & ~FX_DISPATCH_IRP_TO_IO_QUEUE_FLAGS_MASK) { +#else + if (Flags != WDF_DISPATCH_IRP_TO_IO_QUEUE_NO_FLAGS) { +#endif + 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(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, majorFunction, minorFunction, + device->GetObjectHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + // + // Make sure queue can handle the request. + // + if (FALSE == queue->IsIoEventHandlerRegistered( + (WDF_REQUEST_TYPE)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, majorFunction, 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; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxdevicebase.cpp b/sdk/lib/drivers/wdf/shared/core/fxdevicebase.cpp new file mode 100644 index 00000000000..63327fd6888 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdevicebase.cpp @@ -0,0 +1,417 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceBase.cpp + +Abstract: + + This is the class implementation for the base device class. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceBase.tmh" +} + +FxDeviceBase::FxDeviceBase( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxDriver* Driver, + __in WDFTYPE Type, + __in USHORT Size + ) : + FxNonPagedObject(Type, Size, FxDriverGlobals) +{ + m_Driver = Driver; + + m_CallbackLockPtr = NULL; + m_CallbackLockObjectPtr = NULL; + + m_DisposeList = NULL; + + m_DmaPacketTransactionStatus = FxDmaPacketTransactionCompleted; + + m_ExecutionLevel = WdfExecutionLevelInheritFromParent; + m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent; + + MarkPassiveDispose(ObjectDoNotLock); + SetDeviceBase(this); +} + +FxDeviceBase::~FxDeviceBase( + VOID + ) +{ + if (m_DisposeList != NULL) { + m_DisposeList->DeleteObject(); + m_DisposeList = NULL; + } + + if (m_CallbackLockPtr != NULL) { + delete m_CallbackLockPtr; + m_CallbackLockPtr = NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceBase::QueryInterface( + __inout FxQueryInterfaceParams* Params + ) +{ + switch (Params->Type) { + case FX_TYPE_DEVICE_BASE: + *Params->Object = this; + break; + + case FX_TYPE_IHASCALLBACKS: + *Params->Object = (IFxHasCallbacks*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; +} + +NTSTATUS +FxDeviceBase::ConfigureConstraints( + __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes + ) +{ + NTSTATUS status; + WDF_EXECUTION_LEVEL driverLevel; + WDF_SYNCHRONIZATION_SCOPE driverScope; + + ASSERT(m_Driver != NULL); + + // + // If WDF_OBJECT_ATTRIBUTES is specified, these override any + // default settings. + // + if (ObjectAttributes != NULL) { + m_ExecutionLevel = ObjectAttributes->ExecutionLevel; + m_SynchronizationScope = ObjectAttributes->SynchronizationScope; + } + + // + // If no WDFDEVICE specific attributes are specified, we + // get them from WDFDRIVER, which allows WDFDRIVER to + // provide a default for all WDFDEVICE's created. + // + m_Driver->GetConstraints(&driverLevel, &driverScope); + + if (m_ExecutionLevel == WdfExecutionLevelInheritFromParent) { + m_ExecutionLevel = driverLevel; + } + + if (m_SynchronizationScope == WdfSynchronizationScopeInheritFromParent) { + m_SynchronizationScope = driverScope; + } + + // + // Configure The Execution Level Constraint + // + if (m_ExecutionLevel == WdfExecutionLevelPassive) { + m_CallbackLockPtr = new(GetDriverGlobals()) + FxCallbackMutexLock(GetDriverGlobals()); + // + // Currently, all event callbacks from FxDevice into the driver + // are from PASSIVE_LEVEL threads, and there is no need to defer + // to a system workitem like IoQueue. So we don't allocate and + // setup an FxSystemWorkItem here. + // + // If the FxDevice starts raising events to the device driver + // whose thread starts out above PASSIVE_LEVEL, then an FxSystemWorkItem + // would need to be allocated when WdfExecutionLevelPassive is specified. + // + // (FDO and PDO variants of FxDevice may own their own event dispatch + // and deferral logic separate from FxDevice.) + // + } + else { + m_CallbackLockPtr = new(GetDriverGlobals()) + FxCallbackSpinLock(GetDriverGlobals()); + } + + // + // Finish initializing the spin/mutex lock. + // + if (NULL == m_CallbackLockPtr) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT, + "WDFDEVICE %p, could not allocate callback lock, %!STATUS!", + GetHandle(), status); + goto Done; + } + + m_CallbackLockPtr->Initialize(this); + m_CallbackLockObjectPtr = this; + + status = STATUS_SUCCESS; + +Done: + return status; +} + +VOID +FxDeviceBase::GetConstraints( + __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, + __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) +{ + if (ExecutionLevel != NULL) { + *ExecutionLevel = m_ExecutionLevel; + } + + if (SynchronizationScope != NULL) { + *SynchronizationScope = m_SynchronizationScope; + } +} + +FxCallbackLock* +FxDeviceBase::GetCallbackLockPtr( + __out_opt FxObject** LockObject + ) +{ + if (LockObject != NULL) { + *LockObject = m_CallbackLockObjectPtr; + } + + return m_CallbackLockPtr; +} + + +VOID +FxDeviceBase::Init( + __in MdDeviceObject DeviceObject, + __in MdDeviceObject AttachedDevice, + __in MdDeviceObject PhysicalDevice + ) +{ + m_DeviceObject.SetObject(DeviceObject); + m_AttachedDevice.SetObject(AttachedDevice); + m_PhysicalDevice.SetObject(PhysicalDevice); +} + +FxDeviceBase* +FxDeviceBase::_SearchForDevice( + __in FxObject* Object, + __out_opt IFxHasCallbacks** Callbacks + ) +{ + FxObject* pParent, *pOrigParent; + FxDeviceBase* pDeviceBase; + FxQueryInterfaceParams cbParams = { (PVOID*) Callbacks, FX_TYPE_IHASCALLBACKS, 0 }; + PVOID pTag; + + pDeviceBase = Object->GetDeviceBase(); + if (pDeviceBase == NULL) { + DoTraceLevelMessage( + Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT, + "WDFHANDLE %p does not have a WDFDEVICE as an ancestor", + Object->GetObjectHandle()); + return NULL; + } + + if (Callbacks == NULL) { + // + // Caller is not interested in the callbacks interface, just return + // now without searching for it. + // + return pDeviceBase; + } + + // + // Init out parameter. + // + *Callbacks = NULL; + + pOrigParent = Object; + pTag = pOrigParent; + + // + // By adding a reference now, we simulate what GetParentObjectReferenced + // does later, thus allowing simple logic on when/how to release the + // reference on exit. + // + Object->ADDREF(pTag); + + do { + // + // If successful, Callbacks will be != NULL + // + if (NT_SUCCESS(Object->QueryInterface(&cbParams))) { + ASSERT(*Callbacks != NULL); + // + // Release the reference previously taken by the top of the function + // or GetParentObjectReferenced in a previous pass in the loop. + // + Object->RELEASE(pTag); + return pDeviceBase; + } + + pParent = Object->GetParentObjectReferenced(pTag); + + // + // Release the reference previously taken by the top of the function + // or GetParentObjectReferenced in a previous pass in the loop. + // + Object->RELEASE(pTag); + + Object = pParent; + } while (Object != NULL); + + ASSERT(Object == NULL); + + // + // Queue presented requests do not have parents (to increase performance). + // Try to find the callback interface on this object's device base. + // + if (NT_SUCCESS(pDeviceBase->QueryInterface(&cbParams))) { + ASSERT(*Callbacks != NULL); + // + // Success, we got a callback interface. + // + return pDeviceBase; + } + + DoTraceLevelMessage( + pOrigParent->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGOBJECT, + "WDFHANDLE %p does not have a callbacks interface in its object tree" + "(WDFDEVICE %p)", pOrigParent->GetObjectHandle(), + pDeviceBase->GetHandle()); + + return pDeviceBase; +} + +FxDeviceBase* +FxDeviceBase::_SearchForDevice( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ) +{ + FxObject* pParentObject; + FxDeviceBase* pDeviceBase; + + if (Attributes == NULL || Attributes->ParentObject == NULL) { + return NULL; + } + + FxObjectHandleGetPtr(FxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*) &pParentObject); + + pDeviceBase = _SearchForDevice(pParentObject, NULL); + + return pDeviceBase; +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceBase::AllocateTarget( + _Out_ FxIoTarget** Target, + _In_ BOOLEAN SelfTarget + ) +/*++ + +Routine Description: + + Allocates an IO Target or an Self IO target for the FxDevice. + +Arguments: + + Target - Out - returns the pointer to the allocated IO target. + + SelfTarget - If TRUE allocates an Self IO Target, if FALSE allocates + a regular IO target. + +Returns: + + NTSTATUS + +--*/ +{ + FxIoTarget* pTarget; + NTSTATUS status; + + if (SelfTarget) { + pTarget = (FxIoTarget*) new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) + FxIoTargetSelf(GetDriverGlobals(), sizeof(FxIoTargetSelf)); + } else { + pTarget = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) + FxIoTarget(GetDriverGlobals(), sizeof(FxIoTarget)); + } + + if (pTarget == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p could not allocate a WDFIOTARGET, %!STATUS!", + GetHandle(), status); + + goto Done; + } + + status = AddIoTarget(pTarget); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p failed to initialize (add) a WDFIOTARGET, %!STATUS!", + GetHandle(), status); + + goto Done; + } + + status = pTarget->Init(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p failed to initialize a WDFIOTARGET, %!STATUS!", + GetHandle(), status); + + goto Done; + } + + status = pTarget->Commit(WDF_NO_OBJECT_ATTRIBUTES, NULL, this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p failed to initialize (commit) a WDFIOTARGET, %!STATUS!", + GetHandle(), status); + + goto Done; + } + + status = STATUS_SUCCESS; + +Done: + if (!NT_SUCCESS(status)) { + if (pTarget != NULL) { + pTarget->DeleteFromFailedCreate(); + pTarget = NULL; + } + } + + *Target = pTarget; + + return status; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxdevicecontrolapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxdevicecontrolapi.cpp new file mode 100644 index 00000000000..54450c19f7f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdevicecontrolapi.cpp @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxDeviceControlAPI.cpp + +Abstract: + + This module implements external DDIs for control devices + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceControlAPI.tmh" +} + +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfControlFinishInitializing)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals); + + MxDeviceObject device(pDevice->GetDeviceObject()); + + if (pDevice->IsLegacy()) { + pDevice->m_PkgWmi->Register(); + device.SetFlags(device.GetFlags() & ~DO_DEVICE_INITIALIZING); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p not a control device", Device); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +} // entire extern "C" for the file + diff --git a/sdk/lib/drivers/wdf/shared/core/fxdeviceinit.cpp b/sdk/lib/drivers/wdf/shared/core/fxdeviceinit.cpp new file mode 100644 index 00000000000..3d84e3488af --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdeviceinit.cpp @@ -0,0 +1,323 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInit.cpp + +Abstract: + Internals for WDFDEVICE_INIT + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceInit.tmh" +} + +WDFDEVICE_INIT::WDFDEVICE_INIT( + __in FxDriver* Driver + ) : + Driver(Driver) +{ + DriverGlobals = Driver->GetDriverGlobals(); + + ReadWriteIoType = WdfDeviceIoBuffered; + PowerPageable = TRUE; + Inrush = FALSE; + DeviceType = FILE_DEVICE_UNKNOWN; + Characteristics = FILE_DEVICE_SECURE_OPEN; + + RtlZeroMemory(&FileObject, sizeof(FileObject)); + FileObject.AutoForwardCleanupClose = WdfUseDefault; + + DeviceName = NULL; + CreatedDevice = NULL; + + CreatedOnStack = FALSE; + Exclusive = FALSE; + + RequiresSelfIoTarget = FALSE; + + RemoveLockOptionFlags = 0; + + RtlZeroMemory(&PnpPower.PnpPowerEventCallbacks, sizeof(PnpPower.PnpPowerEventCallbacks)); + RtlZeroMemory(&PnpPower.PolicyEventCallbacks, sizeof(PnpPower.PolicyEventCallbacks)); + PnpPower.PnpStateCallbacks = NULL; + PnpPower.PowerStateCallbacks = NULL; + PnpPower.PowerPolicyStateCallbacks = NULL; + + PnpPower.PowerPolicyOwner = WdfUseDefault; + + InitType = FxDeviceInitTypeFdo; + + RtlZeroMemory(&Fdo.EventCallbacks, sizeof(Fdo.EventCallbacks)); + RtlZeroMemory(&Fdo.ListConfig, sizeof(Fdo.ListConfig)); + RtlZeroMemory(&Fdo.ListConfigAttributes, sizeof(Fdo.ListConfigAttributes)); + Fdo.Filter = FALSE; + + RtlZeroMemory(&Pdo.EventCallbacks, sizeof(Pdo.EventCallbacks)); + Pdo.Raw = FALSE; + Pdo.Static = FALSE; + Pdo.DeviceID = NULL; + Pdo.InstanceID = NULL; + Pdo.ContainerID = NULL; + Pdo.DefaultLocale = 0x0; + Pdo.DescriptionEntry = NULL; + Pdo.ForwardRequestToParent = FALSE; + + RtlZeroMemory(&Security, sizeof(Security)); + + RtlZeroMemory(&RequestAttributes, sizeof(RequestAttributes)); + + PreprocessInfo = NULL; + + IoInCallerContextCallback = NULL; + + InitializeListHead(&CxDeviceInitListHead); + + ReleaseHardwareOrderOnFailure = WdfReleaseHardwareOrderOnFailureEarly; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + DeviceControlIoType = WdfDeviceIoBuffered; + DirectTransferThreshold = 0; + + DevStack = NULL; + + KernelDeviceName = NULL; + + PdoKey = NULL; + + DevInstanceID = NULL; + + DriverID = 0; +#endif +} + +WDFDEVICE_INIT::~WDFDEVICE_INIT() +{ + PLIST_ENTRY next; + + if (PnpPower.PnpStateCallbacks != NULL) { + delete PnpPower.PnpStateCallbacks; + } + + if (PnpPower.PowerStateCallbacks != NULL) { + delete PnpPower.PowerStateCallbacks; + } + + if (PnpPower.PowerPolicyStateCallbacks != NULL) { + delete PnpPower.PowerPolicyStateCallbacks; + } + + if (DeviceName != NULL) { + DeviceName->DeleteObject(); + } + if (Pdo.DeviceID != NULL) { + Pdo.DeviceID->DeleteObject(); + } + if (Pdo.InstanceID != NULL) { + Pdo.InstanceID->DeleteObject(); + } + if (Pdo.ContainerID != NULL) { + Pdo.ContainerID->DeleteObject(); + } + + FxDeviceText::_CleanupList(&Pdo.DeviceText); + + if (Security.Sddl != NULL) { + Security.Sddl->DeleteObject(); + } + if (PreprocessInfo != NULL) { + delete PreprocessInfo; + } + + while(!IsListEmpty(&CxDeviceInitListHead)) { + next = RemoveHeadList(&CxDeviceInitListHead); + PWDFCXDEVICE_INIT cxInit; + cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry); + InitializeListHead(next); + delete cxInit; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + delete [] KernelDeviceName; + delete [] ConfigRegistryPath; + delete [] DevInstanceID; + + if (PdoKey != NULL) { + RegCloseKey(PdoKey); + PdoKey = NULL; + } +#endif + +} + +_Must_inspect_result_ +NTSTATUS +WDFDEVICE_INIT::AssignName( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in const UNICODE_STRING* Name + ) +{ + if (DeviceName == NULL) { + DeviceName = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxString(FxDriverGlobals); + + if (DeviceName == NULL) { + NTSTATUS status; + + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "DeviceName is NULL, %!STATUS!", status); + + return status; + } + + // + // Clear out the autogenerate flag since we have a specific name + // + Characteristics &= ~FILE_AUTOGENERATED_DEVICE_NAME; + } + + return DeviceName->Assign(Name); +} + +_Must_inspect_result_ +PWDFDEVICE_INIT +WDFDEVICE_INIT::_AllocateControlDeviceInit( + __in FxDriver* Driver, + __in const UNICODE_STRING* SDDLString + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PWDFDEVICE_INIT pInit; + NTSTATUS status; + + pFxDriverGlobals = Driver->GetDriverGlobals(); + + pInit = new(pFxDriverGlobals) WDFDEVICE_INIT(Driver); + + if (pInit == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDRIVER 0x%p couldn't allocate WDFDEVICE_INIT", + Driver); + return NULL; + } + + pInit->InitType = FxDeviceInitTypeControlDevice; + + // + // Since we require and SDLL string, initialize to autogenerated device + // name so the driver doesn't have to worry about creating a name if they + // don't want it (useful if creating a DO for WMI tracing for instance). + // + pInit->Characteristics |= FILE_AUTOGENERATED_DEVICE_NAME; + + pInit->Security.Sddl = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxString(pFxDriverGlobals); + + if (pInit->Security.Sddl != NULL) { + status = pInit->Security.Sddl->Assign(SDDLString); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDRIVER 0x%p couldn't create Security String object %!STATUS!", + Driver, status); + } + + if (!NT_SUCCESS(status)) { + delete pInit; + pInit = NULL; + } + + return pInit; +} + +BOOLEAN +WDFDEVICE_INIT::ShouldCreateSecure( + VOID + ) +{ + // + // Driver explicitly set a class or SDDL, we have to create a secure + // device. This will be true for all control devices (SDDL required) + // and raw PDOs (class required), could be true for FDOs or filters as + // well. + // + if (Security.DeviceClassSet || Security.Sddl != NULL) { + return TRUE; + } + + // + // See if there is a name for the device + // + if (HasName()) { + if (IsPdoInit()) { + + + + + + + + + + + + + + ASSERT(Pdo.Raw == FALSE); + + DoTraceLevelMessage( + DriverGlobals, + TRACE_LEVEL_WARNING, + TRACINGDEVICE, + "WDFDRIVER 0x%p asked for a named device object, but the PDO " + "will be created without a name because an SDDL string has not " + "been specified for the PDO.", + Driver + ); + return FALSE; + } + else { + // + // We are creating a named FDO or filter + // + ASSERT(IsFdoInit()); + return TRUE; + } + } + + // + // No name involved (FDO or filter) + // + ASSERT(IsFdoInit()); + + return FALSE; +} + +VOID +WDFDEVICE_INIT::AddCxDeviceInit( + __in PWDFCXDEVICE_INIT CxDeviceInit + ) +{ + InsertHeadList(&CxDeviceInitListHead, &CxDeviceInit->ListEntry); +} + diff --git a/sdk/lib/drivers/wdf/shared/core/fxdeviceinitapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxdeviceinitapi.cpp new file mode 100644 index 00000000000..02588d42775 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdeviceinitapi.cpp @@ -0,0 +1,2711 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInitApi.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceInitApi.tmh" +} + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V1_9, *PWDF_PNPPOWER_EVENT_CALLBACKS_V1_9; + + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V1_5; + +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_9 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_9, *PWDF_PDO_EVENT_CALLBACKS_V1_9; + + +// +// Extern "C" the entire file +// +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitFree)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + if (DeviceInit->CreatedOnStack == FALSE) { + delete DeviceInit; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetIoType)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + WDF_DEVICE_IO_TYPE IoType + ) +{ + DDI_ENTRY(); + + WDF_IO_TYPE_CONFIG ioTypeConfig; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + WDF_IO_TYPE_CONFIG_INIT(&ioTypeConfig); + ioTypeConfig.ReadWriteIoType = IoType; + + DeviceInit->AssignIoType(&ioTypeConfig); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceInit); + + if (IoTypeConfig->Size != sizeof(WDF_IO_TYPE_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "IoTypeConfig size (%d) incorrect, expected %d, %!STATUS!", + IoTypeConfig->Size, + sizeof(WDF_IO_TYPE_CONFIG), status); + return; + } + + DeviceInit->AssignIoType(IoTypeConfig); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetExclusive)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + BOOLEAN Exclusive + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->Exclusive = Exclusive; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetDeviceType)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + DEVICE_TYPE DeviceType + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->DeviceType = DeviceType; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetPowerNotPageable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->PowerPageable = FALSE; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetPowerPageable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->PowerPageable = TRUE; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetPowerInrush)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + // + // If you are inrush, there is no way you can be power pageable + // + DeviceInit->Inrush = TRUE; + DeviceInit->PowerPageable = FALSE; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceInitAssignName)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in_opt + PCUNICODE_STRING DeviceName + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + status = FxVerifierCheckIrqlLevel(DeviceInit->DriverGlobals, + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceName != NULL) { + status = FxValidateUnicodeString(DeviceInit->DriverGlobals, + DeviceName); + if (!NT_SUCCESS(status)) { + return status; + } + } + + if (DeviceName == NULL) { + if (DeviceInit->DeviceName != NULL) { + DeviceInit->DeviceName->RELEASE(NULL); + DeviceInit->DeviceName = NULL; + } + + if (DeviceInit->IsPdoInit()) { + // + // Make sure a PDO has a name + // + DeviceInit->Characteristics |= FILE_AUTOGENERATED_DEVICE_NAME; + } + + return STATUS_SUCCESS; + } + + return DeviceInit->AssignName(DeviceInit->DriverGlobals, DeviceName); + +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetCharacteristics)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + ULONG DeviceCharacteristics, + __in + BOOLEAN OrInValues + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + if (OrInValues) { + DeviceInit->Characteristics |= DeviceCharacteristics | FILE_DEVICE_SECURE_OPEN; + } + else { + DeviceInit->Characteristics = DeviceCharacteristics | FILE_DEVICE_SECURE_OPEN; + } + + // + // If the autogenerate flag is on, clear out the device name + // + if ((DeviceCharacteristics & FILE_AUTOGENERATED_DEVICE_NAME) && + DeviceInit->DeviceName != NULL) { + DeviceInit->DeviceName->RELEASE(NULL); + DeviceInit->DeviceName = NULL; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + __in_opt + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ) + +/*++ + +Routine Description: + + Registers callbacks for file object support. + + Defaults to WdfDeviceFileObjectNoFsContext. + +Arguments: + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_FILEOBJECT_CLASS normalizedFileClass; + WDF_FILEOBJECT_CLASS fileClass; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, FileObjectConfig); + + if (FileObjectConfig->Size != sizeof(WDF_FILEOBJECT_CONFIG)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid FileObjectConfig Size %d, expected %d", + FileObjectConfig->Size, sizeof(WDF_FILEOBJECT_CONFIG)); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + status = FxValidateObjectAttributes( + pFxDriverGlobals, + FileObjectAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED | + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | + FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED + ); + + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Validate AutoForwardCleanupClose + // + switch (FileObjectConfig->AutoForwardCleanupClose) { + case WdfTrue: + case WdfFalse: + case WdfUseDefault: + break; + + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid FileObjectConfig->AutoForwardCleanupClose value 0x%x, " + "expected WDF_TRI_STATE value", FileObjectConfig->AutoForwardCleanupClose); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + DeviceInit->FileObject.Set = TRUE; + + DeviceInit->FileObject.AutoForwardCleanupClose = + FileObjectConfig->AutoForwardCleanupClose; + + fileClass = FileObjectConfig->FileObjectClass; + + // + // Remove bit flags and validate file object class value. + // + normalizedFileClass = FxFileObjectClassNormalize(fileClass); + + if (normalizedFileClass == WdfFileObjectInvalid || + normalizedFileClass > WdfFileObjectWdfCannotUseFsContexts) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Out of range FileObjectConfig->FileObjectClass %d", + fileClass); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // UMDF doesn't support storing object handle at FsContext or FxContxt2. + // Update the class to WdfFileObjectWdfCannotUseFsContexts for UMDF. + // + if (pFxDriverGlobals->IsUserModeDriver && + (normalizedFileClass == WdfFileObjectWdfCanUseFsContext || + normalizedFileClass == WdfFileObjectWdfCanUseFsContext2)) { + + // + // update the FileObjectClass value + // + BOOLEAN canBeOptional = + (fileClass & WdfFileObjectCanBeOptional) ? TRUE : FALSE; + + fileClass = WdfFileObjectWdfCannotUseFsContexts; + if (canBeOptional) { + fileClass = (WDF_FILEOBJECT_CLASS) + (fileClass | WdfFileObjectCanBeOptional); + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDEVICE, + "FileObjectConfig->FileObjectClass value (%d) has been updated" + " to a UMDF-supported value %d", normalizedFileClass, + WdfFileObjectWdfCannotUseFsContexts); + + // + // re-obtain the normalized class + // + normalizedFileClass = FxFileObjectClassNormalize(fileClass); + } + + // + // The optional flag can only be combined with a subset of values. + // + if (FxIsFileObjectOptional(fileClass)) { + switch(normalizedFileClass) { + case WdfFileObjectWdfCanUseFsContext: + case WdfFileObjectWdfCanUseFsContext2: + case WdfFileObjectWdfCannotUseFsContexts: + break; + + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid FileObjectConfig->FileObjectClass %d", + fileClass); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + break; // just in case static verification tools complain. + } + } + + DeviceInit->FileObject.Class = fileClass; + + RtlCopyMemory(&DeviceInit->FileObject.Callbacks, + FileObjectConfig, + sizeof(DeviceInit->FileObject.Callbacks)); + + if (FileObjectAttributes != NULL) { + RtlCopyMemory(&DeviceInit->FileObject.Attributes, + FileObjectAttributes, + sizeof(DeviceInit->FileObject.Attributes)); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetRequestAttributes)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, RequestAttributes); + + // + // Parent of all requests created from WDFDEVICE are parented by the + // WDFDEVICE. + // + status = FxValidateObjectAttributes(pFxDriverGlobals, + RequestAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + RtlCopyMemory(&DeviceInit->RequestAttributes, + RequestAttributes, + sizeof(WDF_OBJECT_ATTRIBUTES)); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceInitAssignSDDLString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in_opt + PCUNICODE_STRING SDDLString + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (SDDLString == NULL) { + // + // Since we require the SDDL on control device creation, you can't + // clear it! + // + if (DeviceInit->IsControlDeviceInit()) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (DeviceInit->Security.Sddl != NULL) { + DeviceInit->Security.Sddl->RELEASE(NULL); + DeviceInit->Security.Sddl = NULL; + } + + return STATUS_SUCCESS; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, SDDLString); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->Security.Sddl == NULL) { + DeviceInit->Security.Sddl = new(pFxDriverGlobals, + WDF_NO_OBJECT_ATTRIBUTES) + FxString(pFxDriverGlobals); + + if (DeviceInit->Security.Sddl == NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create Security descriptor" + " STATUS_INSUFFICIENT_RESOURCES "); + + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + return DeviceInit->Security.Sddl->Assign(SDDLString); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetDeviceClass)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + CONST GUID* DeviceClassGuid + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DeviceClassGuid); + + DeviceInit->Security.DeviceClassSet = TRUE; + RtlCopyMemory(&DeviceInit->Security.DeviceClass, + DeviceClassGuid, + sizeof(GUID)); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, PnpPowerEventCallbacks); + + if (PnpPowerEventCallbacks->Size != sizeof(WDF_PNPPOWER_EVENT_CALLBACKS) && + PnpPowerEventCallbacks->Size != sizeof(_WDF_PNPPOWER_EVENT_CALLBACKS_V1_9)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PnpPowerEventCallbacks size %d is invalid, exptected %d", + PnpPowerEventCallbacks->Size, sizeof(WDF_PNPPOWER_EVENT_CALLBACKS) + ); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; + } + + // + // Make sure only one of the callbacks EvtDeviceUsageNotification or + // EvtDeviceUsageNotificationEx is provided by driver for >V1.9. + // + if (PnpPowerEventCallbacks->Size > sizeof(WDF_PNPPOWER_EVENT_CALLBACKS_V1_9) && + PnpPowerEventCallbacks->EvtDeviceUsageNotification != NULL && + PnpPowerEventCallbacks->EvtDeviceUsageNotificationEx != NULL) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Driver can provide either EvtDeviceUsageNotification or " + "EvtDeviceUsageNotificationEx callback but not both"); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; + } + + // + // Driver's PnpPowerEventCallbacks structure may be from a previous + // version and therefore may be different in size than the current version + // that framework is using. Therefore, copy only PnpPowerEventCallbacks->Size + // bytes and not sizeof(PnpPowerEventCallbacks) bytes. + // + RtlCopyMemory(&DeviceInit->PnpPower.PnpPowerEventCallbacks, + PnpPowerEventCallbacks, + PnpPowerEventCallbacks->Size); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, PowerPolicyEventCallbacks); + + // + // The WDF_POWER_POLICY_EVENT_CALLBACKS structure size increased after v1.5. + // Since this api is backwards compatible, it can accept either the current + // structure or the older version. Validate the size of the structure here + // so that it is one of the two supported sizes. + // + if (PowerPolicyEventCallbacks->Size != sizeof(WDF_POWER_POLICY_EVENT_CALLBACKS) && + PowerPolicyEventCallbacks->Size != sizeof(WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PowerPolicyEventCallbacks size %d is invalid, expected %d", + PowerPolicyEventCallbacks->Size, sizeof(WDF_POWER_POLICY_EVENT_CALLBACKS) + ); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + // + // Only one of EvtDeviceArmWakeFromSx and EvtDeviceArmWakeFromSxWithReason + // callbacks should be specified if the given power policy callbacks structure + // is from a version after v1.5 + // + if (PowerPolicyEventCallbacks->Size > sizeof(WDF_POWER_POLICY_EVENT_CALLBACKS_V1_5) && + PowerPolicyEventCallbacks->EvtDeviceArmWakeFromSx != NULL && + PowerPolicyEventCallbacks->EvtDeviceArmWakeFromSxWithReason != NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PowerPolicyEventCallbacks can have either EvtDeviceArmWakeFromSx " + "or EvtDeviceArmWakeFromSxWithReason callback pointer, but not both" + ); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + RtlCopyMemory(&DeviceInit->PnpPower.PolicyEventCallbacks, + PowerPolicyEventCallbacks, + PowerPolicyEventCallbacks->Size); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + BOOLEAN IsPowerPolicyOwner + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->PnpPower.PowerPolicyOwner = IsPowerPolicyOwner ? WdfTrue : WdfFalse; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + WDF_DEVICE_PNP_STATE PnpState, + __in + PFN_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION EvtDevicePnpStateChange, + __in + ULONG CallbackTypes + ) +{ + DDI_ENTRY(); + + FxPnpStateCallbackInfo* pCallback; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + ULONG normalizedState; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, EvtDevicePnpStateChange); + + normalizedState = WdfDevStateNormalize(PnpState); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (normalizedState < WdfDevStatePnpObjectCreated || normalizedState > WdfDevStatePnpNull) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Pnp State is invalid %!STATUS!", status); + + return status; + } + + if ((CallbackTypes & ~StateNotificationAllStates) != 0 || + CallbackTypes == 0x0) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "CallbackTypes is invalid %!STATUS!", status); + + return status; + } + + if (DeviceInit->PnpPower.PnpStateCallbacks == NULL) { + + DeviceInit->PnpPower.PnpStateCallbacks = + new (pFxDriverGlobals) FxPnpStateCallback(); + + if (DeviceInit->PnpPower.PnpStateCallbacks == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object PnpStateCallbacks %!STATUS!", status); + + return status; + } + } + + pCallback = &DeviceInit->PnpPower.PnpStateCallbacks->m_Methods[ + normalizedState - WdfDevStatePnpObjectCreated]; + + pCallback->Callback = EvtDevicePnpStateChange; + pCallback->Types = CallbackTypes; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + WDF_DEVICE_POWER_STATE PowerState, + __in + PFN_WDF_DEVICE_POWER_STATE_CHANGE_NOTIFICATION EvtDevicePowerStateChange, + __in + ULONG CallbackTypes + ) +{ + DDI_ENTRY(); + + FxPowerStateCallbackInfo* pCallback; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + ULONG normalizedState; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, EvtDevicePowerStateChange); + + normalizedState = WdfDevStateNormalize(PowerState); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (normalizedState < WdfDevStatePowerObjectCreated || + normalizedState >= WdfDevStatePowerNull) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PowerState State is invalid %!STATUS!", status); + + return status; + } + + if ((CallbackTypes & ~StateNotificationAllStates) != 0 || + CallbackTypes == 0x0) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "CallbackTypes is invalid %!STATUS!" + "STATUS_INVALID_PARAMETER", status); + + return status; + } + + if (DeviceInit->PnpPower.PowerStateCallbacks == NULL) { + DeviceInit->PnpPower.PowerStateCallbacks = + new (pFxDriverGlobals) FxPowerStateCallback(); + + if (DeviceInit->PnpPower.PowerStateCallbacks == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object PowerStateCallbacks %!STATUS!", status); + + return status; + } + } + + pCallback = &DeviceInit->PnpPower.PowerStateCallbacks->m_Methods[ + normalizedState - WdfDevStatePowerObjectCreated]; + + pCallback->Callback = EvtDevicePowerStateChange; + pCallback->Types = CallbackTypes; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState, + __in + PFN_WDF_DEVICE_POWER_POLICY_STATE_CHANGE_NOTIFICATION EvtDevicePowerPolicyStateChange, + __in + ULONG CallbackTypes + ) +{ + DDI_ENTRY(); + + FxPowerPolicyStateCallbackInfo* pCallback; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + ULONG normalizedState; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, EvtDevicePowerPolicyStateChange); + + normalizedState = WdfDevStateNormalize(PowerPolicyState); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (normalizedState < WdfDevStatePwrPolObjectCreated || + normalizedState >= WdfDevStatePwrPolNull) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PowerPolicyState State is invalid %!STATUS!", status); + + return status; + } + + if ((CallbackTypes & ~StateNotificationAllStates) != 0 || + CallbackTypes == 0x0) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "CallbackTypes is invalid %!STATUS!", status); + + return status; + } + + if (DeviceInit->PnpPower.PowerPolicyStateCallbacks == NULL) { + DeviceInit->PnpPower.PowerPolicyStateCallbacks = + new (pFxDriverGlobals) FxPowerPolicyStateCallback(); + + if (DeviceInit->PnpPower.PowerPolicyStateCallbacks == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object PowerPolicyStateCallbacks %!STATUS!", status); + + return status; + } + } + + pCallback = &DeviceInit->PnpPower.PowerPolicyStateCallbacks->m_Methods[ + normalizedState - WdfDevStatePwrPolObjectCreated]; + + pCallback->Callback = EvtDevicePowerPolicyStateChange; + pCallback->Types = CallbackTypes; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmIrpPreprocess, + __in + UCHAR MajorFunction, + __drv_when(NumMinorFunctions > 0, __in_bcount(NumMinorFunctions)) + __drv_when(NumMinorFunctions == 0, __in_opt) + PUCHAR MinorFunctions, + __in + ULONG NumMinorFunctions + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, EvtDeviceWdmIrpPreprocess); + + if (NumMinorFunctions > 0) { + FxPointerNotNull(pFxDriverGlobals, MinorFunctions); + } + + // + // ARRAY_SIZE(DeviceInit->PreprocessInfo->Dispatch) just returns a constant + // size, it does not actually deref PreprocessInfo (which could be NULL) + // + if (MajorFunction >= ARRAY_SIZE(DeviceInit->PreprocessInfo->Dispatch)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "MajorFunction is invalid" + "STATUS_INVALID_PARAMETER" + ); + + return STATUS_INVALID_PARAMETER; + } + + if (DeviceInit->PreprocessInfo == NULL) { + DeviceInit->PreprocessInfo = new(pFxDriverGlobals) FxIrpPreprocessInfo(); + + if (DeviceInit->PreprocessInfo == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object PreprocessInfo" + "STATUS_INSUFFICIENT_RESOURCES" + ); + + + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NumMinorFunctions > 0) { + if (DeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions != 0) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Already assigned Minorfunctions" + "STATUS_INVALID_DEVICE_REQUEST" + ); + return STATUS_INVALID_DEVICE_REQUEST; + } + + DeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions = + (PUCHAR) FxPoolAllocate(pFxDriverGlobals, + NonPagedPool, + sizeof(UCHAR) * NumMinorFunctions); + + if (DeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions == NULL) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object MinorFunctions" + "STATUS_INSUFFICIENT_RESOURCES" + ); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlCopyMemory( + &DeviceInit->PreprocessInfo->Dispatch[MajorFunction].MinorFunctions[0], + &MinorFunctions[0], + NumMinorFunctions + ); + + DeviceInit->PreprocessInfo->Dispatch[MajorFunction].NumMinorFunctions = + NumMinorFunctions; + } + + DeviceInit->PreprocessInfo->Dispatch[MajorFunction].EvtDevicePreprocess = + EvtDeviceWdmIrpPreprocess; + + return STATUS_SUCCESS; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ) + +/*++ + +Routine Description: + + Registers an I/O pre-processing callback for the device. + + If registered, any I/O for the device is first presented to this + callback function before being placed in any I/O Queue's. + + The callback is invoked in the thread and/or DPC context of the + original WDM caller as presented to the I/O package. No framework + threading, locking, synchronization, or queuing occurs, and + responsibility for synchronization is up to the device driver. + + This API is intended to support METHOD_NEITHER IRP_MJ_DEVICE_CONTROL's + which must access the user buffer in the original callers context. The + driver would probe and lock the buffer pages from within this event + handler using the functions supplied on the WDFREQUEST object, storing + any required mapped buffers and/or pointers on the WDFREQUEST context + whose size is set by the RequestContextSize of the WDF_DRIVER_CONFIG structure. + + It is the responsibility of this routine to either complete the request, or + pass it on to the I/O package through WdfDeviceEnqueueRequest(Device, Request). + +Arguments: + DeviceInit - Device initialization structure + + EvtIoInCallerContext - Pointer to driver supplied callback function + +Return Value: + +--*/ +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), EvtIoInCallerContext); + + DeviceInit->IoInCallerContextCallback = EvtIoInCallerContext; + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetRemoveLockOptions)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_REMOVE_LOCK_OPTIONS RemoveLockOptions + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + ULONG validFlags = WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO; + + FxPointerNotNull(fxDriverGlobals, DeviceInit); + + FxPointerNotNull(fxDriverGlobals, RemoveLockOptions); + + if (RemoveLockOptions->Size != sizeof(WDF_REMOVE_LOCK_OPTIONS)) { + // + // Size is wrong, bail out + // + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "RemoveLockOptions %p Size incorrect, expected %d, " + "got %d", + RemoveLockOptions, sizeof(WDF_REMOVE_LOCK_OPTIONS), + RemoveLockOptions->Size); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + if ((RemoveLockOptions->Flags & ~validFlags) != 0) { + // + // Invalid flag + // + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "RemoveLockOptions %p Flags 0x%x invalid, " + "valid mask is 0x%x", + RemoveLockOptions, RemoveLockOptions->Flags, + validFlags); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + if (FxDeviceInitTypeControlDevice == DeviceInit->InitType) { + // + // At this time this feature is not supported on control-devices. + // + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "WdfDeviceInitSetRemoveLockOptions is not " + "supported on control devices"); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + DeviceInit->RemoveLockOptionFlags = RemoveLockOptions->Flags; +Done: + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + if ((ReleaseHardwareOrderOnFailure == + WdfReleaseHardwareOrderOnFailureInvalid) || + (ReleaseHardwareOrderOnFailure > + WdfReleaseHardwareOrderOnFailureAfterDescendants)) { + DoTraceLevelMessage( + DeviceInit->DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Out of range WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE %d", + ReleaseHardwareOrderOnFailure); + FxVerifierDbgBreakPoint(DeviceInit->DriverGlobals); + return; + } + + DeviceInit->ReleaseHardwareOrderOnFailure = ReleaseHardwareOrderOnFailure; +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + A client or Cx calls this API to indicate that it would like to leverage an + Self IO target. + + For now the Self targets are not supported for PDOs, Miniport Device, + or non pnp Devices. + +Arguments: + + DeviceInit - Pointer to the WDFDEVICE_INIT structure + +Returns: + + VOID + +--*/ +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->RequiresSelfIoTarget = TRUE; +} + + + +// +// BEGIN FDO specific functions +// + +__drv_maxIRQL(DISPATCH_LEVEL) +PDEVICE_OBJECT +WDFEXPORT(WdfFdoInitWdmGetPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + if (DeviceInit->IsNotFdoInit()) { + DoTraceLevelMessage( + DeviceInit->DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO" + ); + + return NULL; + } + + return reinterpret_cast(DeviceInit->Fdo.PhysicalDevice); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfFdoInitOpenRegistryKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + ULONG DeviceInstanceKeyType, + __in + ACCESS_MASK DesiredAccess, + __in_opt + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + __out + WDFKEY* Key + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + + if (DeviceInit->IsNotFdoInit()) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO, %!STATUS!", + status); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + return FxDevice::_OpenKey(pFxDriverGlobals, + DeviceInit, + NULL, + DeviceInstanceKeyType, + DesiredAccess, + KeyAttributes, + Key); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfFdoInitSetFilter)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + if (!NT_SUCCESS(FxVerifierCheckIrqlLevel(pFxDriverGlobals, + PASSIVE_LEVEL))) { + return; + } + if (DeviceInit->IsNotFdoInit()) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO"); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + DeviceInit->Fdo.Filter = TRUE; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfFdoInitQueryProperty)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + DEVICE_REGISTRY_PROPERTY DeviceProperty, + __in + ULONG BufferLength, + __out_bcount_full_opt(BufferLength) + PVOID PropertyBuffer, + __out + PULONG ResultLength + ) +/*++ + +Routine Description: + Retrieves the requested device property for the given device + +Arguments: + DeviceInit - Device initialization structure + + DeviceProperty - the property being queried + + BufferLength - length of PropertyBuffer in bytes + + PropertyBuffer - Buffer which will receive the property being queried + + ResultLength - if STATUS_BUFFER_TOO_SMALL is returned, then this will contain + the required length + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, ResultLength); + if (BufferLength > 0) { + FxPointerNotNull(pFxDriverGlobals, PropertyBuffer); + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotFdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO, %!STATUS!", + status); + return status; + } + + status = FxDevice::_QueryProperty(pFxDriverGlobals, + DeviceInit, + NULL, + NULL, + DeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength); + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + DEVICE_REGISTRY_PROPERTY DeviceProperty, + __in + __drv_strictTypeMatch(__drv_typeExpr) + POOL_TYPE PoolType, + __in_opt + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + __out + WDFMEMORY* PropertyMemory + ) +/*++ + +Routine Description: + Allocates and retrieves the requested device property for the given device init + +Arguments: + DeviceInit - Device initialization structure + + DeviceProperty - the property being queried + + PoolType - what type of pool to allocate + + PropertyMemoryAttributes - attributes to associate with PropertyMemory + + PropertyMemory - handle which will receive the property buffer + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, PropertyMemory); + + *PropertyMemory = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag); + + status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotFdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO, %!STATUS!", + status); + + return status; + } + + status = FxDevice::_AllocAndQueryProperty(pFxDriverGlobals, + DeviceInit, + NULL, + NULL, + DeviceProperty, + PoolType, + PropertyMemoryAttributes, + PropertyMemory); + return status; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfFdoInitSetEventCallbacks)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_FDO_EVENT_CALLBACKS FdoEventCallbacks + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, FdoEventCallbacks); + + if (!NT_SUCCESS(FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL))) { + return; + } + + if (DeviceInit->IsNotFdoInit()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (FdoEventCallbacks->Size != sizeof(WDF_FDO_EVENT_CALLBACKS)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "FdoEventCallbacks size %d is invalid, expected %d", + FdoEventCallbacks->Size, sizeof(WDF_FDO_EVENT_CALLBACKS) + ); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (FdoEventCallbacks->EvtDeviceFilterAddResourceRequirements != NULL && + FdoEventCallbacks->EvtDeviceRemoveAddedResources == NULL) { + // + // Not allowed to add resources without filtering them out later + // + DoTraceLevelMessage( + GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_ERROR, TRACINGPNP, + "Must set EvtDeviceRemoveAddedResources if " + "EvtDeviceFilterAddResourceRequirements (%p) is set", + FdoEventCallbacks->EvtDeviceFilterAddResourceRequirements); + + FxVerifierDbgBreakPoint(GetFxDriverGlobals(DriverGlobals)); + return; + } + + RtlCopyMemory(&DeviceInit->Fdo.EventCallbacks, + FdoEventCallbacks, + sizeof(DeviceInit->Fdo.EventCallbacks)); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfFdoInitSetDefaultChildListConfig)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __inout + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_CHILD_LIST_CONFIG Config, + __in_opt + PWDF_OBJECT_ATTRIBUTES DefaultDeviceListAttributes + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + size_t totalDescriptionSize; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + totalDescriptionSize = 0; + + FxPointerNotNull(pFxDriverGlobals, Config); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + if (DeviceInit->IsNotFdoInit()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + status = FxChildList::_ValidateConfig(pFxDriverGlobals, + Config, + &totalDescriptionSize); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (DefaultDeviceListAttributes != NULL) { + status = FxValidateObjectAttributes(pFxDriverGlobals, + DefaultDeviceListAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + RtlCopyMemory(&DeviceInit->Fdo.ListConfigAttributes, + DefaultDeviceListAttributes, + sizeof(DeviceInit->Fdo.ListConfigAttributes)); + } + + RtlCopyMemory(&DeviceInit->Fdo.ListConfig, + Config, + sizeof(WDF_CHILD_LIST_CONFIG)); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ) +/*++ + +Routine Description: + + This routine queries device property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + DeviceInit - WDF DeviceInit structure pointer. + + DeviceProperty - A pointer to WDF_DEVICE_PROPERTY_DATA structure. + + BufferLength - The size, in bytes, of the buffer that is pointed to by + PropertyBuffer. + + PropertyBuffer - A caller-supplied pointer to a caller-allocated buffer that + receives the requested information. The pointer can be NULL + if the BufferLength parameter is zero. + + ResultLength - A caller-supplied location that, on return, contains the + size, in bytes, of the information that the method stored in + PropertyBuffer. If the function's return value is + STATUS_BUFFER_TOO_SMALL, this location receives the required + buffer size. + + Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves + the property data, the routine writes the property type value + to this variable. This value indicates the type of property + data that is in the Data buffer. + +Return Value: + + Method returns an NTSTATUS value. This routine might return one of the + following values. + + STATUS_BUFFER_TOO_SMALL - The supplied buffer is too small to receive the + information. The ResultLength member receives the + size of buffer required. + STATUS_SUCCESS - The operation succeeded. + STATUS_INVALID_PARAMETER - One of the parameters is incorrect. + + The method might return other NTSTATUS values. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DeviceProperty); + + if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "PropertyData size (%d) incorrect, expected %d, %!STATUS!", + DeviceProperty->Size, + sizeof(WDF_DEVICE_PROPERTY_DATA), status); + return status; + } + + FxPointerNotNull(pFxDriverGlobals, ResultLength); + if (BufferLength > 0) { + FxPointerNotNull(pFxDriverGlobals, PropertyBuffer); + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotFdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO, %!STATUS!", + status); + return status; + } + + status = FxDevice::_QueryPropertyEx(pFxDriverGlobals, + DeviceInit, + NULL, + DeviceProperty, + FxDeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength, + Type); + return status; +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +/*++ + +Routine Description: + + This routine queries device property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + DeviceInit - WDF DeviceInit pointer. + + PropertyData - A pointer to WDF_DEVICE_PROPERTY_ DATA structure. + + PoolType - A POOL_TYPE-typed enumerator that specifies the type of memory + to be allocated. + + PropertyMemoryAttributes - optional, A pointer to a caller-allocated + WDF_OBJECT_ATTRIBUTES structure that describes object attributes + for the memory object that the function will allocate. This + parameter is optional and can be WDF_NO_OBJECT_ATTRIBUTES. + + PropertyMemory - A pointer to a WDFMEMORY-typed location that receives a + handle to a framework memory object. + + Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves + the property data, the routine writes the property type value to + this variable. This value indicates the type of property data + that is in the Data buffer. + +Return Value: + + Method returns an NTSTATUS value. This routine might return one of the + following values. It might return other NTSTATUS-codes as well. + + STATUS_SUCCESS The operation succeeded. + STATUS_INVALID_PARAMETER One of the parameters is incorrect. + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DeviceProperty); + + if (DeviceProperty->Size != sizeof(WDF_DEVICE_PROPERTY_DATA)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "PropertyData size (%d) incorrect, expected %d, %!STATUS!", + DeviceProperty->Size, + sizeof(WDF_DEVICE_PROPERTY_DATA), status); + return status; + } + + FxPointerNotNull(pFxDriverGlobals, PropertyMemory); + + *PropertyMemory = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag); + + status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotFdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for an FDO, %!STATUS!", + status); + + return status; + } + + status = FxDevice::_AllocAndQueryPropertyEx(pFxDriverGlobals, + DeviceInit, + NULL, + DeviceProperty, + FxDeviceProperty, + PoolType, + PropertyMemoryAttributes, + PropertyMemory, + Type); + return status; +} + +// +// END FDO specific functions +// + +// +// BEGIN PDO specific functions +// +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +PWDFDEVICE_INIT +WDFEXPORT(WdfPdoInitAllocate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE ParentDevice + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PWDFDEVICE_INIT pInit; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + ParentDevice, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return NULL; + } + + if (pDevice->IsFdo() == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Parent device is not a FDO (must use WDFCHILDLIST to use a PDO as a parent)" + ); + + return NULL; + } + + pInit = new(pFxDriverGlobals) WDFDEVICE_INIT(pDevice->GetDriver()); + if (pInit == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create WDFDEVICE_INIT object"); + + return NULL; + } + + pInit->SetPdo(pDevice); + + // + // Dynamically created PDOs are not created with this API, rather they go + // through WDFCHILDLIST's callback. + // + pInit->Pdo.Static = TRUE; + + return pInit; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfPdoInitSetEventCallbacks)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PWDF_PDO_EVENT_CALLBACKS DispatchTable + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DispatchTable); + + if (!NT_SUCCESS(FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL))) { + return; + } + + if (DeviceInit->IsNotPdoInit()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (DispatchTable->Size != sizeof(WDF_PDO_EVENT_CALLBACKS) && + DispatchTable->Size != sizeof(WDF_PDO_EVENT_CALLBACKS_V1_9)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "DispatchTable size %d is invalid, expected %d", + DispatchTable->Size, sizeof(WDF_PDO_EVENT_CALLBACKS)); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; // STATUS_INFO_LENGTH_MISMATCH; + } + + RtlCopyMemory(&DeviceInit->Pdo.EventCallbacks, + DispatchTable, + sizeof(WDF_PDO_EVENT_CALLBACKS)); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAssignDeviceID)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PCUNICODE_STRING DeviceID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DeviceID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, DeviceID); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + return status; + } + + if (DeviceInit->Pdo.DeviceID == NULL) { + DeviceInit->Pdo.DeviceID = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxString(pFxDriverGlobals); + + if (DeviceInit->Pdo.DeviceID == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate DeviceID object, %!STATUS!", + status); + return status; + } + } + + status = DeviceInit->Pdo.DeviceID->Assign(DeviceID); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAssignInstanceID)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PCUNICODE_STRING InstanceID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, InstanceID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, InstanceID); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST ; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + return status; + } + + if (DeviceInit->Pdo.InstanceID == NULL) { + DeviceInit->Pdo.InstanceID = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxString(pFxDriverGlobals); + + if (DeviceInit->Pdo.InstanceID == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate InstanceID object, %!STATUS!", + status); + return status; + } + } + + status = DeviceInit->Pdo.InstanceID->Assign(InstanceID); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAddHardwareID)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PCUNICODE_STRING HardwareID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxString* pID; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, HardwareID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, HardwareID); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST ; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + return status; + } + + pID = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) FxString(pFxDriverGlobals); + if (pID == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate String object %!STATUS!", status); + return status; + } + + status = pID->Assign(HardwareID); + if (NT_SUCCESS(status)) { + status = (DeviceInit->Pdo.HardwareIDs.Add(pFxDriverGlobals, pID)) ? + STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + } + + // + // Upon success, the FxCollection will have taken a reference. + // Upon failure, this is object cleanup. + // + pID->Release(); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAddCompatibleID)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PCUNICODE_STRING CompatibleID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxString* pID; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, CompatibleID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, CompatibleID); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + return status; + } + + pID = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) FxString(pFxDriverGlobals); + if (pID == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate String object" + "STATUS_INSUFFICIENT_RESOURCES " + ); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pID->Assign(CompatibleID); + if (NT_SUCCESS(status)) { + status = (DeviceInit->Pdo.CompatibleIDs.Add(pFxDriverGlobals, pID)) ? + STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + } + + // + // Upon success, the FxCollection will have taken a reference. Upon failure, + // this is object cleanup. + // + pID->Release(); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAssignContainerID)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PCUNICODE_STRING ContainerID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, ContainerID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ContainerID); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST ; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + return status; + } + + if (DeviceInit->Pdo.ContainerID == NULL) { + DeviceInit->Pdo.ContainerID = new(pFxDriverGlobals, + WDF_NO_OBJECT_ATTRIBUTES) + FxString(pFxDriverGlobals); + + if (DeviceInit->Pdo.ContainerID == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate ContainerID object, %!STATUS!", + status); + + return status; + } + } + + status = DeviceInit->Pdo.ContainerID->Assign(ContainerID); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAddDeviceText)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PCUNICODE_STRING DeviceDescription, + __in + PCUNICODE_STRING DeviceLocation, + __in + LCID LocaleId + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDeviceText *pDeviceText; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DeviceDescription); + FxPointerNotNull(pFxDriverGlobals, DeviceLocation); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, DeviceDescription); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, DeviceLocation); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", status); + return status; + } + + pDeviceText = new(pFxDriverGlobals, PagedPool) FxDeviceText(); + + if (pDeviceText == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate DeviceText object, %!STATUS!", status); + + return status; + } + + pDeviceText->m_LocaleId = LocaleId; + + pDeviceText->m_Description = FxDuplicateUnicodeStringToString( + pFxDriverGlobals, DeviceDescription); + + if (pDeviceText->m_Description == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate DeviceDescription string, %!STATUS!", status); + + goto Done; + } + + pDeviceText->m_LocationInformation = FxDuplicateUnicodeStringToString( + pFxDriverGlobals, DeviceLocation); + + if (pDeviceText->m_LocationInformation == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't allocate DeviceLocation string, %!STATUS!", status); + + goto Done; + } + + // + // Insert at the end of the list and update end of the list + // + *DeviceInit->Pdo.LastDeviceTextEntry = &pDeviceText->m_Entry; + DeviceInit->Pdo.LastDeviceTextEntry = &pDeviceText->m_Entry.Next; + +Done: + if (!NT_SUCCESS(status)) { + delete pDeviceText; + } + + return status; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfPdoInitSetDefaultLocale)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + LCID LocaleId + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + if (!NT_SUCCESS(FxVerifierCheckIrqlLevel(pFxDriverGlobals, + PASSIVE_LEVEL))) { + return; + } + + if (DeviceInit->IsNotPdoInit()) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + DeviceInit->Pdo.DefaultLocale = LocaleId; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfPdoInitAssignRawDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + CONST GUID* DeviceClassGuid + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, DeviceClassGuid); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit->IsNotPdoInit()) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + return status; + } + + DeviceInit->Pdo.Raw = TRUE; + DeviceInit->Security.DeviceClassSet = TRUE; + RtlCopyMemory(&DeviceInit->Security.DeviceClass, + DeviceClassGuid, + sizeof(GUID)); + + return STATUS_SUCCESS; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfPdoInitAllowForwardingRequestToParent)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + if (DeviceInit->IsNotPdoInit()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a PDO, %!STATUS!", + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + DeviceInit->Pdo.ForwardRequestToParent = TRUE; + return ; +} + + + +// +// END PDO specific functions +// + +// +// BEGIN CONTROL DEVICE specific functions +// + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +PWDFDEVICE_INIT +WDFEXPORT(WdfControlDeviceInitAllocate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in + CONST UNICODE_STRING* SDDLString + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver* pDriver; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID*) &pDriver, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, SDDLString); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return NULL; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, SDDLString); + if (!NT_SUCCESS(status)) { + return NULL; + } + + return WDFDEVICE_INIT::_AllocateControlDeviceInit(pDriver, SDDLString); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfControlDeviceInitSetShutdownNotification)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDFDEVICE_INIT DeviceInit, + __in + PFN_WDF_DEVICE_SHUTDOWN_NOTIFICATION Notification, + __in + UCHAR Flags + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + pFxDriverGlobals = DeviceInit->DriverGlobals; + + FxPointerNotNull(pFxDriverGlobals, Notification); + + if (DeviceInit->IsNotControlDeviceInit()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Not a PWDFDEVICE_INIT for a control device"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if ((Flags & ~(WdfDeviceShutdown | WdfDeviceLastChanceShutdown)) != 0) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WdfDeviceShutdown Flags 0x%x are invalid", Flags); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + DeviceInit->Control.ShutdownNotification = Notification; + DeviceInit->Control.Flags |= Flags; +} + +// +// END CONTROL DEVICE specific functions +// + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxdisposelist.cpp b/sdk/lib/drivers/wdf/shared/core/fxdisposelist.cpp new file mode 100644 index 00000000000..c1443cae701 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdisposelist.cpp @@ -0,0 +1,305 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDisposeList.hpp + +Abstract: + + This class implements a Disposal list for deferring Dispose + processing from dispatch to passive level. + + It works tightly with FxObject, and is a friend class. + +Author: + + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxDisposeList.hpp" + +// Tracing support +extern "C" { +#include "FxDisposeList.tmh" +} + +FxDisposeList::FxDisposeList( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_DISPOSELIST, 0, FxDriverGlobals) +{ + m_List.Next = NULL; + m_ListEnd = &m_List.Next; + + m_SystemWorkItem = NULL; + m_WorkItemThread = NULL; +} + +FxDisposeList::~FxDisposeList() +{ + ASSERT(m_List.Next == NULL); +} + +NTSTATUS +FxDisposeList::_Create( + PFX_DRIVER_GLOBALS FxDriverGlobals, + PVOID WdmObject, + FxDisposeList** pObject + ) +{ + FxDisposeList* list; + NTSTATUS status; + + *pObject = NULL; + + list = new(FxDriverGlobals) FxDisposeList(FxDriverGlobals); + + if (list == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = list->Initialize(WdmObject); + + if (NT_SUCCESS(status)) { + *pObject = list; + } + else { + list->DeleteFromFailedCreate(); + } + + return status; +} + +NTSTATUS +FxDisposeList::Initialize( + PVOID WdmObject + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + MarkDisposeOverride(ObjectDoNotLock); + + status = FxSystemWorkItem::_Create(FxDriverGlobals, + WdmObject, + &m_SystemWorkItem + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not allocate workitem: %!STATUS!", status); + return status; + } + + m_WdmObject = WdmObject; + + return STATUS_SUCCESS; +} + +BOOLEAN +FxDisposeList::Dispose( + ) +{ + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->DeleteObject(); + m_SystemWorkItem = NULL; + } + + ASSERT(m_List.Next == NULL); + + __super::Dispose(); + + return TRUE; +} + +VOID +FxDisposeList::Add( + FxObject* Object + ) + +/*++ + +Routine Description: + + Add an object to the cleanup list. + + + + + + + + The caller is expected to manage any reference counts on + the object while on the cleanup list + +Arguments: + + object - Object to cleanup at passive level + +Returns: + + None + +--*/ + +{ + KIRQL irql; + BOOLEAN previouslyEmpty; + + Lock(&irql); + + ASSERT(Object->m_DisposeSingleEntry.Next == NULL); + + previouslyEmpty = m_List.Next == NULL ? TRUE : FALSE; + + // + // Add to the end of m_List + // + *m_ListEnd = &Object->m_DisposeSingleEntry; + + // + // Update the end + // + m_ListEnd = &Object->m_DisposeSingleEntry.Next; + + if (previouslyEmpty) { + m_SystemWorkItem->TryToEnqueue(_WorkItemThunk, this); + } + + Unlock(irql); +} + +VOID +FxDisposeList::DrainListLocked( + PKIRQL PreviousIrql + ) +{ + FxObject* pObject; + PSINGLE_LIST_ENTRY pEntry; + + // + // Process items on the list until it is empty + // + while (m_List.Next != NULL) { + pEntry = m_List.Next; + + // + // Remove pEntry from the list + // + m_List.Next = pEntry->Next; + + // + // Indicate pEntry is no longer in the list + // + pEntry->Next = NULL; + + // + // Convert back to the object + // + pObject = FxObject::_FromDisposeEntry(pEntry); + + // + // If the list is empty, we just popped off the entry and we need to + // update m_ListEnd to a head of the list so it points to valid pool. + // + if (m_List.Next == NULL) { + m_ListEnd = &m_List.Next; + } + + Unlock(*PreviousIrql); + + // + // Invoke the objects deferred dispose entry + // + pObject->DeferredDisposeWorkItem(); + + // + // pObject may be invalid at this point due to its dereferencing itself + // + Lock(PreviousIrql); + } +} + +VOID +FxDisposeList::_WorkItemThunk( + __in PVOID Parameter + ) +{ + FxDisposeList* pThis; + KIRQL irql; + + pThis = (FxDisposeList*) Parameter; + + pThis->Lock(&irql); + + pThis->DrainListLocked(&irql); + + pThis->Unlock(irql); +} + +VOID +FxDisposeList::WaitForEmpty( + ) + +/*++ + +Routine Description: + + Wait until the list goes empty with no items. + + Note, on wakeup, new items could have been added, only the assurance + is that the list at least went empty for a moment. + + This allows a waiter to wait for all previous Add() items to + finishing processing before return. + +Arguments: + +Returns: + +--*/ + +{ + KIRQL irql; + BOOLEAN wait; + + Lock(&irql); + + wait = TRUE; + + if (m_WorkItemThread == Mx::MxGetCurrentThread()) { + + + + + + + + ASSERT(FALSE); + DrainListLocked(&irql); + wait = FALSE; + } + + Unlock(irql); + + if (wait) { + m_SystemWorkItem->WaitForExit(); + } + + // Should only be true for an empty list + ASSERT(m_List.Next == NULL); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxdriver.cpp b/sdk/lib/drivers/wdf/shared/core/fxdriver.cpp new file mode 100644 index 00000000000..1dc3bc70a6e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdriver.cpp @@ -0,0 +1,656 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriver.cpp + +Abstract: + + This is the main driver framework. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "fxiotarget.hpp" + +// Tracing support +extern "C" { +#include "FxDriver.tmh" +} + +FxDriver::FxDriver( + __in MdDriverObject ArgDriverObject, + __in PWDF_DRIVER_CONFIG DriverConfig, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_DRIVER, sizeof(FxDriver), FxDriverGlobals), + m_DriverObject(ArgDriverObject), + m_CallbackMutexLock(FxDriverGlobals) +{ + RtlInitUnicodeString(&m_RegistryPath, NULL); + + + + + + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_ExecutionLevel = WdfExecutionLevelDispatch; +#else + m_ExecutionLevel = WdfExecutionLevelPassive; +#endif + + m_SynchronizationScope = WdfSynchronizationScopeNone; + + m_CallbackLockPtr = NULL; + m_CallbackLockObjectPtr = NULL; + + m_DisposeList = NULL; + + // + // These are initialized up front so that sub objects + // can have the right configuration + // + WDF_DRIVER_CONFIG_INIT(&m_Config, NULL); + + // Only copy the smallest of what is specified and our size + RtlCopyMemory(&m_Config, DriverConfig, min(sizeof(m_Config), DriverConfig->Size) ); + + m_DebuggerConnected = FALSE; + +#if FX_IS_USER_MODE + m_DriverParametersKey = NULL; +#endif +} + +FxDriver::~FxDriver() +{ + // Make it always present right now even on free builds + if (IsDisposed() == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGDRIVER, + "FxDriver 0x%p not disposed: this maybe a driver reference count " + "problem with WDFDRIVER 0x%p", this, GetObjectHandleUnchecked()); + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_OBJECT_ERROR, + (ULONG_PTR) GetObjectHandleUnchecked(), + (ULONG_PTR) this); + } + + // + // Free the memory for the registry path if required. + // + if (m_RegistryPath.Buffer) { + FxPoolFree(m_RegistryPath.Buffer); + } + + if (m_DisposeList != NULL) { + m_DisposeList->DeleteObject(); + } + +#if FX_IS_USER_MODE + // + // Close the R/W handle to the driver's service parameters key + // that we opened during Initialize. + // + if (m_DriverParametersKey != NULL) { + NTSTATUS status = FxRegKey::_Close(m_DriverParametersKey); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Cannot close Driver Parameters key %!STATUS!", + status); + } + m_DriverParametersKey = NULL; + } + + // + // The host-created driver object holds a reference to this + // FxDriver object. Clear it, since this object was deleted. + // + ClearDriverObjectFxDriver(); +#endif +} + +BOOLEAN +FxDriver::Dispose( + VOID + ) +{ + if (m_DisposeList != NULL) { + m_DisposeList->WaitForEmpty(); + } + + return __super::Dispose(); +} + +VOID +FxDriver::Unload( + __in MdDriverObject DriverObject + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver *pDriver; + + pDriver = FxDriver::GetFxDriver(DriverObject); + if (pDriver == NULL) { + return; + } + + pFxDriverGlobals = pDriver->GetDriverGlobals(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Unloading WDFDRIVER %p, PDRIVER_OBJECT_UM %p", + pDriver->GetHandle(), DriverObject); + // + // Invoke the driver if they specified an unload routine. + // + if (pDriver->m_DriverUnload.Method) { + pDriver->m_DriverUnload.Invoke(pDriver->GetHandle()); + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Driver unload routine Exit WDFDRIVER %p, PDRIVER_OBJECT_UM %p", + pDriver->GetHandle(), DriverObject); + } + + // + // Delete the FxDriver object. + // + // This releases the FxDriver reference. Must be called at PASSIVE + // + pDriver->DeleteObject(); + + pFxDriverGlobals->Driver = NULL; + + FxDestroy(pFxDriverGlobals); +} + +VOID +FxDriver::_InitializeDriverName( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + Create a CHAR version of the service name contained in RegistryPath. + +Arguments: + RegistryPath - the path to the service name in the registry. + +Return Value: + None + + --*/ +{ + PWCHAR pCur, pBegin, pEnd; + + RtlZeroMemory(&FxDriverGlobals->Public.DriverName[0], + sizeof(FxDriverGlobals->Public.DriverName) ); + + if (RegistryPath == NULL) { + return; + } + + pBegin = RegistryPath->Buffer; + + // + // pEnd is one past the end of the string, while pCur is a pointer to the + // last character of the string. We will decrement pCur down towards the + // beginning of the string. + // + pEnd = pBegin + (RegistryPath->Length / sizeof(WCHAR)); + pCur = pEnd - 1; + + for ( ; *pCur != L'\\' && pCur != pBegin; pCur--) { + DO_NOTHING(); + } + + if (pCur != pBegin && *pCur == L'\\') { + size_t regLen; + ULONG i; + + pCur++; + + // + // Can't use wcslen becuase this is a UNICODE_STRING which means that it + // does not necessarily have a terminating NULL in the buffer. + // + regLen = pEnd - pCur; + if (regLen > WDF_DRIVER_GLOBALS_NAME_LEN-1) { + regLen = WDF_DRIVER_GLOBALS_NAME_LEN-1; + } + + + for (i = 0; i < regLen; i++) { + FxDriverGlobals->Public.DriverName[i] = (CHAR) pCur[i]; + } + } + else { + NTSTATUS status; + +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE + status = RtlStringCbCopyA(FxDriverGlobals->Public.DriverName, + sizeof(FxDriverGlobals->Public.DriverName), + "WDF"); +#else // USER_MODE + HRESULT hr; + hr = StringCbCopyA(FxDriverGlobals->Public.DriverName, + sizeof(FxDriverGlobals->Public.DriverName), + "WDF"); + if (HRESULT_FACILITY(hr) == FACILITY_WIN32) { + status = WinErrorToNtStatus(HRESULT_CODE(hr)); + } + else { + status = SUCCEEDED(hr) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + } +#endif + + UNREFERENCED_PARAMETER(status); + ASSERT(NT_SUCCESS(status)); + } +} + +VOID +FxDriver::_InitializeTag( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_DRIVER_CONFIG Config + ) +/*++ + +Routine Description: + Tries to create a tag for the driver based off of its name. This tag is + used for allocations made on behalf of the driver so that it is easier to + track which allocations belong to which image. + +Arguments: + Config - driver writer provided config. in the future, may contain a tag + value in it + +Return Value: + None + + --*/ +{ + PCHAR pBegin; + size_t length; + + UNREFERENCED_PARAMETER(Config); + + length = strlen(FxDriverGlobals->Public.DriverName); + pBegin = &FxDriverGlobals->Public.DriverName[0]; + + if (length >= 3) { + // + // If the driver name begins with "WDF" (case insensitive), start after + // "WDF" + // + if ((pBegin[0] == 'w' || pBegin[0] == 'W') && + (pBegin[1] == 'd' || pBegin[1] == 'D') && + (pBegin[2] == 'f' || pBegin[2] == 'F')) { + length -=3; + pBegin += 3; + } + } + + if (length <= 2) { + // + // 2 or less characters is not a unique enough tag, just use the default + // tag. + // + FxDriverGlobals->Tag = FX_TAG; + } + else { + + if (length > sizeof(ULONG)) { + length = sizeof(ULONG); + } + + // + // This copies the bytes in the right order (so that they appear correct + // when dumped as a sequence of chars) + // + RtlCopyMemory(&FxDriverGlobals->Tag, + pBegin, + length); + + FxDriverGlobals->Public.DriverTag = FxDriverGlobals->Tag; + } +} + +_Must_inspect_result_ +NTSTATUS +FxDriver::Initialize( + __in PCUNICODE_STRING ArgRegistryPath, + __in PWDF_DRIVER_CONFIG Config, + __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes + ) +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + NTSTATUS status; + + // WDFDRIVER can not be deleted by the device driver + MarkNoDeleteDDI(); + + MarkDisposeOverride(ObjectDoNotLock); + + // + // Configure Constraints + // + ConfigureConstraints(DriverAttributes); + + if (m_DriverObject.GetObject() == NULL) { + return STATUS_UNSUCCESSFUL; + } + + // Allocate FxDisposeList + status = FxDisposeList::_Create(FxDriverGlobals, m_DriverObject.GetObject(), &m_DisposeList); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Store FxDriver in Driver object extension + // + status = AllocateDriverObjectExtensionAndStoreFxDriver(); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Store away the callback functions. + // + if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) { + // + // Caller doesn't want to override the dispatch table. That + // means that they want to create everything and still be in + // control (or at least the port driver will take over) + // + m_DriverDeviceAdd.Method = Config->EvtDriverDeviceAdd; + m_DriverUnload.Method = Config->EvtDriverUnload; + } + + if (ArgRegistryPath != NULL) { + USHORT length; + + length = ArgRegistryPath->Length + sizeof(UNICODE_NULL); + + m_RegistryPath.Length = ArgRegistryPath->Length; + m_RegistryPath.MaximumLength = length; + m_RegistryPath.Buffer = (PWSTR) FxPoolAllocate( + GetDriverGlobals(), PagedPool, length); + + if (m_RegistryPath.Buffer != NULL) { + RtlCopyMemory(m_RegistryPath.Buffer, + ArgRegistryPath->Buffer, + ArgRegistryPath->Length); + + // + // other parts of WDF assumes m_RegistryPath.Buffer is + // a null terminated string. make sure it is. + // + m_RegistryPath.Buffer[length/sizeof(WCHAR)- 1] = UNICODE_NULL; + } + else { + // + // We failed to allocate space for the registry path + // so set the length to 0. + // + m_RegistryPath.Length = 0; + m_RegistryPath.MaximumLength = 0; + + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) { + if ((Config->DriverInitFlags & WdfDriverInitNoDispatchOverride) == 0) { + UCHAR i; + + // + // Set up dispatch routines. + // + if (Config->DriverInitFlags & WdfDriverInitNonPnpDriver) { + // + // NT4 style drivers must clear the AddDevice field in the + // driver object so that they can be unloaded while still + // having device objects around. + // + // If AddDevice is set, NT considers the driver a pnp driver + // and will not allow net stop to unload the driver. + // + m_DriverObject.SetDriverExtensionAddDevice(NULL); + + // + // Unload for an NT4 driver is still optional if the driver + // does not want to be stopped (through net stop for + // instance). + // + if (Config->EvtDriverUnload != NULL) { + m_DriverObject.SetDriverUnload(Unload); + } + else { + m_DriverObject.SetDriverUnload(NULL); + } + + } + else { + // + // PnP driver, set our routines up + // + m_DriverObject.SetDriverExtensionAddDevice(AddDevice); + m_DriverObject.SetDriverUnload(Unload); + } + + // + // For any major control code that we use a remove lock, the + // following locations must be updated: + // + // 1) FxDevice::_RequiresRemLock() which decides if the remlock + // is required + // 2) FxDefaultIrpHandler::Dispatch might need to be changed if + // there is catchall generic post processing that must be done + // 3) Whereever the major code irp handler completes the irp or + // sends it down the stack. A good design would have all + // spots in the irp handler where this is done to call a + // common function. + // + WDFCASSERT(IRP_MN_REMOVE_DEVICE != 0x0); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { + if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) { + m_DriverObject.SetMajorFunction(i, FxDevice::Dispatch); + } + else { + m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLock); + } + } +#else // USER_MODE + for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { + if (FxDevice::_RequiresRemLock(i, 0x0) == FxDeviceRemLockNotRequired) { + m_DriverObject.SetMajorFunction(i, FxDevice::DispatchUm); + } + else { + m_DriverObject.SetMajorFunction(i, FxDevice::DispatchWithLockUm); + } + } +#endif + } + + // + // Determine if the debugger is connected. + // +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + if (KD_DEBUGGER_ENABLED == TRUE && KD_DEBUGGER_NOT_PRESENT == FALSE) { + m_DebuggerConnected = TRUE; + } +#endif + + // + // Log this notable event after tracing has been initialized. + // + + + + + + + if ((Config->DriverInitFlags & WdfDriverInitNonPnpDriver) && + Config->EvtDriverUnload == NULL) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "Driver Object %p, reg path %wZ cannot be " + "unloaded, no DriverUnload routine specified", + m_DriverObject.GetObject(), &m_RegistryPath); + } + +#if FX_IS_USER_MODE + // + // Open a R/W handle to the driver's service parameters key + // + status = OpenParametersKey(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Cannot open Driver Parameters key %!STATUS!", + status); + } +#endif + } + + return status; +} + +_Must_inspect_result_ +FxString * +FxDriver::GetRegistryPath( + VOID + ) +{ + FxString *pString; + + pString = new(GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) + FxString(GetDriverGlobals()); + + if (pString != NULL) { + NTSTATUS status; + + status = pString->Assign(m_RegistryPath.Buffer); + + if (!NT_SUCCESS(status)) { + pString->Release(); + pString = NULL; + } + } + + return pString; +} + + +VOID +FxDriver::ConfigureConstraints( + __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes + ) +/*++ + +Routine Description: + + Determine the pointer to the proper lock to acquire + for event callbacks from the FxDriver to the device driver + depending on the configured locking model. + +Arguments: + DriverAttributes - caller supplied scope and level, used only if they + are not InheritFromParent. + +Returns: + None + +--*/ +{ + BOOLEAN automaticLockingRequired; + + automaticLockingRequired = FALSE; + + // Initialize the mutex lock + m_CallbackMutexLock.Initialize(this); + + + + + + + + + + MarkPassiveCallbacks(ObjectDoNotLock); + + m_CallbackLockPtr = &m_CallbackMutexLock; + m_CallbackLockObjectPtr = this; + + // + // Use the caller supplied scope and level only if they are not + // InheritFromParent. + // + if (DriverAttributes != NULL) { + + if (DriverAttributes->ExecutionLevel != + WdfExecutionLevelInheritFromParent) { + m_ExecutionLevel = DriverAttributes->ExecutionLevel; + } + + if (DriverAttributes->SynchronizationScope != + WdfSynchronizationScopeInheritFromParent) { + m_SynchronizationScope = DriverAttributes->SynchronizationScope; + } + } + + // + // If the driver asks for any synchronization, we synchronize the + // WDFDRIVER object's own callbacks as well. + // + // (No option to extend synchronization for regular operations + // across all WDFDEVICE objects) + // + if (m_SynchronizationScope == WdfSynchronizationScopeDevice || + m_SynchronizationScope == WdfSynchronizationScopeQueue) { + + automaticLockingRequired = TRUE; + } + + // + // No FxDriver events are delivered from a thread that is + // not already at PASSIVE_LEVEL, so we don't need to + // allocate an FxSystemWorkItem if the execution level + // constraint is WdfExecutionLevelPassive. + // + // If any events are added FxDriver that could occur on a thread + // that is above PASSIVE_LEVEL, then an FxSystemWorkItem would + // need to be allocated to deliver those events similar to the + // code in FxIoQueue. + // + + // + // Configure FxDriver event callback locks + // + if (automaticLockingRequired) { + m_DriverDeviceAdd.SetCallbackLockPtr(m_CallbackLockPtr); + } + else { + m_DriverDeviceAdd.SetCallbackLockPtr(NULL); + } +} + diff --git a/sdk/lib/drivers/wdf/shared/core/fxdriverapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxdriverapi.cpp new file mode 100644 index 00000000000..67243d61d31 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxdriverapi.cpp @@ -0,0 +1,522 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriverApi.cpp + +Abstract: + + This module contains the "C" interface for the FxDriver object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include +#include "FxDriverApi.tmh" +} + +#include "FxTelemetry.hpp" + +// +// extern the whole file +// +extern "C" { + +// +// Driver Pool Allocations +// + + +__drv_maxIRQL(PASSIVE_LEVEL) +PWSTR +WDFEXPORT(WdfDriverGetRegistryPath)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDriver *pDriver; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID *)&pDriver, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return NULL; + } + + return pDriver->GetRegistryPathUnicodeString()->Buffer; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDriverCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + MdDriverObject DriverObject, + __in + PCUNICODE_STRING RegistryPath, + __in_opt + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + __in + PWDF_DRIVER_CONFIG DriverConfig, + __out_opt + WDFDRIVER* Driver + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver *pDriver; + NTSTATUS status; + WDFDRIVER hDriver; + const LONG validFlags = WdfDriverInitNonPnpDriver | + WdfDriverInitNoDispatchOverride; + + hDriver = NULL; + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DriverObject); + FxPointerNotNull(pFxDriverGlobals, RegistryPath); + FxPointerNotNull(pFxDriverGlobals, DriverConfig); + + // + // Validate the size of the input Driver Config structure. The size changed + // after v1.1. The size is the same for v1.1 and v1.0, verify that. + // + WDFCASSERT(sizeof(WDF_DRIVER_CONFIG_V1_0) == sizeof(WDF_DRIVER_CONFIG_V1_1)); + + if (DriverConfig->Size != sizeof(WDF_DRIVER_CONFIG) + && + DriverConfig->Size != sizeof(WDF_DRIVER_CONFIG_V1_1)) { + + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "WDF_DRIVER_CONFIG got Size %d, expected v1.1 size %d or cur ver size %d, %!STATUS!", + DriverConfig->Size, + sizeof(WDF_DRIVER_CONFIG_V1_1), sizeof(WDF_DRIVER_CONFIG), status); + + return status; + } + + // + // Validate the DriverInitFlags value in the Driver Config. + // + if ((DriverConfig->DriverInitFlags & ~validFlags) != 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "DriverInitFlags 0x%x invalid, valid flags are 0x%x, %!STATUS!", + DriverConfig->DriverInitFlags, validFlags, status); + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, RegistryPath); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Driver and Public.Driver are set once WdfDriverCreate returns successfully. + // If they are set, that means this DDI has already been called for this + // client. Return an error if this occurrs. + // + if (pFxDriverGlobals->Driver != NULL || + pFxDriverGlobals->Public.Driver != NULL) { + + status = STATUS_DRIVER_INTERNAL_ERROR; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "WdfDriverCreate can only be called one time per " + "WDM PDRIVER_OBJECT %p, %!STATUS!", + DriverObject, status); + + return status; + } + + if (Driver != NULL) { + *Driver = NULL; + } + + // + // Initializing the tag requires initializing the driver name first. + // + FxDriver::_InitializeDriverName(pFxDriverGlobals, RegistryPath); + + // + // Initialize the tag before any allocation so that we can use the correct + // tag value when allocating on behalf of the driver (for all allocations, + // including FxDriver). + // + // Use the client's driver tag value if they specified one. First check + // to make sure the size of the structure is the new size (vs the old size + // in v1.1). + // + // ' kdD' - was the default tag in many DDKs, don't allow its use. + // + if (DriverConfig->Size == sizeof(WDF_DRIVER_CONFIG) && + DriverConfig->DriverPoolTag != 0x0 && + DriverConfig->DriverPoolTag != ' kdD') { + // + // Copy directly using the driver's value + // + pFxDriverGlobals->Tag = DriverConfig->DriverPoolTag; + pFxDriverGlobals->Public.DriverTag = DriverConfig->DriverPoolTag; + } + else { + // + // Derive the value from the driver's service name + // + FxDriver::_InitializeTag(pFxDriverGlobals, DriverConfig); + } + + // + // Check to see if this is an NT4 style device driver. If so, fail if they + // specified an AddDevice routine. If no dispatch override is set, + // do not do any checking at all. + // + if (DriverConfig->DriverInitFlags & WdfDriverInitNoDispatchOverride) { + DO_NOTHING(); + } + else if ((DriverConfig->DriverInitFlags & WdfDriverInitNonPnpDriver) && + DriverConfig->EvtDriverDeviceAdd != NULL) { + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Invalid Driver flags or EvtDriverDeviceAdd callback already added" + "STATUS_INVALID_PARAMETER"); + + return STATUS_INVALID_PARAMETER; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, DriverAttributes, + (FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED | + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | + FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED) + ); + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // FxDriver stores the driver wide configuration + // + FxInitialize(pFxDriverGlobals, DriverObject, RegistryPath, DriverConfig); + + // + // FxDriver stores the driver wide configuration + // + pDriver = new(pFxDriverGlobals, DriverAttributes) + FxDriver(DriverObject, DriverConfig, pFxDriverGlobals); + + if (pDriver != NULL) { + + if (NT_SUCCESS(status)) { + + status = pDriver->Initialize(RegistryPath, DriverConfig, DriverAttributes); + + if (NT_SUCCESS(status)) { + status = pDriver->Commit(DriverAttributes, (WDFOBJECT*)&hDriver, FALSE); + } + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Only return a valid handle on success. Upon error, release any memory + // and do not rely on any other function (like the driver unload routine) to + // be called. + // + if (NT_SUCCESS(status)) { + // + // **** Note **** + // Do not introduce failures after this point without ensuring + // FxObject::DeleteFromFailedCreate has a chance to clear out any + // assigned callbacks on the object. + // + + // + // Store the WDFDRIVER and FxDriver* globally so the driver can retrieve + // it anytime. + // + pFxDriverGlobals->Driver = pDriver; + pFxDriverGlobals->Public.Driver = hDriver; + + // + // Record the flags so that diagnostics knows what type of driver it is. + // + pFxDriverGlobals->Public.DriverFlags |= DriverConfig->DriverInitFlags; + + if (DriverConfig->DriverInitFlags & + (WdfDriverInitNoDispatchOverride | WdfDriverInitNonPnpDriver)) { + // + // If there is no dispatch override or if it is an NT4 legacy style + // driver then we will not displace unload in the stub if one was not + // specified. + // + if (DriverConfig->EvtDriverUnload != NULL) { + pFxDriverGlobals->Public.DisplaceDriverUnload = TRUE; + } + else { + pFxDriverGlobals->Public.DisplaceDriverUnload = FALSE; + } + } + else { + pFxDriverGlobals->Public.DisplaceDriverUnload = TRUE; + } + + if (Driver != NULL) { + *Driver = hDriver; + } + + if (FX_TELEMETRY_ENABLED(g_TelemetryProvider, pFxDriverGlobals)) { + FxAutoString imageName; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + const PWCHAR pVersionStr = + FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WDF_BUILD_NUMBER) ; +#else // USER_MODE + const PWCHAR pVersionStr = + FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WUDF_SERVICE_VERSION) ; +#endif + + // + // GetImageName can fail if the registry cannot be accessed. This + // can happen during system shutdown. Since the image name is only + // used for telemetry the failure can be ignored. + // + (VOID) GetImageName(pFxDriverGlobals, &imageName.m_UnicodeString); + + WDF_CENSUS_EVT_WRITE_DRIVER_LOAD(g_TelemetryProvider, + pFxDriverGlobals, + imageName.m_UnicodeString.Buffer, + pVersionStr); + } + } + else { + if (pDriver != NULL) { + pDriver->DeleteFromFailedCreate(); + } + + FxDestroy(pFxDriverGlobals); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDriverRegisterTraceInfo)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PDRIVER_OBJECT DriverObject, + __in + PFN_WDF_TRACE_CALLBACK EvtTraceCallback, + __in + PVOID ControlBlock + ) +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(EvtTraceCallback); + UNREFERENCED_PARAMETER(ControlBlock); + + return STATUS_NOT_SUPPORTED; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDriverRetrieveVersionString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in + WDFSTRING String + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver* pDriver; + FxString* pString; + NTSTATUS status; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + const PWCHAR pVersionStr = + L"Kernel Mode Driver Framework version " + FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WDF_BUILD_NUMBER) ; + + const PWCHAR pVersionStrVerifier = + L"Kernel Mode Driver Framework (verifier on) version " + FX_MAKE_WSTR(__WDF_MAJOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WDF_MINOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WDF_BUILD_NUMBER); +#else // USER_MODE + const PWCHAR pVersionStr = + L"User Mode Driver Framework version " + FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WUDF_SERVICE_VERSION) ; + + const PWCHAR pVersionStrVerifier = + L"User Mode Driver Framework (verifier on) version " + FX_MAKE_WSTR(__WUDF_MAJOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WUDF_MINOR_VERSION_STRING) L"." + FX_MAKE_WSTR(__WUDF_SERVICE_VERSION); +#endif + + // + // Even though it is unused, still convert it to make sure a valid handle is + // being passed in. + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID *)&pDriver, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, String); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + String, + FX_TYPE_STRING, + (PVOID *)&pString); + + status = pString->Assign( + pFxDriverGlobals->FxVerifierOn ? pVersionStrVerifier : pVersionStr + ); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +BOOLEAN +WDFEXPORT(WdfDriverIsVersionAvailable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver* pDriver; + NTSTATUS status; + ULONG major, minor; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + major = __WDF_MAJOR_VERSION; + minor = __WDF_MINOR_VERSION; +#else + major = __WUDF_MAJOR_VERSION; + minor = __WUDF_MINOR_VERSION; +#endif + + // + // Even though it is unused, still convert it to make sure a valid handle is + // being passed in. + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID *)&pDriver, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, VersionAvailableParams); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return FALSE; + } + + if (VersionAvailableParams->Size != sizeof(WDF_DRIVER_VERSION_AVAILABLE_PARAMS)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "VersionAvailableParams Size 0x%x, expected 0x%x, %!STATUS!", + VersionAvailableParams->Size, sizeof(WDF_DRIVER_VERSION_AVAILABLE_PARAMS), + status); + + return FALSE; + } + + // + // We log at TRACE_LEVEL_INFORMATION so that we know it gets into the IFR at + // all times. This will make it easier to debug drivers which fail to load + // when a new minor version of WDF is installed b/c they are failing + // version checks. + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "IsVersionAvailable, current WDF ver major %d, minor %d, caller asking " + "about major %d, minor %d", major, minor, + VersionAvailableParams->MajorVersion, VersionAvailableParams->MinorVersion); + + // + // Currently we only support one major version per KMDF binary and we support + // all minor versions of that major version down to 0x0. + // + if (VersionAvailableParams->MajorVersion == major && + VersionAvailableParams->MinorVersion <= minor) { + return TRUE; + } + + return FALSE; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxfileobject.cpp b/sdk/lib/drivers/wdf/shared/core/fxfileobject.cpp new file mode 100644 index 00000000000..339ddabcc24 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxfileobject.cpp @@ -0,0 +1,565 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObject.hpp + +Abstract: + + This module implements a frameworks managed FileObject + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxFileObject.tmh" +} + +// +// Public constructors +// + + +FxFileObject::FxFileObject( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in MdFileObject pWdmFileObject, + __in FxDevice* pDevice + ) : + FxNonPagedObject(FX_TYPE_FILEOBJECT, sizeof(FxFileObject), FxDriverGlobals) +{ + m_FileObject.SetFileObject(pWdmFileObject); + m_PkgContext = NULL; + m_Device = pDevice; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + RtlInitUnicodeString(&m_FileName, NULL); + m_RelatedFileObject = NULL; +#endif + + // + // Cannot be deleted by the device driver + // + MarkNoDeleteDDI(); +} + +FxFileObject::~FxFileObject() +{ +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + SAFE_RELEASE(m_RelatedFileObject); +#endif +} + +// +// 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; +} + +// +// 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; +} + +// +// 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; +} + +VOID +FxFileObject::DeleteFileObjectFromFailedCreate( + VOID + ) +{ + KIRQL irql; + + // + // Remove it from the list of FxFileObjects on the FxDevice + // + m_Device->Lock(&irql); + RemoveEntryList(&m_Link); + m_Device->Unlock(irql); + + // Delete the file object + DeleteFromFailedCreate(); +} + +_Must_inspect_result_ +NTSTATUS +FxFileObject::QueryInterface( + __in FxQueryInterfaceParams* Params + ) +/*++ + +Routine Description: + This routine is used to return the pointer to the Object itself. + +Arguments: + Params - query interface parameters. + +Return Value: + NTSTATUS + +--*/ + +{ + switch (Params->Type) { + case FX_TYPE_FILEOBJECT: + *Params->Object = (FxFileObject*) this; + break; + + case FX_TYPE_IHASCALLBACKS: + *Params->Object = (IFxHasCallbacks*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; +} + +VOID +FxFileObject::GetConstraints( + __in WDF_EXECUTION_LEVEL* ExecutionLevel, + __in WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) +/*++ + +Routine Description: + This routine implements the GetConstraints IfxCallback. The caller gets the + ExecutionLevel and the SynchronizationScope of the FileObject. The FileObject's + SynchronizationScope and ExecutionLevel is strored in the FxPkgGeneral object. + +Arguments: + ExecutionLevel - (opt) receives the execution level. + + SynchronizationScope - (opt) receives the synchronization scope. + +Return Value: + None + +--*/ + +{ + // + // Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time. + // + return GetDevice()->m_PkgGeneral->GetConstraintsHelper(ExecutionLevel, SynchronizationScope); +} + +_Must_inspect_result_ +FxCallbackLock* +FxFileObject::GetCallbackLockPtr( + __deref_out_opt FxObject** LockObject + ) +/*++ + +Routine Description: + This routine implements the GetCallbackLockPtr IfxCallback. The caller gets the + LockObject to be used before calling the driver callbacks. + +Arguments: + LockObject - receives the lock object. + +Return Value: + FxCallbackLock * + +--*/ + +{ + // + // Get it from FxPkgGeneral which has the File attributes passed to it at device Creation time. + // + return GetDevice()->m_PkgGeneral->GetCallbackLockPtrHelper(LockObject); +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/fxfileobjectapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxfileobjectapi.cpp new file mode 100644 index 00000000000..4589ddfbd6e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxfileobjectapi.cpp @@ -0,0 +1,181 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectApi.cpp + +Abstract: + + This modules implements the C API's for the FxFileObject. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" +#include "FxFileObject.hpp" + +extern "C" { +#include "FxFileObjectApi.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +__drv_maxIRQL(PASSIVE_LEVEL) +PUNICODE_STRING +WDFEXPORT(WdfFileObjectGetFileName)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFFILEOBJECT FileObject + ) + +/*++ + +Routine Description: + + This returns the UNICODE_STRING for the FileName inside + the WDM fileobject. + +Arguments: + + FileObject - WDFFILEOBJECT + +Return Value: + + PUNICODE_STRING (file name) + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return NULL; + } + + if (pFO->GetWdmFileObject() != NULL) { + return pFO->GetFileName(); + } + else { + return NULL; + } +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfFileObjectGetFlags)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFFILEOBJECT FileObject + ) + +/*++ + +Routine Description: + + This returns the flags inside the WDM fileobject. + +Arguments: + + FileObject - WDFFILEOBJECT + +Return Value: + + ULONG (flags) + +--*/ + +{ + DDI_ENTRY(); + + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + if (pFO->GetWdmFileObject() != NULL) { + return pFO->GetFlags(); + } + else { + return 0x0; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfFileObjectGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFFILEOBJECT FileObject + ) + +/*++ + +Routine Description: + + This returns the Device that the fileobject is associated with. + +Arguments: + + FileObject - WDFFILEOBJECT + +Return Value: + + WDFDEVICE + +--*/ + +{ + DDI_ENTRY(); + + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + return pFO->GetDevice()->GetHandle(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxirpqueue.cpp b/sdk/lib/drivers/wdf/shared/core/fxirpqueue.cpp new file mode 100644 index 00000000000..26baa1d236f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxirpqueue.cpp @@ -0,0 +1,964 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIrpQueue.cpp + +Abstract: + + This module implements a common queue structure for the + driver frameworks built around the Cancel Safe Queue model + +Author: + + + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxIrpQueue.tmh" +} + +// +// Public constructors +// + +FxIrpQueue::FxIrpQueue( + VOID + ) +{ + InitializeListHead(&m_Queue); + + m_LockObject = NULL; + + m_CancelCallback = NULL; + + m_RequestCount = 0; +} + +FxIrpQueue::~FxIrpQueue() +{ + ASSERT(IsListEmpty(&m_Queue)); +} + +VOID +FxIrpQueue::Initialize( + __in FxNonPagedObject* LockObject, + __in PFN_IRP_QUEUE_CANCEL Callback + ) + +/*++ + +Routine Description: + + Initialize the FxIrpQueue. + + Set the callback for when an IRP gets cancelled. + + The callback function is only called when an IRP + gets cancelled, and is called with no locks held. + + The cancel function that the caller registers is + responsible for completing the IRP with IoCompleteRequest. + + If no Cancel Callback is set, or is set to NULL, IRP's will + be automatically completed with STATUS_CANCELED by + the FxIrpQueue when they are canceled. + + + If the caller supplies a LockObject, this object is used + to synchronize cancellation access to the list, but it is + expected that the caller be holding the same lock for insert/remove + operations. This allows the caller to perform insert/remove operations + using its own lock in a race free manner. + + If a LockObject is not supplied, the FxIrpQueue uses its own lock. + +Arguments: + + LockObject - Object whose lock controls the queue + + Callback - Driver callback function + +Returns: + + None + +--*/ + +{ + ASSERT(LockObject != NULL); + + m_CancelCallback = Callback; + m_LockObject = LockObject; +} + + +_Must_inspect_result_ +NTSTATUS +FxIrpQueue::InsertTailRequest( + __inout MdIrp Irp, + __in_opt PMdIoCsqIrpContext Context, + __out_opt ULONG* pRequestCount + ) + +/*++ + +Routine Description: + + Enqueue a request to the end of the queue (FIFO) and + marks it as pending. + + The PMdIoCsqIrpContext is associated with the IRP. + + PIO_CSQ_IRP_CONTEXT must be in non-paged pool, and can + not be released until the IRP is is finally released from + the queue. + +Arguments: + + Irp - Pointer to IRP + + Context - Pointer to caller allocated CSQ context + + pRequestCount - Location to return new request count of queue + after insertion + +Returns: + + STATUS_SUCCESS - Operation completed. + + STATUS_CANCELLED - Request was cancelled, and not inserted + Call is responsible for completing it. +--*/ + +{ + NTSTATUS Status; + + // Note: This marks the IRP Pending + Status = InsertIrpInQueue( + Irp, // Irp to insert + Context, // PIO_CSQ_IRP_CONTEXT + FALSE, // InsertInHead + pRequestCount + ); + + return Status; +} + + +_Must_inspect_result_ +NTSTATUS +FxIrpQueue::InsertHeadRequest( + __inout MdIrp Irp, + __in_opt PMdIoCsqIrpContext Context, + __out_opt ULONG* pRequestCount + ) + +/*++ + +Routine Description: + + Enqueue a request to the head of the queue and + marks it as pending. + + The PIO_CSQ_IRP_CONTEXT is associated with the IRP. + + PIO_CSQ_IRP_CONTEXT must be in non-paged pool, and can + not be released until the IRP is is finally released from + the queue. + +Arguments: + + Irp - Pointer to IRP + + Context - Pointer to caller allocated CSQ context + + pRequestCount - Location to return new request count of queue + after insertion +Returns: + + STATUS_SUCCESS - Operation completed. + + STATUS_CANCELLED - Request was cancelled, and not inserted + Call is responsible for completing it. +--*/ + +{ + NTSTATUS Status; + + // Note: This marks the IRP Pending + Status = InsertIrpInQueue( + Irp, // Irp to insert + Context, // PIO_CSQ_IRP_CONTEXT + TRUE, // InsertInHead + pRequestCount + ); + + return Status; +} + + +MdIrp +FxIrpQueue::GetNextRequest( + __out PMdIoCsqIrpContext* pCsqContext + ) + +/*++ + +Routine Description: + + Returns an IRP from the queue, and if successful + the IRP is no longer on the CSQ (m_Queue) and + is not non-cancellable. + +--*/ + +{ + return RemoveNextIrpFromQueue(NULL, pCsqContext); +} + + +_Must_inspect_result_ +NTSTATUS +FxIrpQueue::GetNextRequest( + __in_opt PMdIoCsqIrpContext TagContext, + __in_opt MdFileObject FileObject, + __out FxRequest** ppOutRequest + ) + +/*++ + +Routine Description: + + Returns a request from the queue using an optional + FileObject or TagContext. + +--*/ + +{ + MdIrp Irp; + FxRequest* pRequest; + PMdIoCsqIrpContext pCsqContext; + + if( TagContext == NULL ) { + + // + // Returns an IRP from the queue, and if successful + // the IRP is no longer on the CSQ (m_Queue) and + // is not non-cancellable. + // + Irp = RemoveNextIrpFromQueue( + FileObject, // PeekContext + &pCsqContext + ); + + if( Irp != NULL ) { + + pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext); + + *ppOutRequest = pRequest; + + return STATUS_SUCCESS; + } + else { + return STATUS_NO_MORE_ENTRIES; + } + } + else { + + // Handle TagRequest Case + Irp = RemoveIrpFromQueueByContext( + TagContext + ); + + if( Irp != NULL ) { + pRequest = FxRequest::RetrieveFromCsqContext(TagContext); + + *ppOutRequest = pRequest; + + return STATUS_SUCCESS; + } + else { + return STATUS_NOT_FOUND; + } + } +} + +_Must_inspect_result_ +NTSTATUS +FxIrpQueue::PeekRequest( + __in_opt PMdIoCsqIrpContext TagContext, + __in_opt MdFileObject FileObject, + __out FxRequest** ppOutRequest + ) + +/*++ + +Routine Description: + + PeekRequest allows a caller to enumerate through requests in + a queue, optionally only returning requests that match a specified + FileObject. + + The first call specifies TagContext == NULL, and the first request + in the queue that matches the FileObject is returned. + + Subsequent requests specify the previous request value as the + TagContext, and searching will continue at the request that follows. + + If the queue is empty, there are no requests after TagContext, or no + requests match the FileObject, NULL is returned. + + If FileObject == NULL, this matches any FileObject in a request. + + If a WDF_REQUEST_PARAMETERS structure is supplied, the information + from the request is returned to allow the driver to further examine + the request to decide whether to service it. + + If a TagRequest is specified, and it is not found, the return + status STATUS_NOT_FOUND means that the queue should + be re-scanned. This is because the TagRequest was cancelled from + the queue, or if the queue was active, delivered to the driver. + There may still be un-examined requests on the queue that match + the drivers search criteria, but the search marker has been lost. + + Re-scanning the queue starting with TagRequest == NULL and + continuing until STATUS_NO_MORE_ENTRIES is returned will ensure + all requests have been examined. + + Enumerating an active queue with this API could result in the + driver frequently having to re-scan. + + If a successful return of a Request object handle occurs, the driver + *must* call WdfObjectDereference when done with it. + + NOTE: Synchronization Details + + The driver is allowed to "peek" at requests that are still on + the Cancel Safe Queue without removing them. This means that + the peek context value used (TagRequest) could go away while + still holding it. This does not seem bad in itself, but the request + could immediately be re-used by a look aside list and be re-submitted + to the queue. At this point, the "tag" value means a completely different + request. + + This race is dealt with by reference counting the FxRequest object + that contains our PIO_CSQ_IRP_CONTEXT, so its memory remains valid + after a cancel, and the driver explicitly releases it with + WdfObjectDereference. + + But if this reference is not added under the CSQ's spinlock, there + could be a race in which the I/O gets cancelled and the cancel + callback completes the request, before we add our reference count. + This would then result in attempting to reference count invalid + memory. So to close this race, this routine returns the referenced + FxRequest object as its result. + +Arguments: + + TagRequest - If !NULL, request to begin search at + + FileObject - If !NULL, FileObject to match in the request + + +Returns: + + STATUS_NOT_FOUND - TagContext was specified, but not + found in the queue. This could be + because the request was cancelled, + or is part of an active queue and + the request was passed to the driver + or forwarded to another queue. + + STATUS_NO_MORE_ENTRYS - The queue is empty, or no more requests + match the selection criteria of TagRequest + and FileObject specified above. + + STATUS_SUCCESS - A request context was returned in + pOutRequest. + +--*/ + +{ + PLIST_ENTRY nextEntry; + FxIrp nextIrp(NULL); + PMdIoCsqIrpContext pCsqContext; + BOOLEAN FoundTag = (TagContext == NULL) ? TRUE : FALSE; + FxRequest* pRequest; + + for( nextEntry = m_Queue.Flink; nextEntry != &this->m_Queue; nextEntry = nextEntry->Flink) { + + nextIrp.SetIrp(FxIrp::GetIrpFromListEntry(nextEntry)); + + if(nextIrp.IsCanceled()) { + // + // This IRP is cancelled and the WdmCancelRoutine is about to run or waiting + // for us to drop the lock. So skip this one. + // + continue; + } + + pCsqContext = (PMdIoCsqIrpContext)nextIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY); + + if( FoundTag ) { + + if( FileObject != NULL ) { + + if(nextIrp.GetFileObject() == FileObject ) { + + pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext); + + // + // Must add the reference here under the protection + // of the cancel safe queues spinlock + // + pRequest->ADDREF(NULL); + + *ppOutRequest = pRequest; + + return STATUS_SUCCESS; + } + } + else { + + pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext); + + // + // Must add the reference here under the protection + // of the cancel safe queues spinlock + // + pRequest->ADDREF(NULL); + + *ppOutRequest = pRequest; + + return STATUS_SUCCESS; + } + } + else { + + // If we found the tag, we want the *next* entry + if( pCsqContext == TagContext ) { + FoundTag = TRUE; + } + } + + } + + // + // If the caller supplied a tag, and it was + // not found, return a different code since + // the caller needs to re-scan the queue. + // + if( (TagContext != NULL) && !FoundTag ) { + return STATUS_NOT_FOUND; + } + else { + return STATUS_NO_MORE_ENTRIES; + } +} + +MdIrp +FxIrpQueue::RemoveRequest( + __in PMdIoCsqIrpContext Context + ) +/*++ + +Routine Description: + + Returns a request from the queue. + +--*/ +{ + MdIrp Irp; + + ASSERT(Context != NULL); + + // + // Returns an IRP from the queue, and if success + // the IRP is no longer on the CSQ (m_Queue) and + // is not non-cancellable. + // + Irp = RemoveIrpFromQueueByContext(Context); + + return Irp; +} + +_Must_inspect_result_ +NTSTATUS +FxIrpQueue::InsertIrpInQueue( + __inout MdIrp Irp, + __in_opt PMdIoCsqIrpContext Context, + __in BOOLEAN InsertInHead, + __out_opt ULONG* pRequestCount + ) +/*++ + +Routine Description: + + Insert the IRP in the queue. If the IRP is already cancelled + it removes the IRP from the queue and returns STATUS_CANCELLED. + + If the IRP is cancelled and the CancelRoutine has already started + execution, then this function returns STATUS_SUCCESS. + +Arguments: + + Irp - Pointer to IRP + + Context - Pointer to caller allocated CSQ context + + InsertInHead - TRUE for head, FALSE for tail. + + pRequestCount - Location to return new request count of queue + after insertion + +Returns: + + STATUS_SUCCESS - Operation completed. + + STATUS_CANCELLED - if the request is already cancelled. + +--*/ +{ + FxIrp irp(Irp); + MdCancelRoutine cancelRoutine; + NTSTATUS status = STATUS_SUCCESS; + + // + // Set the association between the context and the IRP. + // + + if (Context) { + irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, Context); + Context->Irp = Irp; + Context->Csq = (PIO_CSQ)this; + + + + + + + + + + + Context->Type = FX_IRP_QUEUE_ENTRY_IDENTIFIER; + } else { + + // + // Currently always require context, but this will change when we + // allow queuing or low level IRP's without FxRequest headers allocated + // + ASSERT(FALSE); + + irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, this); + } + + // See if it's a head insertion + if( InsertInHead ) { + InsertHeadList( + &m_Queue, + irp.ListEntry() + ); + } + else { + InsertTailList( + &m_Queue, + irp.ListEntry() + ); + } + + m_RequestCount++; + + if( pRequestCount != NULL ) { + *pRequestCount = m_RequestCount; + } + + irp.MarkIrpPending(); + + cancelRoutine = irp.SetCancelRoutine(_WdmCancelRoutineInternal); + + ASSERT(!cancelRoutine); + UNREFERENCED_PARAMETER(cancelRoutine); + + if (irp.IsCanceled()) { + + cancelRoutine = irp.SetCancelRoutine(NULL); + + if (cancelRoutine) { + + // Remove the IRP from the list + RemoveIrpFromListEntry(&irp); + + if (Context) { + Context->Irp = NULL; + } + + irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL); + + // + // Caller does not want us to recurse on their lock by invoking + // the m_CancelCallback on the insert path. So they will complete + // the IRP themselves. + // + return STATUS_CANCELLED; + } else { + + // + // The cancel routine beat us to it. + // + DO_NOTHING(); + } + + } + + return status; +} + +VOID +FX_VF_METHOD(FxIrpQueue, VerifyRemoveIrpFromQueueByContext)( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PMdIoCsqIrpContext Context + ) +/*++ + +Routine Description: + + Makes sure that the specified Request (context) belongs to this IRP queue. + +--*/ +{ + PAGED_CODE_LOCKED(); + + if (FxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) { + if (Context->Irp != NULL && + (Context->Type != FX_IRP_QUEUE_ENTRY_IDENTIFIER || + Context->Csq != (PIO_CSQ)this)) { + + // + // This should never happen. Bugcheck before corrupting memory. + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Irp 0x%p (Context 0x%p) not on IRP queue 0x%p\n", + Context->Irp, Context, this); + + FxVerifierBugCheck(FxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_REQUEST_NOT_IN_QUEUE, + (ULONG_PTR) Context); + } + } +} + +MdIrp +FxIrpQueue::RemoveIrpFromQueueByContext( + __in PMdIoCsqIrpContext Context + ) +/*++ + +Routine Description: + + Using the context it remove the associated IRP from the queue. + +--*/ +{ + MdIrp irp; + MdCancelRoutine cancelRoutine; + + if (Context->Irp ) { + // + // Make sure the Irp belongs to this queue. + // + ASSERT(Context->Csq == (PIO_CSQ)this); + VerifyRemoveIrpFromQueueByContext(m_LockObject->GetDriverGlobals(), + Context); + + irp = Context->Irp; + + FxIrp fxIrp(irp); + + cancelRoutine = fxIrp.SetCancelRoutine(NULL); + if (!cancelRoutine) { + return NULL; + } + + ASSERT(Context == fxIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY)); + + RemoveIrpFromListEntry(&fxIrp); + + // + // Break the association. + // + + Context->Irp = NULL; + fxIrp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL); + + ASSERT(Context->Csq == (PIO_CSQ)this); + + return irp; + + } else { + return NULL; + } +} + + +MdIrp +FxIrpQueue::PeekNextIrpFromQueue( + __in_opt MdIrp Irp, + __in_opt PVOID PeekContext + ) +/*++ + +Routine Description: + + This API look up IRP's in the queue. + + If Irp == NULL, it returns one from the head + of the queue. + + If Irp != NULL, it is a "peek context", and the + routine returns the *next* IRP in the queue. + +--*/ +{ + PLIST_ENTRY nextEntry; + PLIST_ENTRY listHead; + FxIrp irp(Irp); + FxIrp nextIrp(NULL); + + listHead = &m_Queue; + + // + // If the IRP is NULL, we will start peeking from the listhead, else + // we will start from that IRP onwards. This is done under the + // assumption that new IRPs are always inserted at the tail. + // + + if(Irp == NULL) { + nextEntry = listHead->Flink; + } else { + nextEntry = irp.ListEntry()->Flink; + } + + while(nextEntry != listHead) { + + nextIrp.SetIrp(FxIrp::GetIrpFromListEntry(nextEntry)); + + // + // If PeekContext is supplied, it's a search for an IRP associated + // with a particular file object. + // + if(PeekContext) { + + if(nextIrp.GetFileObject() == (MdFileObject) PeekContext) { + break; + } + } else { + break; + } + + nextIrp.SetIrp(NULL); + + nextEntry = nextEntry->Flink; + } + + return nextIrp.GetIrp(); +} + +MdIrp +FxIrpQueue::RemoveNextIrpFromQueue( + __in_opt PVOID PeekContext, + __out_opt PMdIoCsqIrpContext* pCsqContext + ) +/*++ + +Routine Description: + + This routine will return a pointer to the next IRP in the queue adjacent to + the irp passed as a parameter. If the irp is NULL, it returns the IRP at the head of + the queue. + +--*/ +{ + PMdIoCsqIrpContext context; + MdCancelRoutine cancelRoutine; + FxIrp fxIrp(NULL); + + fxIrp.SetIrp(PeekNextIrpFromQueue(NULL, PeekContext)); + + for (;;) { + + if (!fxIrp.GetIrp()) { + return NULL; + } + + cancelRoutine = fxIrp.SetCancelRoutine(NULL); + if (!cancelRoutine) { + fxIrp.SetIrp(PeekNextIrpFromQueue(fxIrp.GetIrp(), PeekContext)); + continue; + } + + RemoveIrpFromListEntry(&fxIrp); // Remove this IRP from the queue + + break; + } + + context = (PMdIoCsqIrpContext)fxIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY); + if (context->Type == FX_IRP_QUEUE_ENTRY_IDENTIFIER) { + context->Irp = NULL; + ASSERT(context->Csq == (PIO_CSQ)this); + } + + if(pCsqContext != NULL) { + *pCsqContext = context; + } + + fxIrp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL); + + return fxIrp.GetIrp(); +} + + +VOID +FxIrpQueue::_WdmCancelRoutineInternal( + __inout MdDeviceObject DeviceObject, + __in __drv_useCancelIRQL MdIrp Irp + ) +/*++ + +Routine Description: + + This is the function called by WDM on the IRP when a cancel occurs + +--*/ +{ + PMdIoCsqIrpContext irpContext; + FxIrpQueue* p; + KIRQL irql; + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER (DeviceObject); + + Mx::ReleaseCancelSpinLock(irp.GetCancelIrql()); + + irpContext = (PMdIoCsqIrpContext)irp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY); + + // + // Decide if we have a PIO_CSQ_IRP_CONTEXT or an FxIrpQueue* + // + if (irpContext->Type == FX_IRP_QUEUE_ENTRY_IDENTIFIER) { + p = (FxIrpQueue*)irpContext->Csq; + } else { + ASSERT(FALSE); + p = (FxIrpQueue*)irpContext; + } + + ASSERT(p); + + p->LockFromCancel(&irql); + + // Remove the IRP from the list + p->RemoveIrpFromListEntry(&irp); + + // + // Break the association if necessary. + // + + if (irpContext != (PMdIoCsqIrpContext)p) { + irpContext->Irp = NULL; + + irp.SetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY, NULL); + } + + // + // We are calling cancel-callback of the owning object with the lock + // held so that it can successfully deliver the canceled request to the driver + // if needed. If we don't hold the lock, we run into a race condition between + // thread that's deleting the queue and this routine that's trying to deliver + // a request to the queue being deleted. So the way it happens is that the dispose + // call of queue waits for the request count to go zero. When we remove the + // last Irp from the list above, we end up dropping the count to zero. This causes + // the delete thread to run thru and destroy the FxIoQueue object. So to avoid that + // after popping the request from the FxIrpQueue, we have to call into the FxIoQueue + // with the lock and insert the request back into the FxIoQueue list so that delete + // thread will wait until the request is delivered to the driver. + // + if( p->m_CancelCallback != NULL ) { + p->m_CancelCallback(p, Irp, irpContext, irql); + } + else { + + p->UnlockFromCancel(irql); + + // + // Dispose of the IRP ourselves + // + irp.SetStatus(STATUS_CANCELLED); + irp.SetInformation(0); + + DoTraceLevelMessage(p->m_LockObject->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Irp 0x%p on Queue 0x%p Cancelled\n", Irp, p); + + // + // Breakpoint for now. This usually means that someone + // is going to leak some driver frameworks state... + // + FxVerifierDbgBreakPoint(p->m_LockObject->GetDriverGlobals()); + + irp.CompleteRequest(IO_NO_INCREMENT); + } +} + +BOOLEAN +FxIrpQueue::IsIrpInQueue( + __in PMdIoCsqIrpContext Context + ) +/*++ + +Routine Description: + Enumerates the list to see if any of the IRPs there has + a context that matches the input one. + +--*/ +{ + PLIST_ENTRY nextEntry; + FxIrp nextIrp(NULL); + PMdIoCsqIrpContext pCsqContext; + + nextEntry = m_Queue.Flink; + + while( nextEntry != &m_Queue ) { + nextIrp.SetIrp(FxIrp::GetIrpFromListEntry(nextEntry)); + + pCsqContext = (PMdIoCsqIrpContext)nextIrp.GetContext(FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY); + + if( pCsqContext == Context ) { + ASSERT(Context->Irp == nextIrp.GetIrp()); + return TRUE; + } + + nextEntry = nextEntry->Flink; + } + + return FALSE; +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/fxlock.cpp b/sdk/lib/drivers/wdf/shared/core/fxlock.cpp new file mode 100644 index 00000000000..560e6ebc822 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxlock.cpp @@ -0,0 +1,59 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxLock.cpp + +Abstract: + + This module contains the implementation of FxLock + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +VOID +FxLock::Initialize( + __in FxObject * ParentObject + ) +/*++ + +Routine Description: + This is called to initialize the verifier with the object type so it can + track lock order and sequence. + +Arguments: + ParentObject - the owning object + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = ParentObject->GetDriverGlobals(); + + if (pFxDriverGlobals->FxVerifierLock) { + // + // Allocation failure is not fatal, we just won't track anything + // + + (void) FxVerifierLock::CreateAndInitialize(&m_Verifier, + pFxDriverGlobals, + ParentObject); + } +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxlookasidelist.cpp b/sdk/lib/drivers/wdf/shared/core/fxlookasidelist.cpp new file mode 100644 index 00000000000..b5867a75d75 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxlookasidelist.cpp @@ -0,0 +1,217 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxLookasideList.cpp + +Abstract: + + This module implements a frameworks managed FxLookasideList + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "FxLookasideList.hpp" + +FxLookasideList::FxLookasideList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in ULONG PoolTag + ) : + FxObject(FX_TYPE_LOOKASIDE, ObjectSize, FxDriverGlobals), + m_BufferSize(0), m_PoolTag(PoolTag), m_MemoryObjectSize(0) +/*++ + +Routine Description: + Constructor for FxLookasideList + +Arguments: + ObjectSize - Size of the derived object. + + PoolTag - Tag to use when allocating memory. + +Return Value: + None + + --*/ +{ +} + +FxLookasideList::~FxLookasideList() +/*++ + +Routine Description: + Destructor for FxLookasideList. Default implementation does nothing. + Derived classes will call the appropriate NTOS export to remove itself from + the list of lookaside lists. + +Arguments: + None + +Return Value: + None + + --*/ +{ +} + +_Must_inspect_result_ +NTSTATUS +FxLookasideList::InitializeLookaside( + __in USHORT BufferSize, + __in USHORT MemoryObjectSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) +/*++ + +Routine Description: + Computes the memory object size to be used by the derived class. This + function handles the overflow in computing the size and returns an error + if that occurs. + +Arguments: + BufferSize - the length of the buffer being allocated alongside the object + + MemoryObjectSize - the raw size of the FxObject derived object, ie + sizeof(FxMemoryBufferFromLookaside) + + MemoryAttributes - attributes to be associated for each memory object created + +Return Value: + None + + --*/ +{ + size_t size; + NTSTATUS status; + + if (MemoryAttributes != NULL) { + RtlCopyMemory(&m_MemoryAttributes, + MemoryAttributes, + sizeof(m_MemoryAttributes)); + } + else { + RtlZeroMemory(&m_MemoryAttributes, sizeof(m_MemoryAttributes)); + } + + status = FxCalculateObjectTotalSize(GetDriverGlobals(), + MemoryObjectSize, + BufferSize, + &m_MemoryAttributes, + &size); + + if (!NT_SUCCESS(status)) { + // + // FxCalculateObjectTotalSize logs an error to the IFR + // + return status; + } + + status = FxPoolAddHeaderSize(GetDriverGlobals(), size, &size); + if (!NT_SUCCESS(status)) { + // + // FxPoolAddHeaderSize logs to the IFR on error + // + return status; + } + + // + // It is *required* to set these values only once we know we are returning + // success b/c the derived classes use == 0 as an indication that Initialization + // failed and that any associated lookaside lists were not initialized. + // + m_MemoryObjectSize = size; + m_BufferSize = BufferSize; + + return status; +} + +#pragma prefast(push) + + + +//This routine intentionally accesses the header of the allocated memory. +#pragma prefast(disable:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) +PVOID +FxLookasideList::InitObjectAlloc( + __out_bcount(this->m_MemoryObjectSize) PVOID Alloc + ) +/*++ + +Routine Description: + Initializes the object allocation so that it can be tracked and inserted + in this drivers POOL. + +Arguments: + Alloc - the raw allocation + +Return Value: + the start of where the object memory should be, not necessarily == Alloc + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PFX_POOL_HEADER pHeader; + PFX_POOL_TRACKER tracker; + + pFxDriverGlobals = GetDriverGlobals(); + + RtlZeroMemory(Alloc, m_MemoryObjectSize); + + if (pFxDriverGlobals->IsPoolTrackingOn()) { + // + // PoolTracking is active, so format and insert + // a tracker in the NonPagedHeader list of the pool. + // + tracker = (PFX_POOL_TRACKER) Alloc; + pHeader = WDF_PTR_ADD_OFFSET_TYPE(Alloc, + sizeof(FX_POOL_TRACKER), + PFX_POOL_HEADER); + + pHeader->Base = Alloc; + pHeader->FxDriverGlobals = pFxDriverGlobals; + + FxPoolInsertNonPagedAllocateTracker( + &pFxDriverGlobals->FxPoolFrameworks, + tracker, + m_BufferSize, + m_PoolTag, + _ReturnAddress()); + } + else { + // + // PoolTracking is inactive, only format FX_POOL_HEADER area. + // + pHeader = (PFX_POOL_HEADER) Alloc; + pHeader->Base = Alloc; + pHeader->FxDriverGlobals = pFxDriverGlobals; + } + + return &pHeader->AllocationStart[0]; +} +#pragma prefast(pop) + +VOID +FxLookasideList::_Reclaim( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout PNPAGED_LOOKASIDE_LIST List, + __in FxMemoryBufferFromLookaside* Memory + ) +{ + PFX_POOL_HEADER pHeader; + + pHeader = FxObject::_CleanupPointer(FxDriverGlobals, (FxObject*) Memory); + + FxFreeToNPagedLookasideList(List, pHeader->Base); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxlookasidelistapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxlookasidelistapi.cpp new file mode 100644 index 00000000000..bb6b84c152e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxlookasidelistapi.cpp @@ -0,0 +1,300 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxLookasideListApi.cpp + +Abstract: + + This modules implements the C API's for the FxLookasideList. + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "FxNPagedLookasideList.hpp" +#include "FxPagedLookasideList.hpp" + +extern "C" { +#include "FxLookasideListAPI.tmh" +} + +extern "C" { + +_Must_inspect_result_ +__drv_when(PoolType == 1 || PoolType == 257, __drv_maxIRQL(APC_LEVEL)) +__drv_when(PoolType == 0 || PoolType == 256, __drv_maxIRQL(DISPATCH_LEVEL)) +NTSTATUS +WDFAPI +WDFEXPORT(WdfLookasideListCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES LookasideAttributes, + __in + __drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + __in + __drv_strictTypeMatch(__drv_typeExpr) + POOL_TYPE PoolType, + __in_opt + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + __in_opt + ULONG PoolTag, + __out + WDFLOOKASIDE* PLookaside + ) +/*++ + +Routine Description: + Creates a WDFLOOKASIDE list handle. The returned handle can then create + WDFMEMORY handles on behalf of the client driver. The underlying + WDFLOOKASIDE is a true NTOS lookaside list (of the appropriate paged or + npaged variety). + +Arguments: + LookasideAttributes - Object attributes for the lookaside handle being + created + + BufferSize - Specifies how big each buffer created by the lookaside is + + PoolType - Indicates whether the lookaside list is to create paged or + nonpaged WDFMEMORY handles. + + MemoryAttributes - Attributes to be associated with each memory handle created + using the created lookaside list handle + + PoolTag - Pool tag to use for each allocation. If 0, the frameworks tag + will be used + + PLookaside - Pointer to store the created handle + +Return Value: + STATUS_INVALID_PARAMETER if any of the required parameters are incorrect + + STATUS_INSUFFICIENT_RESOURCES if no memory is available to create the list + + STATUS SUCCESS if succesful + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxLookasideList *pLookaside; + WDFLOOKASIDE hLookaside; + NTSTATUS status; + FxObject* pParent; + + pParent = NULL; + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle( + pFxDriverGlobals, + LookasideAttributes))) { + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + LookasideAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + else if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle( + pFxDriverGlobals, + MemoryAttributes))) { + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + MemoryAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, PLookaside); + + hLookaside = NULL; + *PLookaside = NULL; + + if (BufferSize == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Zero BufferSize not allowed, %!STATUS!", status); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, LookasideAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, MemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (PoolTag == 0) { + PoolTag = pFxDriverGlobals->Tag; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, PoolTag); + + // + // Create the appropriate object + // + if (FxIsPagedPoolType(PoolType) == FALSE) { + if (BufferSize < PAGE_SIZE) { + pLookaside = new(pFxDriverGlobals, LookasideAttributes) + FxNPagedLookasideList(pFxDriverGlobals, PoolTag); + } + else { + pLookaside = new(pFxDriverGlobals, LookasideAttributes) + FxNPagedLookasideListFromPool(pFxDriverGlobals, PoolTag); + } + } + else { + FxDeviceBase* pLookasideDB, *pMemoryDB; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + pLookasideDB = FxDeviceBase::_SearchForDevice(pFxDriverGlobals, + LookasideAttributes); + + pMemoryDB = FxDeviceBase::_SearchForDevice(pFxDriverGlobals, + MemoryAttributes); + + if (pLookasideDB != NULL && pMemoryDB != NULL && + pLookasideDB != pMemoryDB) { + status = STATUS_INVALID_PARAMETER; + + // + // No need to check if LookasideAttributes or MemoryAttributes are + // equal to NULL b/c we could not get a valid pLookasideDB or + // pMemoryDB if they were NULL. + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Lookaside Attributes ancestor WDFDEVICE %p (from ParentObject %p) " + " is not the same as Memory Attributes ancestor WDFDEVICE %p " + "(from ParentObject %p), %!STATUS!", + pLookasideDB->GetHandle(), LookasideAttributes->ParentObject, + pMemoryDB->GetHandle(), MemoryAttributes->ParentObject, + status); + + return status; + } + + // + // For paged allocations we always split the WDFMEMORY from its buffer + // pointer because the memory behind the WDFMEMORY must be non pageable + // while its buffer is pageable. + // + pLookaside = new(pFxDriverGlobals, LookasideAttributes) + FxPagedLookasideListFromPool(pFxDriverGlobals, + PoolTag, + pLookasideDB, + pMemoryDB); + } + + if (pLookaside == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pLookaside->Initialize(BufferSize, MemoryAttributes); + + if (NT_SUCCESS(status)) { + // + // Follow the global driver policy and either return a PVOID cookie or + // an index into a handle table. + // + status = pLookaside->Commit(LookasideAttributes, (WDFOBJECT*)&hLookaside); + } + + if (NT_SUCCESS(status)) { + *PLookaside = hLookaside; + } + else { + pLookaside->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfMemoryCreateFromLookaside)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFLOOKASIDE Lookaside, + __out + WDFMEMORY* Memory + ) +/*++ + +Routine Description: + Allocates a WDFMEMORY handle from a lookaside HANDLE that the caller + previously created with WdfLookasideListCreate. + +Arguments: + Lookaside - Handle to a lookaside list previously created by the caller + + Memory - Handle to be returned to the caller + +Return Value: + NTSTATUS + + --*/ +{ + FxLookasideList* pLookaside; + FxMemoryObject *pMemory; + WDFMEMORY hMemory; + NTSTATUS status; + + pLookaside = NULL; + pMemory = NULL; + + // + // Make sure the caller passed in a valid handle + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Lookaside, + FX_TYPE_LOOKASIDE, + (PVOID*)&pLookaside); + + FxPointerNotNull(pLookaside->GetDriverGlobals(), Memory); + + *Memory = NULL; + + status = pLookaside->Allocate(&pMemory); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pMemory->Commit(&pLookaside->m_MemoryAttributes, + (WDFOBJECT*) &hMemory); + + if (NT_SUCCESS(status)) { + *Memory = hMemory; + } + else { + pMemory->DeleteFromFailedCreate(); + } + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxmemorybuffer.cpp b/sdk/lib/drivers/wdf/shared/core/fxmemorybuffer.cpp new file mode 100644 index 00000000000..828a19479df --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxmemorybuffer.cpp @@ -0,0 +1,181 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBuffer.cpp + +Abstract: + + This module implements a frameworks managed FxMemoryBuffer + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "FxMemoryBuffer.hpp" + +extern "C" { +#include "FxMemoryBuffer.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxMemoryBuffer::_Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in ULONG PoolTag, + __in size_t BufferSize, + __in POOL_TYPE PoolType, + __out FxMemoryObject** Object + ) +{ + FxMemoryBuffer* pBuffer; + + pBuffer = new(DriverGlobals, Attributes, (USHORT) BufferSize, PoolTag, PoolType) + FxMemoryBuffer(DriverGlobals, BufferSize); + + if (pBuffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + *Object = pBuffer; + + return STATUS_SUCCESS; +} + +FxMemoryBuffer::FxMemoryBuffer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize + ) : + FxMemoryObject(FxDriverGlobals, + (USHORT) COMPUTE_OBJECT_SIZE(sizeof(*this), (ULONG) BufferSize), + BufferSize) +/*++ + +Routine Description: + Constructor for FxMemoryBuffer. Initializes the entire data structure. + +Arguments: + BufferSize - Size of the buffer represented by this object + + We round up the object size (via COMPUTE_OBJECT_SIZE) because the object, + the context and the memory it returns via GetBuffer() are all in one allocation + and the returned memory needs to match the alignment that raw pool follows. + + Note on downcasting to USHORT + ============================== + Note that FxMemoryBuffer is used for buffer less than a page size, and + object-size and buffer-size are added and allocated together. + Downcasting to USHORT is safe because size of object plus buffer (ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, Memory); + + if (FxIsPagedPoolType(PoolType)) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + } + + if (BufferSize == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "BufferSize == 0 not allowed, %!STATUS!", status); + return status; + } + + *Memory = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (PoolTag == 0) { + PoolTag = pFxDriverGlobals->Tag; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, PoolTag); + + status = FxMemoryObject::_Create( + pFxDriverGlobals, + Attributes, + PoolType, + PoolTag, + BufferSize, + &pBuffer); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = pBuffer->Commit(Attributes, (WDFOBJECT*)&hMemory); + + if (NT_SUCCESS(status)) { + *Memory = hMemory; + if (Buffer != NULL) { + *Buffer = pBuffer->GetBuffer(); + } + } + else { + pBuffer->DeleteFromFailedCreate(); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PVOID +WDFAPI +WDFEXPORT(WdfMemoryGetBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFMEMORY Memory, + __out_opt + size_t* BufferSize + ) +/*++ + +Routine Description: + Retrieves the raw pointers associated with WDFMEMORY handle + +Arguments: + Memory - handle to the WDFMEMORY + + BufferSize - the size / length of the buffer + +Return Value: + raw buffer + + --*/ +{ + DDI_ENTRY(); + + IFxMemory* pMemory; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Memory, + IFX_TYPE_MEMORY, + (PVOID*)&pMemory); + + if (BufferSize != NULL) { + *BufferSize = pMemory->GetBufferSize(); + } + + return pMemory->GetBuffer(); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfMemoryCopyToBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFMEMORY SourceMemory, + __in + size_t SourceOffset, + __out_bcount( NumBytesToCopyTo) + PVOID Buffer, + __in + __drv_when(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ) +/*++ + +Routine Description: + Copies memory from a WDFMEMORY handle to a raw pointer + +Arguments: + SourceMemory - Memory handle whose contents we are copying from. + + SourceOffset - Offset into SourceMemory from which the copy starts. + + Buffer - Memory whose contents we are copying into + + NumBytesToCopyTo - Number of bytes to copy into buffer. + +Return Value: + + STATUS_BUFFER_TOO_SMALL - SourceMemory is smaller than the requested number + of bytes to be copied. + + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxMemory* pSource; + WDFMEMORY_OFFSET srcOffsets; + WDFMEMORY_OFFSET dstOffsets; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + SourceMemory, + IFX_TYPE_MEMORY, + (PVOID*) &pSource); + + pFxDriverGlobals = pSource->GetDriverGlobals(); + + FxPointerNotNull(pFxDriverGlobals, Buffer); + + if (NumBytesToCopyTo == 0) { + status =STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Zero bytes to copy not allowed, %!STATUS!", status); + return status; + } + + RtlZeroMemory(&srcOffsets, sizeof(srcOffsets)); + srcOffsets.BufferLength = NumBytesToCopyTo; + srcOffsets.BufferOffset = SourceOffset; + + RtlZeroMemory(&dstOffsets, sizeof(dstOffsets)); + dstOffsets.BufferLength = NumBytesToCopyTo; + dstOffsets.BufferOffset = 0; + + return pSource->CopyToPtr(&srcOffsets, + Buffer, + NumBytesToCopyTo, + &dstOffsets); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfMemoryCopyFromBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFMEMORY DestinationMemory, + __in + size_t DestinationOffset, + __in + PVOID Buffer, + __in + __drv_when(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ) +/*++ + +Routine Description: + Copies memory from a raw pointer into a WDFMEMORY handle + +Arguments: + DestinationMemory - Memory handle whose contents we are copying into + + DestinationOffset - Offset into DestinationMemory from which the copy + starts. + + Buffer - Buffer whose context we are copying from + + NumBytesToCopyFrom - Number of bytes to copy from + +Return Value: + + STATUS_INVALID_BUFFER_SIZE - DestinationMemory is not large enough to contain + the number of bytes requested to be copied + + NTSATUS + + --*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFMEMORY_OFFSET srcOffsets; + WDFMEMORY_OFFSET dstOffsets; + IFxMemory* pDest; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + DestinationMemory, + IFX_TYPE_MEMORY, + (PVOID*) &pDest); + + pFxDriverGlobals = pDest->GetDriverGlobals(); + + FxPointerNotNull(pFxDriverGlobals, Buffer); + + if (NumBytesToCopyFrom == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Zero bytes to copy not allowed, %!STATUS!", status); + return status; + } + + RtlZeroMemory(&srcOffsets, sizeof(srcOffsets)); + srcOffsets.BufferLength = NumBytesToCopyFrom; + srcOffsets.BufferOffset = 0; + + RtlZeroMemory(&dstOffsets, sizeof(dstOffsets)); + dstOffsets.BufferLength = NumBytesToCopyFrom; + dstOffsets.BufferOffset = DestinationOffset; + + return pDest->CopyFromPtr(&dstOffsets, + Buffer, + NumBytesToCopyFrom, + &srcOffsets); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxmemorybufferfromlookaside.cpp b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferfromlookaside.cpp new file mode 100644 index 00000000000..2938c42039c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferfromlookaside.cpp @@ -0,0 +1,298 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferFromLookaside.cpp + +Abstract: + + This module implements a frameworks managed FxMemoryBufferFromLookaside + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "FxNPagedLookasideList.hpp" +#include "FxMemoryBufferFromLookaside.hpp" + +FxMemoryBufferFromLookaside::FxMemoryBufferFromLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize + ) : + FxMemoryObject(FxDriverGlobals, + COMPUTE_OBJECT_SIZE(sizeof(*this), (ULONG) BufferSize), + BufferSize), + m_pLookaside(Lookaside) +/*++ + +Routine Description: + Constructor for this object. Remembers which lookaside list this object + was allocated from + + We round up the object size (via COMPUTE_OBJECT_SIZE) because the object, + the context and the memory it returns via GetBuffer() are all in one allocation + and the returned memory needs to match the alignment that raw pool follows. + +Arguments: + Lookaside - The lookaside list which this object will return itself to when + its last reference is removed + + BufferSize - The buffer size associated with this object + +Return Value: + None + + --*/ +{ + Init(); +} + +FxMemoryBufferFromLookaside::FxMemoryBufferFromLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in USHORT ObjectSize + ) : + FxMemoryObject(FxDriverGlobals, ObjectSize, BufferSize), + m_pLookaside(Lookaside) +/*++ + +Routine Description: + Constructor for this object. Remembers which lookaside list this object + was allocated from + + There is no round up of the ObjectSize because the derived class may not + embed the buffer in the same allocation as the object. If it were to do so, + the derived object should do the round up on its own. + +Arguments: + Lookaside - The lookaside list which this object will return itself to when + its last reference is removed + + BufferSize - The buffer size associated with this object + + ObjectSize - The size of this object. + +Return Value: + None + + --*/ +{ + Init(); +} + +VOID +FxMemoryBufferFromLookaside::Init( + VOID + ) +{ + m_pLookaside->ADDREF(this); +} + + + +FxMemoryBufferFromLookaside::~FxMemoryBufferFromLookaside() +/*++ + +Routine Description: + Destructor for this object. This function does nothing, it lets + SelfDestruct do all the work. + +Arguments: + +Return Value: + + --*/ +{ +} + +_Must_inspect_result_ +PVOID +FxMemoryBufferFromLookaside::operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout PVOID ValidMemory, + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Displacement new operator overload. Since the lookaside list actually + allocates the memory block, we just return the block given to us. + +Arguments: + Size - Compiler supplied parameter indicating the + sizeof(FxMemoryBufferFromLookaside) + + FxDriverGlobals - Driver's globals. + + ValidMemory - Previously allocated block + + BufferSize - The buffer size associated with this object + + Attributes - Description of context. + +Return Value: + ValidMemory pointer value + + --*/ +{ + size_t objectSize; + + UNREFERENCED_PARAMETER(Size); + + ASSERT(Size >= sizeof(FxMemoryBufferFromLookaside)); + + // + // We round up the object size (via COMPUTE_OBJECT_SIZE) because the object, + // and the buffer are all in one allocation and the returned memory needs to + // match the alignment that raw pool follows. + // + // Note that FxMemoryBufferFromLookaside is used for buffer less than a page + // size so downcasting to USHORT (via COMPUTE_OBJECT_SIZE) is safe because + // size of object plus buffer (Reclaim(this); + pLookaside->RELEASE(this); +} + +FxMemoryBufferFromPoolLookaside::FxMemoryBufferFromPoolLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in_bcount(BufferSize) PVOID Buffer + ) : + FxMemoryBufferFromLookaside(FxDriverGlobals, + Lookaside, + BufferSize, + sizeof(*this)), + m_Pool(Buffer) +{ +} + +FxMemoryBufferFromPoolLookaside::FxMemoryBufferFromPoolLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in_bcount(BufferSize) PVOID Buffer, + __in USHORT ObjectSize + ) : + FxMemoryBufferFromLookaside(FxDriverGlobals, + Lookaside, + BufferSize, + ObjectSize), + m_Pool(Buffer) +{ +} + +VOID +FxMemoryBufferFromPoolLookaside::SelfDestruct( + VOID + ) +{ + // + // Free the 2ndary allocation + // + ((FxLookasideListFromPool*) m_pLookaside)->ReclaimPool(m_Pool); + + // + // Free the object itself + // + __super::SelfDestruct(); +} + +_Must_inspect_result_ +PVOID +FxMemoryBufferFromPoolLookaside::operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout PVOID ValidMemory, + __in PWDF_OBJECT_ATTRIBUTES Attributes + ) +{ + size_t objectSize; + + UNREFERENCED_PARAMETER(Size); + + ASSERT(Size >= sizeof(FxMemoryBufferFromPoolLookaside)); + + objectSize = COMPUTE_OBJECT_SIZE(sizeof(FxMemoryBufferFromPoolLookaside), 0); + + return FxObjectAndHandleHeaderInit( + FxDriverGlobals, + ValidMemory, + (USHORT) objectSize, + Attributes, + FxObjectTypeExternal + ); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxmemorybufferfrompool.cpp b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferfrompool.cpp new file mode 100644 index 00000000000..6715ec344d5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferfrompool.cpp @@ -0,0 +1,160 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferFromPool.cpp + +Abstract: + + This module implements a frameworks managed FxMemoryBufferFromPool + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +FxMemoryBufferFromPool::FxMemoryBufferFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize + ) : + FxMemoryObject(FxDriverGlobals, sizeof(*this), BufferSize) +/*++ + +Routine Description: + Constructor for this object. + +Arguments: + BufferSize - The buffer size associated with this object + +Return Value: + None + + --*/ +{ + m_Pool = NULL; +} + +FxMemoryBufferFromPool::FxMemoryBufferFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize, + __in USHORT ObjectSize + ) : + FxMemoryObject(FxDriverGlobals, ObjectSize, BufferSize) +/*++ + +Routine Description: + Constructor for this object. + +Arguments: + BufferSize - The buffer size associated with this object + + ObjectSize - size of the derived object + +Return Value: + None + + --*/ +{ + m_Pool = NULL; +} + +FxMemoryBufferFromPool::~FxMemoryBufferFromPool() +/*++ + +Routine Description: + Destructor for this object. This function does nothing, it lets + SelfDestruct do all the work. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (m_Pool != NULL) { + MxMemory::MxFreePool(m_Pool); + } +} + +_Must_inspect_result_ +NTSTATUS +FxMemoryBufferFromPool::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in POOL_TYPE PoolType, + __in ULONG PoolTag, + __in size_t BufferSize, + __out FxMemoryObject** Buffer + ) +{ + CfxDeviceBase* pDeviceBase; + FxMemoryBufferFromPool* pBuffer; + NTSTATUS status; + BOOLEAN isPaged; + + isPaged = FxIsPagedPoolType(PoolType); + + if (isPaged) { + pDeviceBase = FxDeviceBase::_SearchForDevice(FxDriverGlobals, + Attributes); + } + else { + pDeviceBase = NULL; + } + + // + // FxMemoryBufferFromPool can handle paged allocation as well. We only + // use FxMemoryPagedBufferFromPool if we have an FxDeviceBase that we can use + // in the dispose path, otherwise these 2 classes are the same. + // + if (pDeviceBase != NULL) { + ASSERT(isPaged); + pBuffer = new(FxDriverGlobals, Attributes) + FxMemoryPagedBufferFromPool(FxDriverGlobals, BufferSize, pDeviceBase); + } + else { + pBuffer = new(FxDriverGlobals, Attributes) + FxMemoryBufferFromPool(FxDriverGlobals, BufferSize); + } + + if (pBuffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = STATUS_SUCCESS; + + if (pBuffer->AllocateBuffer(PoolType, PoolTag) == FALSE) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (!NT_SUCCESS(status)) { + pBuffer->DeleteFromFailedCreate(); + return status; + } + + if (isPaged) { + // + // Callbacks might be a bit excessive (passive dispose is what we are + // really after) because this object has no callbacks, but this is being + // proactive in case any callbacks are added. If they are added, this + // will take care of them w/out additional changes to object setup. + // + pBuffer->MarkPassiveCallbacks(ObjectDoNotLock); + } + + *Buffer = pBuffer; + + return STATUS_SUCCESS; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxmemorybufferpreallocated.cpp b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferpreallocated.cpp new file mode 100644 index 00000000000..d708a2e9a89 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferpreallocated.cpp @@ -0,0 +1,156 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferPreallocated.cpp + +Abstract: + + This module implements a frameworks managed FxMemoryBufferPreallocated + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "FxMemoryBufferPreallocated.hpp" + +FxMemoryBufferPreallocated::FxMemoryBufferPreallocated( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ size_t BufferSize + ) : + FxMemoryObject(FxDriverGlobals, sizeof(*this), BufferSize), + m_pBuffer(Buffer) +/*++ + +Routine Description: + Contstructor for this object. Stores off all the pointers and sizes passed + in by the caller. + +Arguments: + Buffer - Buffer to associate with this object + + BufferSize - Size of Buffer in bytes + +Return Value: + None + + --*/ +{ +} + +FxMemoryBufferPreallocated::FxMemoryBufferPreallocated( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ USHORT ObjectSize, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ size_t BufferSize + ) : + FxMemoryObject(FxDriverGlobals, ObjectSize, BufferSize), + m_pBuffer(Buffer) +/*++ + +Routine Description: + Contstructor for this object. Stores off all the pointers and sizes passed + in by the caller. + +Arguments: + ObjectSize - Size of the derived object + + Buffer - Buffer to associate with this object + + BufferSize - Size of Buffer in bytes + +Return Value: + None + + --*/ +{ +} + + +FxMemoryBufferPreallocated::FxMemoryBufferPreallocated( + __in USHORT ObjectSize, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : FxMemoryObject(FxDriverGlobals, ObjectSize, 0), m_pBuffer(NULL) +/*++ + +Routine Description: + Contstructor for this object. Stores off all the pointers and sizes passed + in by the caller. + +Arguments: + ObjectSize - Size of the derived object. + +Return Value: + None + + --*/ +{ +} + +FxMemoryBufferPreallocated::~FxMemoryBufferPreallocated() +/*++ + +Routine Description: + Destructor for this object. Does nothing with the client memory since + the client owns it. + +Arguments: + None + +Return Value: + None + + --*/ +{ +} + +_Must_inspect_result_ +NTSTATUS +FxMemoryBufferPreallocated::QueryInterface( + __inout FxQueryInterfaceParams* Params + ) +{ + if (Params->Type == FX_TYPE_MEMORY_PREALLOCATED) { + *Params->Object = (FxMemoryBufferPreallocated*) this; + return STATUS_SUCCESS; + } + else { + return __super::QueryInterface(Params); + } +} + +VOID +FxMemoryBufferPreallocated::UpdateBuffer( + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ size_t BufferSize + ) +/*++ + +Routine Description: + Updates the internal pointer to a new value. + + +Arguments: + Buffer - new buffer + + BufferSize - length of Buffer in bytes + +Return Value: + None. + + --*/ + +{ + m_pBuffer = Buffer; + m_BufferSize = BufferSize; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxmemorybufferpreallocatedapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferpreallocatedapi.cpp new file mode 100644 index 00000000000..7063e4c70cf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxmemorybufferpreallocatedapi.cpp @@ -0,0 +1,177 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferPreallocatedApi.cpp + +Abstract: + + This modules implements the C API's for the FxMemoryBufferPreallocated. + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "FxMemoryBufferPreallocated.hpp" + +extern "C" { +#include "FxMemoryBufferPreallocatedAPI.tmh" +} + +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCreatePreallocated)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __in + PVOID Buffer, + __in + __drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + __out //deref cud be null if unable to allocate memory + WDFMEMORY* PMemory + )/*++ + +Routine Description: + External API provided to the client driver to create a WDFMEMORY object + whose associated buffers are supplied by the caller. This API is provided + so that the caller does not need to allocate a new buffer every time she + wants to pass a WDFMEMORY object to an API which requires it. It is up to + the client driver to free the Buffer and Context at the appropriate time. + +Arguments: + Attributes - Context to associate with the returned WDFMEMORY handle + + Buffer - Buffer to associate with the returned WDFMEMORY handle + + BufferSize - Size of Buffer in bytes + + PMemory - Handle to be returned to the caller + +Return Value: + STATUS_INVALID_PARAMETER - if required parameters are incorrect + + STATUS_INSUFFICIENT_RESOURCES - if no resources are available + + STATUS_SUCCESS - success + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxMemoryBufferPreallocated *pBuffer; + WDFMEMORY hMemory; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + Attributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, Buffer); + FxPointerNotNull(pFxDriverGlobals, PMemory); + + *PMemory = NULL; + + if (BufferSize == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Zero BufferSize not allowed, %!STATUS!", status); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + if (!NT_SUCCESS(status)) { + return status; + } + + pBuffer = new(pFxDriverGlobals, Attributes) + FxMemoryBufferPreallocated(pFxDriverGlobals, Buffer, BufferSize); + + if (pBuffer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pBuffer->Commit(Attributes, (WDFOBJECT*)&hMemory); + + if (NT_SUCCESS(status)) { + *PMemory = hMemory; + } + else { + pBuffer->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + __drv_when(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxMemoryBufferPreallocated* pMemory; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Memory, + FX_TYPE_MEMORY_PREALLOCATED, + (PVOID*) &pMemory, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Buffer); + + if (BufferSize == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Zero BufferSize not allowed, %!STATUS!", status); + return status; + } + + pMemory->UpdateBuffer(Buffer, BufferSize); + + return STATUS_SUCCESS; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxmemoryobject.cpp b/sdk/lib/drivers/wdf/shared/core/fxmemoryobject.cpp new file mode 100644 index 00000000000..9625f751f3d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxmemoryobject.cpp @@ -0,0 +1,319 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryObject.cpp + +Abstract: + + This module implements a frameworks managed FxMemoryObject + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxMemoryObject.tmh" +} + +FxMemoryObject::FxMemoryObject( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in size_t BufferSize + ) : + // intentionally do not pass IFX_TYPE_MEMORY to the base constructor + // because we need to pass the interface back when converting from + // handle to object and that will require a different this pointer offset + // which will be handled by QueryInterface + FxObject(FX_TYPE_OBJECT, ObjectSize, FxDriverGlobals), + m_BufferSize(BufferSize) +{ + // + // Since we are passing the generic object type FX_TYPE_OBJECT to FxObject, + // we need to figure out on our own if need to allocate a tag tracker or not. + // + if (IsDebug()) { + AllocateTagTracker(IFX_TYPE_MEMORY); + } +} + +_Must_inspect_result_ +NTSTATUS +FxMemoryObject::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in POOL_TYPE PoolType, + __in ULONG PoolTag, + __in size_t BufferSize, + __out FxMemoryObject** Object + ) +{ + // + // If the buffer is + // a) a PAGE or larger + // b) we are debugging allocations + // c) less then a page and pageable + // + // separate the object from its memory so that we can assure + // + // 1) the buffer pointer is PAGE aligned + // 2) the kernel's buffer overrun/underrun checking can be used + // 3) for case c), that the object is non pageable while the memory pointer + // it returns to the driver is pageable + // + + // + // By placing FxIsPagedPool last in the list, BufferSize < PAGE_SIZE + // + if (BufferSize >= PAGE_SIZE || + (FxDriverGlobals->FxVerifierOn && FxDriverGlobals->FxPoolTrackingOn) || + FxIsPagedPoolType(PoolType)) { + return FxMemoryBufferFromPool::_Create( + FxDriverGlobals, + Attributes, + PoolType, + PoolTag, + BufferSize, + Object); + } + else { + + // + // Before the changes for NxPool this code path assumed NonPagedPool + // + // To maintain compatibility with existing behavior (and add on NxPool + // options we pass in PoolType to FxMemoryBuffer::_Create but + // normalize NonPagedPool variants to NonPagedPool. + // + switch(PoolType) + { + case NonPagedPoolBaseMustSucceed: + case NonPagedPoolBaseCacheAligned: + case NonPagedPoolBaseCacheAlignedMustS: + PoolType = NonPagedPool; + } + + return FxMemoryBuffer::_Create( + FxDriverGlobals, + Attributes, + PoolTag, + BufferSize, + PoolType, + Object); + } +} + +_Must_inspect_result_ +NTSTATUS +IFxMemory::CopyFromPtr( + __in_opt PWDFMEMORY_OFFSET DestinationOffsets, + __in_bcount(SourceBufferLength) PVOID SourceBuffer, + __in size_t SourceBufferLength, + __in_opt PWDFMEMORY_OFFSET SourceOffsets + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + // + // We read from the supplied buffer writing to the current FxMemoryBuffer + // + if (GetFlags() & IFxMemoryFlagReadOnly) { + // + // FxMemoryBuffer is not writeable + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Target WDFMEMORY 0x%p is ReadOnly", GetHandle()); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return STATUS_ACCESS_VIOLATION; + } + + return _CopyPtrToPtr( + SourceBuffer, + SourceBufferLength, + SourceOffsets, + GetBuffer(), + GetBufferSize(), + DestinationOffsets + ); +} + +_Must_inspect_result_ +NTSTATUS +IFxMemory::CopyToPtr( + __in_opt PWDFMEMORY_OFFSET SourceOffsets, + __out_bcount(DestinationBufferLength)PVOID DestinationBuffer, + __in size_t DestinationBufferLength, + __in_opt PWDFMEMORY_OFFSET DestinationOffsets + ) +/*++ + +Routine Description: + + Worker routine for the various copy APIs. Verifies that a copy will not + overrun a buffer, or write into a read only memory buffer + +Arguments: + + SourceOffsets - Offsets into SourceBuffer from which the copy starts. If + NULL, an offset of 0 is used. + + DestinationBuffer - Memory whose contents we are copying into + + DestinationBufferLength - Size of DestinationBuffer in bytes + + DestinationOffsets - Offsets into DestinationMemory from which the copy + starts and indicates how many bytes to copy. If length is 0 or + parameter is NULL, the entire length of DestinationMemory is used. + +Return Value: + STATUS_BUFFER_TOO_SMALL - SourceMemory is smaller then the requested number + of bytes to be copied. + STATUS_INVALID_BUFFER_SIZE - DestinationMemory is not large enough to contain + the number of bytes requested to be copied + NTSTATUS + + --*/ +{ + // + // We are reading from the FxMemoryBuffer, so no need to check for ReadOnly + // + return _CopyPtrToPtr( + GetBuffer(), + GetBufferSize(), + SourceOffsets, + DestinationBuffer, + DestinationBufferLength, + DestinationOffsets + ); +} + +_Must_inspect_result_ +NTSTATUS +IFxMemory::_CopyPtrToPtr( + __in_bcount(SourceBufferLength)PVOID SourceBuffer, + __in size_t SourceBufferLength, + __in_opt PWDFMEMORY_OFFSET SourceOffsets, + __out_bcount(DestinationBufferLength) PVOID DestinationBuffer, + __in size_t DestinationBufferLength, + __in_opt PWDFMEMORY_OFFSET DestinationOffsets + ) +/*++ + +Routine Description: + Worker routine for the various copy APIs. Verifies that a copy will not + overrun a buffer. + +Arguments: + SourceBuffer - Memory whose contents we are copying from. + + SourceBufferLength - Size of SourceBuffer in bytes + + SourceOffsets - Offsets into SourceBuffer from which the copy starts. If + NULL, an offset of 0 is used. + + DestinationBuffer - Memory whose contents we are copying into + + DestinationBufferLength - Size of DestinationBuffer in bytes + + DestinationOffsets - Offsets into DestinationMemory from which the copy + starts and indicates how many bytes to copy. If length is 0 or + parameter is NULL, the entire length of DestinationMemory is used. + +Return Value: + STATUS_BUFFER_TOO_SMALL - SourceMemory is smaller then the requested number + of bytes to be copied. + STATUS_INVALID_BUFFER_SIZE - DestinationMemory is not large enough to contain + the number of bytes requested to be copied + NTSTATUS + + --*/ +{ + size_t srcSize, copyLength; + PUCHAR pSrcBuf, pDstBuf; + + if (SourceBuffer == NULL) { + return STATUS_INVALID_PARAMETER; + } + + pSrcBuf = (PUCHAR) SourceBuffer; + srcSize = SourceBufferLength; + + pDstBuf = (PUCHAR) DestinationBuffer; + copyLength = DestinationBufferLength; + + if (SourceOffsets != NULL) { + if (SourceOffsets->BufferOffset != 0) { + if (SourceOffsets->BufferOffset >= srcSize) { + // + // Offset is beyond end of buffer + // + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Adjust the start and source size to reflect the offset info the + // source + // + pSrcBuf += SourceOffsets->BufferOffset; + srcSize -= SourceOffsets->BufferOffset; + } + } + + if (DestinationOffsets != NULL) { + if (DestinationOffsets->BufferOffset != 0) { + if (DestinationOffsets->BufferOffset >= copyLength) { + // + // Offset is beyond end of buffer + // + return STATUS_INVALID_BUFFER_SIZE; + } + + // + // Adjust the start and copy length to reflect the offset info the + // destination + // + pDstBuf += DestinationOffsets->BufferOffset; + copyLength -= DestinationOffsets->BufferOffset; + } + + // + // Non zero buffer length overrides previously calculated copy length + // + if (DestinationOffsets->BufferLength != 0) { + // + // Is the desired buffer length greater than the amount of buffer + // available? + // + if (DestinationOffsets->BufferLength > copyLength) { + return STATUS_INVALID_BUFFER_SIZE; + } + + copyLength = DestinationOffsets->BufferLength; + } + } + + // + // Compare the final computed copy length against the length of the source + // buffer. + // + if (copyLength > srcSize) { + return STATUS_BUFFER_TOO_SMALL; + } + + RtlCopyMemory(pDstBuf, pSrcBuf, copyLength); + + return STATUS_SUCCESS; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxpagedlookasidelist.cpp b/sdk/lib/drivers/wdf/shared/core/fxpagedlookasidelist.cpp new file mode 100644 index 00000000000..7bd3ea1de6f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxpagedlookasidelist.cpp @@ -0,0 +1,310 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPagedLookasideList.cpp + +Abstract: + + This module implements a frameworks managed FxPagedLookasideList + +Author: + +Environment: + + kernel mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxPagedLookasideList.hpp" +#include "FxMemoryBufferFromLookaside.hpp" + +FxPagedLookasideListFromPool::FxPagedLookasideListFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag, + __in FxDeviceBase* DeviceBase, + __in FxDeviceBase* MemoryDeviceBase + ) : FxLookasideListFromPool(FxDriverGlobals, sizeof(*this), PoolTag), + m_RawBufferSize(0), m_MemoryDeviceBase(MemoryDeviceBase) +{ + SetDeviceBase(DeviceBase); + + // + // Callbacks might be a bit excessive (passive dispose is what we are + // really after) because this object has no callbacks, but this is being + // proactive in case any callbacks are added. If they are added, this + // will take care of them w/out additional changes to object setup. + // + MarkPassiveCallbacks(ObjectDoNotLock); +} + +FxPagedLookasideListFromPool::~FxPagedLookasideListFromPool( + VOID + ) +{ + if (m_MemoryObjectSize != 0) { + Mx::MxDeleteNPagedLookasideList(&m_ObjectLookaside); + } + + if (m_RawBufferSize != 0) { + Mx::MxDeletePagedLookasideList(&m_PoolLookaside); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPagedLookasideListFromPool::Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) +{ + size_t rawBufferSize; + NTSTATUS status; + + if (BufferSize >= PAGE_SIZE) { + // + // We don't want to burn extra entire pages for tracking information + // so we just use the size as is. + // + rawBufferSize = BufferSize; + } + else { + // + // Allocate extra space for tracking the allocation + // + status = FxPoolAddHeaderSize(GetDriverGlobals(), + BufferSize, + &rawBufferSize); + + if (!NT_SUCCESS(status)) { + // + // FxPoolAddHeaderSize logs to the IFR on error + // + return status; + } + } + + if (UsePagedBufferObject()) { + status = InitializeLookaside(0, + sizeof(FxMemoryPagedBufferFromPoolLookaside), + MemoryAttributes); + } + else { + status = InitializeLookaside(0, + sizeof(FxMemoryBufferFromPoolLookaside), + MemoryAttributes); + } + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // We use m_RawBufferSize == 0 as a condition not to delete the lookaside, so + // only assign it a value once we know success is guaranteed. + // + m_BufferSize = BufferSize; + m_RawBufferSize = rawBufferSize; + + // + // Initialize a non paged pool with these characteristics. All FxObject + // derived objects must come from non paged pool. + // + Mx::MxInitializeNPagedLookasideList(&m_ObjectLookaside, + NULL, + NULL, + 0, + m_MemoryObjectSize, + m_PoolTag, + 0); + + // + // Initialize a paged pool with these characteristics. + // + // Free and Allocate are left intentionally NULL so that we use the Ex + // versions. + // + // bufferSize is used b/c it is full size of the object + pool requirements. + // m_BufferSize is the size the client wants the buffer to be. + // + Mx::MxInitializePagedLookasideList(&m_PoolLookaside, + NULL, + NULL, + 0, + m_RawBufferSize, + m_PoolTag, + 0); + + return status; +} + +#pragma prefast(push) + + + +//This routine intentionally accesses the header of the allocated memory. +#pragma prefast(disable:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY) +PVOID +FxPagedLookasideListFromPool::InitPagedAlloc( + __out_bcount(this->m_RawBufferSize) PVOID Alloc + ) +/*++ + +Routine Description: + Initializes the object allocation so that it can be tracked and inserted + in this drivers POOL. + +Arguments: + Alloc - the raw allocation + +Return Value: + the start of where the object memory should be, not necessarily == Alloc + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PFX_POOL_HEADER pHeader; + PFX_POOL_TRACKER tracker; + + pFxDriverGlobals = GetDriverGlobals(); + + RtlZeroMemory(Alloc, m_RawBufferSize); + + if (pFxDriverGlobals->IsPoolTrackingOn()) { + // + // PoolTracking is active, so format and insert + // a tracker in the NonPagedHeader list of the pool. + // + tracker = (PFX_POOL_TRACKER) Alloc; + pHeader = WDF_PTR_ADD_OFFSET_TYPE(Alloc, + sizeof(FX_POOL_TRACKER), + PFX_POOL_HEADER); + + pHeader->Base = Alloc; + pHeader->FxDriverGlobals = pFxDriverGlobals; + + FxPoolInsertPagedAllocateTracker( + &pFxDriverGlobals->FxPoolFrameworks, + tracker, + m_RawBufferSize, + m_PoolTag, + _ReturnAddress()); + } + else { + // + // PoolTracking is inactive, only format FX_POOL_HEADER area. + // + pHeader = (PFX_POOL_HEADER) Alloc; + pHeader->Base = Alloc; + pHeader->FxDriverGlobals = pFxDriverGlobals; + } + + return &pHeader->AllocationStart[0]; +} +#pragma prefast(pop) + +_Must_inspect_result_ +NTSTATUS +FxPagedLookasideListFromPool::Allocate( + __out FxMemoryObject** PPMemory + ) +{ + FxMemoryBufferFromPoolLookaside* pBuffer; + PVOID pObj, pBuf; + + // + // Allocate the object which will contain the 2ndary allocation + // + pObj = FxAllocateFromNPagedLookasideList(&m_ObjectLookaside); + + if (pObj == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + pObj = InitObjectAlloc(pObj); + + // + // Create the 2ndary allocation (the one the driver writer uses), what will + // be FxMemoryBufferFromPoolLookaside::m_Pool below. + // + pBuf = FxAllocateFromPagedLookasideList(&m_PoolLookaside); + if (pBuf == NULL) { + // + // This case is safe because Reclaim doesn't treat the pointer as an + // object, rather it just performs pointer math and then frees the alloc + // + Reclaim((FxMemoryBufferFromPoolLookaside*) pObj); + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (m_BufferSize < PAGE_SIZE) { + // + // For allocations < PAGE, allocate a header, otherwise leave the + // allocation alone. + // + pBuf = InitPagedAlloc(pBuf); + } + else { + // + // There is no tracking info before the real allocation start since we + // don't want to burn an entire page. + // + DO_NOTHING(); + } + + // + // Construct a new FxMemoryBufferFromPoolLookaside using the pool will allocated + // above. + // + // Both objects will know that the base object is one allocation and the + // buffer is another. FxMemoryPagedBufferFromPoolLookaside also knows to + // dispose itself on the owning FxDeviceBase* pointer. + // + if (UsePagedBufferObject()) { + pBuffer = new(GetDriverGlobals(), pObj, &m_MemoryAttributes) + FxMemoryPagedBufferFromPoolLookaside(GetDriverGlobals(), + this, + m_BufferSize, + pBuf, + m_MemoryDeviceBase); + } + else { + pBuffer = new(GetDriverGlobals(), pObj, &m_MemoryAttributes) + FxMemoryBufferFromPoolLookaside(GetDriverGlobals(), + this, + m_BufferSize, + pBuf); + } + + // + // pBuffer might be displaced if there is a debug extension + // + ASSERT(_GetBase(pBuffer) == pObj); + + // + // Callbacks might be a bit excessive (passive dispose is what we are + // really after) because this object has no callbacks, but this is being + // proactive in case any callbacks are added. If they are added, this + // will take care of them w/out additional changes to object setup. + // + pBuffer->MarkPassiveCallbacks(ObjectDoNotLock); + + *PPMemory = pBuffer; + + return STATUS_SUCCESS; +} + +VOID +FxPagedLookasideListFromPool::Reclaim( + __in FxMemoryBufferFromLookaside * Memory + ) +{ + _Reclaim(GetDriverGlobals(), &m_ObjectLookaside, Memory); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequest.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequest.cpp new file mode 100644 index 00000000000..75f8ae583ec --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequest.cpp @@ -0,0 +1,3217 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequest.cpp + +Abstract: + + This module implements FxRequest object + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequest.tmh" +} + + + + + + +#define WDF_REQUEST_REUSE_MUST_COMPLETE 2 + +FxRequest::FxRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in MdIrp Irp, + __in FxRequestIrpOwnership Ownership, + __in FxRequestConstructorCaller Caller, + __in USHORT ObjectSize + ) : + FxRequestBase(FxDriverGlobals, + ObjectSize, + Irp, + Ownership, + Caller) +{ + m_OutputBufferOffset = FIELD_OFFSET(FxRequest, m_OutputBufferOffset); + m_SystemBufferOffset = FIELD_OFFSET(FxRequest, m_SystemBufferOffset); + m_IoQueue = NULL; + + m_PowerStopState = FxRequestPowerStopUnknown; + + InitializeListHead(&m_OwnerListEntry); + InitializeListHead(&m_OwnerListEntry2); + InitializeListHead(&m_ForwardProgressList); + + m_Presented = (Caller == FxRequestConstructorCallerIsDriver) ? TRUE : FALSE; + m_Reserved = FALSE; + m_ForwardProgressQueue = NULL; + m_ForwardRequestToParent = FALSE; + m_InternalContext = NULL; +} + +#if DBG +FxRequest::~FxRequest( + VOID + ) +{ + ASSERT(IsListEmpty(&m_OwnerListEntry)); + ASSERT(IsListEmpty(&m_OwnerListEntry2)); +} +#endif // DBG + +_Must_inspect_result_ +NTSTATUS +FxRequest::_CreateForPackage( + __in CfxDevice* Device, + __in PWDF_OBJECT_ATTRIBUTES RequestAttributes, + __in MdIrp Irp, + __deref_out FxRequest** Request + ) +/*++ + +Routine Description: + + Creates an FxRequest object and returns its pointer to the caller. + +Arguments: + + Device - Pointer to FxDevice object request will be associated with + + RequestAttributes - Specifies the object's attributes for the request. + + Irp - Pointer to Irp + + Request - Pointer to location to store the returned FxRequest pointer + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + FxRequest* pRequest; + + *Request = NULL; + + // + // Allocate the new FxRequest object in the per driver tracking pool + // + pRequest = new(Device, RequestAttributes) FxRequestFromLookaside(Device, Irp); + + if (pRequest == NULL) { + DoTraceLevelMessage( + Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Memory allocation failed %!STATUS!", + STATUS_INSUFFICIENT_RESOURCES); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // For forward progress the IRP can be NULL. + // + if (Irp != NULL) { + pRequest->AssignMemoryBuffers(Device->GetIoTypeForReadWriteBufferAccess()); + } + + // + // Improve I/O perf by not parenting it to device. However, if verifier is + // turned on, the request is parented to the device to help track reference + // leaks. + // + if (Device->GetDriverGlobals()->FxRequestParentOptimizationOn) { + status = pRequest->Commit(RequestAttributes, + NULL, + NULL, + FALSE); + } + else { + status = pRequest->Commit(RequestAttributes, + NULL, + Device, + FALSE); + } + + if (NT_SUCCESS(status)) { + *Request = pRequest; + } + else { + DoTraceLevelMessage( + Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Could not commit FxRequest %!STATUS!", status); + pRequest->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes, + __in_opt MdIrp Irp, + __in_opt FxIoTarget* Target, + __in FxRequestIrpOwnership Ownership, + __in FxRequestConstructorCaller Caller, + __deref_out FxRequest** Request + ) +{ + WDFOBJECT hRequest; + NTSTATUS status; + FxRequest* pRequest; + + *Request = NULL; + + status = FxValidateObjectAttributes(FxDriverGlobals, RequestAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + pRequest = new (FxDriverGlobals, RequestAttributes) + FxRequest(FxDriverGlobals, + Irp, + Ownership, + Caller, + sizeof(FxRequest)); + + if (pRequest != NULL) { + if (Target != NULL) { + status = pRequest->ValidateTarget(Target); + } + + if (NT_SUCCESS(status)) { + status = pRequest->Commit(RequestAttributes, &hRequest, NULL, TRUE); + } + + if (NT_SUCCESS(status)) { + *Request = pRequest; + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Handle create failed %!STATUS!", status); + + if (Irp != NULL) { + // + // Clear the irp out of the request so that the destructor does + // not free it. Since we are returning failure, the caller does + // not expect the PIRP passed in to be freed. + // + pRequest->SetSubmitIrp(NULL, FALSE); + } + + pRequest->DeleteFromFailedCreate(); + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Irp %p Ownership %!FxRequestIrpOwnership! FxRequest %p, status %!STATUS!", + Irp, Ownership, *Request, status); + + return status; +} + +NTSTATUS +FxRequest::SetInformation( + __in ULONG_PTR Information + ) +/*++ + +Routine Description: + + Set the IRP's IoStatus.Information field. + + NOTE: If the caller calls Complete(status, information), as opposed + to Complete(status), the value will get overwritten. + +Arguments: + + Information - Information value to set + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + if (pFxDriverGlobals->FxVerifierIO) { + NTSTATUS status; + KIRQL irql; + + Lock(&irql); + + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + if (NT_SUCCESS(status)) { + m_Irp.SetInformation(Information); + } + + Unlock(irql); + + return status; + } + else { + m_Irp.SetInformation(Information); + return STATUS_SUCCESS; + } +} + +ULONG_PTR +FxRequest::GetInformation( + VOID + ) +/*++ + +Routine Description: + + Get the IRP's IoStatus.Information field. + + +Arguments: + + None + +Returns: + + ULONG_PTR + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + // Verifier + if (pFxDriverGlobals->FxVerifierIO) { + ULONG_PTR info; + KIRQL irql; + NTSTATUS status; + + Lock(&irql); + + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + if (!NT_SUCCESS(status)) { + info = NULL; + } + else { + info = m_Irp.GetInformation(); + } + + Unlock(irql); + + return info; + } + else { + return m_Irp.GetInformation(); + } +} + +KPROCESSOR_MODE +FxRequest::GetRequestorMode( + VOID + ) +/*++ + +Routine Description: + Get the Irp->RequestorMode value. + +Arguments: + None + +Returns: + KPROCESSOR_MODE + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + if (pFxDriverGlobals->FxVerifierIO) { + KPROCESSOR_MODE mode; + KIRQL irql; + NTSTATUS status; + + Lock(&irql); + + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + if (!NT_SUCCESS(status)) { + mode = UserMode; + } else { + mode = m_Irp.GetRequestorMode(); + } + + Unlock(irql); + + return mode; + } + else { + return m_Irp.GetRequestorMode(); + } +} + + +VOID +FX_VF_METHOD(FxRequest, VerifyCompleteInternal)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ NTSTATUS Status + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + ULONG length; + KIRQL irql; + BOOLEAN validateLength; + + PAGED_CODE_LOCKED(); + + Lock(&irql); + + if (GetDriverGlobals()->FxVerifierIO ) { + (VOID) VerifyRequestIsNotCompleted(GetDriverGlobals()); + } else { + ASSERT(m_Completed == FALSE); + } + + + if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) && + (m_VerifierFlags & FXREQUEST_FLAG_CANCELLED) == 0x0) { + + // + // We could trace each sentence separate, but that takes up valuable + // room in the IFR. Instead, trace the entire "paragraph" as one + // message so that we have more room in the IFR. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Completing Cancelable WDFREQUEST %p. " + + "This results in a race condition in the device driver that can " + "cause double completions. " + + "Call WdfRequestUnmarkCancelable before WdfRequestComplete. " + + "If WdfRequestUnmarkCancelable returns STATUS_CANCELLED, " + "do not complete the request until the EvtIoCancel handler is called. " + + "The straightforward way to ensure this is to complete a canceled " + "request from the EvIoCancel callback.", + + GetHandle() + ); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + } + + validateLength = FALSE; + length = 0; + + switch (m_Irp.GetMajorFunction()) { + case IRP_MJ_READ: + length = m_Irp.GetParameterReadLength(); + validateLength = TRUE; + break; + + case IRP_MJ_WRITE: + length = m_Irp.GetParameterWriteLength(); + validateLength = TRUE; + break; + + case IRP_MJ_DEVICE_CONTROL: + if (m_Irp.GetRequestorMode() == UserMode) { + length = m_Irp.GetParameterIoctlOutputBufferLength(); + + if (length > 0) { + validateLength = TRUE; + } + else { + // + // For an output length == 0, a driver can indicate the number + // of bytes used of the input buffer. + // + DO_NOTHING(); + } + } + else { + // + // If the IOCTL came from kernel mode, the same reasoning applies + // here as for an internal IOCTL...we don't know deterministically + // how to find the output buffer length. + // + DO_NOTHING(); + } + break; + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + // + // Because the current stack location can use any part of the union + // (like Parameters.Others instead of Parameters.DeviceIoControl), we + // cannot deterministically figure out the output buffer length for + // internal IOCTLs. + // + // || || Fall through || || + // \/ \/ \/ \/ + default: + DO_NOTHING(); + } + + // + // We shouldn't validate the information field if the status is warning + // because it's valid for a driver to fill partial data in the buffer + // and ask for large buffer size. + // + if (validateLength && + NT_SUCCESS(Status) && + m_Irp.GetInformation() > length) { + + WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA data; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p, MJ 0x%x, Information 0x%I64x is greater then " + "buffer length 0x%x", GetHandle(), m_Irp.GetMajorFunction(), + m_Irp.GetInformation(), length); + + data.Request = GetHandle(); + data.Irp = reinterpret_cast(m_Irp.GetIrp()); + data.OutputBufferLength = length; + data.Information = m_Irp.GetInformation(); + data.MajorFunction = m_Irp.GetMajorFunction(); + + FxVerifierBugCheck( + GetDriverGlobals(), + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH, + (ULONG_PTR) &data + ); + + // will not get here + } + + // Set IRP to NULL when NT IRP is completed + m_Completed = TRUE; + + Unlock(irql); +} + +NTSTATUS +FxRequest::CompleteInternal( + __in NTSTATUS Status + ) + +/*++ + +Routine Description: + + Internal worker to complete the current request object. + + This is called with the FxRequest object lock held, and + state validation as far as IRP completion already done. + + Callers must use Complete(Status), or Complete(Status,Information) + + It returns with the FxRequest object locked *released* + +Arguments: + + Status - Status to complete the request with + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + MdIrp pIrp; + FxRequestCompletionState state; + FxIoQueue* queue; + CfxDevice* pRefedDevice; + + pFxDriverGlobals = GetDriverGlobals(); + queue = NULL; + // + // Store off the irp into a local variable + // + pIrp = m_Irp.GetIrp(); + + // + // Lock is no longer required, since it's only used + // by verifier for already completed requests. This is a + // serious driver error anyway + // + + + VerifyCompleteInternal(pFxDriverGlobals, Status); + + if (pFxDriverGlobals->FxVerifierOn == FALSE) { + // + // No lock needed in non-verifier case since this is only + // used to detect double completions with verifier on + // + ASSERT(m_Completed == FALSE); + m_Completed = TRUE; + } + + + + + + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + + + + + + + + ULONG flagsMasked = m_Irp.GetFlags() & IRP_INPUT_OPERATION; + if (m_Irp.GetMajorFunction()== IRP_MJ_DEVICE_CONTROL && + m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_BUFFERED && + m_Irp.GetRequestorMode() == UserMode && + m_Irp.GetParameterIoctlOutputBufferLength()== 0 && + (flagsMasked != 0)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver that handled WDFREQUEST 0x%p is requesting data to " + " be written back to the UserBuffer by returing a non zero value " + " in the Irp 0x%p Information field even though the OutputBufferLength " + " is zero", GetObjectHandle(), pIrp); + + // + // We will assert only if the Information field is not zero to warn + // the developer that it's a bad thing to do. However, we do avoid + // corruption of UserBuffer on completion by clearing the flag + // erroneously set by the I/O manager. + // + if (m_Irp.GetInformation() != 0L) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + + // + // Clear the flag to prevent the I/O manager from coping the + // data back from the SystemBuffer to Irp->UserBuffer + // + m_Irp.SetFlags(m_Irp.GetFlags() & (~IRP_INPUT_OPERATION)); + } +#endif + + // + // If the status code is one of the framework facility codes, + // map it to a standard NTSTATUS + // + + + if ((Status & 0x0FFF0000) == (FACILITY_DRIVER_FRAMEWORK << 16)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Converting WDF NTSTATUS value 0x%x...", Status); + + switch (Status) { + case STATUS_WDF_PAUSED: + case STATUS_WDF_BUSY: + Status = STATUS_DEVICE_BUSY; + break; + + case STATUS_WDF_INTERNAL_ERROR: + Status = STATUS_INTERNAL_ERROR; + break; + + case STATUS_WDF_TOO_FRAGMENTED: + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Unknown WDF NTSTATUS 0x%x", Status); + Status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "... to %!STATUS!", Status); + } + + if (IsAllocatedFromIo() == FALSE && IsCanComplete() == FALSE) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + + // + // It is invalid to complete any requests on an IRPQUEUE + // + ASSERTMSG("WDFREQUEST is part of a WDFQUEUE, it could be Cancellable\n", + (m_IrpQueue == NULL)); + + state = (FxRequestCompletionState) m_CompletionState; + queue = m_IoQueue; + + // + // Some I/O request cleanup. Do not do this for driver created requests. + // + if (IsAllocatedFromIo()) { + // + // Set the completion state to none + // + m_CompletionState = FxRequestCompletionStateNone; + + if (IsReserved() == FALSE) { + // + // Don't set the Queue to NULL for reserved requests. + // + m_IoQueue = NULL; + } + } + + // + // IMPORTANT: the context must free its references before the request is + // completed. Any of these references could be on a memory interface that is + // an embedded interface in this object. If this reference + // is left outstanding when we check m_IrpReferenceCount below, we would + // bugcheck (and the driver writer would be unaware of why things are going + // wrong). + // + // Also, if the driver is freeing the referenced mmemory interface in its + // cleanup routine, we don't want an oustanding reference against it. + // + if (m_RequestContext != NULL) { + // + // m_RequestContext will be freed when the FxRequest's desctructor runs + // + m_RequestContext->ReleaseAndRestore(this); + } + + // + // If the request is not presented to the driver then clear the + // cleanup & destroy callbacks before calling PerformEarlyDispose. + // + if (m_Presented == FALSE) { + ClearEvtCallbacks(); + } + + if (IsReserved() == FALSE && IsAllocatedFromIo()) { + // + // Fire the driver supplied Cleanup callback if set + // + // This will allow the driver to release any IRP specific resources such + // as MDLs before we complete the IRP back to the OS, and release the + // process/thread reference. + // + // This is also the callback used to tell the driver the WDM IRP is going + // away if it has used the WDM "escape" API's to either get the IRP, or + // any resources it references. + // + + // + // If a cleanup callback has been registered, we call it + // just before completing the IRP to WDM, which can cause any + // associated buffers, MDLs, or memory interfaces to be invalidated. + // + if (EarlyDispose() == FALSE) { + VerifierBreakpoint_RequestEarlyDisposeDeferred(GetDriverGlobals()); + } + + // + // Now that the entire tree is disposed, we want to destroy all of the + // children. This will not put this object in the destroyed state. For + // m_IrpReferenceCount to go to zero, we need to destroy the child WDFMEMORYs + // that were created when we probed and locked the buffers. + // + DestroyChildren(); + } + else { + // + // We don't call cleanup callback for Reserved Requests. + // The driver can perform any cleanp it wants before completing the Request + // or before reusing the Reserved Request in its Dispatch callback. + + + + + + + DO_NOTHING(); + } + + // + // If this is non-zero, indicates a reference count problem on any + // WDFMEMORY objects returned to the device driver from this WDFREQUEST. + // + if (m_IrpReferenceCount != 0) { + // + // NOTE: you cannot call GetBuffer or GetMdl + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST, + "WDFREQUEST 0x%p, PIRP 0x%p, Major Function 0x%x, completed with " + "outstanding references on WDFMEMORY 0x%p or 0x%p retrieved from " + "this request", + GetObjectHandle(), m_Irp.GetIrp(), m_Irp.GetMajorFunction(), + ((m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) || + (m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid)) ? + m_SystemBuffer.GetHandle() : NULL, + ((m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) || + (m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid)) ? + m_OutputBuffer.GetHandle() : NULL + ); + + if ((m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) || + (m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST, + "WDFMEMORY 0x%p, buffer %p, PMDL %p, length %I64d bytes", + m_SystemBuffer.GetHandle(), m_SystemBuffer.GetBuffer(), + m_SystemBuffer.GetMdl(), m_SystemBuffer.GetBufferSize()); + } + + if ((m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) || + (m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGREQUEST, + "IOCTL output WDFMEMORY 0x%p, buffer %p, PMDL %p, length %I64d bytes", + m_OutputBuffer.GetHandle(), m_OutputBuffer.GetBuffer(), + m_OutputBuffer.GetMdl(), m_OutputBuffer.GetBufferSize()); + } + + FxVerifierBugCheck(pFxDriverGlobals, + WDF_VERIFIER_FATAL_ERROR, + (ULONG_PTR) GetObjectHandle(), + (ULONG_PTR) m_IrpReferenceCount); + } + + FxIrp irp(pIrp); + + // + // Complete the NT IRP through the frameworks FxIrp + // + irp.SetStatus(Status); + + ASSERT(IsCancelRoutineSet() == FALSE); + + // + // For driver created requests we need to use two phase + // completion (pre and post) to detach the request from the queue before the + // IRP is completed, and then allow a new request to be dispatched. + // Note that the IRP is actually completed when the reference on this object + // goes to 1 (See FxRequest::Release() for more info). + // + if (IsAllocatedFromIo() == FALSE) { + // + // Do not touch the request after this call. + // Do not clear the request's IRP field before making this call. + // + PreProcessCompletionForDriverRequest(state, queue); + } + else { + // + // We only clear the irp from this object after PerformEarlyDispose has been + // called. m_SystemBuffer and m_OutputBuffer use m_Irp to return their + // buffers and their WDFMEMORY handles should be valid in the cleanup routine + // for the WDFREQUEST. We also keep m_Irp valid until after the + // m_IrpReferenceCount check, so we can trace out the buffers in case of + // error. + // + m_Irp.SetIrp(NULL); + + if (irp.GetMajorFunction() == IRP_MJ_CREATE) { + // + // If this is the last handle to be closed on the device, then the call + // to CreateCompleted can cause the device to be deleted if the create + // has failed. We add a reference so that we make sure we have a device + // to free the request memory back to. + // + pRefedDevice = GetDevice(); + pRefedDevice->ADDREF(&irp); + + pRefedDevice->m_PkgGeneral->CreateCompleted(&irp); + } + else { + pRefedDevice = NULL; + } + + // + // WDM IRP is completed. + // + irp.CompleteRequest(GetPriorityBoost()); + + if (IsReserved() == FALSE) { + PostProcessCompletion(state, queue); + } + else { + PostProcessCompletionForReserved(state, queue); + } + + if (pRefedDevice != NULL) { + pRefedDevice->RELEASE(&irp); + pRefedDevice = NULL; + } + } + + return Status; +} + + +VOID +FxRequest::PostProcessCompletion( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ) +{ + // + // Fire frameworks internal callback event if one is set + // (FxIoQueue or IoTarget's internal use) + // + if (State != FxRequestCompletionStateNone) { + // + // NOTE: This occurs after the IRP has already been released, + // and is only used for notification that the request + // has completed. + // + if (State & FxRequestCompletionStateIoPkgFlag) { + GetDevice()->m_PkgIo->RequestCompletedCallback(this); + } + else { + ASSERT(Queue != NULL); + Queue->RequestCompletedCallback(this); + //FxIoQueueToMx::RequestCompletedCallback(Queue, this); + } + + // + // DeleteObject will dereference the object reference taken when the callback + // was registered + // + DeleteEarlyDisposedObject(); + } + else { + // + // Caller still wants the FxRequest class to be valid on return, + // but must call DeleteObject in order to ensure the object is + // no longer assigned any child objects, etc. + // + ADDREF(FXREQUEST_COMPLETE_TAG); + DeleteObject(); + } +} + +VOID +FxRequest::PostProcessCompletionForReserved( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ) +{ + // + // Fire frameworks internal callback event if one is set + // (FxIoQueue or IoTarget's internal use) + // + if (State != FxRequestCompletionStateNone) { + // + // NOTE: This occurs after the IRP has already been released, + // and is only used for notification that the request + // has completed. + // + if (State & FxRequestCompletionStateIoPkgFlag) { + GetDevice()->m_PkgIo->RequestCompletedCallback(this); + } + else { + ASSERT(m_IoQueue == Queue); + Queue->RequestCompletedCallback(this); + } + } + else { + // + // Caller still wants the FxRequest class to be valid on return, + // but must call DeleteObject in order to ensure the object is + // no longer assigned any child objects, etc. + // + ADDREF(FXREQUEST_COMPLETE_TAG); + } + + RELEASE(FXREQUEST_FWDPRG_TAG); +} + +// +// Handles pre-process completion for driver-created-requests queued by the driver. +// +VOID +FxRequest::PreProcessCompletionForDriverRequest( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ) +{ + ASSERT(State == FxRequestCompletionStateNone || + State == FxRequestCompletionStateQueue); + // + // Fire frameworks internal callback (pre) event if one is set. + // + if (FxRequestCompletionStateQueue == State) { + // + // NOTE: This occurs before the IRP has already been released, + // and is only used to notify the queue to remove this request from this queue's + // internal lists. A second notification (lPostProcessCompletionForAllocatedDriver) + // is made after the IRP is completed. + // + Queue->PreRequestCompletedCallback(this); + } + else if (Queue != NULL){ + // + // On return from PostProcessCompletionForDriverRequest, caller (framework) + // will try to release the last ref. Increase the ref count so request stays alive until + // driver invokes WdfObjectDelete on this request. + // + ADDREF(FXREQUEST_COMPLETE_TAG); + } + + // + // Let the system know that it is OK to complete this request. + // + RELEASE(FXREQUEST_DCRC_TAG); +} + +// +// Handles post-process completion for driver-created-requests queued by the driver. +// On return the driver can delete the request with WdfObjectDelete. +// NOTE: request may be already gone/reused. Do not dereference this or access any of its +// members... its pointer is only used for logging. +// +VOID +FxRequest::PostProcessCompletionForDriverRequest( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ) +{ + // + // NOTE: Do not touch the request object here. The request object may already be + // re-used or deleted. + // + + ASSERT(State == FxRequestCompletionStateNone || + State == FxRequestCompletionStateQueue); + // + // Fire frameworks internal callback (post) event if one is set. + // + if (FxRequestCompletionStateQueue == State) { + // + // NOTE: This occurs after the IRP has already been released, and is only used + // to notify the queue to update its internal state and if appropriate, send + // another request. + // + Queue->PostRequestCompletedCallback(this); + } +} + +VOID +FxRequest::FreeRequest( + VOID + ) +/*++ + +Routine Description: + + This routine is called to free a reserved request or in case of Fxpkgio + a non-reserved request. + +--*/ +{ + // + // Restore any fields if necessary + // + if (m_RequestContext != NULL) { + // + // m_RequestContext will be freed when the FxRequest's destructor runs + // + m_RequestContext->ReleaseAndRestore(this); + } + + // + // If the request is not presented to the driver then clear the + // cleanup & destroy callbacks before calling PerformEarlyDispose. + // + if (m_Presented == FALSE) { + ClearEvtCallbacks(); + } + + DeleteObject(); +} + +VOID +FX_VF_METHOD(FxRequest, VerifyPreProcessSendAndForget) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + PAGED_CODE_LOCKED(); + + if (m_CompletionRoutine.m_Completion != NULL) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p cannot send and forget will not execute completion " + "routine %p", + GetHandle(), m_CompletionRoutine.m_Completion); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + + + + + + + + + } + + // + // You cannot fire and forget a create irp if we created a WDFFILEOBJECT + // for it since you must post process the status of the create because + // the create can fail in the driver to which we are sending the irp. + // + if ((m_Irp.GetMajorFunction() == IRP_MJ_CREATE) + && + (FxFileObjectClassNormalize(GetDevice()->GetFileObjectClass()) != + WdfFileObjectNotRequired)) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p cannot send and forget a create request which " + "has a WDFFILEOBJECT created for it, it must have a completion " + "routine and be post processsed", GetHandle()); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } +} + +VOID +FxRequest::PreProcessSendAndForget( + VOID + ) +{ + VerifyPreProcessSendAndForget(GetDriverGlobals()); + + // + // To be sent and forgotten, the irp must have been presented + // + ASSERT(m_Presented); + + // + // To be sent and forgotten, the irp must not have a formatted IO context. + // + ASSERT(HasContext() == FALSE); + + // + // If the driver writer setup the next stack location using the current + // stack location or did a manual IO_STACK_LOCATION copy, we do not want to + // skip the current stack location that their format is used by the target + // driver. + // + if (m_NextStackLocationFormatted == FALSE) { + m_Irp.SkipCurrentIrpStackLocation(); + } + + if (IsReserved() == FALSE) { + + // + // If a cleanup callback has been registered, we call it + // just before sending the IRP on its way. The contract is that the cleanup + // routine for a WDFREQUEST is called while the PIRP is still valid. + // + if (EarlyDispose() == FALSE) { + VerifierBreakpoint_RequestEarlyDisposeDeferred(GetDriverGlobals()); + } + + // + // Now that the entire tree is disposed, we want to destroy all of the + // children. This will not put this object in the destroyed state. For + // m_IrpReferenceCount to go to zero, we need to destroy the child WDFMEMORYs + // that were created when we probed and locked the buffers. + // + DestroyChildren(); + } +} + +VOID +FxRequest::PostProcessSendAndForget( + VOID + ) +{ + FxRequestCompletionState state; + FxIoQueue* pQueue; + + m_Irp.SetIrp(NULL); + + // + // Capture the m_IoQueue value before making any other calls. + // Note: m_IoQueue could be NULL if the request is freed before it's queued. + // + pQueue = m_IoQueue; + + ASSERT(m_CompletionState != FxRequestCompletionStateNone); + + state = (FxRequestCompletionState) m_CompletionState; + m_CompletionState = FxRequestCompletionStateNone; + + // + // Technically we did not complete the irp, but a send and forget is + // functionally the same. We no longer own the irp. + // + if (IsReserved() == FALSE) { + PostProcessCompletion(state, pQueue); + } + else { + // + // Release checks m_Completed flag to decide whether to return + // the request to reserved pool. + // + m_Completed = TRUE; + PostProcessCompletionForReserved(state, pQueue); + } +} + +NTSTATUS +FxRequest::GetStatus( + VOID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + + if (pFxDriverGlobals->FxVerifierIO) { + KIRQL irql; + + Lock(&irql); + + + + + + + + + status = m_Irp.GetStatus(); + + Unlock(irql); + + return status; + } + else { + return m_Irp.GetStatus(); + } +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetParameters( + __out PWDF_REQUEST_PARAMETERS Parameters + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + // + // No lock needed. Only reason this may be invalid is due + // to previous completion, which is a serious driver bug + // that will result in a crash anyway. + // + + if (pFxDriverGlobals->FxVerifierIO) { + KIRQL irql; + NTSTATUS status; + + Lock(&irql); + + status = VerifyRequestIsCurrentStackValid(pFxDriverGlobals); + if (NT_SUCCESS(status)) { + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + } + + Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + ASSERT(Parameters->Size >= sizeof(WDF_REQUEST_PARAMETERS)); + + // How much we copied + Parameters->Size = sizeof(WDF_REQUEST_PARAMETERS); + + + // Copy parameters + Parameters->Type = (WDF_REQUEST_TYPE)m_Irp.GetMajorFunction(); + Parameters->MinorFunction = m_Irp.GetMinorFunction(); + + // Copy the Parameters structure which we are a subset of + m_Irp.CopyParameters(Parameters); + + if (pFxDriverGlobals->FxVerifierIO) { + // + // If verifier is on, and the operation is an IRP_MJ_DEVICE_CONTROL + // with METHOD_NEITHER, then set Type3InputBuffer to zero since + // this should not be used to pass parameters in the normal path + // + if((m_Irp.GetMajorFunction() == IRP_MJ_DEVICE_CONTROL) && + m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) { + Parameters->Parameters.DeviceIoControl.Type3InputBuffer = NULL; + } + } + + return STATUS_SUCCESS; +} + + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetMemoryObject( + __deref_out IFxMemory** MemoryObject, + __out PVOID* Buffer, + __out size_t* Length + ) +{ + PMDL pMdl; + NTSTATUS status; + ULONG length; + KIRQL irql; + BOOLEAN mapMdl, mdlMapped; + UCHAR majorFunction; + + status = STATUS_SUCCESS; + length = 0x0; + mapMdl = FALSE; + mdlMapped = FALSE; + irql = PASSIVE_LEVEL; + majorFunction = m_Irp.GetMajorFunction(); + + + // + // Verifier + // + if (GetDriverGlobals()->FxVerifierIO) { + status = VerifyRequestIsNotCompleted(GetDriverGlobals()); + if (!NT_SUCCESS(status)) { + goto Done; + } + if (m_Irp.GetRequestorMode() == UserMode + && + (majorFunction == IRP_MJ_WRITE || + majorFunction == IRP_MJ_READ) + && + GetDevice()->GetIoType() == WdfDeviceIoNeither) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to get UserMode Buffer Pointer for WDFDEVICE 0x%p, " + "WDFREQUEST 0x%p, %!STATUS!", + GetDevice()->GetHandle(), GetHandle(), status); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver must use buffered or direct I/O for this call, or use " + "WdfDeviceInitSetIoInCallerContextCallback to probe and lock " + "user mode memory"); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + + if ((m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid) == 0x00) { + Lock(&irql); + } + + // + // We must dig into the IRP to get the buffer, length, and readonly status + // + + switch (majorFunction) { + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + length = m_Irp.GetParameterIoctlInputBufferLength(); + + if (length == 0) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p InputBufferLength length is zero, %!STATUS!", + GetObjectHandle(), status); + + goto Done; + } + + if (m_Irp.GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) { + // + // Internal device controls are kernel mode to kernel mode, and deal + // with direct unmapped pointers. + // + // In addition, a normal device control with + // RequestorMode == KernelMode is also treated as kernel mode + // to kernel mode since the I/O Manager will not generate requests + // with this setting from a user mode request. + // + if ((m_Irp.GetRequestorMode() == KernelMode) || + (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) { + DO_NOTHING(); + } + else { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to get UserMode Buffer Pointer for METHOD_NEITHER " + "DeviceControl 0x%x, WDFDEVICE 0x%p, WDFREQUEST 0x%p, " + "%!STATUS!", + m_Irp.GetParameterIoctlCode(), + GetDevice()->GetHandle(), GetHandle(), status); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT I/O for " + "this call, or use WdfDeviceInitSetIoInCallerContextCallback to " + "probe and lock user mode memory %!STATUS!", + STATUS_INVALID_DEVICE_REQUEST); + + goto Done; + } + } + break; + + case IRP_MJ_READ: + length = m_Irp.GetParameterReadLength(); + + if (GetDevice()->GetIoTypeForReadWriteBufferAccess() == WdfDeviceIoDirect) { + KMDF_ONLY_CODE_PATH_ASSERT(); + mapMdl = TRUE; + } + break; + + case IRP_MJ_WRITE: + length = m_Irp.GetParameterWriteLength(); + + if (GetDevice()->GetIoTypeForReadWriteBufferAccess() == WdfDeviceIoDirect) { + KMDF_ONLY_CODE_PATH_ASSERT(); + mapMdl = TRUE; + } + break; + + default: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Unrecognized Major Function 0x%x on WDFDEVICE 0x%p WDFREQUEST 0x%p", + majorFunction, GetDevice()->GetHandle(), GetHandle()); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + status = STATUS_INVALID_DEVICE_REQUEST; + goto Done; + } + + if (length == 0) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p length is zero, %!STATUS!", + GetHandle(), status); + + goto Done; + } + + // + // See if we need to map + // + if (mapMdl && (m_RequestBaseFlags & FxRequestBaseSystemMdlMapped) == 0x00) { + pMdl = m_Irp.GetMdl(); + + if (pMdl == NULL) { + // + // Zero length transfer + // + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, direct io device, PMDL is NULL, " + "%!STATUS!", GetHandle(), status); + + ASSERT(length == 0); + } + else { + PVOID pVA; + + // + // PagePriority may need to be a property, and/or parameter to + // this call + // + // + // Upon success, MmGetSystemAddressForMdlSafe stores the mapped + // VA pointer in the pMdl and upon subsequent calls to + // MmGetSystemAddressForMdlSafe, no mapping is done, just + // the stored VA is returned. FxRequestSystemBuffer relies + // on this behavior and, more importantly, relies on this function + // to do the initial mapping so that FxRequestSystemBuffer::GetBuffer() + // will not return a NULL pointer. + // + pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority); + + if (pVA == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p could not get a system address for PMDL " + "0x%p, %!STATUS!", GetHandle(), pMdl, status); + } + else { + // + // System will automatically release the mapping PTE's when + // the MDL is released by the I/O request + // + + + + + + m_SystemBuffer.SetMdl(m_Irp.GetMdl()); + + m_RequestBaseFlags |= FxRequestBaseSystemMdlMapped; + } + } + } + +Done: + if ((m_RequestBaseStaticFlags & FxRequestBaseStaticSystemBufferValid) == 0x00) { + Unlock(irql); + } + + if (NT_SUCCESS(status)) { + *MemoryObject = &m_SystemBuffer; + + if (mapMdl) { + *Buffer = Mx::MxGetSystemAddressForMdlSafe(m_SystemBuffer.m_Mdl, + NormalPagePriority); + } + else { + *Buffer = m_SystemBuffer.m_Buffer; + } + + *Length = length; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetDeviceControlOutputMemoryObject( + __deref_out IFxMemory** MemoryObject, + __out PVOID* Buffer, + __out size_t* Length + ) +/*++ + +Routine Description: + + Return the IRP_MJ_DEVICE_CONTROL OutputBuffer. + + The memory buffer is valid in any thread/process context, + and may be accessed at IRQL > PASSIVE_LEVEL. + + The memory buffer is automatically released when the request + is completed. + + The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or for any request other than IRP_MJ_DEVICE_CONTROL. + + The Memory buffer is as follows for each buffering mode: + + METHOD_BUFFERED: + + Irp->UserBuffer // This is actually a system address + + METHOD_IN_DIRECT: + + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + + METHOD_OUT_DIRECT: + + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + + METHOD_NEITHER: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The buffer is only valid until the request is completed. + +Arguments: + + MemoryObject - Pointer location to return the memory object interface. + + Buffer - Pointer location to return buffer ptr + + Length - Pointer location to return buffer length. + +Returns: + + NTSTATUS + +--*/ +{ + size_t length; + NTSTATUS status; + KIRQL irql; + BOOLEAN mapMdl; + UCHAR majorFunction; + + UNREFERENCED_PARAMETER(Buffer); + UNREFERENCED_PARAMETER(Length); + + status = STATUS_SUCCESS; + length = 0; + irql = PASSIVE_LEVEL; + mapMdl = FALSE; + + // + // Verifier + // + if (GetDriverGlobals()->FxVerifierIO ) { + status = VerifyRequestIsNotCompleted(GetDriverGlobals()); + if (!NT_SUCCESS(status)) { + return status; + } + } + + if ((m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid) == 0x00) { + Lock(&irql); + } + + // + // See if we already have a validated buffer + // + //if (m_RequestBaseFlags & FxRequestBaseOutputBufferValid) { + // status = STATUS_SUCCESS; + //} + + majorFunction = m_Irp.GetMajorFunction(); + + ASSERT(majorFunction == IRP_MJ_DEVICE_CONTROL || + majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL); + + length = m_Irp.GetParameterIoctlOutputBufferLength(); + + if (length == 0) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p IOCTL output buffer length is zero, %!STATUS!", + GetHandle(), status); + + goto Done; + } + + switch (m_Irp.GetParameterIoctlCodeBufferMethod()) { + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with read access + // + case METHOD_IN_DIRECT: + // || || fall || || + // \/ \/ through \/ \/ + + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with read access + // + case METHOD_OUT_DIRECT: + mapMdl = TRUE; + break; + + case METHOD_NEITHER: + // + // Internal device controls are kernel mode to kernel mode, and deal + // with direct unmapped pointers. + // + // In addition, a normal device control with + // RequestorMode == KernelMode is also treated as kernel mode + // to kernel mode since the I/O Manager will not generate requests + // with this setting from a user mode request. + // + if ((m_Irp.GetRequestorMode() == KernelMode) || + (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) { + DO_NOTHING(); + } + else { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to get UserMode Buffer Pointer for " + "METHOD_NEITHER DeviceControl 0x%x, WDFDEVICE 0x%p, " + "WDFREQUEST 0x%p, %!STATUS!", + m_Irp.GetParameterIoctlCode(), + GetDevice()->GetHandle(), GetObjectHandle(), status); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT " + "I/O for this call, or use " + "WdfDeviceInitSetIoInCallerContextCallback to probe and " + "lock user mode memory"); + } + break; + } + + if (mapMdl && (m_RequestBaseFlags & FxRequestBaseOutputMdlMapped) == 0x0) { + PMDL pMdl; + PVOID pVA; + + + pMdl = m_Irp.GetMdl(); + + if (pMdl == NULL) { + // + // Zero length transfer + // + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, METHOD_IN_DIRECT IOCTL PMDL is NULL, " + "%!STATUS!", GetHandle(), status); + + ASSERT( + m_Irp.GetParameterIoctlOutputBufferLength()== 0 + ); + } + else { + // + // PagePriority may need to be a property, and/or parameter to + // this call + // + // + // Upon success, MmGetSystemAddressForMdlSafe stores the mapped + // VA pointer in the pMdl and upon subsequent calls to + // MmGetSystemAddressForMdlSafe, no mapping is done, just + // the stored VA is returned. FxRequestOutputBuffer relies + // on this behavior and, more importantly, relies on this function + // to do the initial mapping so that FxRequestOutputBuffer::GetBuffer() + // will not return a NULL pointer. + // + pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority); + + if (pVA == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p could not get a system address for PMDL" + "0x%p, %!STATUS!", GetHandle(), pMdl, status); + } + else { + m_OutputBuffer.SetMdl(pMdl); + m_RequestBaseFlags |= FxRequestBaseOutputMdlMapped; + status = STATUS_SUCCESS; + } + } + } + +Done: + if ((m_RequestBaseStaticFlags & FxRequestBaseStaticOutputBufferValid) == 0x00) { + Unlock(irql); + } + + if (NT_SUCCESS(status)) { + *MemoryObject = &m_OutputBuffer; + if (mapMdl) { + *Buffer = Mx::MxGetSystemAddressForMdlSafe(m_OutputBuffer.m_Mdl, + NormalPagePriority); + } + else { + *Buffer = m_OutputBuffer.m_Buffer; + } + *Length = length; + } + + return status; +} + +FxRequestCompletionState +FxRequest::SetCompletionState( + __in FxRequestCompletionState NewState + ) +{ + FxRequestCompletionState oldState; + + // + // The flag by itself should never be specified + // + ASSERT(NewState != FxRequestCompletionStateIoPkgFlag); + + // + // No need to lock. Only the "owner" can set the completion + // callback function, and this is when under the general + // FxIoQueue lock. + // + + // Request is already completed, awaiting final dereference + if (m_Completed) { + oldState = FxRequestCompletionStateNone; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p has already been completed", + GetHandle()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + else { + ASSERT(m_Irp.GetIrp() != NULL); + + oldState = (FxRequestCompletionState) m_CompletionState; + + m_CompletionState = (BYTE) NewState; + + if (NewState == FxRequestCompletionStateNone && + oldState != FxRequestCompletionStateNone) { + // + // Cancelling a callback, so release the callback reference + // + RELEASE(FXREQUEST_STATE_TAG); + } + else if (NewState != FxRequestCompletionStateNone && + oldState == FxRequestCompletionStateNone) { + // + // Adding a callback requires a reference + // + ADDREF(FXREQUEST_STATE_TAG); + } + else { + // + // else we leave the current reference alone + // + DO_NOTHING(); + } + } + + return oldState; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyInsertIrpQueue) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxIrpQueue* IrpQueue + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + // + // Check to make sure we are not already in an Irp queue + // + if (m_IrpQueue != NULL) { + status = STATUS_INTERNAL_ERROR; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Already in FxIrpQueue 0x%p WDFREQUEST 0x%p %!STATUS!", + IrpQueue, GetHandle(), status); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + + goto Done; + } + + // + // If request is completed, fail. + // This is because the driver can complete the request + // right away in another thread while returning STATUS_PENDING + // from EvtIoDefault + // + status = VerifyRequestIsNotCompleted(FxDriverGlobals); + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::InsertTailIrpQueue( + __in FxIrpQueue* IrpQueue, + __out_opt ULONG* pRequestCount + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + + // No locking required since only one accessor till inserted on queue + + status = VerifyInsertIrpQueue(pFxDriverGlobals, IrpQueue); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // If a request is on an IrpQueue, it must be referenced + // + + + + + + + ADDREF(FXREQUEST_QUEUE_TAG); + + ASSERT(m_Completed == FALSE); + ASSERT(m_IrpQueue == NULL); + + m_IrpQueue = IrpQueue; + + status = IrpQueue->InsertTailRequest(m_Irp.GetIrp(), + &m_CsqContext, + pRequestCount); + + // + // If this insert failed, we must release the extra reference we took + // + if (!NT_SUCCESS(status)) { + MarkRemovedFromIrpQueue(); + RELEASE(FXREQUEST_QUEUE_TAG); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::InsertHeadIrpQueue( + __in FxIrpQueue* IrpQueue, + __out_opt ULONG* pRequestCount + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + + // No locking required since only one accessor till inserted on queue + + status = VerifyInsertIrpQueue(pFxDriverGlobals, IrpQueue); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // If a request is on an IrpQueue, it must be referenced + // + + + + + + + ADDREF(FXREQUEST_QUEUE_TAG); + + ASSERT(m_Completed == FALSE); + ASSERT(m_IrpQueue == NULL); + + m_IrpQueue = IrpQueue; + + status = IrpQueue->InsertHeadRequest(m_Irp.GetIrp(), + &m_CsqContext, + pRequestCount); + + // + // If this insert failed, we must release the extra reference we took + // + if (!NT_SUCCESS(status)) { + MarkRemovedFromIrpQueue(); + RELEASE(FXREQUEST_QUEUE_TAG); + } + + return status; +} + +// +// Remove request from its IRP queue +// +_Must_inspect_result_ +NTSTATUS +FxRequest::RemoveFromIrpQueue( + __in FxIrpQueue* IrpQueue + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + MdIrp pIrp; + + pFxDriverGlobals = GetDriverGlobals(); + + // + // Cancel Safe Queues allow this request + // removal to be race free even if the + // request has been cancelled already. + // + // It signals this by returning NULL for + // the Irp. + // + pIrp = IrpQueue->RemoveRequest(&m_CsqContext); + + if (pIrp == NULL) { + + // + // Cancel routine removed it from the cancel + // safe queue. + // + // The cancel handler will remove this reference + // in FxIoQueue::_IrpCancelForDriver / + // FxIrpQueue::_WdmCancelRoutineInternal + // + + return STATUS_CANCELLED; + } + else { + + // + // We retrieved the Irp from the cancel safe queue + // without it having been cancelled first. + // + // It is no longer cancelable + // + if (pFxDriverGlobals->FxVerifierOn) { + if (m_IrpQueue == NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p not on IrpQueue", + GetHandle()); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + + MarkRemovedFromIrpQueue(); + + RELEASE(FXREQUEST_QUEUE_TAG); + + return STATUS_SUCCESS; + } +} + +// +// Function to return the next FxRequest from an FxIrpQueue +// +_Must_inspect_result_ +FxRequest* +FxRequest::GetNextRequest( + __in FxIrpQueue* IrpQueue + ) +{ + MdIrp pIrp; + FxRequest* pRequest; + PMdIoCsqIrpContext pCsqContext; + + pIrp = IrpQueue->GetNextRequest(&pCsqContext); + + if (pIrp == NULL) { + return NULL; + } + + // Irp is not cancellable now + pRequest = FxRequest::RetrieveFromCsqContext(pCsqContext); + + // Must tell the request it's off the queue + pRequest->MarkRemovedFromIrpQueue(); + + // Remove reference placed when on IrpQueue + pRequest->RELEASE(FXREQUEST_QUEUE_TAG); + + return pRequest; +} + +// +// Function to return an FxRequest from an FxIrpQueue based +// on optional context and/or file object. +// +_Must_inspect_result_ +NTSTATUS +FxRequest::GetNextRequest( + __in FxIrpQueue* IrpQueue, + __in_opt MdFileObject FileObject, + __in_opt FxRequest* TagRequest, + __deref_out FxRequest** ppOutRequest + ) +{ + NTSTATUS Status; + FxRequest* pRequest; + PMdIoCsqIrpContext TagCsqContext; + + if( TagRequest != NULL ) { + TagCsqContext = TagRequest->GetCsqContext(); + } + else { + TagCsqContext = NULL; + } + + Status = IrpQueue->GetNextRequest( TagCsqContext, FileObject, &pRequest ); + if( !NT_SUCCESS(Status) ) { + return Status; + } + + // Irp is not cancellable now + + // Must tell the request its off the queue + pRequest->MarkRemovedFromIrpQueue(); + + // Remove reference placed when on IrpQueue + pRequest->RELEASE(FXREQUEST_QUEUE_TAG); + + *ppOutRequest = pRequest; + + return STATUS_SUCCESS; +} + +// +// Allow peeking at requests in the IrpQueue +// +_Must_inspect_result_ +NTSTATUS +FxRequest::PeekRequest( + __in FxIrpQueue* IrpQueue, + __in_opt FxRequest* TagRequest, + __in_opt MdFileObject FileObject, + __out_opt PWDF_REQUEST_PARAMETERS Parameters, + __deref_out FxRequest** ppOutRequest + ) +{ + NTSTATUS Status; + + PMdIoCsqIrpContext TagContext = NULL; + + // + // IrpQueue::PeekRequest works with CSQ_CONTEXT + // structures since this is the only value that + // is valid across cancellation. + // + if( TagRequest != NULL ) { + TagContext = TagRequest->GetCsqContext(); + } + + Status = IrpQueue->PeekRequest( + TagContext, + FileObject, + ppOutRequest + ); + if(NT_SUCCESS(Status)) { + + if( Parameters != NULL ) { + Status = (*ppOutRequest)->GetParameters(Parameters); + } + } + + return Status; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::Reuse( + __in PWDF_REQUEST_REUSE_PARAMS ReuseParams + ) +{ + FxIrp currentIrp; + FxRequestContext* pContext; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + // + // Make sure request is not pended in IoTarget. + // + if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) { + SHORT flags; + KIRQL irql; + + Lock(&irql); + flags = GetVerifierFlagsLocked(); + if (flags & FXREQUEST_FLAG_SENT_TO_TARGET) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver is trying to reuse WDFREQUEST 0x%p while it is still " + "active on WDFIOTARGET 0x%p. ", + GetTraceObjectHandle(), GetTarget()->GetHandle()); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + Unlock(irql); + } + + // + // For drivers 1.9 and above (for maintaining backwards compatibility) + // deregister previously registered completion routine. + // + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { + SetCompletionRoutine(NULL, NULL); + } + + pContext = NULL; + currentIrp.SetIrp(m_Irp.GetIrp()); + + if (currentIrp.GetIrp() != NULL) { + // + // Release all outstanding references and restore original fields in + // the PIRP + // + if (m_RequestContext != NULL) { + m_RequestContext->ReleaseAndRestore(this); + } + + if (m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO) { + // + // An irp presented by io queue can only reset a limited state + // + if (ReuseParams->Flags & WDF_REQUEST_REUSE_SET_NEW_IRP) { + // + // Not allowed to set a new irp + // + return STATUS_WDF_REQUEST_INVALID_STATE; + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + currentIrp.SetStatus(ReuseParams->Status); + currentIrp.SetCancel(FALSE); +#else + // + // For UMDF, host sets cancel flag to false as part of Reuse(), so no + // need to have a separate call for UMDF (that's why host irp doesn't + // expose any interface to set this independently). + + + + + // + currentIrp.Reuse(ReuseParams->Status); +#endif + m_Completed = FALSE; + m_Canceled = FALSE; + + return STATUS_SUCCESS; + } + else if (m_IrpAllocation == REQUEST_ALLOCATED_DRIVER) { + // + // Release outstanding reference on a must complete driver request. + // + if (m_CanComplete && m_Completed == FALSE) { + ASSERT(GetRefCnt() >= 2); + + if (pFxDriverGlobals->FxVerifierOn) { + ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED); + } + + RELEASE(FXREQUEST_DCRC_TAG); + } + } + } + else { + // + // We should not have a m_RequestContext with anything to ReleaseAndRestore + // because there is no IRP to have anything formatted off of. + // + DO_NOTHING(); + } + + // + // This cannot be a request on a queue + // + ASSERT(m_CompletionState == FxRequestCompletionStateNone && + m_IoQueue == NULL); + + if (ReuseParams->Flags & WDF_REQUEST_REUSE_SET_NEW_IRP) { + currentIrp.SetIrp((MdIrp)ReuseParams->NewIrp); + + // + // If we are replacing an internal irp, we must free it later. + // + if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) { + MdIrp pOldIrp; + + ASSERT(m_CanComplete == FALSE); + pOldIrp = m_Irp.SetIrp(currentIrp.GetIrp()); + + if (pOldIrp != NULL) { + FxIrp oldIrp(pOldIrp); + oldIrp.FreeIrp(); + } + } + else { + (void) m_Irp.SetIrp(currentIrp.GetIrp()); + } + + m_IrpAllocation = REQUEST_ALLOCATED_DRIVER; + } + + // + // Only reinitialize an internal irp. If the irp is external, then its + // still valid. + // + if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL && currentIrp.GetIrp() != NULL) { + ASSERT(m_CanComplete == FALSE); + ASSERT(m_Completed == FALSE); + currentIrp.Reuse(ReuseParams->Status); + + // + // For UMDF, host sets cancel flag to false as part of Reuse(), so no + // need to have a separate call for UMDF (that's why host irp doesn't + // expose any interface to set this independently). + + + + + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + currentIrp.SetCancel(FALSE); +#endif + } + + // + // If necessary, reinit the request to support WdfRequestComplete. + // + if (ReuseParams->Flags & WDF_REQUEST_REUSE_MUST_COMPLETE) { + NTSTATUS status; + + // + // WDF guarantees a successful return code when the driver calls Reuse() from its + // completion routine with valid input. + // + + // + // This feature can only be used from WDF v1.11 and above. + // + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue, %!STATUS!", + GetTraceObjectHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // 'must_complete' flag requires an IRP. + // + if (currentIrp.GetIrp() == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver is trying to reuse WDFREQUEST 0x%p without " + "specifying an IRP with " + "WDF_REQUEST_REUSE_MUST_COMPLETE flag, %!STATUS!", + GetTraceObjectHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Do not support internal IRPs. + // + if (m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver is trying to reuse WDFREQUEST 0x%p holding an" + "internal allocated IRP with " + "WDF_REQUEST_REUSE_MUST_COMPLETE flag, %!STATUS!", + GetTraceObjectHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Ref count must be 1. + // + if (GetRefCnt() != 1) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver is trying to reuse WDFREQUEST 0x%p with " + "WDF_REQUEST_REUSE_MUST_COMPLETE flag while request is " + "being referenced, reference count:%d, %!STATUS!", + GetTraceObjectHandle(), GetRefCnt(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Make sure current IRP stack location is valid. + // + if (currentIrp.IsCurrentIrpStackLocationValid() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "IRP %p of WDFREQUEST %p doesn't have a valid" + " stack location, %!STATUS!", + currentIrp.GetIrp(), GetHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // This ref is removed when: + // (a) the request is completed or + // (b) the request is reused and old request/IRP was never sent and completed. + // + ADDREF(FXREQUEST_DCRC_TAG); + + // + // Note: strange why ClearFieldsForReuse() is not used all the time... just in case, + // keeping old logic for compatibility. + // + ClearFieldsForReuse(); + m_CanComplete = TRUE; + + if (pFxDriverGlobals->FxVerifierOn) { + SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED); + } + } + else { + m_CanComplete = FALSE; + m_Completed = FALSE; + m_Canceled = FALSE; + + if (pFxDriverGlobals->FxVerifierOn) { + ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED); + } + } + + return STATUS_SUCCESS; +} + +// +// Return the FxFileObject if associated with this request +// +_Must_inspect_result_ +NTSTATUS +FxRequest::GetFileObject( + __deref_out_opt FxFileObject** FileObject + ) +{ + NTSTATUS status; + FxFileObject* pFileObject; + CfxDevice* pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFileObject = NULL; + pFxDriverGlobals = GetDriverGlobals(); + + pDevice = GetDevice(); + + if (pFxDriverGlobals->FxVerifierIO) { + KIRQL irql; + *FileObject = NULL; + + Lock(&irql); + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + + Unlock(irql); + if (!NT_SUCCESS(status)) { + return status; + } + + } + + if (NULL == m_Irp.GetFileObject() && IsAllocatedDriver()) { + ASSERT(TRUE == m_CanComplete); + // + // This is a 'must_complete' driver created request. + // + *FileObject = NULL; + return STATUS_SUCCESS; + } + + status = FxFileObject::_GetFileObjectFromWdm( + pDevice, + pDevice->GetFileObjectClass(), + m_Irp.GetFileObject(), + &pFileObject + ); + + if (NT_SUCCESS(status) && pFileObject != NULL) { + *FileObject = pFileObject; + return STATUS_SUCCESS; + } + else if (NT_SUCCESS(status) && + FxIsFileObjectOptional(pDevice->GetFileObjectClass())) { + // + // Driver told us that it is ok for the file object to be NULL. + // + *FileObject = NULL; + return STATUS_SUCCESS; + } + else { + return STATUS_INVALID_DEVICE_REQUEST; + } +} + +VOID +FxRequest::AddIrpReference( + VOID + ) +/*++ + +Routine Description: + + Adds a reference to the IRP contained in the request. + + This is used to check that FxRequest::Complete is not + called with outstanding references to any IRP related + fields such as memory buffers. + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + pFxDriverGlobals = GetDriverGlobals(); + + if (pFxDriverGlobals->FxVerifierOn) { + KIRQL irql; + + Lock(&irql); + + (VOID)VerifyRequestIsNotCompleted(pFxDriverGlobals); + + Unlock(irql); + } + + InterlockedIncrement(&m_IrpReferenceCount); + + return; +} + +VOID +FxRequest::ReleaseIrpReference( + VOID + ) +/*++ + +Routine Description: + + Release a reference to the IRP contained in the request. + +Arguments: + + None + +Return Value: + + None + +--*/ +{ + LONG count; + + count = InterlockedDecrement(&m_IrpReferenceCount); + + if( count < 0 ) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to release an IRP reference without adding " + "one first WDFREQUEST 0x%p",GetHandle()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + return; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyProbeAndLock) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE_LOCKED(); + + MdEThread thread = m_Irp.GetThread(); + + // + // Some kernel mode drivers issue I/O without setting this + // + if (thread != NULL) { + // + // Currently DDK level headers don't let us reach into a threads + // parent process, so we can't do the process level check, just + // a thread level check. + // + if (m_Irp.GetRequestorMode() == UserMode && thread != Mx::GetCurrentEThread()) { + status = STATUS_ACCESS_VIOLATION; + + // Error, wrong process context... + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to access user mode memory from the wrong process " + "Irp->Tail.Overlay.Thread 0x%p, PsGetCurrentThread 0x%p, " + "%!STATUS!", thread, Mx::GetCurrentEThread(), status); + + return status; + } + } + else { + // Irp->Thread should be issued for all user mode requests + ASSERT(m_Irp.GetRequestorMode() == KernelMode); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyStopAcknowledge) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ BOOLEAN Requeue + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + Lock(&irql); + + // + // Make sure the driver is calling this function in the context + // of EvtIoStop callback. + // + status = VerifyRequestIsInEvtIoStopContext(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (m_Completed == FALSE && Requeue) { + + // Make sure the driver owns the request + + status = VerifyRequestIsDriverOwned(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Can't re-enqueue a cancelable request + // + status = VerifyRequestIsNotCancelable(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + } + +Done: + Unlock(irql); + return status; +} + +VOID +FxRequest::StopAcknowledge( + __in BOOLEAN Requeue + ) +/*++ + +Routine Description: + + This routine saves the acknowledgement in the request object + which will be looked at and processed later by the queue + dispatch event loop + +Arguments: + + Requeue - if TRUE, put the request back into the head + of queue from which it was delivered to the driver. +Return Value: + + None + +--*/ +{ + NTSTATUS status; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + status = VerifyStopAcknowledge(FxDriverGlobals, Requeue); + if(!NT_SUCCESS(status)) { + return; + } + + if (Requeue) { + m_PowerStopState = FxRequestPowerStopAcknowledgedWithRequeue; + } + else { + m_PowerStopState = FxRequestPowerStopAcknowledged; + } + + return; +} + +ULONG +FxRequest::AddRefOverride( + __in WDFOBJECT_OFFSET Offset, + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +{ + if (Offset != 0x0) { + ASSERT(Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset) || + Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset)); + AddIrpReference(); + return 2; + } + else { + return FxObject::AddRef(Tag, Line, File); + } +} + +ULONG +FxRequest::ReleaseOverride( + __in WDFOBJECT_OFFSET Offset, + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +{ + if (Offset != 0x0) { + ASSERT(Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset) || + Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset)); + ReleaseIrpReference(); + return 1; + } + else { + return FxObject::Release(Tag, Line, File); + } +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::QueryInterface( + __in FxQueryInterfaceParams* Params + ) +{ + switch (Params->Type) { + case FX_TYPE_REQUEST: + *Params->Object = (FxRequest*) this; + break; + + case IFX_TYPE_MEMORY: + if (Params->Offset == FIELD_OFFSET(FxRequest, m_SystemBufferOffset)) { + *Params->Object = (IFxMemory*) &m_SystemBuffer; + break; + } + else if (Params->Offset == FIELD_OFFSET(FxRequest, m_OutputBufferOffset)) { + *Params->Object = (IFxMemory*) &m_OutputBuffer; + break; + } + + // || || Fall || || + // \/ \/ through \/ \/ + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; +} + +VOID +FX_VF_METHOD(FxRequest, VerifierBreakpoint_RequestEarlyDisposeDeferred) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + PAGED_CODE_LOCKED(); + + // + // For backwards compatibility break only if WDF is v1.11 or above, or if + // the developer/client enabled these tests on down-level drivers. + // + if (FxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p deferred the dispose operation. This normally " + "indicates that at least one of its children asked for passive " + "level disposal. This is not supported.", GetHandle()); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsDriverOwned) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_OWNED) == 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p is not owned by the driver, %!STATUS!", + GetHandle(), status); + + // + // See if it's a tag request, since this could be a common mistake + // + if (m_VerifierFlags & FXREQUEST_FLAG_TAG_REQUEST) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p has been " + "used as a TagRequest in WdfIoQueueFindRequest. " + "A TagRequest cannot be used until it is retrieved " + "by WdfIoQueueRetrieveFoundRequest", + GetHandle()); + } + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsCancelable)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) == 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p is not cancelable, %!STATUS!", + GetHandle(), status); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsNotCancelable)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if (m_VerifierFlags & FXREQUEST_FLAG_DRIVER_CANCELABLE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p should be unmarked cancelable by calling " + "WdfRequestUnmarkCancelable, %!STATUS!", + GetHandle(), status); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsInCallerContext)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT) == 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "This call is valid only in EvtIoInCallerContext callback, " + "WDFREQUEST 0x%p, %!STATUS!", GetHandle(), status); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsInEvtIoStopContext)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if ((m_VerifierFlags & FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT) == 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "This call is valid only in EvtIoStop callback, " + "WDFREQUEST 0x%p, %!STATUS!", GetHandle(), status); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsNotCompleted)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if (m_Completed) { + status = STATUS_INTERNAL_ERROR; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p is already completed, %!STATUS!", + GetHandle(), status); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsTagRequest) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + // + // A request that has been marked as a tag request can be retrieved + // by the driver by calling WdfIoQueueRetrieveNextRequest instead of + // WdfIoQueueRetrieveFoundRequest. Some drivers use multiple threads + // to scan the queue, not the best design but allowed. This means that + // it is possible for one thread to remove and complete a request that is + // used as a tag by another thread. + // + if (FALSE == m_Completed && (0x0 == (m_VerifierFlags & + (FXREQUEST_FLAG_TAG_REQUEST | FXREQUEST_FLAG_DRIVER_OWNED)))) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Request 0x%p is not returned by WdfIoQueueFindRequest, " + "%!STATUS!", GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsAllocatedFromIo)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if (IsAllocatedFromIo() == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Request 0x%p was not allocated for an incoming IRP, " + "%!STATUS!", GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + + } else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestIsCurrentStackValid)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + MdIrp irp; + + PAGED_CODE_LOCKED(); + + // + //Make sure there is an IRP. + // + irp = GetFxIrp()->GetIrp(); + if (NULL == irp) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't have an IRP, %!STATUS!", + GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + // + // Validate the IRP's stack location values. + // + if (m_Irp.IsCurrentIrpStackLocationValid() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "IRP %p of WDFREQUEST %p doesn't have a valid" + " stack location, %!STATUS!", + irp, GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + status = STATUS_SUCCESS; + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxRequest, VerifyRequestCanBeCompleted)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) { + status = VerifyRequestIsAllocatedFromIo(FxDriverGlobals); + goto Done; + } + + // + // Validate the IRP's stack location. + // + status = VerifyRequestIsCurrentStackValid(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Note: There is no guarantees that the request has a completion routine in the current + // IRP stack location; thus we cannot check for it. + // + + // + // Make sure this request can be completed. + // + if (IsCanComplete() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "IRP %p of WDFREQUEST %p cannot be completed, " + "%!STATUS!", + GetFxIrp()->GetIrp(), GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + status = STATUS_SUCCESS; + +Done: + return status; +} + +ULONG +FxRequest::Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +{ + ULONG retValue; + BOOLEAN reservedRequest; + BOOLEAN allocFromIo; + BOOLEAN canComplete; + + // + // This may be the last ref, copy flags before calling Release(). + // + reservedRequest = IsReserved(); + allocFromIo = IsAllocatedFromIo(); + canComplete = IsCanComplete(); + + retValue = __super::Release(Tag, Line, File); + + if (reservedRequest && retValue == 1 && m_Completed) { + // + // Reserved requests should have an associated queue all the time. + // + m_ForwardProgressQueue->ReturnReservedRequest(this); + } + else if (allocFromIo == FALSE && canComplete && retValue == 1 && m_Completed) { + + FxRequestCompletionState state; + FxIoQueue* queue; + + // + // Make a local copy before request is gone. + // + state = (FxRequestCompletionState) m_CompletionState; + queue = m_IoQueue; + + m_CompletionState = FxRequestCompletionStateNone; + m_IoQueue = NULL; + + // + // We are now ready to complete this driver created request. + // + FxIrp irp(m_Irp.GetIrp()); + + m_Irp.SetIrp(NULL); + + irp.CompleteRequest(GetPriorityBoost()); + + PostProcessCompletionForDriverRequest(state, queue); + } + + return retValue; +} + +FxRequestFromLookaside::FxRequestFromLookaside( + __in CfxDevice* Device, + __in MdIrp Irp + ) : FxRequest(Device->GetDriverGlobals(), + Irp, + FxRequestDoesNotOwnIrp, + FxRequestConstructorCallerIsFx, + sizeof(FxRequestFromLookaside)) +{ + SetDeviceBase(Device->GetDeviceBase()); +} + +PVOID +FxRequestFromLookaside::operator new( + __in size_t Size, + __in CfxDevice* Device, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ) +{ + UNREFERENCED_PARAMETER(Size); + + // + // Allocate out of a device specific lookaside list + // + return Device->AllocateRequestMemory(Attributes); +} + +VOID +FxRequestFromLookaside::SelfDestruct( + VOID + ) +{ + CfxDevice* pDevice; + PFX_POOL_HEADER pHeader; + + // + // Store off the device in case the destructor chain sets it to NULL. + // + pDevice = GetDevice(); + ASSERT(pDevice != NULL); + + // + // Destroy the object + // + FxRequestFromLookaside::~FxRequestFromLookaside(); + + if (IsRequestForwardedToParent()) { + + #if FX_VERBOSE_TRACE + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Free FxRequest* %p memory", this); + #endif + + // + // Remove the request from the list of outstanding requests against this + // driver. + // + pHeader = FxObject::_CleanupPointer(GetDriverGlobals(), this); + MxMemory::MxFreePool(pHeader->Base); + } + else { + pDevice->FreeRequestMemory(this); + } +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequestapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequestapi.cpp new file mode 100644 index 00000000000..f5dad9e06fb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequestapi.cpp @@ -0,0 +1,3766 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestApi.cpp + +Abstract: + + This module implements FxRequest object + +Author: + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestApi.tmh" + +// +// Verifiers +// +// Do not supply Argument names +FX_DECLARE_VF_FUNCTION_P1( +NTSTATUS, +VerifyRequestComplete, + _In_ FxRequest* + ); + +// Do not supply Argument names +FX_DECLARE_VF_FUNCTION_P1( +NTSTATUS, +VerifyWdfRequestIsCanceled, + _In_ FxRequest* + ); + +//Do not supply argument names +FX_DECLARE_VF_FUNCTION_P1( +NTSTATUS, +VerifyWdfRequestForwardToIoQueue, + _In_ FxRequest* + ); + +//Do not supply argument names +FX_DECLARE_VF_FUNCTION_P1( +NTSTATUS, +VerifyWdfRequestForwardToParentDeviceIoQueue, + _In_ FxRequest* + ); + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + __in_opt + WDFIOTARGET Target, + __out + WDFREQUEST* Request + ) + +/*++ + +Routine Description: + Creates a WDFREQUEST handle that is suitable to be submitted to the provided + target + +Arguments: + RequestAttributes - Attributes associated with the request. If NULL, the + size of the user context associated with the request will be + the default size specified in WdfDriverCreate. + + Target - Target for which the request will be sent to. If NULL, then + WdfRequestChangeTarget must be called before the request is formatted + or sent to any target + + Request - Pointer which will receive the newly created request + +Return Value: + NT_SUCCESS if successful, otherwise appropriate error code + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + FxIoTarget* pTarget; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + if (Target != NULL) { + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Target, + FX_TYPE_IO_TARGET, + (PVOID*)&pTarget, + &pFxDriverGlobals); + } + else { + pTarget = NULL; + + // + // For class extension support, get globals from parent object. + // + if (RequestAttributes != NULL && + RequestAttributes->ParentObject != NULL) { + + FxObjectHandleGetGlobals( + pFxDriverGlobals, + RequestAttributes->ParentObject, + &pFxDriverGlobals); + } + } + + FxPointerNotNull(pFxDriverGlobals, Request); + *Request = NULL; + + status = FxRequest::_Create(pFxDriverGlobals, + RequestAttributes, + NULL, + pTarget, + FxRequestOwnsIrp, + FxRequestConstructorCallerIsDriver, + &pRequest); + + if (NT_SUCCESS(status)) { + *Request = pRequest->GetHandle(); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Created WDFREQUEST %p, %!STATUS!", + *Request, status); +#endif // FX_VERBOSE_TRACE + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestCreateFromIrp)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + __in + MdIrp Irp, + __in + BOOLEAN RequestFreesIrp, + __out + WDFREQUEST* Request + ) + +/*++ + +Routine Description: + Creates a request handle that uses an external IRP instead of an internally + allocated irp. + +Arguments: + RequestAttributes - Attributes associated with the request. If NULL, the + size of the user context associated with the request will be + the default size specified in WdfDriverCreate. + + Irp - The IRP to use + + RequestFreesIrp - If TRUE, when the request handle is destroyed, it will + free the IRP with IoFreeIrp. If FALSE, it is the responsibility of the + calller to free the IRP + + Request - Pointer which will receive the newly created request + +Return Value: + NT_SUCCESS or appropriate error code + + --*/ + +{ + FxRequest* pRequest; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // For class extension support, get globals from parent object. + // + if (RequestAttributes != NULL && + RequestAttributes->ParentObject != NULL) { + + FxObjectHandleGetGlobals( + pFxDriverGlobals, + RequestAttributes->ParentObject, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, Irp); + FxPointerNotNull(pFxDriverGlobals, Request); + + *Request = NULL; + + status = FxRequest::_Create(pFxDriverGlobals, + RequestAttributes, + Irp, + NULL, + RequestFreesIrp ? FxRequestOwnsIrp + : FxRequestDoesNotOwnIrp, + FxRequestConstructorCallerIsDriver, + &pRequest); + + if (NT_SUCCESS(status)) { + *Request = pRequest->GetHandle(); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Irp %p RequestFreesIrp %d WDFREQUEST %p created", + Irp, RequestFreesIrp, *Request); +#endif // FX_VERBOSE_TRACE + } + + return status; +} + + +#define WDF_REQUEST_REUSE_VALID_FLAGS_V1_9 \ + (WDF_REQUEST_REUSE_SET_NEW_IRP) + +#define WDF_REQUEST_REUSE_VALID_FLAGS \ + (WDF_REQUEST_REUSE_SET_NEW_IRP | WDF_REQUEST_REUSE_MUST_COMPLETE) + + + + + + + +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestReuse)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ) +/*++ + +Routine Description: + Clears out the internal state of the irp, which includes, but is not limited + to: + a) Any internal allocations for the previously formatted request + b) The completion routine and its context + c) The request's intended i/o target + d) All of the internal IRP's stack locations + +Arguments: + Request - The request to be reused. + + ReuseParams - Parameters controlling the reuse of the request, see comments + for each field in the structure for usage + +Return Value: + NT_SUCCESS or appropriate error code + + --*/ + { + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + ULONG validFlags; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ReuseParams); + + if (ReuseParams->Size != sizeof(WDF_REQUEST_REUSE_PARAMS)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "ReuseParams Size %d, expected %d %!STATUS!", + ReuseParams->Size, sizeof(WDF_REQUEST_REUSE_PARAMS), + STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + validFlags = WDF_REQUEST_REUSE_VALID_FLAGS; + } + else { + validFlags = WDF_REQUEST_REUSE_VALID_FLAGS_V1_9; + } + + if (ReuseParams->Flags & ~validFlags) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "ReuseParams Flags 0x%x, valid mask 0x%x, %!STATUS!", + ReuseParams->Flags, + (ULONG) ~validFlags, + STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + return pRequest->Reuse(ReuseParams); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestChangeTarget)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + WDFIOTARGET IoTarget + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + FxIoTarget* pTarget; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxObjectHandleGetPtr(pFxDriverGlobals, + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*)&pTarget); + + return pRequest->ValidateTarget(pTarget); +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_FUNCTION(VerifyRequestComplete) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* pRequest + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + pRequest->Lock(&irql); + + status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals); + if (NT_SUCCESS(status)) { + status = pRequest->VerifyRequestCanBeCompleted(FxDriverGlobals); + } + + pRequest->Unlock(irql); + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestComplete)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + NTSTATUS RequestStatus + ) + +/*++ + +Routine Description: + + Complete the request with supplied status. + + Any default reference counts implied by handle are invalid after + completion. + +Arguments: + + Request - Handle to the Request object + + RequestStatus - Wdm Status to complete the request with + +Returns: + + None + +--*/ +{ + NTSTATUS status; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); +#if FX_VERBOSE_TRACE + // + // Use object's globals, not the caller's + // + DoTraceLevelMessage(pRequest->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Completing WDFREQUEST 0x%p, %!STATUS!", + Request, RequestStatus); +#endif + status = VerifyRequestComplete(pRequest->GetDriverGlobals(), pRequest ); + if (!NT_SUCCESS(status)) { + return; + } + + pRequest->Complete(RequestStatus); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestCompleteWithPriorityBoost)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + NTSTATUS RequestStatus, + __in + CCHAR PriorityBoost + ) + +/*++ + +Routine Description: + + Complete the request with supplied status. + + Any default reference counts implied by handle are invalid after + completion. + +Arguments: + + Request - Handle to the Request object + + RequestStatus - Wdm Status to complete the request with + + PriorityBoost - A system-defined constant value by which to increment the + run-time priority of the original thread that requested the operation. + +Returns: + + None + +--*/ + +{ + NTSTATUS status; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + +#if FX_VERBOSE_TRACE + // + // Use the object's globals, not the caller's + // + DoTraceLevelMessage(pRequest->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Completing WDFREQUEST 0x%p, %!STATUS!", + Request, RequestStatus); +#endif + status = VerifyRequestComplete(pRequest->GetDriverGlobals(), + pRequest); + if (!NT_SUCCESS(status)) { + return; + } + + pRequest->CompleteWithPriority(RequestStatus, PriorityBoost); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestCompleteWithInformation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + NTSTATUS RequestStatus, + __in + ULONG_PTR Information + ) + +/*++ + +Routine Description: + + Complete the request with supplied status and information. + + Any default reference counts implied by handle are invalid after + completion. + +Arguments: + + Request - Handle to the Request object + + RequestStatus - Wdm Status to complete the request with + + Information - Information to complete request with + +Returns: + + None + +--*/ + +{ + FxRequest *pRequest; + NTSTATUS status; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + +#if FX_VERBOSE_TRACE + // + // Use the object's globals, not the caller's + // + DoTraceLevelMessage(pRequest->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Completing WDFREQUEST 0x%p, %!STATUS!", + Request, RequestStatus); +#endif + status = VerifyRequestComplete(pRequest->GetDriverGlobals(), pRequest); + if (!NT_SUCCESS(status)) { + return; + } + + + pRequest->CompleteWithInformation(RequestStatus, Information); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestSetInformation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + ULONG_PTR Information + ) + +/*++ + +Routine Description: + + Set the transfer information for the request. + + This sets the NT Irp->Status.Information field. + +Arguments: + + Request - Handle to the Request object + + Information - Value to be set + +Returns: + + None + +--*/ + +{ + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + +#if FX_VERBOSE_TRACE + // + // Use the object's globals, not the caller's + // + DoTraceLevelMessage(pRequest->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p, Information 0x%p", + Request, (VOID*)Information); +#endif // FX_VERBOSE_TRACE + + pRequest->SetInformation(Information); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG_PTR +WDFAPI +WDFEXPORT(WdfRequestGetInformation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Get the transfer information for the reuqest. + + +Arguments: + + Request - Handle to the Request object + + +Returns: + + Returns Irp->IoStatus.Information value. + +--*/ + +{ + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + + return pRequest->GetInformation(); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveInputMemory)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __out + WDFMEMORY *Memory + ) +/*++ + +Routine Description: + + Return the WDFMEMORY buffer associated with the request. + + The memory buffer is valid in any thread/process context, + and may be accessed at IRQL > PASSIVE_LEVEL. + + The memory buffer is automatically released when the request + is completed. + + The memory buffers access permissions are validated according + to the command type (IRP_MJ_READ, IRP_MJ_WRITE), and may + only be accessed according to the access semantics of the request. + + The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or if neither of the DO_BUFFERED_IO or DO_DIRECT_IO flags are + configured for the device object. + + The Memory buffer is as follows for each buffering mode: + + DO_BUFFERED_IO: + + Irp->AssociatedIrp.SystemBuffer + + DO_DIRECT_IO: + + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + + NEITHER flag set: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The buffer is only valid until the request is completed. + +Arguments: + + Request - Handle to the Request object + + Memory - Pointer location to return WDFMEMORY handle + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + IFxMemory* pMemory; + PVOID pBuffer; + size_t length; + + pMemory = NULL; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Memory); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + // + // This call is not valid on Read request. + // + if (pRequest->GetFxIrp()->GetMajorFunction() == IRP_MJ_READ) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on the Read request, you should call" + " WdfRequestRetrieveOutputMemory to get the Memory for WDFREQUEST " + "0x%p, %!STATUS!", Request, status); + + return status; + } + + status = pRequest->GetMemoryObject(&pMemory, &pBuffer, &length); + if (NT_SUCCESS(status)) { + *Memory = pMemory->GetHandle(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveOutputMemory)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __out + WDFMEMORY *Memory + ) + +/*++ + +Routine Description: + + Return the WDFMEMORY buffer associated with the request. + + The memory buffer is valid in any thread/process context, + and may be accessed at IRQL > PASSIVE_LEVEL. + + The memory buffer is automatically released when the request + is completed. + + The memory buffers access permissions are validated according + to the command type (IRP_MJ_READ, IRP_MJ_WRITE), and may + only be accessed according to the access semantics of the request. + + The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or if neither of the DO_BUFFERED_IO or DO_DIRECT_IO flags are + configured for the device object. + + The Memory buffer is as follows for each buffering mode: + + DO_BUFFERED_IO: + + Irp->AssociatedIrp.SystemBuffer + + DO_DIRECT_IO: + + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + + NEITHER flag set: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The buffer is only valid until the request is completed. + +Arguments: + + Request - Handle to the Request object + + Memory - Pointer location to return WDFMEMORY handle + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + IFxMemory* pMemory; + PVOID pBuffer; + size_t length; + UCHAR majorFunction; + + pMemory = NULL; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Memory); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + // + // This call is not valid on Write request. + // + majorFunction = pRequest->GetFxIrp()->GetMajorFunction(); + + if (majorFunction == IRP_MJ_WRITE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on the Write request, you should call" + " WdfRequestRetrieveInputMemory to get the Memory for WDFREQUEST " + "0x%p, %!STATUS!", Request, status); + + return status; + } + + if( (majorFunction == IRP_MJ_DEVICE_CONTROL) || + (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) ) { + status = pRequest->GetDeviceControlOutputMemoryObject(&pMemory, &pBuffer, &length); + } + else { + status = pRequest->GetMemoryObject(&pMemory, &pBuffer, &length); + } + + if (NT_SUCCESS(status)) { + *Memory = pMemory->GetHandle(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveInputBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + size_t RequiredLength, + __deref_out_bcount(*Length) + PVOID* Buffer, + __out_opt + size_t* Length + ) +/*++ + +Routine Description: + + Return the memory buffer associated with the request along + with its maximum length. + + The memory buffer is valid in any thread/process context, + and may be accessed at IRQL > PASSIVE_LEVEL. + + The memory buffer is automatically released when the request + is completed. + + The memory buffers access permissions are validated according + to the command type (IRP_MJ_READ, IRP_MJ_WRITE), and may + only be accessed according to the access semantics of the request. + + The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or if neither of the DO_BUFFERED_IO or DO_DIRECT_IO flags are + configured for the device object. + + The Memory buffer is as follows for each buffering mode: + + DO_BUFFERED_IO: + + Irp->AssociatedIrp.SystemBuffer + + DO_DIRECT_IO: + + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + + NEITHER flag set: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The buffer is only valid until the request is completed. + +Arguments: + + Request - Handle to the Request object + + RequiredLength - This is the minimum size expected by the caller + + Buffer - Pointer location to return buffer ptr + + Length - actual size of the buffer. This is >= to RequiredLength + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + IFxMemory* pMemory; + PVOID pBuffer; + size_t length; + + pMemory = NULL; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + // + // Validate the pointers and set its content to NULL + // + FxPointerNotNull(pFxDriverGlobals, Buffer); + *Buffer = NULL; + + if (Length != NULL) { + *Length = 0; + } + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif //FX_VERBOSE_TRACE + + // + // This call is not valid on Read request. + // + if (pRequest->GetFxIrp()->GetMajorFunction() == IRP_MJ_READ) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on the read request, you should call" + " WdfRequestRetrieveOutputBuffer to get the buffer for WDFREQUEST " + "0x%p, %!STATUS!", Request, status); + + return status; + } + + status = pRequest->GetMemoryObject(&pMemory, &pBuffer, &length); + + if (NT_SUCCESS(status)) { + if (length < RequiredLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "WDFREQUEST 0x%p buffer size %I64d is less than RequiredLength " + "%I64d, %!STATUS!", Request, length, RequiredLength, status); + + return status; + } + + *Buffer = pBuffer; + + if (Length != NULL) { + *Length = length; + } + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveOutputBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + size_t RequiredLength, + __deref_out_bcount(*Length) + PVOID* Buffer, + __out_opt + size_t* Length + ) +/*++ + +Routine Description: + + Return the memory buffer associated with the request along + with its maximum length. + + The memory buffer is valid in any thread/process context, + and may be accessed at IRQL > PASSIVE_LEVEL. + + The memory buffer is automatically released when the request + is completed. + + The memory buffers access permissions are validated according + to the command type (IRP_MJ_READ, IRP_MJ_WRITE), and may + only be accessed according to the access semantics of the request. + + The memory buffer is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or if neither of the DO_BUFFERED_IO or DO_DIRECT_IO flags are + configured for the device object. + + The Memory buffer is as follows for each buffering mode: + + DO_BUFFERED_IO: + + Irp->AssociatedIrp.SystemBuffer + + DO_DIRECT_IO: + + MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + + NEITHER flag set: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The buffer is only valid until the request is completed. + +Arguments: + + Request - Handle to the Request object + + RequiredLength - This is the minimum size expected by the caller + + Buffer - Pointer location to return buffer ptr + + Length - actual size of the buffer. This is >= to RequiredLength + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + IFxMemory* pMemory; + PVOID pBuffer; + size_t length; + UCHAR majorFunction; + + pMemory = NULL; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + // + // Validate the pointers and set its content to NULL + // + FxPointerNotNull(pFxDriverGlobals, Buffer); + *Buffer = NULL; + + if (Length != NULL) { + *Length = 0; + } + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif //FX_VERBOSE_TRACE + + // + // This call is not valid on Write request. + // + majorFunction = pRequest->GetFxIrp()->GetMajorFunction(); + + if (majorFunction == IRP_MJ_WRITE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on write request, you should call" + " WdfRequestRetrieveInputBuffer to get the buffer for WDFREQUEST " + "0x%p, %!STATUS!", Request, status); + + return status; + } + + if (majorFunction == IRP_MJ_DEVICE_CONTROL || + majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { + status = pRequest->GetDeviceControlOutputMemoryObject( + &pMemory, &pBuffer, &length); + } + else { + status = pRequest->GetMemoryObject(&pMemory, &pBuffer, &length); + } + + if (NT_SUCCESS(status)) { + if (length < RequiredLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "WDFREQUEST 0x%p buffer size %I64d is less than RequiredLength " + "%I64d, %!STATUS!", Request, length, RequiredLength, status); + + return status; + } + + *Buffer = pBuffer; + + if (Length != NULL) { + *Length = length; + } + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + size_t RequiredLength, + __deref_out_bcount_opt(*Length) + PVOID* InputBuffer, + __out_opt + size_t* Length + ) +/*++ + +Routine Description: + + Returns input buffer of a method-neither request. This function can be + called only in the context of EvtDeviceIoInProcessContextCallback at + PASSIVE_LEVEL. + + This call is valid on public IOCTL and Write request. + + The returned buffer is valid only in the caller's process context. This + call should be typically used in a toplevel or monolithic driver to + guarantee the caller's context. + + + The Memory buffer is as follows for each type of request: + + For IOCTL, it will return irpStack->Parameters.DeviceIoControl.Type3InputBuffer + + For Write, it will return Irp->UserBuffer. + + For read and internal-device control and other type of request, this call + will return an error. + + +Arguments: + + Request - Handle to the Request object + + RequiredLength - minimum length of the buffer expected by the caller. + If it's not this call will return an error. + + + InputBuffer - Pointer location to return buffer ptr + + Length - actual size of the buffer. This is >= to RequiredLength + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + UCHAR majorFunction; + FxDevice* pDevice; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + FxPointerNotNull(pFxDriverGlobals, InputBuffer); + *InputBuffer = NULL; + + if (Length != NULL) { + *Length = 0; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Make sure this function is called in the context of in-process callback + // + if (pFxDriverGlobals->FxVerifierOn) { + KIRQL irql; + + pRequest->Lock(&irql); + + status = pRequest->VerifyRequestIsInCallerContext(pFxDriverGlobals); + + pRequest->Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + FxIrp* irp = pRequest->GetFxIrp(); + + pDevice = FxDevice::GetFxDevice(irp->GetDeviceObject()); + + // + // This call is not valid on Read request. + // + majorFunction = irp->GetMajorFunction(); + + if (majorFunction == IRP_MJ_READ) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on read request, you should call" + " WdfRequestRetrieveUnsafeUserOutputBuffer to get the buffer for " + "WDFREQUEST 0x%p, %!STATUS!", Request, status); + + return status; + } + + if (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on internal-ioctl request, you should call" + " safer WdfRequestRetrieveInputBuffer to get the buffer for " + "WDFREQUEST 0x%p, %!STATUS!", Request, status); + + return status; + } + + if (majorFunction == IRP_MJ_DEVICE_CONTROL && + irp->GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) { + + if (irp->GetParameterIoctlInputBufferLength() < RequiredLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "WDFREQUEST %p buffer size %d is less than RequiredLength %I64d," + " %!STATUS!", + Request, irp->GetParameterIoctlInputBufferLength(), + RequiredLength, status); + + return status; + } + + *InputBuffer = irp->GetParameterIoctlType3InputBuffer(); + if (Length != NULL) { + *Length = irp->GetParameterIoctlInputBufferLength(); + } + + return STATUS_SUCCESS; + + } + else if (majorFunction == IRP_MJ_WRITE && + pDevice->GetIoType() == WdfDeviceIoNeither) { + + if (irp->GetParameterWriteLength() < RequiredLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "WDFREQUEST 0x%p buffer size %d is less than RequiredLength " + "%I64d, %!STATUS!", + Request, irp->GetParameterWriteLength(), RequiredLength, + status); + + return status; + } + + *InputBuffer = pRequest->GetFxIrp()->GetUserBuffer(); + if (Length != NULL) { + *Length = irp->GetParameterWriteLength(); + } + + return STATUS_SUCCESS; + + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Error: This call is valid only on method-neither " + "ioctl and write WDFREQUEST %p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return status; + } + + // NOTREACHED +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + size_t RequiredLength, + __deref_out_bcount_opt(*Length) + PVOID* OutputBuffer, + __out_opt + size_t* Length + ) +/*++ + +Routine Description: + + Returns output buffer of a method-neither request. This function can be called only + in the context of EvtDeviceIoInProcessContextCallback at PASSIVE_LEVEL. + + This call is valid on public IOCTL and Read request. + + The returned buffer is valid only in the caller's process context. This call should + be typically used in a toplevel or monolithic driver to guarantee the caller's context. + + + The Memory buffer is as follows for each type of request: + + For IOCTL, it will return Irp->UserBuffer + + For Read, it will return Irp->UserBuffer. + + For Write and internal-device control and other type of request, this call will return an error. + + +Arguments: + + Request - Handle to the Request object + + RequiredLength - minimum length of the buffer expected by the caller. If it's not + this call will return an error. + + + OutputBuffer - Pointer location to return buffer ptr + + Length - actual size of the buffer. This is >= to RequiredLength + + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + UCHAR majorFunction; + FxDevice* pDevice; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, OutputBuffer); + *OutputBuffer = NULL; + + if (Length != NULL) { + *Length = 0; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Make sure this function is called in the context of in-process callback + // + if (pFxDriverGlobals->FxVerifierOn) { + KIRQL irql; + + pRequest->Lock(&irql); + + status = pRequest->VerifyRequestIsInCallerContext(pFxDriverGlobals); + + pRequest->Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + } + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", pRequest); +#endif // FX_VERBOSE_TRACE + + FxIrp* irp = pRequest->GetFxIrp(); + pDevice = FxDevice::GetFxDevice(irp->GetDeviceObject()); + + // + // This call is not valid on Write request. + // + majorFunction = irp->GetMajorFunction(); + + if (majorFunction == IRP_MJ_WRITE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on Write request, you should call" + " WdfRequestRetrieveUnsafeUserInputBuffer to get the buffer for " + "WDFREQUEST 0x%p, %!STATUS!", Request, status); + + return status; + + } + + if (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on an internal IOCTL request, you should call" + " safer WdfRequestRetrieveOutputBuffer to get the buffer for " + "WDFREQUEST 0x%p, %!STATUS!", Request, status); + + return status; + } + + if (majorFunction == IRP_MJ_DEVICE_CONTROL && + irp->GetParameterIoctlCodeBufferMethod() == METHOD_NEITHER) { + + if (irp->GetParameterIoctlOutputBufferLength() < RequiredLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "WDFREQUEST 0x%p buffer size %d is less than RequiredLength " + "%I64d, %!STATUS!", + Request, irp->GetParameterIoctlOutputBufferLength(), + RequiredLength, status); + + return status; + } + + *OutputBuffer = pRequest->GetFxIrp()->GetUserBuffer(); + + if (Length != NULL) { + *Length = irp->GetParameterIoctlOutputBufferLength(); + } + + return STATUS_SUCCESS; + + } else if (majorFunction == IRP_MJ_READ && + pDevice->GetIoType() == WdfDeviceIoNeither) { + + if (irp->GetParameterReadLength() < RequiredLength) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "WDFREQUEST 0x%p buffer size %d is less than RequiredLength " + "%I64d, %!STATUS!", + Request, irp->GetParameterReadLength(), RequiredLength, + status); + + return status; + } + + *OutputBuffer = pRequest->GetFxIrp()->GetUserBuffer(); + if (Length != NULL) { + *Length = irp->GetParameterReadLength(); + } + + return STATUS_SUCCESS; + + } else { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Error: This call is valid only on method-neither ioctl and read " + "WDFREQUEST 0x%p, %!STATUS!", Request, status); + + return status; + } + + // NOTREACHED +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveInputWdmMdl)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __deref_out + PMDL *Mdl + ) + +/*++ + +Routine Description: + + Return the MDL associated with the request. + + The MDL is automatically released when the request is completed. + + The MDL's access permissions are validated according + to the command type (IRP_MJ_READ, IRP_MJ_WRITE), and may + only be accessed according to the access semantics of the request. + + The MDL is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or if neither of the DO_BUFFERED_IO or DO_DIRECT_IO flags are + configured for the device object. + + The MDL is as follows for each buffering mode: + + DO_BUFFERED_IO: + + MmBuildMdlForNonPagedPool(IoAllocateMdl(Irp->AssociatedIrp.SystemBuffer, ... )) + + DO_DIRECT_IO: + + Irp->MdlAddress + + NEITHER flag set: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The MDL is only valid until the request is completed. + +Arguments: + + Request - Handle to the Request object + + Mdl - Pointer location to return MDL ptr + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Mdl); + *Mdl = NULL; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + // + // This call is not valid on Read request. + // + if (pRequest->GetFxIrp()->GetMajorFunction() == IRP_MJ_READ) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on the Read request, you should call" + " WdfRequestRetrieveOutputMdl to get the Mdl for WFDREQUEST 0x%p, " + " %!STATUS!", Request, STATUS_INVALID_DEVICE_REQUEST); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + status = pRequest->GetMdl(Mdl); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestRetrieveOutputWdmMdl)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __deref_out + PMDL *Mdl + ) + +/*++ + +Routine Description: + + Return the MDL associated with the request. + + The MDL is automatically released when the request is completed. + + The MDL's access permissions are validated according + to the command type (IRP_MJ_READ, IRP_MJ_WRITE), and may + only be accessed according to the access semantics of the request. + + The MDL is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or if neither of the DO_BUFFERED_IO or DO_DIRECT_IO flags are + configured for the device object. + + The MDL is as follows for each buffering mode: + + DO_BUFFERED_IO: + + MmBuildMdlForNonPagedPool(IoAllocateMdl(Irp->AssociatedIrp.SystemBuffer, ... )) + + DO_DIRECT_IO: + + Irp->MdlAddress + + NEITHER flag set: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The MDL is only valid until the request is completed. + +Arguments: + + Request - Handle to the Request object + + Mdl - Pointer location to return MDL ptr + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + UCHAR majorFunction; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Mdl); + *Mdl = NULL; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + // + // This call is not valid on Write request. + // + majorFunction = pRequest->GetFxIrp()->GetMajorFunction(); + if (majorFunction == IRP_MJ_WRITE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "This call is not valid on the Write request, you should call" + " WdfRequestRetrieveInputMemory to get the Memory for WDFREQUEST 0x%p, " + "%!STATUS!",Request, STATUS_INVALID_DEVICE_REQUEST); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + if( (majorFunction == IRP_MJ_DEVICE_CONTROL) || + (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) ) { + status = pRequest->GetDeviceControlOutputMdl(Mdl); + } + else { + status = pRequest->GetMdl(Mdl); + } + + return status; +} + +void +CheckUnionAssumptions( + VOID + ) +/*++ + +Routine Description: + Make sure our assumptions about using the passed in parameters as locals + does not exceed the space allocated on the stack for the passed in variables, + otherwise we could corrupt the stack. + + *DO NOT REMOVE* this function even though no code calls it. Because it uses + WDFCASSERT, if our assumptions were false, it would not compile. + +Arguments: + None. + +Return Value: + None + + --*/ +{ + // ActionUnion check + WDFCASSERT(sizeof(ULONG) <= sizeof(PWDF_DRIVER_GLOBALS)); + // RequestUnion check + WDFCASSERT(sizeof(FxRequest*) <= sizeof(WDFREQUEST)); + // TargetUnion check + WDFCASSERT(sizeof(FxIoTarget*) <= sizeof(WDFIOTARGET)); +} + +#define GLOBALS_ACTION(globals) ((ULONG)(ULONG_PTR)(globals)) +#define PGLOBALS_ACTION(globals) ((PULONG)(PULONG_PTR)(globals)) + +#define GLOBALS_DEVICE(globals) ((FxDevice*)(ULONG_PTR)(globals)) +#define PGLOBALS_DEVICE(globals) ((FxDevice**)(PULONG_PTR)(globals)) + +#define WDFREQUEST_FXREQUEST(handle) ((FxRequest*)(handle)) +#define WDFIOTARGET_FXIOTARGET(handle) ((FxIoTarget*)(handle)) + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfRequestSend)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + WDFIOTARGET Target, + __in_opt + PWDF_REQUEST_SEND_OPTIONS Options + ) +/*++ + +Routine Description: + Sends a previously created and formatted request to the target device + object. The target device object will typically be the device object that + this device is attached to. The submission can also be controlled by a set + of options. + +Arguments: + Request - The request to be submitted + + Target - The target of the request + + Options - Optional options applied to the sending of the request + + In the aggressive attempt to conserve stack space, the passed in parameters + are unionized with the locals this function would need. On an optimized + build, the compiler may already do this, but we want to be extra aggressive + and ensure that this type of stack reuse is done. + +Return Value: + TRUE if the request was sent to the target, FALSE otherwise. + + To retrieve the status of the request, call WdfRequestGetStatus. + WdfRequestGetStatus should only be called if WdfRequestSend returns FALSE + or if the caller specified that the request be synchronous in + WDF_REQUEST_SEND_OPTIONS. Otherwise, the request is asynchronous and the status + will be returned in the request's completion routine. + + --*/ +{ + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*) &Request); + + // + // Request stack memory now holds an FxRequest pointer. + // Request as a handle is no longer valid! + // + if (!NT_SUCCESS(FxValidateRequestOptions( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + Options, WDFREQUEST_FXREQUEST(Request)))) { + + WDFREQUEST_FXREQUEST(Request)->SetStatus(STATUS_INVALID_PARAMETER); + + FxVerifierDbgBreakPoint(WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals()); + return FALSE; + } + + FxObjectHandleGetPtr(WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + Target, + FX_TYPE_IO_TARGET, + (PVOID*) &Target); + + // + // Target stack memory now hold an FxIoTarget pointer. + // Target as a handle is no longer valid! + // + if (Options != NULL && + (Options->Flags & (WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | + WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET)) != 0x0) { + + if (Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS) { + // + // This sets impersonation flags for UMDF. Noop for KMDF. + // + WDFREQUEST_FXREQUEST(Request)->SetImpersonationFlags(Options->Flags); + + *PGLOBALS_ACTION(&DriverGlobals) = SubmitSyncCallCompletion; + (void) WDFIOTARGET_FXIOTARGET(Target)->SubmitSync( + WDFREQUEST_FXREQUEST(Request), + Options, + PGLOBALS_ACTION(&DriverGlobals) + ); + } + else if (Options->Flags & WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET) { + if (WDFREQUEST_FXREQUEST(Request)->IsAllocatedFromIo() == FALSE) { + DoTraceLevelMessage( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p must be a WDFQUEUE presented request", + WDFREQUEST_FXREQUEST(Request)->GetHandle()); + + WDFREQUEST_FXREQUEST(Request)->SetStatus( + STATUS_INVALID_DEVICE_STATE + ); + + *PGLOBALS_ACTION(&DriverGlobals) = 0; + } + else if (WDFREQUEST_FXREQUEST(Request)->HasContext()) { + // + // Cannot send-and-forget a request with formatted IO context. + // + DoTraceLevelMessage( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Cannot send-and-forget WDFREQUEST 0x%p with formatted IO" + " context, %!STATUS!", + WDFREQUEST_FXREQUEST(Request)->GetHandle(), + STATUS_INVALID_DEVICE_REQUEST ); + + WDFREQUEST_FXREQUEST(Request)->SetStatus( + STATUS_INVALID_DEVICE_REQUEST + ); + + *PGLOBALS_ACTION(&DriverGlobals) = 0; + + FxVerifierDbgBreakPoint( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals()); + } + else { + // + // We split processing into pre and post processing to reduce + // stack usage (by not making the call to IoCallDriver in a + // deep function. + // + + // + // This will skip the current stack location + // + WDFREQUEST_FXREQUEST(Request)->PreProcessSendAndForget(); + + // + // This sets impersonation flags for UMDF. Noop for KMDF. + // + WDFREQUEST_FXREQUEST(Request)->SetImpersonationFlags(Options->Flags); + + MdIrp submitIrp = WDFREQUEST_FXREQUEST(Request)->GetSubmitIrp(); + + WDFIOTARGET_FXIOTARGET(Target)->Send(submitIrp); + + // + // This will free the request memory and pop the queue + // + WDFREQUEST_FXREQUEST(Request)->PostProcessSendAndForget(); + return TRUE; + } + } + } + else if (WDFREQUEST_FXREQUEST(Request)->IsCompletionRoutineSet() == FALSE && + WDFREQUEST_FXREQUEST(Request)->IsAllocatedFromIo()) { + // + // Cannot send an asynchronous queue presented request without a + // completion routine. + // + DoTraceLevelMessage( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p is a WDFQUEUE presented request with no" + " completion routine, %!STATUS!", + WDFREQUEST_FXREQUEST(Request)->GetHandle(), + STATUS_INVALID_DEVICE_REQUEST ); + + WDFREQUEST_FXREQUEST(Request)->SetStatus( + STATUS_INVALID_DEVICE_REQUEST + ); + + *PGLOBALS_ACTION(&DriverGlobals) = 0; + + FxVerifierDbgBreakPoint( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals()); + } + else { +#if FX_VERBOSE_TRACE + DoTraceLevelMessage( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Enter: WDFIOTARGET %p, WDFREQUEST %p", + WDFIOTARGET_FXIOTARGET(Target)->GetObjectHandle(), + WDFREQUEST_FXREQUEST(Request)); +#endif // FX_VERBOSE_TRACE + + // + // This sets impersonation flags for UMDF. Noop for KMDF. + // + if (Options != NULL) { + WDFREQUEST_FXREQUEST(Request)->SetImpersonationFlags(Options->Flags); + } + + // + // Submit will return whether the request should be sent *right now*. + // If SubmitSend is clear, then SubmitQueued must be checked. If set, + // then the request was queued, otherwise, the request has failed. + // + // NOTE: by calling FxIoTarget::Submit instead of acquiring the lock + // in this call frame, we don't have expend stack space for the KIRQL + // storage + // + *PGLOBALS_ACTION(&DriverGlobals) = + WDFIOTARGET_FXIOTARGET(Target)->Submit( + WDFREQUEST_FXREQUEST(Request), + Options, + (Options != NULL) ? Options->Flags : 0 + ); + + // DriverGlobals stack memory now hold a ULONG action value. + // DriverGlobals as a pointer is no longer valid! + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage( + WDFIOTARGET_FXIOTARGET(Target)->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "action 0x%x", GLOBALS_ACTION(DriverGlobals)); +#endif // FX_VERBOSE_TRACE + + if (GLOBALS_ACTION(DriverGlobals) & SubmitSend) { + + *PGLOBALS_ACTION(&DriverGlobals) |= SubmitSent; + + ASSERT((GLOBALS_ACTION(DriverGlobals) & SubmitQueued) == 0); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage( + WDFREQUEST_FXREQUEST(Request)->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Sending FxRequest %p (WDFREQUEST %p), Irp %p", + WDFREQUEST_FXREQUEST(Request), + WDFREQUEST_FXREQUEST(Request)->GetHandle(), + WDFREQUEST_FXREQUEST(Request)->GetSubmitIrp()); +#endif // FX_VERBOSE_TRACE + + MdIrp submitIrp = WDFREQUEST_FXREQUEST(Request)->GetSubmitIrp(); + + WDFIOTARGET_FXIOTARGET(Target)->Send(submitIrp); + } + else if (GLOBALS_ACTION(DriverGlobals) & SubmitQueued) { + // + // To the caller, we saw and sent the request (and all the cancel + // semantics of a sent request still work). + // + *(PGLOBALS_ACTION(&DriverGlobals)) |= SubmitSent; + } + } + + return (GLOBALS_ACTION(DriverGlobals) & SubmitSent) ? TRUE : FALSE; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestGetStatus)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) +{ + FxRequest* pRequest; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + + return pRequest->GetStatus(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFAPI +WDFEXPORT(WdfRequestCancelSentRequest)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + Cancels a previously submitted request. + +Arguments: + Request - The previously submitted request + +Return Value: + TRUE if the cancel was *attempted*. The caller must still synchronize with + the request's completion routine since TRUE just means the owner of the + request was successfully asked to cancel the request. + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + BOOLEAN result; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST %p to be cancelled", Request); + + result = pRequest->Cancel(); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Exit: WDFREQUEST %p, result %d", Request, result); +#endif // FX_VERBOSE_TRACE + + return result; +} + +_Must_inspect_result_ +__drv_maxIRQL(APC_LEVEL) +BOOLEAN +WDFEXPORT(WdfRequestIsFrom32BitProcess)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) +/*++ + +Routine Description: + Indicates to the caller if the I/O request originated in a 32 bit process + or not. On 32 bit systems, this function always returns TRUE. + +Arguments: + Request - The request being queried + +Return Value: + TRUE if the request came from a 32 bit process, FALSE otherwise. + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + BOOLEAN result; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest, + &pFxDriverGlobals); + + result = pRequest->GetFxIrp()->Is32bitProcess(); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST %p is from 32 bit process = %d", + Request, result); +#endif // FX_VERBOSE_TRACE + + return result; +} + +__drv_maxIRQL(DISPATCH_LEVEL) + +VOID +WDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) +/*++ + +Routine Description: + Copies the current Irp stack location to the next one. This is the + equivalent of IoCopyCurrentIrpStackLocationToNext. + +Arguments: + Request - The request that will be formatted. + +Return Value: + None + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + FxIrp* irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST %p", Request); +#endif // FX_VERBOSE_TRACE + + irp = pRequest->GetSubmitFxIrp(); + + if (irp->GetIrp() == NULL) { + FxVerifierBugCheck(pFxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_NULL_IRP, + (ULONG_PTR) Request); + return; // not reached + } + + // + // 1 is the minimum for CurrentLocation. Since the next stack location is + // CurrentLocation-1, the CurrentLocation must be at least 2. + // + if (irp->HasStack(2) == FALSE) { + FxVerifierBugCheck(pFxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_NO_MORE_STACK_LOCATIONS, + (ULONG_PTR) irp->GetIrp()); + return; // not reached + } + + pRequest->m_NextStackLocationFormatted = TRUE; + irp->CopyCurrentIrpStackLocationToNext(); + + pRequest->VerifierSetFormatted(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestWdmFormatUsingStackLocation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + PIO_STACK_LOCATION Stack + ) + +/*++ + +Routine Description: + Sets the next IRP stack location to the one provided by the caller. The + Context and CompletionRoutine values will be ignored. If the caller wants + to set a completion routine, WdfRequestSetCompletionRoutine should be used + instead. + +Arguments: + Request - The request to be formatted + + Stack - A pointer to an IO_STACK_LOCATION structure that contains + driver-supplied information + +Return Value: + None. + + --*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + FxIrp* pIrp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Stack); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST %p", Request); +#endif // FX_VERBOSE_TRACE + + pIrp = pRequest->GetSubmitFxIrp(); + + if (pIrp == NULL) { + FxVerifierBugCheck(pFxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_NULL_IRP, + (ULONG_PTR) Request); + return; // not reached + } + + // + // 1 is the minimum for CurrentLocation. Since the next stack location is + // CurrentLocation-1, the CurrentLocation must be at least 2. + // + if (pIrp->GetCurrentIrpStackLocationIndex() < 2) { + FxVerifierBugCheck(pFxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_NO_MORE_STACK_LOCATIONS, + (ULONG_PTR) pIrp); + return; // not reached + } + + pRequest->m_NextStackLocationFormatted = TRUE; + pIrp->CopyToNextIrpStackLocation(Stack); + + pRequest->VerifierSetFormatted(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestSetCompletionRoutine)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in_opt + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + __in_opt + WDFCONTEXT CompletionContext + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST %p, Routine %p, Context %p", + Request, CompletionRoutine, CompletionContext); +#endif // FX_VERBOSE_TRACE + + pRequest->SetCompletionRoutine(CompletionRoutine, CompletionContext); + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestGetParameters)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __out + PWDF_REQUEST_PARAMETERS Parameters + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Parameters); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: Request %p, Parameters %p", Request, Parameters); +#endif // FX_VERBOSE_TRACE + + if (Parameters->Size != sizeof(WDF_REQUEST_PARAMETERS)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Params size %d incorrect, expected %d", + Parameters->Size, sizeof(WDF_REQUEST_PARAMETERS)); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return; + } + + + + + (VOID) pRequest->GetParameters(Parameters); + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfRequestGetCompletionParams)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __out + PWDF_REQUEST_COMPLETION_PARAMS Params + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST %p, Params %p", Request, Params); +#endif // FX_VERBOSE_TRACE + + FxPointerNotNull(pFxDriverGlobals, Params); + + if (Params->Size != sizeof(WDF_REQUEST_COMPLETION_PARAMS)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Params Size 0x%x, expected 0x%x", + Params->Size, sizeof(WDF_REQUEST_COMPLETION_PARAMS)); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pRequest->CopyCompletionParams(Params); + + return; + +} + +__drv_maxIRQL(DISPATCH_LEVEL) +MdIrp +WDFAPI +WDFEXPORT(WdfRequestWdmGetIrp)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + This routine returns the WDM IRP associated with the given + request. + + The WDM IRP is invalid once WdfRequestComplete is called, regardless + of any reference counts on the WDFREQUEST object. + +Arguments: + + Request - Handle to the Request object + +Returns: + + PIRP + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + + return irp; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestAllocateTimer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) +/*++ + +Routine Description: + Preallocates a timer to be associated with the passed in request object. + By preallocating the timer, WdfSendRequest cannot fail with insufficient + resources when attempting to allocate a timer when a timeout constraint has + been passed in. + + If the request already has a timer allocated for it, then the function will + succeed. + +Arguments: + Request - the request to allocate a timer for + +Return Value: + NT_SUCCESS upon success, STATUS_INSUFFICIENT_RESOURCES upon failure + + --*/ + +{ + FxRequest* pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + + return pRequest->CreateTimer(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFFILEOBJECT +WDFAPI +WDFEXPORT(WdfRequestGetFileObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + This routine returns the WDFFILEOBJECT associated with the given + request. + +Arguments: + + Request - Handle to the Request object + +Returns: + + WDFFILEOBJECT handle. + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + FxFileObject* pFO; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest, + &pFxDriverGlobals); + + pFO = NULL; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetDriverGlobals()->IsVerificationEnabled( + 1,9, OkForDownLevel)) { + KIRQL irql; + + pRequest->Lock(&irql); + status = pRequest->VerifyRequestIsDriverOwned(pFxDriverGlobals); + pRequest->Unlock(irql); + if (!NT_SUCCESS(status)) { + return NULL; + } + } + + status = pRequest->GetFileObject(&pFO); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "GetFileobject failed with %!STATUS!", status); + return NULL; + } + else if (NULL == pFO) { + // + // Success and NULL file object: driver during init told us that it + // knows how to handle NULL file objects. + // + return NULL; + } + + return pFO->GetHandle(); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestProbeAndLockUserBufferForRead)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in_bcount(Length) + PVOID Buffer, + __in + size_t Length, + __out + WDFMEMORY* MemoryObject + ) + +/*++ + +Routine Description: + + This routine probes and locks the specified user mode address into + an MDL, and associates it with the WDFREQUEST object. + + The MDL, and its associated system buffer is represented by a WDFMEMORY + object. + + The WDFMEMORY object and the MDL is automatically released when the + WDFREQUEST is completed by WdfRequestComplete. + +Arguments: + + Request - Handle to the Request object + + Buffer - Buffer to probe and lock into an MDL + + Length - Length of buffer + + MemoryObject - Location to return WDFMEMORY handle + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + FxRequestMemory* pMemory; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Buffer); + FxPointerNotNull(pFxDriverGlobals, MemoryObject); + *MemoryObject = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetDriverGlobals()->IsVerificationEnabled( + 1,9, OkForDownLevel)) { + KIRQL irql; + + pRequest->Lock(&irql); + status = pRequest->VerifyRequestIsDriverOwned(pFxDriverGlobals); + pRequest->Unlock(irql); + if (!NT_SUCCESS(status)) { + return status; + } + } + + status = pRequest->ProbeAndLockForRead(Buffer, (ULONG) Length, &pMemory); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "ProbeAndLockForRead failed with %!STATUS!", status); + return status; + } + + *MemoryObject = (WDFMEMORY) pMemory->GetObjectHandle(); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in_bcount(Length) + PVOID Buffer, + __in + size_t Length, + __out + WDFMEMORY* MemoryObject + ) + +/*++ + +Routine Description: + + This routine probes and locks the specified user mode address into + an MDL, and associates it with the WDFREQUEST object. + + The MDL, and its associated system buffer is represented by a WDFMEMORY + object. + + The WDFMEMORY object and the MDL is automatically released when the + WDFREQUEST is completed by WdfRequestComplete. + +Arguments: + + Request - Handle to the Request object + + Buffer - Buffer to probe and lock into an MDL + + Length - Length of buffer + + MemoryObject - Location to return WDFMEMORY handle + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + FxRequestMemory* pMemory; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Buffer); + FxPointerNotNull(pFxDriverGlobals, MemoryObject); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetDriverGlobals()->IsVerificationEnabled( + 1,9, OkForDownLevel)) { + KIRQL irql; + + pRequest->Lock(&irql); + status = pRequest->VerifyRequestIsDriverOwned(pFxDriverGlobals); + pRequest->Unlock(irql); + if (!NT_SUCCESS(status)) { + return status; + } + } + + status = pRequest->ProbeAndLockForWrite(Buffer, (ULONG) Length, &pMemory); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "ProbeAndLockForWrite failed with %!STATUS!", status); + return status; + } + + *MemoryObject = (WDFMEMORY)pMemory->GetObjectHandle(); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +KPROCESSOR_MODE +WDFAPI +WDFEXPORT(WdfRequestGetRequestorMode)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Returns the RequestorMode information from the IRP. + + +Arguments: + + Request - Handle to the Request object + + +Returns: + + KPROCESSOR_MODE is CCHAR + +--*/ + +{ + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest); + + return pRequest->GetRequestorMode(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFQUEUE +WDFAPI +WDFEXPORT(WdfRequestGetIoQueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Returns the queue handle that currently owns the request. + + +Arguments: + + Request - Handle to the Request object + + +Returns: + + WDFQUEUE + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetCurrentQueue() == NULL) { + // + // For a driver-created request, the queue can be NULL. It is not + // necessarily an error to call WdfRequestGetIoQueue on a driver- + // created request, because the caller may not really know whether or + // not the request is driver-created. + // + // For example, it is possible for a class extension to create a request + // and pass it to the client driver, in which case the client driver + // wouldn't really know whether or not it was driver-created. Or a + // client driver is might be using a helper library for some of its + // tasks and it might pass in a request object to the helper library. In + // this case, the helper library wouldn't really know whether or not the + // request was driver-created. Therefore, the log message below is at + // verbose level and not at error or warning level. + // + DoTraceLevelMessage(pFxDriverGlobals, + TRACE_LEVEL_VERBOSE, + TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue", + Request); + return NULL; + } + + if (pRequest->GetFxIrp()->GetMajorFunction() == IRP_MJ_CREATE) { + // + // If the queue for Create is the framework internal queue + // return NULL. + // + FxPkgGeneral* devicePkgGeneral = pRequest->GetDevice()->m_PkgGeneral; + + if (devicePkgGeneral->GetDeafultInternalCreateQueue() == + pRequest->GetCurrentQueue()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Getting queue handle for Create request is " + "not allowed for WDFREQUEST 0x%p", pRequest); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return NULL; + } + } + + return (WDFQUEUE) pRequest->GetCurrentQueue()->GetObjectHandle(); +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_FUNCTION(VerifyWdfRequestForwardToIoQueue) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* request + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE_LOCKED(); + + // + // * Is request I/O allocated but without a queue? This should not happen. + // * Is WDF driver v1.9 or below trying to use this feature? We don't allow it. + // + if (request->IsAllocatedDriver() == FALSE || + FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue, %!STATUS!", + request->GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return status; + } + + // + // Make sure current IRP stack location is valid. See helper routine for error msgs. + // + status = request->VerifyRequestCanBeCompleted(FxDriverGlobals); + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestForwardToIoQueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + WDFQUEUE DestinationQueue + ) + +/*++ + +Routine Description: + + Forward a request presented on one queue to another driver + managed queue. + + A request may only be forwarded from a queues dispatch routine. + + If the request is successfully forwarded to the DestinationQueue, it + is no longer owned by the driver, but by the DestinationQueue. + + Both the source queue and destination queue should be part of the + same device. + + The driver gets ownership of the request when it receives it + from the DestinationQueue through EvtIo callback, or WdfIoQueueRetrieveNextRequest. + +Arguments: + + + Request - Request object to forward. + + DestinationQueue - Queue that is to receive the request. + +Returns: + + STATUS_SUCCESS - Request was forwarded to Queue and driver no + longer owns it. + + !STATUS_SUCCESS - Request was not forwarded to the Queue, and + the driver still owns the request and is responsible + for either completing it, or eventually successfully + forwarding it to a Queue. +--*/ + +{ + PFX_DRIVER_GLOBALS fxDriverGlobals; + PFX_DRIVER_GLOBALS cxDriverGlobals; + FxRequest* request; + FxIoQueue* queue; + NTSTATUS status; + + cxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Validate destination queue handle + // + FxObjectHandleGetPtrAndGlobals(cxDriverGlobals, + DestinationQueue, + FX_TYPE_QUEUE, + (PVOID*)&queue, + &fxDriverGlobals); + + // + // Validate request object handle + // + FxObjectHandleGetPtr(fxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*)&request); + + // + // If present, let the queue do the heavy lifting. + // + if (request->GetCurrentQueue() != NULL) { + status = request->GetCurrentQueue()->ForwardRequest(queue, request); + goto Done; + } + + // + // Basic verification. + // + status = VerifyWdfRequestForwardToIoQueue(fxDriverGlobals, request); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // OK, queue this request. + // + status = queue->QueueDriverCreatedRequest(request, FALSE); + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_FUNCTION(VerifyWdfRequestForwardToParentDeviceIoQueue) ( + _In_ PFX_DRIVER_GLOBALS fxDriverGlobals, + _In_ FxRequest* request + ) +{ + NTSTATUS status; + FxIrp* irp; + + PAGED_CODE_LOCKED(); + + // + // * Is request I/O allocated but without a queue? This should not happen. + // * Is WDF driver v1.9 or below trying to use this feature? We don't allow it. + // + if (request->IsAllocatedDriver() == FALSE || + fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue, %!STATUS!", + request->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Make sure current IRP stack location is valid. + // + status = request->VerifyRequestCanBeCompleted(fxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Make sure IRP has space for at least another stack location. + // + irp = request->GetFxIrp(); + + ASSERT(irp->GetIrp() != NULL); + + if (irp->GetCurrentIrpStackLocationIndex() <= 1) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "IRP %p of WDFREQUEST %p doesn't enough stack " + "locations, %!STATUS!", + irp, request->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + +Done: + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestForwardToParentDeviceIoQueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + WDFQUEUE ParentDeviceQueue, + __in + PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions + ) + +/*++ + +Routine Description: + + Forward a request presented on one queue to parent Device queue. + + A request may only be forwarded from a queues dispatch routine. + + If the request is successfully forwarded to the ParentDeviceQueue, it + is no longer owned by the driver, but by the ParentDeviceQueue. + + The driver gets ownership of the request when it receives it + from the DestinationQueue through EvtIo callback, or WdfIoQueueRetrieveNextRequest. + +Arguments: + + + Request - Request object to forward. + + ParentDeviceQueue - Queue that is to receive the request. + + ForwardOptions - A pointer to a caller-allocated WDF_REQUEST_FORWARD_OPTIONS + structure + +Returns: + + STATUS_SUCCESS - Request was forwarded to Queue and driver no + longer owns it. + + !STATUS_SUCCESS - Request was not forwarded to the Queue, and + the driver still owns the request and is responsible + for either completing it, or eventually successfully + forwarding it to a Queue. +--*/ + +{ + PFX_DRIVER_GLOBALS fxDriverGlobals; + NTSTATUS status; + FxRequest* request; + FxIoQueue* queue; + + // + // Validate destination queue handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + ParentDeviceQueue, + FX_TYPE_QUEUE, + (PVOID*)&queue, + &fxDriverGlobals); + + // + // Validate request object handle + // + FxObjectHandleGetPtr(fxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*)&request); + FxPointerNotNull(fxDriverGlobals, ForwardOptions); + + if (ForwardOptions->Size != sizeof(WDF_REQUEST_FORWARD_OPTIONS)) { + // + // Size is wrong, bale out + // + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "ForwardOptions %p Size incorrect, expected %d, " + "got %d, %!STATUS!", + ForwardOptions, sizeof(WDF_REQUEST_FORWARD_OPTIONS), + ForwardOptions->Size, + status); + + goto Done; + } + + if ((ForwardOptions->Flags & ~WDF_REQUEST_FORWARD_OPTION_SEND_AND_FORGET) != 0) { + // + // Invalid flag + // + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "ForwardOptions %p Flags 0x%x invalid, " + "valid mask is 0x%x, %!STATUS!", + ForwardOptions, ForwardOptions->Flags, + WDF_REQUEST_FORWARD_OPTION_SEND_AND_FORGET, + status); + + goto Done; + } + + // + // If present, let the queue do the heavy lifting. + // + if (request->GetCurrentQueue() != NULL) { + status = request->GetCurrentQueue()->ForwardRequestToParent( + queue, + request, + ForwardOptions); + goto Done; + } + + // + // Basic verification. + // + status = VerifyWdfRequestForwardToParentDeviceIoQueue(fxDriverGlobals, + request); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // OK, queue this request. + // + status = queue->QueueDriverCreatedRequest(request, TRUE); + +Done: + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestRequeue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Requeue the request - only allowed if the queue is a manual queue. + +Arguments: + + Request - Request to requeue + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + // + // GetCurrentQueue may return NULL if the request is driver created request + // or the if the call is made in the context of InProcessContextCallback. + // + if (pRequest->GetCurrentQueue() == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue %!STATUS!", + Request, STATUS_INVALID_DEVICE_REQUEST); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_INVALID_DEVICE_REQUEST; + } + + return pRequest->GetCurrentQueue()->Requeue(pRequest); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfRequestMarkCancelable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ) + +/*++ + +Routine Description: + + Mark the specified request as cancelable + +Arguments: + + Request - Request to mark as cancelable. + + EvtRequestCancel - cancel routine to be invoked when the + request is cancelled. + +Returns: + + None + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + NTSTATUS status; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, EvtRequestCancel); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetCurrentQueue() == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue", + Request); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + status = pRequest->GetCurrentQueue()->RequestCancelable(pRequest, + TRUE, + EvtRequestCancel, + FALSE); + UNREFERENCED_PARAMETER(status); //for fre build + ASSERT(status == STATUS_SUCCESS); + +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestMarkCancelableEx)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ) + +/*++ + +Routine Description: + + Mark the specified request as cancelable. Do not call the specified cancel + routine if IRP is already cancelled but instead return STATUS_CANCELLED. + Caller is responsible for completing the request with STATUS_CANCELLED. + +Arguments: + + Request - Request to mark as cancelable. + + EvtRequestCancel - cancel routine to be invoked when the + request is cancelled. + +Returns: + + STATUS_SUCCESS - The request has been marked cancelable. + STATUS_CANCELLED - The IRP is already cancelled. + NTSTATUS - Other values are possible when verifier is enabled. + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + NTSTATUS status; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, EvtRequestCancel); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetCurrentQueue() == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue %!STATUS!", + Request, STATUS_INVALID_DEVICE_REQUEST); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_INVALID_DEVICE_REQUEST; + } + + status = pRequest->GetCurrentQueue()->RequestCancelable(pRequest, + TRUE, + EvtRequestCancel, + TRUE); + + ASSERT(status == STATUS_SUCCESS || status == STATUS_CANCELLED); + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfRequestUnmarkCancelable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Unmark the specified request as cancelable + +Arguments: + + Request - Request to unmark as cancelable. + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + if (pRequest->GetCurrentQueue() == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p doesn't belong to any queue %!STATUS!", + Request, STATUS_INVALID_DEVICE_REQUEST); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_INVALID_DEVICE_REQUEST; + } + + return pRequest->GetCurrentQueue()->RequestCancelable(pRequest, + FALSE, + NULL, + FALSE); +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_FUNCTION(VerifyWdfRequestIsCanceled)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* pRequest + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + pRequest->Lock(&irql); + + status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals); + if (NT_SUCCESS(status)) { + status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals); + } + + pRequest->Unlock(irql); + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfRequestIsCanceled)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) + +/*++ + +Routine Description: + + Check to see if the request is cancelled by the I/O manager. + This call is valid only on a driver owned non-cancelable request. + +Arguments: + + Request - Request being checked. + +Returns: + + BOOLEAN + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + NTSTATUS status; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + status = VerifyWdfRequestIsCanceled(pRequest->GetDriverGlobals(), pRequest); + if (!NT_SUCCESS(status)) { + return FALSE; + } + + return pRequest->IsCancelled(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfRequestStopAcknowledge)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request, + __in + BOOLEAN Requeue + ) + +/*++ + +Routine Description: + + The driver calls this to acknowledge that it is no longer + attempting to perform I/O on the request which was provided in + the EvtIoStop event callback notification. + + The device driver must arrange to no longer touch any hardware + resources before making this call. + +Arguments: + + Request - Request being stopped + + Requeue - True if the request is to be placed back on the front of the queue, + and re-delivered to the device driver on resume. + +Returns: + + None + +--*/ + +{ + FxRequest* pRequest; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + pRequest->StopAcknowledge(Requeue); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfRequestIsReserved)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFREQUEST Request + ) +/*++ + +Routine Description: + This is used to determine if a Request is a reserved request. Reserved + Requests are used for forward progress. + +Arguments: + + Request - Request being checked + + +Returns: + + BOOLEAN + +--*/ + +{ + FxRequest* pRequest; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + // + // Validate request object handle + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + return pRequest->IsReserved(); +} + + +} // extern "C" the whole file diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequestbase.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequestbase.cpp new file mode 100644 index 00000000000..134bf6a50ca --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequestbase.cpp @@ -0,0 +1,832 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestBase.cpp + +Abstract: + + This module implements FxRequestBase object + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestBase.tmh" +} + +FxRequestBase::FxRequestBase( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in_opt MdIrp Irp, + __in FxRequestIrpOwnership Ownership, + __in FxRequestConstructorCaller Caller, + __in FxObjectType ObjectType + ) : FxNonPagedObject(FX_TYPE_REQUEST, ObjectSize, FxDriverGlobals, ObjectType), + m_Irp(Irp) +{ + // + // By default requests cannot be completed except for request associated with + // IRP allocated from I/O (upper drivers). + // + m_CanComplete = FALSE; + + // + // After is all said and done with assigning to m_IrpAllocation value, if + // m_Irp().GetIrp == NULL, then m_IrpAllocation can be overridden in + // ValidateTarget. + // + if (Caller == FxRequestConstructorCallerIsDriver) { + if (Ownership == FxRequestOwnsIrp) { + // + // Driver writer gave the irp to the framework but still owns it + // or there is no irp passed in when the FxRequest was created. + // + m_IrpAllocation = REQUEST_ALLOCATED_INTERNAL; + } + else { + // + // Driver writer gave the irp to the framework but still owns it + // + m_IrpAllocation = REQUEST_ALLOCATED_DRIVER; + } + + // + // Cleanup request's context in Dispose. Please see Dispose below + // for specific scenario we are trying to fix. Enable Dispose only if + // driver is v1.11 or above b/c it may be possible that older driver + // may have used invalid/bad scenarios similar to this one: + // - create target object. + // - create one or more driver created requests parented to the target. + // - send one or more of these requests to the target (lower stack). + // - delete the target object while requests are pending. + // Deleting a target while it has a pending request is a valid + // operation, what is not valid is for these request to be also + // parented to the target at the same time. + // In this scenario if we turn on Dispose, the Dispose callback will + // be called before the request is completed. + // Note that if the driver had specified any Cleanup callbacks on + // these requests, these also are called before the requests are + // completed. + // + if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1, 11)) { + MarkDisposeOverride(); + } + } + else if (Ownership == FxRequestOwnsIrp) { + // + // The request will own the irp and free it when the request is freed + // + m_IrpAllocation = REQUEST_ALLOCATED_INTERNAL; + } + else { + // + // Request is owned by the io queue + // + m_IrpAllocation = REQUEST_ALLOCATED_FROM_IO; + m_CanComplete = TRUE; + } + + m_Target = NULL; + m_TargetFlags = 0; + + m_TargetCompletionContext = NULL; + + m_Completed = m_Irp.GetIrp() ? FALSE : TRUE; + m_Canceled = FALSE; + + m_PriorityBoost = 0; + + m_RequestContext = NULL; + m_Timer = NULL; + + InitializeListHead(&m_ListEntry); + m_DrainSingleEntry.Next = NULL; + + m_IrpReferenceCount = 0; + + m_IrpQueue = NULL; + + m_SystemBufferOffset = 0; + m_OutputBufferOffset = 0; + m_IrpCompletionReferenceCount = 0; + + m_AllocatedMdl = NULL; + + m_VerifierFlags = 0; + m_RequestBaseFlags = 0; + m_RequestBaseStaticFlags = 0x0; + m_CompletionState = FxRequestCompletionStateNone; +} + +FxRequestBase::~FxRequestBase( + VOID + ) +{ + MdIrp irp; + + // + // Since m_ListEntry is a union with the CSQ context and the irp have just + // come off of a CSQ, we cannot be guaranteed that the m_ListEntry is + // initialized to point to itself. + // + // ASSERT(IsListEmpty(&m_ListEntry)); + + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // If an MDL is associated with the request, free it + // + if (m_AllocatedMdl != NULL) { + FxMdlFree(GetDriverGlobals(), m_AllocatedMdl); + } +#endif + + irp = m_Irp.GetIrp(); + + // + // If the request was created through WdfRequestCreate, formatted, and not + // reused, we can still have a request context. + // + if (m_RequestContext != NULL) { + if (irp != NULL) { + m_RequestContext->ReleaseAndRestore(this); + } + + delete m_RequestContext; + } + + if (irp != NULL && m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) { + m_Irp.FreeIrp(); + } + + if (m_Timer != NULL) { + delete m_Timer; + } +} + +VOID +FX_VF_METHOD(FxRequestBase, VerifyDispose) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + SHORT flags; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + Lock(&irql); + flags = GetVerifierFlagsLocked(); + if (flags & FXREQUEST_FLAG_SENT_TO_TARGET) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver is trying to delete WDFREQUEST 0x%p while it is still " + "active on WDFIOTARGET 0x%p. ", + GetTraceObjectHandle(), GetTarget()->GetHandle()); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + Unlock(irql); +} + +BOOLEAN +FxRequestBase::Dispose() +{ + // + // Make sure request is not in use. + // + VerifyDispose(GetDriverGlobals()); + + // + // Now call Cleanup on any handle context's exposed + // to the device driver. + // + CallCleanup(); + + // + // Call the request's cleanup (~dtor or Dispose). + // + if (m_RequestContext != NULL) { + if (IsAllocatedFromIo() == FALSE && m_Irp.GetIrp() != NULL) { + // + // This code allows the following scenario to work correctly b/c + // the original request can be completed without worrying that the + // new request's context has references on the original request. + // + // * Driver receives an ioctl request. + // * Driver creates a new request. + // * Driver formats the new request with buffers from original ioctl. + // * Driver sends the new request synchronously. + // * Driver retrieves info/status from the new request. + // * Driver deletes the new request. + // * Driver completes the original request. + // + m_RequestContext->ReleaseAndRestore(this); + + // + // ~dtor cleans up everything. No need to call its Dispose method. + // + delete m_RequestContext; + m_RequestContext = NULL; + } + else { + // + // Let request's context know that Dispose is in progress. + // RequestContext may receive the following two calls after Dispose: + // . ReleaseAndRestore if an IRP is still present. + // . Destructor + // + m_RequestContext->Dispose(); + } + } + + return FALSE; +} + +VOID +FxRequestBase::ClearFieldsForReuse( + VOID + ) +{ +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (m_AllocatedMdl != NULL) { + FxMdlFree(GetDriverGlobals(), m_AllocatedMdl); + m_AllocatedMdl = NULL; + } +#endif + + m_RequestBaseFlags = 0; + m_RequestBaseStaticFlags = 0x0; + m_VerifierFlags = 0; + m_Canceled = FALSE; + + SetCompleted(FALSE); + SetPriorityBoost(0); + + m_NextStackLocationFormatted = FALSE; + + if (m_Timer != NULL) { + delete m_Timer; + m_Timer = NULL; + } + + m_Target = NULL; + m_TargetFlags = 0; + m_TargetCompletionContext = NULL; + + InitializeListHead(&m_ListEntry); + + m_DrainSingleEntry.Next = NULL; + m_IrpCompletionReferenceCount = 0; + m_CompletionState = FxRequestCompletionStateNone; +} + +_Must_inspect_result_ +NTSTATUS +FxRequestBase::ValidateTarget( + __in FxIoTarget* Target + ) +{ + MdIrp pIrp, pOldIrp; + FxIrp fxIrp; + NTSTATUS status; + + pOldIrp = NULL; + + pIrp = GetSubmitIrp(); + fxIrp.SetIrp(pIrp); + + // + // Must restore to the previous irp in case we reallocate the irp + // + ContextReleaseAndRestore(); + + if (Target->HasValidStackSize() == FALSE) { + + // + // Target is closed down + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p is closed, cannot validate, %!STATUS!", + Target->GetHandle(), status); + } + else if (pIrp != NULL && Target->HasEnoughStackLocations(&fxIrp)) { + status = STATUS_SUCCESS; + } + else if (pIrp == NULL || m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) { + // + // Try to allocate a new irp. + // + pIrp = FxIrp::AllocateIrp(Target->m_TargetStackSize, Target->GetDevice()); + + if (pIrp == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate irp for WDFREQUEST %p for WDFIOTARGET %p," + " %!STATUS!", GetTraceObjectHandle(), Target->GetHandle(), status); + } + else { + pOldIrp = SetSubmitIrp(pIrp, FALSE); + m_IrpAllocation = REQUEST_ALLOCATED_INTERNAL; + status = STATUS_SUCCESS; + } + } + else { + // + // The internal IRP is not owned by this object, so we can't reallocate + // it. + // + + + + + + + + status = STATUS_REQUEST_NOT_ACCEPTED; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Cannot reallocate PIRP for WDFREQUEST %p using WDFIOTARGET %p," + " %!STATUS!", GetTraceObjectHandle(), Target->GetHandle(), status); + } + + if (pOldIrp != NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Freeing irp %p from WDFREQUEST %p\n", + pOldIrp, GetTraceObjectHandle()); + FxIrp oldIrp(pOldIrp); + oldIrp.FreeIrp(); + } + + return status; +} + +MdIrp +FxRequestBase::SetSubmitIrp( + __in_opt MdIrp NewIrp, + __in BOOLEAN FreeIrp + ) +{ + MdIrp pOldIrp, pIrpToFree; + + pIrpToFree = NULL; + pOldIrp = m_Irp.SetIrp(NewIrp); + + if (NewIrp != NULL) { + m_Completed = FALSE; + } + + // + // If there is a previous irp that is not the current value and we + // allocated it ourselves and the caller wants us to free it, do so. + // + if (pOldIrp != NULL && + pOldIrp != NewIrp && + m_IrpAllocation == REQUEST_ALLOCATED_INTERNAL) { + if (FreeIrp) { + FxIrp oldIrp(pOldIrp); + oldIrp.FreeIrp(); + } + else { + pIrpToFree = pOldIrp; + } + } + + return pIrpToFree; +} + +VOID +FxRequestBase::CompleteSubmittedNoContext( + VOID + ) +/*++ + +Routine Description: + Invokes the completion routine and uses a completion params that is on the + stack. This is in a separate function so that we only consume the stack + space if we need to. + +Arguments: + None + +Return Value: + None + + --*/ +{ + WDF_REQUEST_COMPLETION_PARAMS params; + + params.Type = WdfRequestTypeNoFormat; + + GetSubmitFxIrp()->CopyStatus(¶ms.IoStatus); + + RtlZeroMemory(¶ms.Parameters, sizeof(params.Parameters)); + + + // + // Once we call the completion routine we can't touch any fields anymore + // since the request may be resent down the stack. + // + ClearCompletionRoutine()(GetHandle(), + m_Target->GetHandle(), + ¶ms, + ClearCompletionContext()); +} + +VOID +FxRequestBase::CompleteSubmitted( + VOID + ) +/*++ + +Routine Description: + Routine that handles the setting up of the request packet for being passed + back to the completion routine. This includes copying over parameters from + the PIRP and any dereferences necessary. + +Arguments: + None. + +Return Value: + None. + + --*/ +{ + FxIoTarget* pTarget; + + pTarget = m_Target; + + FX_TRACK_DRIVER(GetDriverGlobals()); + + if (GetDriverGlobals()->FxVerifierOn) { + // + // Zero out any values previous driver may have set; when completing the irp + // through FxRequest::CompleteInternal, we check to see what the lastest + // package was (stored off in the DriverContext). Since the request was + // sent off to another devobj, don't assume any valid values in the + // DriverContext anymore. + // + ZeroOutDriverContext(); + + // + // ClearFormatted also checks for WdfVefiefierOn, but that's OK + // + VerifierClearFormatted(); + } + + if (m_RequestContext != NULL) { + // + // Always do the copy because the driver can retrieve the parameters + // later even if there is no completion routine set. + // + GetSubmitFxIrp()->CopyStatus( + &m_RequestContext->m_CompletionParams.IoStatus + ); + + m_RequestContext->CopyParameters(this); + + // + // Call the completion routine if present. Once we call the completion + // routine we can't touch any fields anymore since the request may be resent + // down the stack. + // + if (m_CompletionRoutine.m_Completion != NULL) { + ClearCompletionRoutine()(GetHandle(), + pTarget->GetHandle(), + &m_RequestContext->m_CompletionParams, + ClearCompletionContext()); + } + } + else if (m_CompletionRoutine.m_Completion != NULL) { + // + // Only put a completion parameters struct on the stack if we have to. + // By putting it into a separate function, we can control stack usage + // in this way. + // + CompleteSubmittedNoContext(); + } + + // + // Release the tag that was acquired when the request was submitted or + // pended. + // + RELEASE(pTarget); +} + +BOOLEAN +FxRequestBase::Cancel( + VOID + ) +/*++ + +Routine Description: + Attempts to cancel a previously submitted or pended request. + +Arguments: + None + +Return Value: + TRUE if the request was successfully cancelled, FALSE otherwise + + --*/ +{ + BOOLEAN result; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p", this); + + // + // It is critical to set m_Canceled before we check the reference count. + // We could be racing with FxIoTarget::SubmitLocked and if this call executes + // before SubmitLocked, the completion reference count will still be zero. + // SubmitLocked will check m_Canceled after setting the reference count to + // one so that it decrement the count back. + // + m_Canceled = TRUE; + + // + // If the ref count is zero, the irp has completed already. This means we + // cannot safely touch the underlying PIRP because we cannot guarantee it + // will not be completed from underneath us. + // + if (FxInterlockedIncrementGTZero(&m_IrpCompletionReferenceCount) != 0) { + // + // Successfully incremented the ref count. The PIRP will not be completed + // until the count goes to zero. + // + // Cancelling the irp handles all 2 states: + // + // 1) the request is pended in a target. the target will attempt to + // complete the request immediately in the cancellation routine, but + // will not be able to because of the added count to the ref count + // done above. The count will move back to zero below and + // CompletedCanceledRequest will complete the request + // + // 2) The irp is in flight to the target WDM device. In which case the + // target WDM device should complete the request immediatley. If + // it does not, it becomes the same as the case where the target WDM + // device has already pended it and placed a cancellation routine + // on the request and the request will (a)synchronously complete + // + result = m_Irp.Cancel(); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p, PIRP %p, cancel result %d", + this, m_Irp.GetIrp(), result); + + // + // If the count goes to zero, the completion routine ran, but deferred + // completion ownership to this thread since we had the outstanding + // refeference. + // + if (InterlockedDecrement(&m_IrpCompletionReferenceCount) == 0) { + + // + // Since completion ownership was claimed, m_Target will be valid + // until m_Target->CompleteRequest executes because the target will + // not delete while there is outstanding I/O. + // + ASSERT(m_Target != NULL); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p, PIRP %p, completed synchronously in cancel call, " + "completing request on target %p", this, m_Irp.GetIrp(), m_Target); + + m_Target->CompleteCanceledRequest(this); + } + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Could not cancel request %p, already completed", this); + + result = FALSE; + } + + return result; +} + +VOID +FxRequestBase::_TimerDPC( + __in PKDPC Dpc, + __in_opt PVOID Context, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) +/*++ + +Routine Description: + DPC for the request timer. It lets the FxIoTarget associated with the + request handle the cancellation synchronization with the PIRP's + completion routine. + +Arguments: + Dpc - The DPC itself (part of FxRequestExtension) + + Context - FxRequest* that has timed out + + SystemArgument1 - Ignored + + SystemArgument2 - Ignored + +Return Value: + None. + + --*/ +{ + FxRequest* pRequest; + FxIoTarget* pTarget; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + // + // No need to grab FxRequest::Lock b/c if there is a timer running, then the + // request is guaranteed to be associated with a target. + // + pRequest = (FxRequest*) Context; + pTarget = pRequest->m_Target; + + ASSERT(pTarget != NULL); + pTarget->TimerCallback(pRequest); +} + +_Must_inspect_result_ +NTSTATUS +FxRequestBase::CreateTimer( + VOID + ) +/*++ + +Routine Description: + Late time initialization of timer related structures, we only init + timer structures if we are going to use them. + +Arguments: + None + +Assumes: + m_Target->Lock() is being held by the caller + +Return Value: + None + + --*/ + +{ + FxRequestTimer* pTimer; + PVOID pResult; + NTSTATUS status; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + if (m_Timer != NULL) { + return STATUS_SUCCESS; + } + + + + + + pTimer = new (FxDriverGlobals) FxRequestTimer(); + + if(pTimer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pTimer->Timer.Initialize(this, _TimerDPC, 0); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Failed to initialize timer for request %p", this); + delete pTimer; + return status; + } + + pResult = InterlockedCompareExchangePointer((PVOID*)&m_Timer, pTimer, NULL); + + if (pResult != NULL) { + // + // Another value was set before we could set it, free our timer now + // + delete pTimer; + } + + return STATUS_SUCCESS; +} + +VOID +FxRequestBase::StartTimer( + __in LONGLONG Timeout + ) +/*++ + +Routine Description: + Starts a timer for the request + +Arguments: + Timeout - How long the timeout should be + +Assumes: + m_Target->Lock() is being held by the caller. + +Return Value: + None + + --*/ +{ + LARGE_INTEGER timeout; + timeout.QuadPart = Timeout; + + m_TargetFlags |= FX_REQUEST_TIMER_SET; + + m_Timer->Timer.Start(timeout); + +} + +_Must_inspect_result_ +BOOLEAN +FxRequestBase::CancelTimer( + VOID + ) +/*++ + +Routine Description: + Cancel a previously queued timer based on this request if one was set. + +Arguments: + None + +Assumes: + Caller is providing synchronization around the call of this function with + regard to m_TargetFlags. + +Return Value: + TRUE if the timer was cancelled successfully or if there was no timer set, + otherwise FALSE if the timer was not cancelled and has fired. + + --*/ +{ + if (m_TargetFlags & FX_REQUEST_TIMER_SET) { + // + // If we can successfully cancel the timer, release the reference + // taken in StartTimer and mark the timer as not queued. + // + + if (m_Timer->Timer.Stop() == FALSE) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p, did not cancel timer", this); + + // + // Leave FX_REQUEST_TIMER_SET set. The timer DPC will clear the it + // + + return FALSE; + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p, canceled timer successfully", this); + + m_TargetFlags &= ~FX_REQUEST_TIMER_SET; + } + + return TRUE; +} + +__declspec(noreturn) +VOID +FxRequestBase::FatalError( + __in NTSTATUS Status + ) +{ + WDF_QUEUE_FATAL_ERROR_DATA data; + + RtlZeroMemory(&data, sizeof(data)); + + data.Queue = NULL; + data.Request = (WDFREQUEST) GetTraceObjectHandle(); + data.Status = Status; + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_QUEUE_FATAL_ERROR, + (ULONG_PTR) &data); +} + diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequestcontext.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequestcontext.cpp new file mode 100644 index 00000000000..80a68d38911 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequestcontext.cpp @@ -0,0 +1,195 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestContext.cpp + +Abstract: + + This module implements FxRequest object + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestContext.tmh" +} + +FxRequestContext::FxRequestContext( + __in FX_REQUEST_CONTEXT_TYPE Type + ) : + m_RequestType(Type), + m_RequestMemory(NULL) + +/*++ + +Routine Description: + Constructs an FxRequestContext and initialized the m_RequestType field + +Arguments: + Type - The type of this request. + + + + + +Return Value: + None. + + --*/ +{ + InitCompletionParams(); +} + +FxRequestContext::~FxRequestContext() +/*++ + +Routine Description: + Destruct for an FxRequestContext. Releases all outstanding references. + +Arguments: + None + +Return Value: + None + + --*/ +{ + ASSERT(m_RequestMemory == NULL); +} + +VOID +FxRequestContext::StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ) +{ + _StoreAndReferenceMemoryWorker(this, &m_RequestMemory, Buffer); +} + +VOID +FxRequestContext::ReleaseAndRestore( + __in FxRequestBase* Request + ) +/*++ + +Routine Description: + This routine releases any outstanding references taken on the previous + format call and restores any fields in the PIRP that were overwritten + when the formatting occurred. + +Arguments: + Irp + +Return Value: + + + --*/ + +{ +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + Request->FreeMdls(); +#else + UNREFERENCED_PARAMETER(Request); +#endif + + if (m_RequestMemory != NULL) { + m_RequestMemory->RELEASE(this); + m_RequestMemory = NULL; + } + + InitCompletionParams(); +} + +VOID +FxRequestContext::_StoreAndReferenceMemoryWorker( + __in PVOID Tag, + __deref_out_opt IFxMemory** PPMemory, + __in FxRequestBuffer* Buffer + ) +{ + ASSERT(*PPMemory == NULL); + + switch (Buffer->DataType) { + case FxRequestBufferMemory: + Buffer->u.Memory.Memory->ADDREF(Tag); + *PPMemory = Buffer->u.Memory.Memory; + break; + + case FxRequestBufferReferencedMdl: + Buffer->u.RefMdl.Memory->ADDREF(Tag); + *PPMemory = Buffer->u.RefMdl.Memory; + break; + + default: + *PPMemory = NULL; + } +} + +VOID +FxRequestContext::FormatWriteParams( + __in_opt IFxMemory* WriteMemory, + __in_opt PWDFMEMORY_OFFSET WriteOffsets + ) +{ + m_CompletionParams.Type = WdfRequestTypeWrite; + + if (WriteMemory != NULL) { + m_CompletionParams.Parameters.Write.Buffer = WriteMemory->GetHandle(); + } + + if (WriteOffsets != NULL) { + m_CompletionParams.Parameters.Write.Offset = + WriteOffsets->BufferOffset; + } + else { + m_CompletionParams.Parameters.Write.Offset = 0; + } +} + +VOID +FxRequestContext::FormatReadParams( + __in_opt IFxMemory* ReadMemory, + __in_opt PWDFMEMORY_OFFSET ReadOffsets + ) +{ + m_CompletionParams.Type = WdfRequestTypeRead; + + if (ReadMemory != NULL) { + m_CompletionParams.Parameters.Read.Buffer = ReadMemory->GetHandle(); + } + + if (ReadOffsets != NULL) { + m_CompletionParams.Parameters.Read.Offset = + ReadOffsets->BufferOffset; + } + else { + m_CompletionParams.Parameters.Read.Offset = 0; + } +} + +VOID +FxRequestContext::FormatOtherParams( + __in FxInternalIoctlParams *InternalIoctlParams + ) +{ + m_CompletionParams.Type = WdfRequestTypeOther; + m_CompletionParams.Parameters.Others.Argument1.Ptr = InternalIoctlParams->Argument1; + m_CompletionParams.Parameters.Others.Argument2.Ptr = InternalIoctlParams->Argument2; + m_CompletionParams.Parameters.Others.Argument4.Ptr = InternalIoctlParams->Argument4; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequestmemory.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequestmemory.cpp new file mode 100644 index 00000000000..22bc0fc2bc9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequestmemory.cpp @@ -0,0 +1,324 @@ + +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRequestMemory.hpp + +Abstract: + + This is the memory object for FxRequest that is sized, and + allows checking for read/write access. + + Its lifetime reference is tied with IRP completion in + FxRequest. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +// +// FxRequestMemory can be an embedded object inside of FxRequest, +// in which it represents the standard WDM IRP buffers. +// +// In addition, FxRequestMemory may be allocated by the device +// driver by probing and locking pages for dealing with direct +// and method_neither I/O types. +// +// In both cases, the lifetime of a WDFMEMORY handle returned from +// FxRequestMemory becomes invalid once FxRequest::Complete is called. +// +// Code exists to assist FxRequest in verifying there are no out +// standing references on the WDFMEMORY handles when a request is +// completed. +// +// Rundown and disposing of FxRequestMemory occur during FxRequest::Complete, +// and not when FxRequest is actually destroyed. This is because they represent +// system buffers and MDLs which must be released before the IRP inside +// the FxRequest is completed. Otherwise an I/O manager bugcheck will occur. +// + +NTSTATUS +FxRequestMemory::Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out FxRequestMemory** Object + ) + +/*++ + +Routine Description: + + Class Factory for FxRequestMemory + +--*/ + +{ + FxRequestMemory* pMemory; + + // Build an FxRequestMemory object now + pMemory = new(DriverGlobals, Attributes) FxRequestMemory(DriverGlobals); + + if (pMemory == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + *Object = pMemory; + + return STATUS_SUCCESS; +} + +FxRequestMemory::FxRequestMemory( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxMemoryBufferPreallocated(sizeof(*this), FxDriverGlobals) +/*++ + +Routine Description: + + Default constructor for this object. + + --*/ +{ + + // + // Our constructor chain: + // + // FxRequestMemory(ObjectSize, PFX_DRIVER_GLOBALS), + // : FxMemoryBufferPreallocated(ObjectSize, PFX_DRIVER_GLOBALS), + // : FxMemoryObject(PFX_DRIVER_GLOBALS, ObjectSize, ObjectSize), + // : FxObject(FX_TYPE_MEMORY, ObjectSize, PFX_DRIVER_GLOBALS) + // + m_Request = NULL; + + m_Mdl = NULL; + + m_Flags = 0; +} + + +FxRequestMemory::~FxRequestMemory( + VOID + ) +/*++ + +Routine Description: + Destructor for this object. Does nothing with the client memory since + the client owns it. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // + // Non-embedded case releases resources in the destructor + // rather than Dispose to ensure all outstanding device driver + // references are gone. + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if( m_Mdl != NULL ) { + Mx::MxUnlockPages(m_Mdl); + FxMdlFree(GetDriverGlobals(), m_Mdl); + m_Mdl = NULL; + } +#endif + + if( m_Request != NULL ) { + m_Request->ReleaseIrpReference(); + m_Request = NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxRequestMemory::QueryInterface( + __in FxQueryInterfaceParams* Params + ) +{ + if (Params->Type == FX_TYPE_REQUEST_MEMORY) { + *Params->Object = (FxRequestMemory*) this; + return STATUS_SUCCESS; + } + else { + return __super::QueryInterface(Params); + } +} + +PVOID +FxRequestMemory::GetBuffer( + VOID + ) +/*++ + +Routine Description: + GetBuffer overload. + + Returns pointer into buffer memory. + +Arguments: + None + +Return Value: + Client supplied buffer from the constructor + + --*/ +{ + return m_pBuffer; +} + +_Must_inspect_result_ +PMDL +FxRequestMemory::GetMdl( + VOID + ) +/*++ + +Routine Description: + GetMdl overload. Returns the embedded MDL + +Arguments: + None + +Return Value: + valid MDL or NULL + + --*/ +{ + return m_Mdl; +} + +VOID +FxRequestMemory::SetBuffer( + _In_ FxRequest* Request, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ PMDL BackingMdl, + _In_ size_t BufferSize, + _In_ BOOLEAN ReadOnly + ) +/*++ + +Routine Description: + Updates the internal pointer to a new value. + + +Arguments: + Request - new Request. + + Buffer - new buffer + + BackingMdl - associated MDL. + + BufferSize - length of Buffer in bytes + + ReadOnly - TRUE if read only buffer. + +Return Value: + None. + + --*/ + +{ + ASSERT(m_pBuffer == NULL); + ASSERT(m_Request == NULL); + ASSERT(m_Mdl == NULL); + + ASSERT(Request != NULL); + + m_pBuffer = Buffer; + m_Mdl = BackingMdl; + m_BufferSize = BufferSize; + + m_Request = Request; + + // + // A single FxRequest IRP reference + // is outstanding until destroy + // + m_Request->AddIrpReference(); + + // Set access checking if its a readonly buffer + if (ReadOnly) { + SetFlags(IFxMemoryFlagReadOnly); + } +} + +VOID +FxRequestMemory::SetMdl( + __in FxRequest* Request, + __in PMDL Mdl, + __in PVOID MdlBuffer, + __in size_t BufferSize, + __in BOOLEAN ReadOnly + ) +/*++ + +Routine Description: + + Sets an MDL on the WDFMEMORY object. + + It can't already have a buffer set. + + We are expected to free the MDL when Disposed. + + This is not used by embedded WDFMEMORY objects whose + MDL comes from the IRP. + +Arguments: + Request - new Request. + + Mdl - new MDL. + + MdlBuffer - associated buffer + + BufferSize - length of Buffer in bytes + + ReadOnly - TRUE if read only buffer. + +Return Value: + None. + + --*/ + +{ + + ASSERT(m_pBuffer == NULL); + ASSERT(m_Mdl == NULL); + ASSERT(m_Request == NULL); + ASSERT(Request != NULL); + + m_Mdl = Mdl; + m_pBuffer = MdlBuffer; + m_BufferSize = BufferSize; + + m_Request = Request; + + // + // A single FxRequest IRP reference is outstanding until destroy + // + m_Request->AddIrpReference(); + + // Set access checking if it's a readonly buffer + if (ReadOnly) { + SetFlags(IFxMemoryFlagReadOnly); + } + + return; +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequestoutputbuffer.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequestoutputbuffer.cpp new file mode 100644 index 00000000000..f1c59c28b47 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequestoutputbuffer.cpp @@ -0,0 +1,327 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestOutputBuffer.cpp + +Abstract: + + This module implements class representing the output buffer in an FxRequest + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestOutputBuffer.tmh" +} + +PVOID +FxRequestOutputBuffer::GetBuffer( + VOID + ) +/*++ + +Routine Description: + Returns the output buffer that has been cached away by the call to SetBuffer() + +Arguments: + None + +Return Value: + Valid memory or NULL on error + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || + irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); + + switch (irp->GetParameterIoctlCodeBufferMethod()) { + case METHOD_BUFFERED: + // + // For buffered ioctls, input and output buffer pointers are same. + // + return m_Buffer; + + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + // + // FxRequest::GetDeviceControlOutputMemoryObject has already called + // MmGetSystemAddressForMdlSafe and returned success, so we know that + // we can safely call MmGetSystemAddressForMdlSafe again to get a + // valid VA pointer. + // + return Mx::MxGetSystemAddressForMdlSafe(m_Mdl, NormalPagePriority); + + case METHOD_NEITHER: + return m_Buffer; + + default: + ASSERT(FALSE); + return NULL; + } +} + +size_t +FxRequestOutputBuffer::GetBufferSize( + VOID + ) +/*++ + +Routine Description: + Returns the size of the buffer returned by GetBuffer() + +Arguments: + None + +Return Value: + Buffer length or 0 on error + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || + irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); + + return irp->GetParameterIoctlOutputBufferLength(); +} + +_Must_inspect_result_ +PMDL +FxRequestOutputBuffer::GetMdl( + VOID + ) +/*++ + +Routine Description: + Returns the PMDL from the irp if one exists, otherwise NULL + +Arguments: + None + +Return Value: + a valid PMDL or NULL (not an error condition) + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || + irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); + + switch (irp->GetParameterIoctlCodeBufferMethod()) { + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + return m_Mdl; + + default: + return NULL; + } +} + +WDFMEMORY +FxRequestOutputBuffer::GetHandle( + VOID + ) +/*++ + +Routine Description: + Returns the handle that will represent this object to the driver writer. + +Arguments: + None + +Return Value: + Valid WDF handle + + --*/ +{ + return GetRequest()->GetMemoryHandle( + FIELD_OFFSET(FxRequest, m_OutputBufferOffset)); +} + +USHORT +FxRequestOutputBuffer::GetFlags( + VOID + ) +/*++ + +Routine Description: + Returns the flags associated with this buffer. This currently only includes + whether the buffer is read only or not + +Arguments: + None + +Return Value: + flags from IFxMemoryFlags + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + ASSERT(irp->GetMajorFunction() == IRP_MJ_DEVICE_CONTROL || + irp->GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL); + + switch (irp->GetParameterIoctlCodeBufferMethod()) { + case METHOD_IN_DIRECT: + return IFxMemoryFlagReadOnly; + + case METHOD_BUFFERED: + case METHOD_OUT_DIRECT: + case METHOD_NEITHER: // since it is neither, we can't tell, so leave it as 0 + default: + return 0; + } +} + +PFX_DRIVER_GLOBALS +FxRequestOutputBuffer::GetDriverGlobals( + VOID + ) +/*++ + +Routine Description: + Returns the driver globals + +Arguments: + none + +Return Value: + Driver globals pointer + + --*/ +{ + return GetRequest()->GetDriverGlobals(); +} + +ULONG +FxRequestOutputBuffer::AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +/*++ + +Routine Description: + Adds an irp reference to the owning FxRequest. This object does not maintain + its own reference count. A request cannot be completed with outstanding + irp references. + +Arguments: + Tag - the tag to use to track the reference + + Line - The line number of the caller + + File - the file name of the caller + +Return Value: + current reference count + + --*/ +{ + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(File); + + GetRequest()->AddIrpReference(); + + return 2; +} + +ULONG +FxRequestOutputBuffer::Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +/*++ + +Routine Description: + Removes an irp reference to the owning FxRequest. This object does not maintain + its own reference count. A request cannot be completed with outstanding + irp references. + +Arguments: + Tag - the tag to use to track the release + + Line - The line number of the caller + + File - the file name of the caller + +Return Value: + current reference count + + --*/ +{ + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(File); + + GetRequest()->ReleaseIrpReference(); + + return 1; +} + +FxRequest* +FxRequestOutputBuffer::GetRequest( + VOID + ) +/*++ + +Routine Description: + Return the owning FxRequest based on this object's address + +Arguments: + None + +Return Value: + owning FxRequest + + --*/ +{ + return CONTAINING_RECORD(this, FxRequest, m_OutputBuffer); +} + +VOID +FxRequestOutputBuffer::Delete( + VOID + ) +/*++ + +Routine Description: + Attempt to delete this interface. Since this is an embedded object, it + cannot be deleted. Since this function is only called internally, the + internal caller knows if the IFxMemory is deletable because the internal + caller allocated the IFxMemory to begin with. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // this function should never be called + ASSERT(FALSE); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxrequestsystembuffer.cpp b/sdk/lib/drivers/wdf/shared/core/fxrequestsystembuffer.cpp new file mode 100644 index 00000000000..801364cdb8f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxrequestsystembuffer.cpp @@ -0,0 +1,317 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestSystemBuffer.cpp + +Abstract: + + This module implements class representing the system buffer in an FxRequest + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestSystemBuffer.tmh" +} + +size_t +FxRequestSystemBuffer::GetBufferSize( + VOID + ) +/*++ + +Routine Description: + Returns the size of the buffer returned by GetBuffer() + +Arguments: + None + +Return Value: + Buffer length or 0 on error + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + switch (irp->GetMajorFunction()) { + case IRP_MJ_READ: + return irp->GetParameterReadLength(); + + case IRP_MJ_WRITE: + return irp->GetParameterWriteLength(); + + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + return irp->GetParameterIoctlInputBufferLength(); + + default: + // should not get here + ASSERT(FALSE); + return 0; + } +} + +_Must_inspect_result_ +PMDL +FxRequestSystemBuffer::GetMdl( + VOID + ) +/*++ + +Routine Description: + Returns the PMDL from the irp if one exists, otherwise NULL + +Arguments: + None + +Return Value: + a valid PMDL or NULL (not an error condition) + + --*/ +{ + FxDevice* pDevice; + FxIrp* irp = GetRequest()->GetFxIrp(); + + switch (irp->GetMajorFunction()) { + case IRP_MJ_READ: + case IRP_MJ_WRITE: + pDevice = FxDevice::GetFxDevice(irp->GetDeviceObject()); + + if (pDevice->GetIoType() == WdfDeviceIoDirect) { + return m_Mdl; + } + // || || Fall through || || + // \/ \/ \/ \/ + + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + // + // For IOCLs, the outbuffer will return the PMDL + // + // || || Fall through || || + // \/ \/ \/ \/ + + default: + return NULL; + } +} + +WDFMEMORY +FxRequestSystemBuffer::GetHandle( + VOID + ) +/*++ + +Routine Description: + Returns the handle that will represent this object to the driver writer. + +Arguments: + None + +Return Value: + Valid WDF handle + + --*/ +{ + return GetRequest()->GetMemoryHandle( + FIELD_OFFSET(FxRequest, m_SystemBufferOffset)); +} + +USHORT +FxRequestSystemBuffer::GetFlags( + VOID + ) +/*++ + +Routine Description: + Returns the flags associated with this buffer. This currently only includes + whether the buffer is read only or not + +Arguments: + None + +Return Value: + flags from IFxMemoryFlags + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + switch (irp->GetMajorFunction()) { + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + switch (irp->GetParameterIoctlCodeBufferMethod()) { + case METHOD_BUFFERED: + case METHOD_NEITHER: + return 0; + + case METHOD_IN_DIRECT: + case METHOD_OUT_DIRECT: + return IFxMemoryFlagReadOnly; + } + + case IRP_MJ_READ: + return 0; + + case IRP_MJ_WRITE: + return IFxMemoryFlagReadOnly; + + default: + ASSERT(FALSE); + return 0; + } +} + +PFX_DRIVER_GLOBALS +FxRequestSystemBuffer::GetDriverGlobals( + VOID + ) +/*++ + +Routine Description: + Returns the driver globals + +Arguments: + none + +Return Value: + Driver globals pointer + + --*/ +{ + return GetRequest()->GetDriverGlobals(); +} + +ULONG +FxRequestSystemBuffer::AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +/*++ + +Routine Description: + Adds an irp reference to the owning FxRequest. This object does not maintain + its own reference count. A request cannot be completed with outstanding + irp references. + +Arguments: + Tag - the tag to use to track the reference + + Line - The line number of the caller + + File - the file name of the caller + +Return Value: + current reference count + + --*/ +{ + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(File); + + GetRequest()->AddIrpReference(); + + // + // This value should never be used by the caller + // + return 2; +} + +ULONG +FxRequestSystemBuffer::Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) +/*++ + +Routine Description: + Removes an irp reference to the owning FxRequest. This object does not maintain + its own reference count. A request cannot be completed with outstanding + irp references. + +Arguments: + Tag - the tag to use to track the release + + Line - The line number of the caller + + File - the file name of the caller + +Return Value: + current reference count + + --*/ +{ + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(File); + + GetRequest()->ReleaseIrpReference(); + + return 1; +} + +FxRequest* +FxRequestSystemBuffer::GetRequest( + VOID + ) +/*++ + +Routine Description: + Return the owning FxRequest based on this object's address + +Arguments: + None + +Return Value: + owning FxRequest + + --*/ +{ + return CONTAINING_RECORD(this, FxRequest, m_SystemBuffer); +} + +VOID +FxRequestSystemBuffer::Delete( + VOID + ) +/*++ + +Routine Description: + Attempt to delete this interface. Since this is an embedded object, it + cannot be deleted. Since this function is only called internally, the + internal caller knows if the IFxMemory is deletable because the internal + caller allocated the IFxMemory to begin with. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // this function should never be called + ASSERT(FALSE); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxsyncrequest.cpp b/sdk/lib/drivers/wdf/shared/core/fxsyncrequest.cpp new file mode 100644 index 00000000000..b92ae4524e3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxsyncrequest.cpp @@ -0,0 +1,191 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSyncRequest.cpp + +Abstract: + + This module implements FxSyncRequest object + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxSyncRequest.tmh" +} + +FxSyncRequest::FxSyncRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt FxRequestContext* Context, + __in_opt WDFREQUEST Request + ) : + FxRequestBase(FxDriverGlobals, + 0, // no handle for this object + NULL, // No PIRP + FxRequestDoesNotOwnIrp, + FxRequestConstructorCallerIsFx, + FxObjectTypeEmbedded) +/*++ + +Routine Description: + Constructs an FxSyncRequest + +Arguments: + Context - Context to associate with this object + + Request - (opt) real Request object. + +Return Value: + None. + + --*/ +{ + // + // If m_CleanContextOnDestroy is TRUE, m_RequestContext is cleared in the + // destructor so that the base class destructor does not free the context. + // This is useful if the context is also stack based. + // + if (Context != NULL) { + m_ClearContextOnDestroy = TRUE; + } + + else { + m_ClearContextOnDestroy = FALSE; + } + + m_RequestContext = Context; + + if (Request == NULL) { + m_TrueRequest = this; + m_RequestBaseFlags |= FxRequestBaseSyncCleanupContext; + } + else { + FxRequest* pRequest; + + FxObjectHandleGetPtr(FxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + m_TrueRequest = pRequest; + + // + // pRequest could be currently formatted and the caller has not reused the request + // in between the format and the sync. send. This will place pRequest into the + // correct state. + // + if (pRequest->m_RequestContext != NULL) { + pRequest->m_RequestContext->ReleaseAndRestore(pRequest); + } + pRequest->SetContext(Context); + pRequest->m_RequestBaseFlags |= FxRequestBaseSyncCleanupContext; + } + + // + // Indicate that there is no object header so when FxObject::Release is + // called on the final ref count removal, it doesn't try to touch hyperspace. + // + SetNoContextHeader(); +} + +FxSyncRequest::~FxSyncRequest( + VOID + ) +/*++ + +Routine Description: + Destroys an FxSyncRequest. Releases the initial reference taken during the + creation of this object. If there are any outstanding references to the + object, the destructor will not exit they are released. + +Arguments: + None. + +Return Value: + None. + + --*/ +{ + ULONG count; + + // + // Release the initial reference taken on create. Use the base release call + // so that we don't unnecessarily set the event unless we have to. + // + count = __super::RELEASE(NULL); + + // + // For a driver supplied request(m_TrueRequest) the request context is + // allocated on the stack so clear it. + // + if (m_TrueRequest != this && m_ClearContextOnDestroy) { + m_TrueRequest->m_RequestContext = NULL; + m_TrueRequest->m_RequestBaseFlags &= ~FxRequestBaseSyncCleanupContext; + } + + // + // Clear the context so that it is not automatically deleted. Useful + // if the caller's context is also allocated on the stack and does not + // need to be freed (as does not have to rememeber to clear the context + // before this object goes out of scope). + // + if (m_ClearContextOnDestroy) { + m_RequestContext = NULL; + } + + if (count > 0) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p, waiting on event %p", + this, m_DestroyedEvent.GetEvent()); + + m_DestroyedEvent.EnterCRAndWaitAndLeave(); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Request %p, wait on event %p done", + this, m_DestroyedEvent.GetEvent()); + } +} + +VOID +FxSyncRequest::SelfDestruct( + VOID + ) +/*++ + +Routine Description: + Override of base class SelfDestruct. Since this is a stack based object, + we must delay the stack caused destruction until all outstanding references + have been released. SelfDestruct is called when the last reference has been + removed from the object. + + Since this is a stack based object, do nothing to free our memory (going out + of scope will do the trick). + +Arguments: + None. + +Return Value: + None. + + --*/ +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "SyncRequest %p, signaling event %p on SelfDestruct", + this, m_DestroyedEvent.GetEvent()); + + m_DestroyedEvent.Set(); +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxsystemworkitem.cpp b/sdk/lib/drivers/wdf/shared/core/fxsystemworkitem.cpp new file mode 100644 index 00000000000..14f673a8392 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxsystemworkitem.cpp @@ -0,0 +1,379 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSystemWorkItem.hpp + +Abstract: + + This module implements a frameworks managed WORKITEM that + can synchrononize with driver frameworks object locks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxSystemWorkItem.hpp" + +// Tracing support +extern "C" { +#include "FxSystemWorkItem.tmh" +} + +// +// Public constructors +// +_Must_inspect_result_ +NTSTATUS +FxSystemWorkItem::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID WdmObject, + __out FxSystemWorkItem** pObject + ) +{ + NTSTATUS status; + FxSystemWorkItem* wi; + + wi = new(FxDriverGlobals) FxSystemWorkItem(FxDriverGlobals); + if (wi == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = wi->Initialize(WdmObject); + if (!NT_SUCCESS(status)) { + wi->Release(); + return status; + } + + *pObject = wi; + + return status; +} + +FxSystemWorkItem::FxSystemWorkItem( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_SYSTEMWORKITEM, 0, FxDriverGlobals), + m_WorkItemCompleted(NotificationEvent, TRUE), + m_RemoveEvent(SynchronizationEvent, FALSE) +{ + m_RunningDown = FALSE; + m_Enqueued = FALSE; + m_Callback = NULL; + m_CallbackArg = NULL; + m_WorkItemRunningCount = 0; + m_OutStandingWorkItem = 1; +} + +FxSystemWorkItem::~FxSystemWorkItem() +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + // + // If this hits, it's because someone destroyed the WORKITEM by + // removing too many references by mistake without calling WdfObjectDelete + // + if( !m_RunningDown && (m_WorkItem.GetWorkItem() != NULL)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WorkItem destroyed without calling " + "FxSystemWorkItem::Delete, or by Framework " + "processing DeviceRemove. " + "Possible reference count problem?"); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + + // Free the workitem + if( m_WorkItem.GetWorkItem() != NULL ) { + m_WorkItem.Free(); + } + + ASSERT(m_Enqueued == FALSE); + ASSERT(m_WorkItemRunningCount == 0L); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxSystemWorkItem::Initialize( + __in PVOID WdmObject + ) +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + NTSTATUS status; + + // + // Mark this object as passive level to ensure that Dispose() is passive + // + MarkPassiveCallbacks(ObjectDoNotLock); + + MarkDisposeOverride(ObjectDoNotLock); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + status = m_WorkItemCompleted.Initialize(NotificationEvent, TRUE); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not initialize m_WorkItemCompleted event " + "status %!status!", status); + return status; + } + + status = m_RemoveEvent.Initialize(SynchronizationEvent, FALSE); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not initialize m_RemoveEvent event " + "status %!status!", status); + return status; + } +#endif + + // + // Allocate the PIO_WORKITEM we will re-use + // + status = m_WorkItem.Allocate((MdDeviceObject) WdmObject); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not allocate IoWorkItem, insufficient resources"); + return status; + } + + ASSERT(m_WorkItem.GetWorkItem() != NULL); + + return STATUS_SUCCESS; +} + +BOOLEAN +FxSystemWorkItem::EnqueueWorker( + __in PFN_WDF_SYSTEMWORKITEM Func, + __in PVOID Parameter, + __in BOOLEAN AssertIfAlreadyQueued + ) +/*++ + +Routine Description: + + Called to queue the workitem. This function, under verifier, will + throw an assert if AssertIfAlreadyQueued parameter is set. + +Arguments: + Func - Callback function. + + Parameter - Callback's context. + + AssertIfAlreadyQueued - is used to make sure that caller doesn't + miss any workitem callback. + +Return Value: + + FALSE + - if the previously queued workitem hasn't run to completion. + - if the object is running down. + + TRUE - workitem is queued. +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + KIRQL irql; + + pFxDriverGlobals = GetDriverGlobals(); + + Lock(&irql); + + if( m_Enqueued ) { + if (AssertIfAlreadyQueued) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WorkItem 0x%p already enqueued IoWorkItem 0x%p", + this, m_WorkItem.GetWorkItem()); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + + Unlock(irql); + return FALSE; + } + + // + // If running down, fail + // + if( m_RunningDown ) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WorkItem 0x%p is already deleted", this); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + Unlock(irql); + return FALSE; + } + + m_WorkItemCompleted.Clear(); + + m_Callback = Func; + m_CallbackArg = Parameter; + + m_Enqueued = TRUE; + + // Add a reference while outstanding + IncrementWorkItemQueued(); + + Unlock(irql); + + m_WorkItem.Enqueue(_WorkItemThunk, this); + + return TRUE; +} + +VOID +FxSystemWorkItem::WorkItemHandler() +{ + PFN_WDF_SYSTEMWORKITEM Callback; + PVOID CallbackArg; + KIRQL irql; + + FX_TRACK_DRIVER(GetDriverGlobals()); + + Lock(&irql); + + m_Enqueued = FALSE; + + Callback = m_Callback; + CallbackArg = m_CallbackArg; + + m_Callback = NULL; + + // + // We should only see this count rise to a small number (like 10 or so). + // + ASSERT(m_WorkItemRunningCount < 0xFF); + + m_WorkItemRunningCount++; + + Unlock(irql); + + Callback(CallbackArg); + + Lock(&irql); + + m_WorkItemRunningCount--; + + // + // The driver could re-enqueue a new callback from within the + // callback handler, which could make m_Enqueued no longer false. + // + // We only set the event specifying the callback as completed when + // we are ensured that no more workitems are enqueued. + // + if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) { + m_WorkItemCompleted.Set(); + } + + Unlock(irql); + + return; +} + +VOID +FxSystemWorkItem::_WorkItemThunk( + __in MdDeviceObject DeviceObject, + __in_opt PVOID Context + ) + +/*++ + +Routine Description: + + This is the static routine called by the kernel's PIO_WORKITEM handler. + + A reference count was taken by Enqueue, which this routine releases + on return. + +Arguments: + +Return Value: + + Nothing. + +--*/ + +{ + FxSystemWorkItem* pWorkItem = (FxSystemWorkItem*)Context; + + UNREFERENCED_PARAMETER(DeviceObject); + + pWorkItem->WorkItemHandler(); + + // Release the reference taken when enqueued + pWorkItem->DecrementWorkItemQueued(); + + return; +} + +// +// Invoked when DeleteObject is called on the object, or its parent. +// +BOOLEAN +FxSystemWorkItem::Dispose( + ) +{ + KIRQL irql; + + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + Lock(&irql); + + ASSERT(!m_RunningDown); + + m_RunningDown = TRUE; + + Unlock(irql); + + ReleaseWorkItemQueuedCountAndWait(); + + return TRUE; +} + +// +// Wait until any outstanding WorkItem has completed safely +// +// Can only be called after Delete +// +// The caller must call AddRef() and Release() around this call +// to ensure the FxSystemWorkItem remains valid while it is doing the +// wait. +// +VOID +FxSystemWorkItem::WaitForExit( + ) +{ + NTSTATUS Status; + + // + // Wait for current workitem to complete processing + // + Status = m_WorkItemCompleted.EnterCRAndWaitAndLeave(); + + ASSERT(NT_SUCCESS(Status)); + UNREFERENCED_PARAMETER(Status); + + // + // This assert is not under a lock, but the code in WorkItemHandler() + // clears m_Enqueued under the lock, thus releasing it with a memory + // barrier. Since we have ensured above that no one can re-queue a request + // due to m_RunningDown, we should not hit this assert unless there + // is a code problem with wakeup occuring while an outstanding + // workitem is running. + // + ASSERT(m_Enqueued == FALSE); + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/fxtimer.cpp b/sdk/lib/drivers/wdf/shared/core/fxtimer.cpp new file mode 100644 index 00000000000..7193f6c409a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxtimer.cpp @@ -0,0 +1,779 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTimer.hpp + +Abstract: + + This module implements a frameworks managed TIMER that + can synchrononize with driver frameworks object locks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxTimer.hpp" + +// Tracing support +extern "C" { +#include "FxTimer.tmh" +} + +// +// Public constructors +// + +FxTimer::FxTimer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_TIMER, sizeof(FxTimer), FxDriverGlobals) +{ + m_Object = NULL; + m_Period = 0; + m_TolerableDelay = 0; + m_CallbackLock = NULL; + m_CallbackLockObject = NULL; + m_Callback = NULL; + m_RunningDown = FALSE; + m_SystemWorkItem = NULL; + m_CallbackThread = NULL; + m_StopThread = NULL; + m_StopAgain = FALSE; + m_StartAborted = FALSE; + + // + // Mark the object has having passive level dispose so that KeFlushQueuedDpcs + // can be called in Dispose(). + // + MarkPassiveDispose(ObjectDoNotLock); + + MarkDisposeOverride(ObjectDoNotLock); +} + +FxTimer::~FxTimer() +{ + // + // If this hits, its because someone destroyed the TIMER by + // removing too many references by mistake without calling WdfObjectDelete + // + if (m_Object != NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFTIMER %p destroyed without calling WdfObjectDelete, " + "or by Framework processing DeviceRemove. Possible reference count " + "problem?", GetObjectHandleUnchecked()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + ASSERT(m_SystemWorkItem == NULL); +} + +_Must_inspect_result_ +NTSTATUS +FxTimer::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_TIMER_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObject* ParentObject, + __out WDFTIMER* Timer + ) +{ + FxTimer* pFxTimer; + NTSTATUS status; + + pFxTimer = new(FxDriverGlobals, Attributes) FxTimer(FxDriverGlobals); + + if (pFxTimer == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pFxTimer->Initialize( + Attributes, + Config, + ParentObject, + Timer + ); + + if (!NT_SUCCESS(status)) { + pFxTimer->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxTimer::Initialize( + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_TIMER_CONFIG Config, + __in FxObject* ParentObject, + __out WDFTIMER* Timer + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxHasCallbacks* pCallbacks; + NTSTATUS status; + BOOLEAN isPassiveTimer; + + pFxDriverGlobals = GetDriverGlobals(); + pCallbacks = NULL; + isPassiveTimer = FALSE; + + m_Period = Config->Period; + + // Set tolerable delay. + if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_7)) { + m_TolerableDelay = Config->TolerableDelay; + } + + if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_11)) { + m_UseHighResolutionTimer = Config->UseHighResolutionTimer; + } + + // Set users callback function + m_Callback = Config->EvtTimerFunc; + + // + // Decide whether to use the legacy KTimer or the new Ktimer2/ExTimer + // and call the appropriate initialization routine. + // The new ExTimers expose two kind of timers:no wake timers and the + // high resolution timers. For kernel mode, these timers are only exposed + // to new clients. + // For user mode,the underlying Threadpool APIs internally were upgraded + // to using the no wake timers and we don't expose the High + // resolution timers. Therefore the user mode code does not need to use + // the ex initialization. + // + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13)) { + status = m_Timer.InitializeEx(this, FxTimer::_FxTimerExtCallbackThunk, m_Period, + m_TolerableDelay, m_UseHighResolutionTimer); + } else { + status = m_Timer.Initialize(this, FxTimer::_FxTimerDpcThunk, m_Period); + } +#else + status = m_Timer.Initialize(this, FxTimer::_FxTimerDpcThunk, m_Period); +#endif + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Failed to initialize timer %!STATUS!", status); + return status; + } + + // + // As long as we are associated, the parent object holds a reference + // count on the TIMER. + // + // We keep an extra reference count since on Dispose, we wait until + // all outstanding DPCs complete before allowing finalization. + // + // This reference must be taken early before we return any failure, + // since Dispose() expects this extra reference, and Dispose() will + // be called even if we return a failure status right now. + // + ADDREF(this); + + m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks); + if (m_DeviceBase == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (Attributes->ExecutionLevel == WdfExecutionLevelPassive) { + isPassiveTimer = TRUE; + } + + // + // Configure Serialization for the callbacks on the supplied object. + // + status = _GetEffectiveLock( + ParentObject, + pCallbacks, + Config->AutomaticSerialization, + isPassiveTimer, + &m_CallbackLock, + &m_CallbackLockObject + ); + + if (!NT_SUCCESS(status)) { + if (status == STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL) { + + + + + + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "ParentObject %p cannot automatically synchronize callbacks " + "with a Timer since it is configured for passive level callback " + "constraints. Set AutomaticSerialization to FALSE. %!STATUS!", + Attributes->ParentObject, status); + } + + return status; + } + + // + // If the caller wants passive callback then create a workitem. + // + if (isPassiveTimer) { + status = FxSystemWorkItem::_Create(pFxDriverGlobals, + m_Device->GetDeviceObject(), + &m_SystemWorkItem + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not allocate workitem: %!STATUS!", status); + return status; + } + } + + // + // We automatically synchronize with and reference count + // the lifetime of the framework object to prevent any TIMER races + // that can access the object while it is going away. + // + + // + // The caller supplied object is the object the caller wants the + // TIMER to be associated with, and the framework must ensure this + // object remains live until the TIMER object is destroyed. Otherwise, + // it could access either object context memory, or an object API + // on a freed object. + // + // Due to the locking model of the framework, the lock may actually + // be owned by a higher level object as well. This is the lockObject + // returned. As long was we are a child of this object, the lockObject + // does not need to be dereferenced since it will notify us of Cleanup + // before it goes away. + // + + // + // Associate the FxTimer with the object. When this object Cleans up, it + // will notify our Dispose function as well. + // + + // + // Add a reference to the parent object we are associated with. + // We will be notified of Cleanup to release this reference. + // + ParentObject->ADDREF(this); + + // + // Save the ptr to the object the TIMER is associated with + // + m_Object = ParentObject; + + // + // Attributes->ParentObject is the same as ParentObject. Since we already + // converted it to an object, use that. + // + status = Commit(Attributes, (WDFOBJECT*)Timer, ParentObject); + + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +VOID +FxTimer::TimerHandler( + VOID + ) +{ + FX_TRACK_DRIVER(GetDriverGlobals()); + + if (m_Callback != NULL) { + + // + // Save the current thread object pointer. We will use this avoid + // deadlock if the driver tries to delete or stop the timer from within + // the callback. + // + m_CallbackThread = Mx::MxGetCurrentThread(); + + if (m_CallbackLock != NULL) { + KIRQL irql = 0; + + m_CallbackLock->Lock(&irql); + m_Callback(GetHandle()); + m_CallbackLock->Unlock(irql); + } + else { + m_Callback(GetHandle()); + } + + m_CallbackThread = NULL; + } +} + +VOID +FxTimer::_FxTimerDpcThunk( + __in PKDPC TimerDpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ) +/*++ + +Routine Description: + + This is the C routine called by the kernel's TIMER DPC handler + +Arguments: + + TimerDpc - our DPC object associated with our Timer + DeferredContext - Context for the TIMER that we setup in DriverEntry + SystemArgument1 - + SystemArgument2 - + +Return Value: + + Nothing. + +--*/ + +{ + FxTimer* pTimer = (FxTimer*)DeferredContext; + + UNREFERENCED_PARAMETER(TimerDpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + if (pTimer->m_SystemWorkItem == NULL) { + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + FxPerfTraceDpc(&pTimer->m_Callback); +#endif + + // + // Dispatch-level timer callback + // + pTimer->TimerHandler(); + } + else { + // + // Passive timer callback.Queue only if the previous one is completed. + // + pTimer->m_SystemWorkItem->TryToEnqueue(_FxTimerWorkItemCallback, pTimer); + } + + return; +} + +VOID +FxTimer::_FxTimerExtCallbackThunk( + __in PEX_TIMER Timer, + __in PVOID Context + ) +/*++ + +Routine Description: + + This is the C routine called by the kernel's ex timer + +Arguments: + + Timer - Ex timer + Context - Context for the TIMER that we passed while creating it + +Return Value: + + Nothing. + +--*/ + +{ + FxTimer* pTimer = (FxTimer*)Context; + + UNREFERENCED_PARAMETER(Timer); + + if (pTimer->m_SystemWorkItem == NULL) { + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + FxPerfTraceDpc(&pTimer->m_Callback); +#endif + + // + // Dispatch-level timer callback + // + pTimer->TimerHandler(); + } + else { + // + // Passive timer callback.Queue only if the previous one is completed. + // + pTimer->m_SystemWorkItem->TryToEnqueue(_FxTimerWorkItemCallback, pTimer); + } + + return; +} + +VOID +FxTimer::_FxTimerWorkItemCallback( + __in PVOID Parameter + ) +/*++ + +Routine Description: + Thunk used when callback must be made at passive-level + +--*/ +{ + FxTimer* pTimer = (FxTimer*)Parameter; + + pTimer->TimerHandler(); + + return; +} + +// +// Called when DeleteObject is called, or when the parent +// is being deleted or Disposed. +// +// Also invoked directly by the cleanup list at our request after +// a Dispose occurs and must be deferred if not at passive level. +// +BOOLEAN +FxTimer::Dispose() +{ + KIRQL irql; + + // MarkPassiveDispose() in Initialize ensures this + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + // + // Signal that we are running down. + // + Lock(&irql); + m_RunningDown = TRUE; + Unlock(irql); + + // + // Cancel the timer, wait for its callback, then cleanup. + // + FlushAndRundown(); + + return TRUE; +} + +VOID +FxTimer::FlushAndRundown( + VOID + ) +/*++ + +Routine Description: + Called by the system work item to finish the rundown. + +Arguments: + None + +Return Value: + None + + --*/ +{ + FxObject* pObject; + + if (m_CallbackThread == Mx::MxGetCurrentThread()) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Deleting WDFTIMER %p from with in the callback will " + "lead to deadlock, PRKTHREAD %p", + GetHandle(), m_CallbackThread); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + // + // Cancel the timer, wait for its callback. + // + Stop(TRUE); + + // + // Delete will also wait for the workitem to exit. + // + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->DeleteObject(); + m_SystemWorkItem = NULL; + } + + // + // Release our reference count to the associated parent object if present + // + if (m_Object != NULL) { + pObject = m_Object; + m_Object = NULL; + + pObject->RELEASE(this); + } + + // + // Perform our final release to ourselves, destroying the FxTimer + // + RELEASE(this); +} + +BOOLEAN +FxTimer::Start( + __in LARGE_INTEGER DueTime + ) + +/*++ + +Routine Description: + + Start or restart the timer + +Arguments: + + DueTime - Time when the timer will be scheduled + +Returns: + + TRUE if a previous timer was reset to the new duetime. + FALSE otherwise. + +--*/ + +{ + KIRQL irql; + BOOLEAN result = FALSE; + BOOLEAN startTimer = FALSE; + + Lock(&irql); + + // + // Basic check to make sure timer object is not deleted. Note that this + // logic is not foolproof b/c someone may dispose the timer just after this + // validation and before the start routine queues the timer; but at least it + // is better than nothing. + // + if (m_RunningDown) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Calling WdfTimerStart when the timer object %p is" + " running down will lead to a crash", + GetHandle()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + else if (m_StopThread != NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFTIMER 0x%p is been stopped by PRKTHREAD 0x%p. " + "Ignoring the request to start timer", + GetHandle(), m_StopThread); + + // + // Let the stop thread know that we aborted this start operation. + // + m_StartAborted = TRUE; + } + else { + // + // Yes, the timer can be started. + // + startTimer = TRUE; + } + + Unlock(irql); + + if (startTimer) { + // + // It may be possible for the timer to fire before the call from + // KeSetTimerEx completes. If this happens and if the timer callback + // disposes the timer object, a dispose work-item is queued. + // This work-item in turn may also run before KeSetTimerEx completes, + // making the object invalid by the time we try to take its Lock() + // below. This ADDREF() prevents the object from going away and it is + // matched by a RELEASE() when we are done. + // + ADDREF(this); + + // + // Call the tolerable timer API only if OS supports it and driver + // requested it. + // + result = m_Timer.StartWithReturn(DueTime, m_TolerableDelay); + + Lock(&irql); + if (m_StopThread != NULL) { + m_StopAgain = TRUE; + } + Unlock(irql); + + // + // See ADDREF() comment above. + // + RELEASE(this); + } + + return result; +} + +BOOLEAN +FxTimer::Stop( + __in BOOLEAN Wait + ) +{ + KIRQL irql; + BOOLEAN result; +#ifdef DBG + ULONG retryCount = 0; +#endif + + if (Wait) { + // + // If the caller specified wait, we will flush the queued DPC's + // to ensure any outstanding timer DPC has finished executing. + // + // The return value of timers is ambiguous in the case of periodic + // timers, so we flush whenever the caller desires to ensure all + // callbacks are complete. + // + + // + // Make sure the stop is not called from within the callback + // because it's semantically incorrect and can lead to deadlock + // if the wait parameter is set. + // + if (m_CallbackThread == Mx::MxGetCurrentThread()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Calling WdfTimerStop from within the WDFTIMER " + "%p callback will lead to deadlock, PRKTHREAD %p", + GetHandle(), m_CallbackThread); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return FALSE; + } + + if (GetDriverGlobals()->FxVerifierOn) { + if (Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WdfTimerStop(Wait==TRUE) called at IRQL > PASSIVE_LEVEL, " + "current IRQL = 0x%x", Mx::MxGetCurrentIrql()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return FALSE; + } + } + + // + // Prevent the callback from restarting the timer. + // + Lock(&irql); + + // + // Driver issue. + // + if (GetDriverGlobals()->IsVerificationEnabled(1, 9, OkForDownLevel) && + m_StopThread != NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Detected multiple calls to WdfTimerStop for " + "WDFTIMER 0x%p, stop in progress on PRKTHREAD 0x%p, " + "current PRKTHREAD 0x%p", + GetHandle(), m_StopThread, Mx::MxGetCurrentThread()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + // + // Reset the flag to find out if the timer's start logic aborts + // b/c of this stop operation. + // + m_StartAborted = FALSE; + + // + // This field is used for the following purposes: + // (a) Let the start thread know not to restart the timer while stop + // is running. + // (b) Detect concurrent calls to stop the timer. + // (c) To remember the thread id of the stopping thread. + // + m_StopThread = Mx::MxGetCurrentThread(); + + do { +#ifdef DBG + retryCount++; +#endif + // + // Reset flag to catch when timer callback is restarting the + // timer. + // + m_StopAgain = FALSE; + Unlock(irql); + + // + // Cancel the timer + // + result = m_Timer.Stop(); + + // + // Wait for the timer's DPC. + // + m_Timer.FlushQueuedDpcs(); + + // + // Wait for the timer's passive work item. + // + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->WaitForExit(); + } + + Lock(&irql); +#ifdef DBG + // + // This loop is run for a max of 2 times. + // + ASSERT(retryCount < 3); +#endif + // + // Re-stop timer if timer was not in queue and + // it got restarted in callback. + // + }while (result == FALSE && m_StopAgain); + + // + // Stop completed. + // + m_StopThread = NULL; + m_StopAgain = FALSE; + + // + // Return TRUE (i.e., timer in queue) if + // (a) stop logic successfully cancelled the timer or + // (b) the start logic aborted b/c of this stop. + // + if (m_StartAborted) { + result = TRUE; + m_StartAborted = FALSE; + } + + Unlock(irql); + } + else { + // + // Caller doesn't want any synchronization. + // Cancel the timer. + // + result = m_Timer.Stop(); + } + + return result; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxtimerapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxtimerapi.cpp new file mode 100644 index 00000000000..3c4a44dacf3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxtimerapi.cpp @@ -0,0 +1,335 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTimerApi.cpp + +Abstract: + + This implements the WDFTIMER API's + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxTimer.hpp" + +extern "C" { +#include "FxTimerApi.tmh" +} + +// +// extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfTimerCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDF_TIMER_CONFIG Config, + __in + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFTIMER * Timer + ) + +/*++ + +Routine Description: + + Create a TIMER object that will call the supplied function + when it fires. It returns a handle to the WDFTIMER object. + +Arguments: + + Config - WDF_TIMER_CONFIG structure. + + Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object, to request + a context memory allocation and a DestroyCallback. + + Timer - Pointer to location to return the resulting WDFTIMER handle. + +Returns: + + STATUS_SUCCESS - A WDFTIMER handle has been created. + +Notes: + + The WDFTIMER object is deleted either when the DEVICE or QUEUE it is + associated with is deleted, or WdfObjectDelete is called. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxObject* pParent; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_REQUIRED); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Config); + FxPointerNotNull(pFxDriverGlobals, Timer); + + if (Config->Size != sizeof(WDF_TIMER_CONFIG) && + Config->Size != sizeof(WDF_TIMER_CONFIG_V1_7) && + Config->Size != sizeof(WDF_TIMER_CONFIG_V1_11)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PWDF_TIMER_CONFIG Size %d, expected %d, %!STATUS!", + Config->Size, sizeof(WDF_TIMER_CONFIG), status); + + return status; + } + + if (Config->Period > MAXLONG) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Period value %u for a periodic timer cannot be greater than " + "MAXLONG, %!STATUS!", Config->Period, status); + + return status; + } + + // + // For version 1.13 and higher, the tolerable delay could + // go upto MAXULONG + // + if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_7) && + (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) == FALSE)) { + if (Config->TolerableDelay > MAXLONG) { + + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "TolerableDelay value %u cannot be greater than MAXLONG, " + "%!STATUS!", Config->TolerableDelay, status); + + return status; + } + } + + if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_11)) { + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + if (Config->UseHighResolutionTimer) { + + status = STATUS_NOT_IMPLEMENTED; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "UseHighResolutionTimer option is not supported for UMDF " + "%!STATUS!", status); + return status; + } +#endif + + if ((Config->TolerableDelay > 0) && + (Config->UseHighResolutionTimer)) { + + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "UseHighResolutionTimer option sepcified with non zero tolerable delay %u " + "%!STATUS!", Config->TolerableDelay, status); + + return status; + } + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Config->Period > 0 && + Attributes->ExecutionLevel == WdfExecutionLevelPassive) { + status = STATUS_NOT_SUPPORTED; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Passive level periodic timer is not supported. " + "Use one shot timer and queue the next timer from the callback " + "or use a dedicated thread, %!STATUS!", + status); + + return status; + } + + return FxTimer::_Create(pFxDriverGlobals, Config, Attributes, pParent, Timer); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfTimerStart)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFTIMER Timer, + __in + LONGLONG DueTime + ) + +/*++ + +Routine Description: + + Enqueue the TIMER to run at the specified time. + +Arguments: + + WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate. + + DueTime - Time to execute + +Returns: + + TRUE if the timer object was in the system's timer queue + +--*/ + +{ + DDI_ENTRY(); + + FxTimer* pFxTimer; + LARGE_INTEGER li; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Timer, + FX_TYPE_TIMER, + (PVOID*)&pFxTimer); + + li.QuadPart = DueTime; + + return pFxTimer->Start(li); +} + +__drv_when(Wait == __true, __drv_maxIRQL(PASSIVE_LEVEL)) +__drv_when(Wait == __false, __drv_maxIRQL(DISPATCH_LEVEL)) +BOOLEAN +WDFEXPORT(WdfTimerStop)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFTIMER Timer, + __in + BOOLEAN Wait + ) + +/*++ + +Routine Description: + + Stop the TIMER + +Arguments: + + WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate. + +Returns: + + TRUE if the timer object was in the system's timer queue + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxTimer* pFxTimer; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Timer, + FX_TYPE_TIMER, + (PVOID*)&pFxTimer, + &pFxDriverGlobals); + + if (Wait) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return FALSE; + } + } + + return pFxTimer->Stop(Wait); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFOBJECT +WDFEXPORT(WdfTimerGetParentObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFTIMER Timer + ) + +/*++ + +Routine Description: + + Return the Parent Object handle supplied to WdfTimerCreate + +Arguments: + + WDFTIMER - Handle to WDFTIMER object created with WdfTimerCreate. + +Returns: + + Handle to the framework object that is the specified timer object's + parent object + +--*/ + +{ + DDI_ENTRY(); + + FxTimer* pFxTimer; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Timer, + FX_TYPE_TIMER, + (PVOID*)&pFxTimer); + + return pFxTimer->GetObject(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/fxworkitem.cpp b/sdk/lib/drivers/wdf/shared/core/fxworkitem.cpp new file mode 100644 index 00000000000..2d3fbb55599 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxworkitem.cpp @@ -0,0 +1,561 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWorkItem.hpp + +Abstract: + + This module implements a frameworks managed WORKITEM that + can synchrononize with driver frameworks object locks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxWorkItem.hpp" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +// +// For DRIVER_OBJECT_UM definition +// +#include "fxldrum.h" +#endif + +// Tracing support +extern "C" { +#include "FxWorkItem.tmh" +} + +FxWorkItem::FxWorkItem( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_WORKITEM, sizeof(FxWorkItem), FxDriverGlobals), + m_WorkItemCompleted(NotificationEvent, TRUE) +{ + m_Object = NULL; + m_Callback = NULL; + m_CallbackLock = NULL; + m_CallbackLockObject = NULL; + m_RunningDown = FALSE; + m_Enqueued = FALSE; + m_WorkItemThread = NULL; + m_WorkItemRunningCount = 0; + + // + // All operations on a workitem are PASSIVE_LEVEL so ensure that any Dispose + // and Destroy callbacks to the driver are as well. + // + MarkPassiveCallbacks(ObjectDoNotLock); + + MarkDisposeOverride(ObjectDoNotLock); +} + + +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; +} + +_Must_inspect_result_ +NTSTATUS +FxWorkItem::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WORKITEM_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObject* ParentObject, + __out WDFWORKITEM* WorkItem + ) +{ + FxWorkItem* pFxWorkItem; + NTSTATUS status; + + pFxWorkItem = new(FxDriverGlobals, Attributes) FxWorkItem(FxDriverGlobals); + + if (pFxWorkItem == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pFxWorkItem->Initialize( + Attributes, + Config, + ParentObject, + WorkItem + ); + + if (!NT_SUCCESS(status)) { + pFxWorkItem->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxWorkItem::Initialize( + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_WORKITEM_CONFIG Config, + __in FxObject* ParentObject, + __out WDFWORKITEM* WorkItem + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxHasCallbacks* pCallbacks; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + status = m_WorkItemCompleted.Initialize(NotificationEvent, TRUE); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not initialize m_WorkItemCompleted event " + "%!STATUS!", status); + return status; + } +#endif + + ASSERT(Config->EvtWorkItemFunc != NULL); + + // Set users callback function + m_Callback = Config->EvtWorkItemFunc; + + // + // As long as we are associated, the parent object holds a reference + // count on the WDFWORKITEM. + // + // This reference must be taken early before we return any failure, + // since Dispose() expects this extra reference, and Dispose() will + // be called even if we return a failure status right now. + // + ADDREF(this); + + // + // WorkItems can be parented by, and optionally serialize with an FxDevice or an FxQueue + // + m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks); + + if (m_DeviceBase == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Determine if it's an FxDevice, or FxIoQueue and get the + // CallbackSpinLock pointer for it. + // + status = _GetEffectiveLock( + ParentObject, + pCallbacks, + Config->AutomaticSerialization, + TRUE, + &m_CallbackLock, + &m_CallbackLockObject + ); + + if (!NT_SUCCESS(status)) { + if (status == STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL) { + + + + + + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "ParentObject %p cannot automatically synchronize callbacks " + "with a WorkItem since it is not configured for passive level " + "callback constraints. Use a WDFDPC instead or set " + "AutomaticSerialization to FALSE." + "%!STATUS!", Attributes->ParentObject, status); + } + + return status; + } + + // + // Allocate the PIO_WORKITEM we will re-use + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_WorkItem.Allocate(m_Device->GetDeviceObject()); +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + m_WorkItem.Allocate( + m_Device->GetDeviceObject(), + (PVOID)&m_Device->GetDriver()->GetDriverObject()->ThreadPoolEnv); +#endif + if (m_WorkItem.GetWorkItem() == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not allocate IoWorkItem, %!STATUS!", status); + return status; + } + + // + // We automatically synchronize with and reference count + // the lifetime of the framework object to prevent any WORKITEM races + // that can access the object while it is going away. + // + + // + // The caller supplied object is the object the caller wants the + // WorkItem to be associated with, and the framework must ensure this + // object remains live until the WorkItem object is destroyed. Otherwise, + // it could access either object context memory, or an object API + // on a freed object. + // + // Due to the locking model of the framework, the lock may actually + // be owned by a higher level object as well. This is the lockObject + // returned. As long as we are a child of this object, the lockObject + // does not need to be dereferenced since it will notify us of Cleanup + // before it goes away. + // + + // + // Associate the FxWorkItem with the object. When this object Cleans up, it + // will notify our Cleanup function as well. + // + + // + // Add a reference to the parent object we are associated with. + // We will be notified of Cleanup to release this reference. + // + ParentObject->ADDREF(this); + + // Save the ptr to the object the WorkItem is associated with + m_Object = ParentObject; + + // + // Attributes->ParentObject is the same as ParentObject. Since we already + // converted it to an object, use that. + // + status = Commit(Attributes, (WDFOBJECT*)WorkItem, ParentObject); + + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +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; +} + +VOID +FxWorkItem::WorkItemHandler( + VOID + ) +{ + KIRQL irql; + + FX_TRACK_DRIVER(GetDriverGlobals()); + + Lock(&irql); + + // + // Mark the workitem as no longer enqueued and completed + // + // The handler is allowed to re-enqueue, so mark it before the callback + // + m_Enqueued = FALSE; + + m_WorkItemRunningCount++; + + Unlock(irql); + + if (m_CallbackLock != NULL) { + m_CallbackLock->Lock(&irql); +#if FX_IS_KERNEL_MODE + FxPerfTraceWorkItem(&m_Callback); +#endif + m_Callback(GetHandle()); + m_CallbackLock->Unlock(irql); + } + else { +#if FX_IS_KERNEL_MODE + FxPerfTraceWorkItem(&m_Callback); +#endif + m_Callback(GetHandle()); + } + + Lock(&irql); + + m_WorkItemRunningCount--; + + // + // The workitem can be re-enqueued by the drivers + // work item handler routine. We can't set the work + // item completed event until we are sure there are + // no outstanding work items. + // + + if (m_WorkItemRunningCount == 0L && m_Enqueued == FALSE) { + m_WorkItemCompleted.Set(); + } + + Unlock(irql); +} + +VOID +FxWorkItem::WorkItemThunk( + __in MdDeviceObject DeviceObject, + __in_opt PVOID Context + ) +/*++ + +Routine Description: + + This is the static routine called by the kernels PIO_WORKITEM handler. + + A reference count was taken by Enqueue, which this routine releases + on return. + +Arguments: + DeviceObject - the devobj we passed to IoCreateWorkItem + + Context - the internal Fx object + +Return Value: + None + +--*/ +{ + FxWorkItem* pWorkItem; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + UNREFERENCED_PARAMETER(DeviceObject); + + pWorkItem = (FxWorkItem*)Context; + pFxDriverGlobals = pWorkItem->GetDriverGlobals(); + + // + // Save the current worker thread object pointer. We will use this avoid + // deadlock if the driver tries to delete or flush the workitem from within + // the callback. + // + pWorkItem->m_WorkItemThread = Mx::MxGetCurrentThread(); + + pWorkItem->WorkItemHandler(); + + pWorkItem->m_WorkItemThread = NULL; + + // + // Release the reference on the FxWorkItem and Globals taken when Enqueue + // was done. This may release the FxWorkItem if it is running down. + // + pWorkItem->RELEASE(WorkItemThunk); + + // + // This may release the driver if it is running down. + // + pFxDriverGlobals->RELEASE(WorkItemThunk); +} + +VOID +FxWorkItem::FlushAndRundown( + VOID + ) +{ + FxObject* pObject; + + // + // Wait for any outstanding workitem to complete if the workitem is not + // deleted from within the workitem callback to avoid deadlock. + // + if (m_WorkItemThread != Mx::MxGetCurrentThread()) { + WaitForSignal(); + } + + // + // Release our reference count to the associated parent object if present + // + if (m_Object != NULL) { + pObject = m_Object; + m_Object = NULL; + + pObject->RELEASE(this); + } + + // + // Perform our final release to ourselves, destroying the FxWorkItem + // + RELEASE(this); +} + +BOOLEAN +FxWorkItem::Dispose( + VOID + ) +/*++ + +Routine Description: + Called when DeleteObject is called, or when the parent is being deleted or + Disposed. + +Arguments: + None + +Return Value: + TRUE if the cleanup routines should be invoked, FALSE otherwise + + --*/ +{ + KIRQL irql; + + Lock(&irql); + m_RunningDown = TRUE; + Unlock(irql); + + FlushAndRundown(); + + return TRUE; +} + +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; +} + +VOID +FxWorkItem::WaitForSignal( + VOID + ) +{ + LARGE_INTEGER timeOut; + NTSTATUS status; + + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + timeOut.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60); + + do { + status = m_WorkItemCompleted.EnterCRAndWaitAndLeave(&timeOut.QuadPart); + if (status == STATUS_TIMEOUT) { + DbgPrint("Thread 0x%p is waiting on WDFWORKITEM 0x%p\n", + Mx::GetCurrentEThread(), + GetHandle()); + } + else { + ASSERT(NT_SUCCESS(status)); + break; + } + } WHILE(TRUE); + + + ASSERT(NT_SUCCESS(status)); + return; +} diff --git a/sdk/lib/drivers/wdf/shared/core/fxworkitemapi.cpp b/sdk/lib/drivers/wdf/shared/core/fxworkitemapi.cpp new file mode 100644 index 00000000000..3d1930060b5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/fxworkitemapi.cpp @@ -0,0 +1,264 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWorkItemApi.cpp + +Abstract: + + This implements the WDFWORKITEM API's + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxWorkItem.hpp" + +extern "C" { +#include "FxWorkItemApi.tmh" +} + + +// +// extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfWorkItemCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PWDF_WORKITEM_CONFIG Config, + __in + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFWORKITEM* WorkItem + ) + +/*++ + +Routine Description: + + Create a WorkItem object that will call the supplied function with + context when it fires. It returns a handle to the WDFWORKITEM object. + +Arguments: + + Config - Pointer to WDF_WORKITEM_CONFIG structure + + Attributes - WDF_OBJECT_ATTRIBUTES to set the parent object and to request + a context memory allocation, and a DestroyCallback. + + WorkItem - Pointer to the created WDFWORKITEM handle. + +Returns: + + STATUS_SUCCESS - A WDFWORKITEM handle has been created. + + The WDFWORKITEM will be automatically deleted when the object it is + associated with is deleted. + +Notes: + + The WDFWORKITEM object is deleted either when the DEVICE or QUEUE it is + associated with is deleted, or WdfObjectDelete is called. + + If the WDFWORKITEM is used to access WDM objects, a Cleanup callback should + be registered to allow references to be released. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxObject* pParent; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_REQUIRED); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Config); + FxPointerNotNull(pFxDriverGlobals, WorkItem); + + if (Config->Size != sizeof(WDF_WORKITEM_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDF_WORKITEM_CONFIG Size got %d, expected %d, %!STATUS!", + Config->Size, sizeof(WDF_WORKITEM_CONFIG), status); + + return status; + } + + if (Config->EvtWorkItemFunc == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Supplied EvtWorkItemFunc == NULL, %!STATUS!", + status); + + return status; + } + + // + // The parent for FxWorkItem is explicitly part of the API, and ties + // synchronization and lifetime. + // + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + if (!NT_SUCCESS(status)) { + return status; + } + + return FxWorkItem::_Create( + pFxDriverGlobals, Config, Attributes, pParent, WorkItem); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfWorkItemEnqueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWORKITEM WorkItem + ) +/*++ + +Routine Description: + + Enqueue a WorkItem to execute. + +Arguments: + + WorkItem - Handle to WDFWORKITEM + +Returns: + + None + +--*/ +{ + DDI_ENTRY(); + + FxWorkItem* pFxWorkItem; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WorkItem, + FX_TYPE_WORKITEM, + (PVOID*)&pFxWorkItem); + + pFxWorkItem->Enqueue(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFOBJECT +WDFEXPORT(WdfWorkItemGetParentObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWORKITEM WorkItem + ) + +/*++ + +Routine Description: + + Return the Object handle supplied to WdfWorkItemCreate + +Arguments: + + WDFWORKITEM - Handle to WDFWORKITEM object created with WdfWorkItemCreate. + +Returns: + + Handle to the framework object that is the specified work-item object's + parent object. + +--*/ + +{ + DDI_ENTRY(); + + FxWorkItem* pFxWorkItem; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WorkItem, + FX_TYPE_WORKITEM, + (PVOID*)&pFxWorkItem); + + return pFxWorkItem->GetAssociatedObject(); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfWorkItemFlush)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWORKITEM WorkItem + ) +/*++ + +Routine Description: + + Wait until any outstanding workitems have completed + +Arguments: + + WorkItem - Handle to WDFWORKITEM + +Returns: + + None + +--*/ +{ + DDI_ENTRY(); + + FxWorkItem* pFxWorkItem; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + WorkItem, + FX_TYPE_WORKITEM, + (PVOID*)&pFxWorkItem); + + // + // Use the object's globals, not the caller's + // + if (!NT_SUCCESS(FxVerifierCheckIrqlLevel(pFxWorkItem->GetDriverGlobals(), + PASSIVE_LEVEL))) { + return; + } + + pFxWorkItem->FlushAndWait(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxdeviceapikm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxdeviceapikm.cpp new file mode 100644 index 00000000000..1588cb823e9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxdeviceapikm.cpp @@ -0,0 +1,959 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceApiKm.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "fxiotarget.hpp" + +extern "C" { +#include "FxDeviceApiKm.tmh" +} + +// +// extern "C" the entire file +// +extern "C" { + +// +// Verifier Functions +// +// Do not specify argument names +FX_DECLARE_VF_FUNCTION_P3( +VOID, +VerifyWdfDeviceWdmDispatchIrp, + _In_ PWDF_DRIVER_GLOBALS, + _In_ FxDevice*, + _In_ WDFCONTEXT + ); + +// Do not specify argument names +FX_DECLARE_VF_FUNCTION_P4( +NTSTATUS, +VerifyWdfDeviceWdmDispatchIrpToIoQueue, + _In_ FxDevice*, + _In_ MdIrp, + _In_ FxIoQueue*, + _In_ ULONG + ); + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PDEVICE_OBJECT DeviceObject + ) +{ + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceObject); + + return FxDevice::GetFxDevice(DeviceObject)->GetHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PDEVICE_OBJECT +WDFEXPORT(WdfDeviceWdmGetDeviceObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + FxDeviceBase *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*) &pDevice); + + return pDevice->GetDeviceObject(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PDEVICE_OBJECT +WDFEXPORT(WdfDeviceWdmGetAttachedDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + FxDeviceBase *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*) &pDevice); + + return pDevice->GetAttachedDevice(); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +PDEVICE_OBJECT +WDFEXPORT(WdfDeviceWdmGetPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +{ + FxDeviceBase *pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*) &pDevice); + + return pDevice->GetPhysicalDevice(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFFILEOBJECT +WDFEXPORT(WdfDeviceGetFileObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + MdFileObject FileObject + ) +/*++ + +Routine Description: + + This functions returns the WDFFILEOBJECT corresponding to the WDM fileobject. + +Arguments: + + Device - Handle to the device to which the WDM fileobject is related to. + + FileObject - WDM FILE_OBJECT structure. + +Return Value: + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxFileObject* pFxFO; + FxDevice *pDevice; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + + + + + + pFxFO = NULL; + + // + // Validate the Device object handle, and get its FxDevice* + // + FxObjectHandleGetPtr(pFxDriverGlobals, + Device, + FX_TYPE_DEVICE, + (PVOID*)&pDevice); + + // + // Call the static GetFileObjectFromWdm function. This will return an error if the + // WDM fileObject is NULL and the device is not exclusive or the device is + // configured to have a WDFFILEOBJECT for every open handle. + // + status = FxFileObject::_GetFileObjectFromWdm( + pDevice, + pDevice->GetFileObjectClass(), + FileObject, + &pFxFO + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "FxFileObject::_GetFileObjectFromWdm returned an error %!STATUS!", + status); + return NULL; + } + + // + // pFxFO can be NULL if the device is configured with FileObjectClass WdfFileObjectNotRequired. + // + return pFxFO != NULL ? pFxFO->GetHandle() : NULL; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +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 +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()); + } +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrp)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + MdIrp Irp, + __in + WDFCONTEXT DispatchContext + ) + +/*++ + +Routine Description: + + Client driver calls this API from its dispatch callback when it decides to hand the IRP + back to framework. + + Cx calls this API from (a) its pre-process callback or (b) its dispatch callback when + it decides to hand the IRP back to the framework. + +Arguments: + Device - WDF Device handle. + + IRP - WDM request. + + DispatchContext - WDF's context (input arg to callback). + +Returns: + IRP's status. + +--*/ + +{ + FxDevice *device; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &device); + + FxPointerNotNull(device->GetDriverGlobals(), Irp); + FxPointerNotNull(device->GetDriverGlobals(), DispatchContext); + + if ((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK) { + // + // Called from a dispach irp callback. + // + DispatchContext = + (WDFCONTEXT)((ULONG_PTR)DispatchContext & ~FX_IN_DISPATCH_CALLBACK); + + // + // DispatchContext is validated by DispatchStep1. + // + status = device->m_PkgIo->DispatchStep1(Irp, DispatchContext); + } + else { + // + // Called from a pre-process irp callback. + // + + // + // Verifier checks. + // + VerifyWdfDeviceWdmDispatchIrp(device->GetDriverGlobals(), + DriverGlobals, + device, + DispatchContext); + + status = device->DispatchPreprocessedIrp(Irp, DispatchContext); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +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); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAddDependentUsageDeviceObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PDEVICE_OBJECT DependentDevice + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DependentDevice); + + return pDevice->m_PkgPnp->AddUsageDevice(DependentDevice); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PDEVICE_OBJECT DependentDevice + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DependentDevice); + + return pDevice->m_PkgPnp->RemoveUsageDevice(DependentDevice); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAssignMofResourceName)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PCUNICODE_STRING MofResourceName + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, MofResourceName); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, MofResourceName); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pDevice->m_MofResourceName.Buffer != NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p MofResourceName already assigned, %!STATUS!", + Device, status); + + return status; + } + + status = FxDuplicateUnicodeString(pFxDriverGlobals, + MofResourceName, + &pDevice->m_MofResourceName); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p couldn't creat duplicate buffer, %!STATUS!", + Device, status); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +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); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceIndicateWakeStatus)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + NTSTATUS WaitWakeStatus + ) +{ + NTSTATUS status; + FxDevice *pDevice; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + if (Device == NULL || + WaitWakeStatus == STATUS_PENDING || WaitWakeStatus == STATUS_CANCELLED) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "NULL WDFDEVICE handle %p or invalid %!STATUS!", + Device, WaitWakeStatus); + return STATUS_INVALID_PARAMETER; + } + + if (pDevice->m_PkgPnp->m_SharedPower.m_WaitWakeOwner) { + if (pDevice->m_PkgPnp->PowerIndicateWaitWakeStatus(WaitWakeStatus)) { + status = STATUS_SUCCESS; + } + else { + // + // There was no request to complete + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p No request to complete" + " STATUS_INVALID_DEVICE_REQUEST", + Device); + + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + else { + // + // We cannot complete what we do not own + // + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p Not the waitwake owner" + " STATUS_INVALID_DEVICE_STATE", + Device); + + status = STATUS_INVALID_DEVICE_STATE; + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetBusInformationForChildren)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PPNP_BUS_INFORMATION BusInformation + ) +{ + FxDevice* pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + FxPointerNotNull(pDevice->GetDriverGlobals(), BusInformation); + + pDevice->m_PkgPnp->SetChildBusInformation(BusInformation); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PDEVICE_OBJECT PhysicalDevice + ) +/*++ + +Routine Description: + Registers a PDO from another non descendant (not verifiable though) pnp + stack to be reported as also requiring removal when this PDO is removed. + + The PDO could be another device enumerated by this driver. + +Arguments: + Device - this driver's PDO + + PhysicalDevice - PDO for another stack + +Return Value: + NTSTATUS + + --*/ +{ + FxDevice* pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + FxPointerNotNull(pDevice->GetDriverGlobals(), PhysicalDevice); + + return pDevice->m_PkgPnp->AddRemovalDevice(PhysicalDevice); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PDEVICE_OBJECT PhysicalDevice + ) +/*++ + +Routine Description: + Deregisters a PDO from another non descendant (not verifiable though) pnp + stack to not be reported as also requiring removal when this PDO is removed. + + The PDO could be another device enumerated by this driver. + +Arguments: + Device - this driver's PDO + + PhysicalDevice - PDO for another stack + +Return Value: + None + + --*/ +{ + FxDevice* pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + FxPointerNotNull(pDevice->GetDriverGlobals(), PhysicalDevice); + + pDevice->m_PkgPnp->RemoveRemovalDevice(PhysicalDevice); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfDeviceClearRemovalRelationsDevices)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device + ) +/*++ + +Routine Description: + Deregisters all PDOs to not be reported as also requiring removal when this + PDO is removed. + +Arguments: + Device - this driver's PDO + +Return Value: + None + + --*/ +{ + FxDevice* pDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice); + + pDevice->m_PkgPnp->ClearRemovalDevicesList(); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +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; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxdevicebasekm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxdevicebasekm.cpp new file mode 100644 index 00000000000..e8576d2519b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxdevicebasekm.cpp @@ -0,0 +1,101 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceBaseKm.cpp + +Abstract: + + This is the class implementation for the base device class. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceBaseKm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceBase::QueryForInterface( + __in const GUID* InterfaceType, + __out PINTERFACE Interface, + __in USHORT Size, + __in USHORT Version, + __in PVOID InterfaceSpecificData, + __in_opt MdDeviceObject TargetDevice + ) +/*++ + +Routine Description: + Send an IRP_MJPNP/IRP_MN_QUERY_INTERFACE irp to a device object and its + attached stack. + +Arguments: + InterfaceType - The type of interface to query for + + Interface - The interface to fill out + + Size - Size of Interface in bytes + + Version - Version of the interface to be queried + + InterfaceSpecificData - Addtional interface data to be queried + + TargetDevice - device in the stack to send the query to. If NULL, the top + of the stack will receive the query. + +Return Value: + NTSTATUS as indicated by the handler of the QI with in the device stack, + STATUS_NOT_SUPPORTED if the QI is not handled. + + --*/ +{ + PDEVICE_OBJECT pTopOfStack; + NTSTATUS status; + + // + // PnP rules dictate you send the QI through the entire stack and not just + // the stack below you...but we let the caller override this. There are + // some stacks which are not PnP reentrant, so sending a QI from a lower + // filter might cause the stack to stop responding if the FDO is synchronously + // sending a PnP irp down the stack already. + // + if (TargetDevice == NULL) { + pTopOfStack = GetAttachedDeviceReference(); + } + else { + // + // To make the exit logic simpler below, just add our own reference. + // + Mx::MxReferenceObject(TargetDevice); + pTopOfStack = TargetDevice; + } + + status = FxQueryInterface::_QueryForInterface( + pTopOfStack, + InterfaceType, + Interface, + Size, + Version, + InterfaceSpecificData + ); + + Mx::MxDereferenceObject(pTopOfStack); + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxdeviceinitkm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxdeviceinitkm.cpp new file mode 100644 index 00000000000..37e42d7ca97 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxdeviceinitkm.cpp @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInitKm.cpp + +Abstract: + Internals for WDFDEVICE_INIT + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceInitKm.tmh" +} + +VOID +WDFDEVICE_INIT::SetPdo( + __in FxDevice* Parent + ) +{ + InitType = FxDeviceInitTypePdo; + + // + // Remember the parent so we can store it later in WdfDeviceCreate + // + Pdo.Parent = Parent; + + // + // PDOs *must* have a name. By setting this flag, the driver writer + // does not need to know this + // + Characteristics |= FILE_AUTOGENERATED_DEVICE_NAME; + + // + // By default, PDOs are not power pageable b/c they do not know how the + // stack above them will work. For a "closed" system where the bus driver + // knows the stack be loaded on its PDO, this may not be true and it + // can use WdfDeviceInitSetPowerPageable to set it back. + // + // In all current shipping OS's, if the parent is power pageable, the + // child must be power pagable as well. + // + if (Parent->IsPowerPageableCapable() == FALSE) { + PowerPageable = FALSE; + } +} + +VOID +WDFDEVICE_INIT::AssignIoType( + _In_ PWDF_IO_TYPE_CONFIG IoTypeConfig + ) +{ + NTSTATUS status; + + if (IoTypeConfig->ReadWriteIoType == WdfDeviceIoUndefined || + IoTypeConfig->ReadWriteIoType > WdfDeviceIoDirect) { + status= STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Out of range Read/Write IoType %d, %!status!", + IoTypeConfig->ReadWriteIoType, status); + FxVerifierDbgBreakPoint(DriverGlobals); + return; + } + + ReadWriteIoType = IoTypeConfig->ReadWriteIoType; + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxdevicekm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxdevicekm.cpp new file mode 100644 index 00000000000..15bcf5aae97 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxdevicekm.cpp @@ -0,0 +1,1037 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceKm.cpp + +Abstract: + + This is the KM specific class implementation for the base Device class. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceKm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::FdoInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + PFX_DRIVER_GLOBALS pGlobals; + NTSTATUS status; + FxPkgFdo * pkgFdo; + + pGlobals = GetDriverGlobals(); + + if (DeviceInit->Fdo.EventCallbacks.EvtDeviceFilterAddResourceRequirements != NULL && + DeviceInit->Fdo.EventCallbacks.EvtDeviceRemoveAddedResources == NULL) { + // + // Not allowed to add resources without filtering them out later + // + DoTraceLevelMessage( + pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Must set EvtDeviceRemoveAddedResources if " + "EvtDeviceFilterAddResourceRequirements (%p) is set", + DeviceInit->Fdo.EventCallbacks.EvtDeviceFilterAddResourceRequirements); + + FxVerifierDbgBreakPoint(pGlobals); + + return STATUS_INVALID_DEVICE_STATE; + } + + // + // All FDOs cannot be deleted through the driver calling WdfObjectDelete + // + MarkNoDeleteDDI(); + + m_PhysicalDevice.SetObject((MdDeviceObject)DeviceInit->Fdo.PhysicalDevice); + + // + // The PDO is known because it was used to bring up this FDO. + // + m_PdoKnown = TRUE; + + // + // Try to create and install the default packages that an FDO contains. + // + + // PnP + status = FxPkgFdo::_Create(pGlobals, (CfxDevice*)this, &pkgFdo); + + if (!NT_SUCCESS(status)) { + return status; + } + else { + m_PkgPnp = pkgFdo; + } + + InstallPackage(m_PkgPnp); + + status = SetFilter(DeviceInit->Fdo.Filter); + if (!NT_SUCCESS(status)) { + return status; + } + + status = GetFdoPkg()->Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + + // + // Should be done after invoking Initialize so that FxPkgFdo::m_EnumInfo is + // already allocated. + // + if (DeviceInit->Fdo.ListConfig.Size > 0) { + status = GetFdoPkg()->CreateDefaultDeviceList( + &DeviceInit->Fdo.ListConfig, + DeviceInit->Fdo.ListConfigAttributes.Size > 0 + ? &DeviceInit->Fdo.ListConfigAttributes + : NULL); + + if (!NT_SUCCESS(status)) { + return status; + } + + SetDeviceTelemetryInfoFlags(DeviceInfoHasDynamicChildren); + } + + // + // If the Size is zero then the driver writer never set any callbacks so we + // can skip this call. + // + if (DeviceInit->Fdo.EventCallbacks.Size != 0) { + status = GetFdoPkg()->RegisterCallbacks(&DeviceInit->Fdo.EventCallbacks); + if (!NT_SUCCESS(status)) { + return status; + } + } + + status = CreateDevice(DeviceInit); + if (NT_SUCCESS(status)) { + // + // If this is an FDO then the PhysicalDevice field will be initialized, + // and we need to attach to the device stack. + // + m_AttachedDevice.SetObject(Mx::MxAttachDeviceToDeviceStack( + m_DeviceObject.GetObject(), m_PhysicalDevice.GetObject())); + + if (m_AttachedDevice.GetObject() == NULL) { + // + // We couldn't attach the device for some reason. + // + Mx::MxDeleteDevice(m_DeviceObject.GetObject()); + m_DeviceObject = NULL; + + status = STATUS_NO_SUCH_DEVICE; + } + else { + // + // If we are a filter device, inherit some state from the + // attached device. + // + if (m_Filter) { + // + // Set the IO type and power pageable status on our device based + // on the attached device's settings. + // + SetFilterIoType(); + + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | + (m_AttachedDevice.GetFlags() & (DO_POWER_PAGABLE | DO_POWER_INRUSH))); + + m_DeviceObject.SetDeviceType(m_AttachedDevice.GetDeviceType()); + m_DeviceObject.SetCharacteristics(m_AttachedDevice.GetCharacteristics()); + + // + // For devices other then filters, m_PowerPageableCapable gets + // set in CreateDevice, but since this is determined for filters + // by the device they have attached to, we must set this value + // later as a special case only for filters. + // + if (m_DeviceObject.GetFlags() & DO_POWER_PAGABLE) { + m_PowerPageableCapable = TRUE; + } + } + else { + // + // We are not a filter, we dictate our own DO flags + // + + // + // Power pageable and inrush are mutually exclusive + // + if (DeviceInit->PowerPageable) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_PAGABLE); + } + else if (DeviceInit->Inrush) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_INRUSH); + } + } + } + } + + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_PkgWmi->PostCreateDeviceInitialize(); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + status = GetFdoPkg()->PostCreateDeviceInitialize(); + + if (NT_SUCCESS(status)) { + // + // Do not clear the DO_DEVICE_INITIALIZING bit here. Instead, either + // let the caller do it in their AddDevice or do it after the AddDevice + // callback returns. + // + // FinishInitializing(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::PdoInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + PFX_DRIVER_GLOBALS pGlobals; + FxPkgPdo* pPkgPdo; + NTSTATUS status; + + pGlobals = GetDriverGlobals(); + + // + // If the child is static, the driver has the ability to delete the child + // device handle in between WdfDeviceCreate succeededing and then adding + // the child to the list of static children. + // + if (DeviceInit->Pdo.Static == FALSE) { + MarkNoDeleteDDI(); + } + + // + // Double check to make sure that the PDO has a name + // + if (DeviceInit->HasName() == FALSE) { + return STATUS_OBJECT_NAME_INVALID; + } + + m_ParentDevice = DeviceInit->Pdo.Parent; + + // + // This reference will be removed when this object is destroyed + // + m_ParentDevice->ADDREF(this); + + pPkgPdo = new(pGlobals) FxPkgPdo(pGlobals, (CfxDevice*)this); + + m_PkgPnp = pPkgPdo; + if (m_PkgPnp == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + InstallPackage(m_PkgPnp); + + status = m_PkgPnp->Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // If the Size is zero then the driver writer never set any callbacks so we + // can skip this call. + // + if (DeviceInit->Pdo.EventCallbacks.Size != 0) { + pPkgPdo->RegisterCallbacks(&DeviceInit->Pdo.EventCallbacks); + } + + status = CreateDevice(DeviceInit); + + if (NT_SUCCESS(status)) { + + // + // We are initializing the PDO, stash away the PDO's device object + // under m_PhysicalDevice as well so that we don't have to check + // for device type later. + // + m_PhysicalDevice = m_DeviceObject; + + if (DeviceInit->Pdo.Raw) { + pPkgPdo->m_RawOK = TRUE; + } + + // + // Power pageable and inrush are mutually exclusive + // + if (DeviceInit->PowerPageable) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_PAGABLE); + } + else if (DeviceInit->Inrush) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_INRUSH); + } + + if (DeviceInit->Pdo.ForwardRequestToParent) { + m_DeviceObject.SetStackSize(m_DeviceObject.GetStackSize() + DeviceInit->Pdo.Parent->GetDeviceObject()->StackSize); + pPkgPdo->m_AllowForwardRequestToParent = TRUE; + } + + status = m_PkgWmi->PostCreateDeviceInitialize(); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pPkgPdo->PostCreateDeviceInitialize(); + + if (NT_SUCCESS(status)) { + // + // Clear the DO_DEVICE_INITIALIZING bit. + // + FinishInitializing(); + } + } + + return status; +} + +VOID +FxDevice::Destroy( + VOID + ) +{ + // + // We must be at passive for IoDeleteDevice + // + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + if (m_DeviceObject.GetObject() != NULL) { + // + // The device object may not go away right away if there are pending + // references on it. But we can't look up our FxDevice anymore, so + // lets clear the DeviceExtension pointer. + // + m_DeviceObject.SetDeviceExtension(NULL); + } + + // + // Since this can be called in the context of the destructor when the ref + // count is zero, use GetObjectHandleUnchecked() to get the handle value. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGDEVICE, + "Deleting !devobj %p, WDFDEVICE %p, attached to !devobj %p", + m_DeviceObject.GetObject(), GetObjectHandleUnchecked(), m_AttachedDevice.GetObject()); + + DetachDevice(); + + if (m_DeviceObject.GetObject() != NULL) { + DeleteSymbolicLink(); + + if (m_DeviceObjectDeleted) { + // + // The device already deleted previously, release the reference we + // took at the time of delete. + // + Mx::MxDereferenceObject(m_DeviceObject.GetObject()); + } + else { + Mx::MxDeleteDevice(m_DeviceObject.GetObject()); + } + + m_DeviceObject.SetObject(NULL); + } + + // + // Clean up any referenced objects + // + if (m_DeviceName.Buffer != NULL) { + FxPoolFree(m_DeviceName.Buffer); + RtlZeroMemory(&m_DeviceName, sizeof(m_DeviceName)); + } + + if (m_MofResourceName.Buffer != NULL) { + FxPoolFree(m_MofResourceName.Buffer); + RtlZeroMemory(&m_MofResourceName, sizeof(m_DeviceName)); + } +} + +VOID +FxDevice::DestructorInternal( + VOID + ) +{ + // NOTHING TO DO +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::ControlDeviceInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + NTSTATUS status; + + m_Legacy = TRUE; + + status = CreateDevice(DeviceInit); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_PkgWmi->PostCreateDeviceInitialize(); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // NOTE: The driver writer must clear the DO_DEVICE_INITIALIZING bit + // via WdfControlFinishInitializing + // + return status; +} + +VOID +FxDevice::AddChildList( + __inout FxChildList* List + ) +{ + if (IsPnp()) { + m_PkgPnp->AddChildList(List); + } +} + +VOID +FxDevice::RemoveChildList( + __inout FxChildList* List + ) +{ + if (IsPnp()) { + m_PkgPnp->RemoveChildList(List); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::AllocateDmaEnablerList( + VOID + ) +{ + if (IsPnp()) { + return m_PkgPnp->AllocateDmaEnablerList(); + } + else { + return STATUS_SUCCESS; + } +} + +VOID +FxDevice::AddDmaEnabler( + __inout FxDmaEnabler* Enabler + ) +{ + if (IsPnp()) { + m_PkgPnp->AddDmaEnabler(Enabler); + } +} + +VOID +FxDevice::RemoveDmaEnabler( + __inout FxDmaEnabler* Enabler + ) +{ + if (IsPnp()) { + m_PkgPnp->RemoveDmaEnabler(Enabler); + } +} + + + + +NTSTATUS +FxDevice::WmiPkgRegister( + VOID + ) +{ + return m_PkgWmi->Register(); +} + +VOID +FxDevice::WmiPkgDeregister( + VOID + ) +{ + m_PkgWmi->Deregister(); +} + +VOID +FxDevice::WmiPkgCleanup( + VOID + ) +{ + m_PkgWmi->Cleanup(); +} + +NTSTATUS +FxDevice::CreateSymbolicLink( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ PCUNICODE_STRING SymbolicLinkName + ) +{ + NTSTATUS status; + PUNICODE_STRING pName; + FxAutoString pdoName; + + // + // Ensure m_DeviceName has been set or we can get the PDO's name + // + if (m_DeviceName.Buffer == NULL) { + MdDeviceObject pPdo; + PWSTR pBuffer; + ULONG length; + + if (IsLegacy()) { + // + // No PDO on a legacy stack, can't call IoGetDeviceProperty + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p has no device name (use WdfDeviceInitAssignName), " + "%!STATUS!", GetHandle(), status); + + return status; + } + + pPdo = GetSafePhysicalDevice(); + if (pPdo == NULL) { + // + // No PDO yet for this device, pnp doesn't know about it. + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p has not yet been reported to pnp, cannot call " + "IoGetDeviceProperty in this state, %!STATUS!", GetHandle(), status); + + return status; + } + + length = 0; + + status = _GetDeviceProperty(pPdo, + DevicePropertyPhysicalDeviceObjectName, + 0, + NULL, + &length); + + if (status != STATUS_BUFFER_TOO_SMALL && !NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p IoGetDeviceProperty failed %!STATUS!", + GetHandle(), status); + return status; + } + else if (length > USHORT_MAX) { + status = STATUS_INTEGER_OVERFLOW; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p PDO name too long (%d, max is %d), %!STATUS!", + GetHandle(), length, USHORT_MAX, status); + + return status; + } + else if (length == 0) { + // + // We can get zero back if the PDO is being deleted. + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p PDO name length is zero, %!STATUS!", + GetHandle(), status); + + return status; + } + + pBuffer = (PWSTR) FxPoolAllocate(FxDriverGlobals, PagedPool, length); + if (pBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p could not allocate buffer for PDO name, %!STATUS!", + GetHandle(), status); + + return status; + } + + // + // pdoName will free pBuffer when it is destructed + // + pdoName.m_UnicodeString.Buffer = pBuffer; + + status = _GetDeviceProperty(pPdo, + DevicePropertyPhysicalDeviceObjectName, + length, + pBuffer, + &length); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p IoGetDeviceProperty failed second time, %!STATUS!", + GetHandle(), status); + return status; + } + + pdoName.m_UnicodeString.Length = (USHORT) length - sizeof(UNICODE_NULL); + pdoName.m_UnicodeString.MaximumLength = (USHORT) length; + + pName = &pdoName.m_UnicodeString; + } + else { + pName = &m_DeviceName; + } + + status = FxDuplicateUnicodeString(FxDriverGlobals, + SymbolicLinkName, + &m_SymbolicLinkName); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p allocate buffer for symbolic name failed, %!STATUS!", + GetHandle(), status); + + return status; + } + + status = Mx::MxCreateSymbolicLink(&m_SymbolicLinkName, pName); + + if (!NT_SUCCESS(status)) { + FxPoolFree(m_SymbolicLinkName.Buffer); + + RtlZeroMemory(&m_SymbolicLinkName, + sizeof(m_SymbolicLinkName)); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p create sybolic link failed, %!STATUS!", + GetHandle(), status); + } + + return status; +} + +NTSTATUS +FxDevice::AssignProperty ( + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ DEVPROPTYPE Type, + _In_ ULONG BufferLength, + _In_opt_ PVOID PropertyBuffer + ) +{ + NTSTATUS status; + const DEVPROPKEY * propertyKey; + LCID lcid; + ULONG flags; + PWDF_DEVICE_PROPERTY_DATA deviceData; + PDEVICE_OBJECT pdo; + + UNREFERENCED_PARAMETER(FxPropertyType); + + ASSERT(FxPropertyType == FxDeviceProperty); + + deviceData = (PWDF_DEVICE_PROPERTY_DATA) PropertyData; + + propertyKey = deviceData->PropertyKey; + lcid = deviceData->Lcid; + flags = deviceData->Flags; + + pdo = GetSafePhysicalDevice(); + + if (pdo == NULL) { + // + // Pnp doesn't know about the PDO yet. + // + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not yet known to PnP manager, cannot call " + "WdfDeviceAssignPropertyEx in this state, %!STATUS!", + GetHandle(), status); + + return status; + } + + status = IoSetDevicePropertyData( + pdo, + propertyKey, + lcid, + flags, + Type, + BufferLength, + PropertyBuffer + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p failed to assign device property, %!STATUS!", + GetHandle(), status); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_OpenKey( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ ULONG DeviceInstanceKeyType, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ WDFKEY* Key + ) +{ + FxRegKey* pKey; + WDFKEY keyHandle; + HANDLE hKey = NULL; + NTSTATUS status; + MdDeviceObject pdo; + + status = FxValidateObjectAttributes(FxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = _ValidateOpenKeyParams(FxDriverGlobals, DeviceInit, Device); + if (!NT_SUCCESS(status)) { + return status; + } + + _Analysis_assume_(DeviceInit != NULL || Device != NULL); + + if (DeviceInit != NULL) { + pdo = DeviceInit->Fdo.PhysicalDevice; + } + else { + pdo = Device->GetSafePhysicalDevice(); + if (pdo == NULL) { + // + // Pnp doesn't know about the PDO yet. + // + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not yet known to PnP manager, cannot open " + "PNP registry keys in this state, %!STATUS!", Device->GetHandle(), status); + return status; + } + } + + pKey = new(FxDriverGlobals, KeyAttributes) FxRegKey(FxDriverGlobals); + + if (pKey == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (Device != NULL) { + pKey->SetDeviceBase(Device); + } + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + + if (NT_SUCCESS(status)) { + status = _OpenDeviceRegistryKey(pdo, + DeviceInstanceKeyType, + DesiredAccess, + &hKey); + if (NT_SUCCESS(status)) { + pKey->SetHandle(hKey); + *Key = keyHandle; + } + } + + if (!NT_SUCCESS(status)) { + // + // No object is being returned, make sure the destroy callback will not + // be called. + // + pKey->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::OpenSettingsKey( + __out HANDLE* Key, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + FxAutoRegKey parent; + MdDeviceObject pdo; + + // + // We need a PDO to open this reg key. in the case of failure to create + // a static PDO, we will go down this path in the pnp state machine, so we + // must check for validity always. + // + pdo = GetSafePhysicalDevice(); + + if (pdo == NULL) { + return STATUS_INVALID_DEVICE_STATE; + } + + status = _OpenDeviceRegistryKey(pdo, + PLUGPLAY_REGKEY_DEVICE, + DesiredAccess, + &parent.m_Key); + if (NT_SUCCESS(status)) { + DECLARE_CONST_UNICODE_STRING(wdf, L"WDF"); + + // + // Create the key if it does not already exist + // + status = FxRegKey::_Create(parent.m_Key, + &wdf, + Key, + DesiredAccess); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_QueryPropertyEx ( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ ULONG BufferLength, + _Out_ PVOID PropertyBuffer, + _Out_ PULONG ResultLength, + _Out_ PDEVPROPTYPE PropertyType + ) +{ + NTSTATUS status; + DEVPROPTYPE propType; + ULONG requiredLength = 0; + const DEVPROPKEY * propertyKey; + LCID lcid; + PWDF_DEVICE_PROPERTY_DATA deviceData; + MdDeviceObject pdo; + + UNREFERENCED_PARAMETER(FxPropertyType); + ASSERT(FxPropertyType == FxDeviceProperty); + + *ResultLength = 0; + *PropertyType = 0; + + status = FxDevice::_ValidateOpenKeyParams(DriverGlobals, + DeviceInit, + Device); + if (!NT_SUCCESS(status)) { + return status; + } + + _Analysis_assume_(DeviceInit != NULL || Device != NULL); + + if (DeviceInit != NULL) { + pdo = DeviceInit->Fdo.PhysicalDevice; + } + else { + pdo = Device->GetSafePhysicalDevice(); + if (pdo == NULL) { + // + // Pnp doesn't know about the PDO yet. + // + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not yet known to PnP manager, cannot query " + "device properties in this state, %!STATUS!", Device->GetHandle(), status); + return status; + } + } + + deviceData = (PWDF_DEVICE_PROPERTY_DATA) PropertyData; + propertyKey = deviceData->PropertyKey; + lcid = deviceData->Lcid; + + status = IoGetDevicePropertyData(pdo, + propertyKey, + lcid, + 0, + BufferLength, + PropertyBuffer, + &requiredLength, + &propType); + if (status == STATUS_BUFFER_TOO_SMALL || NT_SUCCESS(status)) { + *ResultLength = requiredLength; + *PropertyType = propType; + } + else { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Query for property buffer failed, %!STATUS!", + status); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_QueryProperty( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_opt_ MdDeviceObject RemotePdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_opt_ PULONG ResultLength + ) +{ + NTSTATUS status; + MdDeviceObject pdo; + + ASSERT(DeviceInit != NULL || Device != NULL || RemotePdo != NULL); + + if (RemotePdo != NULL) { + pdo = RemotePdo; + } + else { + status = FxDevice::_ValidateOpenKeyParams(FxDriverGlobals, + DeviceInit, + Device); + if (!NT_SUCCESS(status)) { + return status; + } + + if (DeviceInit != NULL) { + pdo = DeviceInit->Fdo.PhysicalDevice; + } + else { + pdo = Device->GetSafePhysicalDevice(); + if (pdo == NULL) { + // + // Pnp doesn't know about the PDO yet. + // + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p is not yet known to PnP manager, cannot query " + "device properties in this state, %!STATUS!", Device->GetHandle(), status); + return status; + } + } + } + + status = _GetDeviceProperty(pdo, + DeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength); + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::OpenDevicemapKeyWorker( + _In_ PFX_DRIVER_GLOBALS pFxDriverGlobals, + _In_ PCUNICODE_STRING KeyName, + _In_ ACCESS_MASK DesiredAccess, + _In_ FxRegKey* pKey + ) +{ + + NTSTATUS status; + UNICODE_STRING registryKeyPath; + wchar_t baseStringBuffer[256] = FX_DEVICEMAP_PATH; + + // + // Unlike UMDF, KMDF can open any DEVICEMAP key directly. Create a fully qualified + // DEVICEMAP path from the provided subkey and pass it to FxRegKey::_OpenKey + // + registryKeyPath.Buffer = baseStringBuffer; + registryKeyPath.MaximumLength = sizeof(baseStringBuffer); + registryKeyPath.Length = sizeof(FX_DEVICEMAP_PATH) - sizeof(UNICODE_NULL); + + status = RtlAppendUnicodeStringToString(®istryKeyPath, KeyName); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Unable to create a DEVICEMAP registry path for subkey %S, %!STATUS!", + KeyName->Buffer, status); + } else { + + status = pKey->Create(NULL, + ®istryKeyPath, + DesiredAccess, + REG_OPTION_VOLATILE, + NULL); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY open failed, %!STATUS!", status); + } + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxdriverapikm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxdriverapikm.cpp new file mode 100644 index 00000000000..cb79187e0a8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxdriverapikm.cpp @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriverApiKm.cpp + +Abstract: + + This module contains the "C" interface for the FxDriver object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include +#include "FxDriverApiKm.tmh" +} + +// +// extern the whole file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDriverOpenParametersRegistryKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in + ACCESS_MASK DesiredAccess, + __in_opt + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + __out + WDFKEY* Key + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDriver* pDriver; + FxRegKey* pKey; + FxAutoRegKey hKey; + WDFKEY keyHandle; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + Driver, + FX_TYPE_DRIVER, + (PVOID*) &pDriver); + + pKey = new(pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals); + + if (pKey == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + + if (NT_SUCCESS(status)) { + // + // Static worker function (no object assignment for opened handled) + // + status = FxRegKey::_OpenKey( + NULL, pDriver->GetRegistryPathUnicodeString(), &hKey.m_Key); + + if (NT_SUCCESS(status)) { + DECLARE_CONST_UNICODE_STRING(parameters, L"Parameters"); + + // + // This will store the resulting handle in pKey + // + status = pKey->Create(hKey.m_Key, ¶meters, DesiredAccess); + + if (NT_SUCCESS(status)) { + *Key = keyHandle; + } + } + } + + if (!NT_SUCCESS(status)) { + pKey->DeleteFromFailedCreate(); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PDRIVER_OBJECT +WDFEXPORT(WdfDriverWdmGetDriverObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver + ) +{ + FxDriver *pDriver; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID*) &pDriver); + + return pDriver->GetDriverObject(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDRIVER +WDFEXPORT(WdfWdmDriverGetWdfDriverHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PDRIVER_OBJECT DriverObject + ) +{ + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DriverObject); + + return FxDriver::GetFxDriver(DriverObject)->GetHandle(); +} + +VOID +WDFEXPORT(WdfDriverMiniportUnload)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver + ) +{ + FxDriver *pDriver; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID *)&pDriver); + + FxDriver::Unload(pDriver->GetDriverObject()); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceMiniportCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __in + PDEVICE_OBJECT DeviceObject, + __in_opt + PDEVICE_OBJECT AttachedDeviceObject, + __in_opt + PDEVICE_OBJECT Pdo, + __out + WDFDEVICE* Device + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver* pDriver; + FxMpDevice* pMpDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Driver, + FX_TYPE_DRIVER, + (PVOID *)&pDriver, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceObject); + + if (AttachedDeviceObject == NULL && Pdo != NULL) { + FxPointerNotNull(pFxDriverGlobals, AttachedDeviceObject); + } + else if (AttachedDeviceObject != NULL && Pdo == NULL) { + FxPointerNotNull(pFxDriverGlobals, Pdo); + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + if (!NT_SUCCESS(status)) { + return status; + } + + pMpDevice = new(pFxDriverGlobals, Attributes) + FxMpDevice(pFxDriverGlobals, + pDriver, + DeviceObject, + AttachedDeviceObject, + Pdo); + + if (pMpDevice == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (AttachedDeviceObject != NULL) { + status = pMpDevice->AllocateTarget(&pMpDevice->m_DefaultTarget, + FALSE /*SelfTarget=FALSE*/); + if (!NT_SUCCESS(status)) { + goto Done; + } + } + + status = FxDisposeList::_Create(pFxDriverGlobals, + pMpDevice->GetDeviceObject(), + &pMpDevice->m_DisposeList); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = pMpDevice->ConfigureConstraints(Attributes); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = pMpDevice->Commit(Attributes, (PVOID*)Device); + if (!NT_SUCCESS(status)) { // follow the same error pattern as above. + goto Done; + } + +Done: + if (!NT_SUCCESS(status)) { + pMpDevice->DeleteFromFailedCreate(); + } + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxdriverkm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxdriverkm.cpp new file mode 100644 index 00000000000..46b64c6f82a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxdriverkm.cpp @@ -0,0 +1,170 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriverKm.cpp + +Abstract: + + This is the main driver framework. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" +#include "fxiotarget.hpp" + +// Tracing support +extern "C" { +#include "FxDriverKm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxDriver::AddDevice( + __in MdDriverObject DriverObject, + __in MdDeviceObject PhysicalDeviceObject + ) +{ + FxDriver *pDriver; + + pDriver = FxDriver::GetFxDriver(DriverObject); + + if (pDriver != NULL) { + return pDriver->AddDevice(PhysicalDeviceObject); + } + + return STATUS_UNSUCCESSFUL; +} + +_Must_inspect_result_ +NTSTATUS +FxDriver::AddDevice( + _In_ MdDeviceObject PhysicalDeviceObject + ) +{ + WDFDEVICE_INIT init(this); + FxDevice* pDevice; + NTSTATUS status; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter AddDevice PDO %p", PhysicalDeviceObject); + + pDevice = NULL; + init.CreatedOnStack = TRUE; + + init.InitType = FxDeviceInitTypeFdo; + init.Fdo.PhysicalDevice = PhysicalDeviceObject; + + status = m_DriverDeviceAdd.Invoke(GetHandle(), &init); + + // + // Caller returned w/out creating a device, we are done. Returning + // STATUS_SUCCESS w/out creating a device and attaching to the stack is OK, + // especially for filter drivers which selectively attach to devices. + // + if (init.CreatedDevice == NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Driver did not create a device in " + "EvtDriverAddDevice, status %!STATUS!", status); + + // + // We do not let filters affect the building of the rest of the stack. + // If they return error, we convert it to STATUS_SUCCESS. + // + if (init.Fdo.Filter && !NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Filter returned %!STATUS! without creating a WDFDEVICE, " + "converting to STATUS_SUCCESS", status); + status = STATUS_SUCCESS; + } + + return status; + } + + pDevice = init.CreatedDevice; + + if (NT_SUCCESS(status)) { + // + // Make sure that DO_DEVICE_INITIALIZING is cleared. + // FxDevice::FdoInitialize does not do this b/c the driver writer may + // want the bit set until sometime after WdfDeviceCreate returns + // + pDevice->FinishInitializing(); + } + else { + // + // Created a device, but returned error. + // + ASSERT(pDevice->IsPnp()); + ASSERT(pDevice->m_CurrentPnpState == WdfDevStatePnpInit); + + status = pDevice->DeleteDeviceFromFailedCreate(status, TRUE); + pDevice = NULL; + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit, status %!STATUS!", status); + + return status; +} + + +_Must_inspect_result_ +NTSTATUS +FxDriver::AllocateDriverObjectExtensionAndStoreFxDriver( + VOID + ) +{ + NTSTATUS status; + FxDriver** ppDriver; + + // + // Prefast is much happier if we take the size of the type rather then + // the size of the variable. + // + status = Mx::MxAllocateDriverObjectExtension( m_DriverObject.GetObject(), + FX_DRIVER_ID, + sizeof(FxDriver**), + (PVOID*)&ppDriver); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // If we succeeded in creating the driver object extension, + // then store our FxDriver pointer in the DriverObjectExtension. + // + *ppDriver = this; + + return STATUS_SUCCESS; +} + +FxDriver* +FxDriver::GetFxDriver( + __in MdDriverObject DriverObject + ) +{ + FxDriver* objExt; + objExt = *(FxDriver **)Mx::MxGetDriverObjectExtension(DriverObject, + FX_DRIVER_ID); + ASSERT(objExt != NULL); + + return objExt; +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxfileobjectapikm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxfileobjectapikm.cpp new file mode 100644 index 00000000000..2c397cb7134 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxfileobjectapikm.cpp @@ -0,0 +1,81 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectApiUm.cpp + +Abstract: + + This modules implements the C API's for the FxFileObject. + +Author: + +Environment: + + Kernel Mode mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" +#include "FxFileObject.hpp" + +extern "C" { +#include "FxFileObjectApiKm.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +PFILE_OBJECT +WDFEXPORT(WdfFileObjectWdmGetFileObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFFILEOBJECT FileObject + ) +/*++ + +Routine Description: + + This functions returns the corresponding WDM fileobject. If the device is opened + by a kernel-mode componenet by sending a IRP_MJ_CREATE irp + directly without a fileobject, this call can return a NULL pointer. + + Creating a WDFFILEOBJECT without an underlying WDM fileobject + is done only for 'exclusive' devices. + + Serenum sends such a create-irp to the serial driver. + +Arguments: + + FileObject - WDFFILEOBJECT + +Return Value: + + +--*/ +{ + DDI_ENTRY(); + + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + return pFO->GetWdmFileObject(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxfileobjectkm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxfileobjectkm.cpp new file mode 100644 index 00000000000..61e1fd979e9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxfileobjectkm.cpp @@ -0,0 +1,97 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectKm.hpp + +Abstract: + + This module implements a frameworks managed FileObject + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxFileObjectKm.tmh" +} + +VOID +FxFileObject::SetFileObjectContext( + _In_ MdFileObject WdmFileObject, + _In_ WDF_FILEOBJECT_CLASS NormalizedFileClass, + _In_ MdIrp Irp, + _In_ FxDevice* Device + ) +{ + MxFileObject wdmFileObject(WdmFileObject); + + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(Device); + + // + // We now must be able to quickly retrieve the FxFileObject* + // from the WDM PFILE_OBJECT when we get I/O requests. + // + // But different driver stacks have different rules, so + // we must be flexible here, including not touching the + // WDM PFILE_OBJECT at all. + // + if( NormalizedFileClass == WdfFileObjectWdfCanUseFsContext ) { + wdmFileObject.SetFsContext(this); + } + else if( NormalizedFileClass == WdfFileObjectWdfCanUseFsContext2 ) { + wdmFileObject.SetFsContext2(this); + } + else { + // + // WdfDeviceFileObjectNoContext will look up the FxFileObject + // from the FxDevice->m_FileObjectListHead at runtime. + // + } +} + +VOID +FxFileObject::Initialize( + _In_ MdIrp CreateIrp + ) +{ + UNREFERENCED_PARAMETER(CreateIrp); + + // + // Not needed for KMDF. + // + DO_NOTHING(); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxFileObject::UpdateProcessKeepAliveCount( + _In_ BOOLEAN Increment + ) +{ + UNREFERENCED_PARAMETER(Increment); + + // + // Not needed for KMDF. + // + DO_NOTHING(); + + return STATUS_NOT_IMPLEMENTED; +} diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxnpagedlookasidelistkm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxnpagedlookasidelistkm.cpp new file mode 100644 index 00000000000..ed81559cb2c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxnpagedlookasidelistkm.cpp @@ -0,0 +1,268 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxNPagedLookasideList.cpp + +Abstract: + + This module implements a frameworks managed FxNPagedLookasideList + +Author: + +Environment: + + kernel mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxNPagedLookasideList.hpp" +#include "FxMemoryBufferFromLookaside.hpp" + +FxNPagedLookasideList::FxNPagedLookasideList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag + ) : + FxLookasideList(FxDriverGlobals, sizeof(*this), PoolTag) +{ +} + +FxNPagedLookasideList::~FxNPagedLookasideList() +{ + if (m_MemoryObjectSize != 0) { + ExDeleteNPagedLookasideList(&m_ObjectLookaside); + } +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideList::Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) +{ + NTSTATUS status; + + // + // This type of class does not support BufferSize greater than 0xFFFF. + // The verification below ensures this contract is respected in both + // free and chk builds. + // + if (BufferSize > MAXUSHORT) { + ASSERT(FALSE); + status = STATUS_INVALID_BUFFER_SIZE; + goto Done; + } + + status = InitializeLookaside((USHORT) BufferSize, + sizeof(FxMemoryBufferFromLookaside), + MemoryAttributes); + + // + // Must be called after InitializeLookaside so that m_MemoryObjectSize is + // computed correctly. + // + if (NT_SUCCESS(status)) { + ASSERT(m_MemoryObjectSize != 0); + + // + // Initialize a non-paged pool with these characteristics. + // + ExInitializeNPagedLookasideList(&m_ObjectLookaside, + NULL, + NULL, + 0, + m_MemoryObjectSize, + m_PoolTag, + 0); + } + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideList::Allocate( + __out FxMemoryObject** PPMemory + ) +{ + FxMemoryBufferFromLookaside *pBuffer; + PVOID p; + + if (PPMemory == NULL) { + return STATUS_INVALID_PARAMETER; + } + + *PPMemory = NULL; + + // + // Get the raw memory allocation. + // + p = FxAllocateFromNPagedLookasideList(&m_ObjectLookaside); + if (p == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + p = InitObjectAlloc(p); + + // + // Construct new FxMemoryBufferFromLookaside + // + pBuffer = new(GetDriverGlobals(), p, m_BufferSize, &m_MemoryAttributes) + FxMemoryBufferFromLookaside(GetDriverGlobals(), this, m_BufferSize); + + // + // pBuffer might be displaced if there is a debug extension + // + ASSERT(_GetBase(pBuffer) == p); + + *PPMemory = pBuffer; + + return STATUS_SUCCESS; +} + +VOID +FxNPagedLookasideList::Reclaim( + __in FxMemoryBufferFromLookaside * Memory + ) +{ + _Reclaim(GetDriverGlobals(), &m_ObjectLookaside, Memory); +} + +FxNPagedLookasideListFromPool::FxNPagedLookasideListFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag + ) : FxLookasideListFromPool(FxDriverGlobals, sizeof(*this), PoolTag) +{ +} + +FxNPagedLookasideListFromPool::~FxNPagedLookasideListFromPool( + VOID + ) +{ + if (m_MemoryObjectSize != 0) { + ExDeleteNPagedLookasideList(&m_ObjectLookaside); + } + + if (m_BufferSize != 0) { + ExDeleteNPagedLookasideList(&m_PoolLookaside); + } +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideListFromPool::Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) +{ + NTSTATUS status; + + status = InitializeLookaside(0, + sizeof(FxMemoryBufferFromPoolLookaside), + MemoryAttributes); + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Initialize a non-paged pool with these characteristics. + // + ExInitializeNPagedLookasideList(&m_ObjectLookaside, + NULL, + NULL, + 0, + m_MemoryObjectSize, + m_PoolTag, + 0); + + m_BufferSize = BufferSize; + + // + // Initialize a non-paged pool with these characteristics. + // + // Free and Allocate are left intentionally NULL so that we use the Ex + // versions. We want to use the Ex versions because the allocations are >= + // PAGE_SIZE and we don't want to burn a whole page for pool tracking. + // + ExInitializeNPagedLookasideList(&m_PoolLookaside, + NULL, + NULL, + 0, + m_BufferSize, + m_PoolTag, + 0); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideListFromPool::Allocate( + __out FxMemoryObject** PPMemory + ) +{ + FxMemoryBufferFromPoolLookaside* pBuffer; + PVOID pObj, pBuf; + + // + // Allocate the object which will contain the 2ndary allocation + // + pObj = FxAllocateFromNPagedLookasideList(&m_ObjectLookaside); + + if (pObj == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + pObj = InitObjectAlloc(pObj); + + // + // Create the 2ndary allocation (the one the driver writer uses), what will + // be FxMemoryBufferFromPoolLookaside::m_Pool below. + // + pBuf = FxAllocateFromNPagedLookasideList(&m_PoolLookaside); + if (pBuf == NULL) { + // + // This case is safe because Reclaim doesn't treat the pointer as an + // object, rather it just performs pointer math and then frees the alloc + // + Reclaim((FxMemoryBufferFromPoolLookaside*) pObj); + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Construct a new FxMemoryBufferFromLookaside using the pool allocated + // above. + // + pBuffer = new(GetDriverGlobals(), pObj, &m_MemoryAttributes) + FxMemoryBufferFromPoolLookaside(GetDriverGlobals(), + this, + m_BufferSize, + pBuf); + + // + // pBuffer might be displaced if there is a debug extension + // + ASSERT(_GetBase(pBuffer) == pObj); + + *PPMemory = pBuffer; + + return STATUS_SUCCESS; +} + +VOID +FxNPagedLookasideListFromPool::Reclaim( + __in FxMemoryBufferFromLookaside * Memory + ) +{ + _Reclaim(GetDriverGlobals(), &m_ObjectLookaside, Memory); +} diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxrequestkm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxrequestkm.cpp new file mode 100644 index 00000000000..a5524e2d394 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxrequestkm.cpp @@ -0,0 +1,906 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestKm.cpp + +Abstract: + + This module implements KM specific FxRequest object routines + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestKm.tmh" +} + +VOID +FxRequest::CheckAssumptions( + VOID + ) +/*++ + +Routine Description: + This routine is never actually called by running code, it just has + WDFCASSERTs who upon failure, would not allow this file to be compiled. + + DO NOT REMOVE THIS FUNCTION just because it is not called by any running + code. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PWDF_REQUEST_PARAMETERS pWdfRequestParameters; + PIO_STACK_LOCATION pIoStackLocation; + + UNREFERENCED_PARAMETER(pWdfRequestParameters); + UNREFERENCED_PARAMETER(pIoStackLocation); + + // + // FxRequest::GetParameters relies on these being exactly the same size + // + WDFCASSERT(sizeof(pWdfRequestParameters->Parameters) == + sizeof(pIoStackLocation->Parameters)); + + // + // The address of the offset in the structure needs to be 8 bit aligned + // so that we can store flags in the bottom 3 bits + // + WDFCASSERT((FIELD_OFFSET(FxRequest, m_SystemBufferOffset) & FxHandleFlagMask) == 0); + WDFCASSERT((FIELD_OFFSET(FxRequest, m_OutputBufferOffset) & FxHandleFlagMask) == 0); + + WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.Length) == + FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.Length)); +} + + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetMdl( + __out PMDL *pMdl + ) +{ + WDF_DEVICE_IO_TYPE ioType; + ULONG length; + PVOID pBuffer; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + KIRQL irql; + PMDL pNewMdl; + UCHAR majorFunction; + + pBuffer = NULL; + length = 0; + pFxDriverGlobals = GetDriverGlobals(); + + Lock(&irql); + + // Verifier + if (pFxDriverGlobals->FxVerifierIO) { + + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + if(!NT_SUCCESS(status)) { + Unlock(irql); + return status; + } + } + + // + // See if we have an IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL + // + majorFunction = m_Irp.GetMajorFunction(); + + if( (majorFunction == IRP_MJ_DEVICE_CONTROL) || + (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) ) { + + switch (m_Irp.GetParameterIoctlCodeBufferMethod()) { + case METHOD_BUFFERED: + pBuffer = m_Irp.GetSystemBuffer(); + length = m_Irp.GetParameterIoctlInputBufferLength(); + + // Fall through to common buffer handler + break; + + case METHOD_IN_DIRECT: + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with read access + // + pBuffer = m_Irp.GetSystemBuffer(); + length = m_Irp.GetParameterIoctlInputBufferLength(); + + // Fall through to common buffer handler + break; + + case METHOD_OUT_DIRECT: + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with write access + // + pBuffer = m_Irp.GetSystemBuffer(); + length = m_Irp.GetParameterIoctlInputBufferLength(); + + // Fall through to common buffer handler + + break; + + case METHOD_NEITHER: + default: + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to get UserMode MDL for METHOD_NEITHER DeviceControl 0x%x, " + "WDFDEVICE 0x%p, WDFREQUEST 0x%p, %!STATUS!", + m_Irp.GetParameterIoctlCode(), + GetDevice()->GetHandle(), GetHandle(), status); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT " + "I/O for this call, or use " + "WdfDeviceInitSetIoInCallerContextCallback to probe " + "and lock user mode memory"); + + *pMdl = NULL; + Unlock(irql); + + return status; + } + } + else { + // + // It's a non-Device Control request, we must know the devices I/O type in + // order to safely return the correct buffer + // + ioType = GetDevice()->GetIoType(); + + if (ioType == WdfDeviceIoBuffered) { + + pBuffer = m_Irp.GetSystemBuffer(); + + // + // Must get the length depending on the request type code + // + if (majorFunction == IRP_MJ_READ) { + length = m_Irp.GetParameterReadLength(); + } + else if (majorFunction == IRP_MJ_WRITE) { + length = m_Irp.GetParameterWriteLength(); + } + else { + // + // Report the error, we can support other IRP_MJ_xxx codes are required + // later + // + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p no Automatic MDL mapping for buffered request" + "major function 0x%x available for WDFDEVICE 0x%p, %!STATUS!", + GetHandle(), majorFunction, GetDevice()->GetHandle(), + status); + + *pMdl = NULL; + + Unlock(irql); + + return status; + } + + // Fall through to common buffer handler + } + else if (ioType == WdfDeviceIoDirect) { + + // + // If driver has used the default DO_DIRECT_IO I/O Mgr has done all the work + // + *pMdl = m_Irp.GetMdl(); + + if (*pMdl == NULL) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p for a direct io device, PMDL is NULL, " + "%!STATUS!", GetHandle(), status); + } + else { + status = STATUS_SUCCESS; + } + + Unlock(irql); + + return status; + } + else if (ioType == WdfDeviceIoNeither) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to get UserMode Buffer Pointer for " + "WDFDEVICE 0x%p, WDFREQUEST 0x%p, %!STATUS!", + GetDevice()->GetHandle(), GetHandle(), status); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver must use buffered or direct I/O for this " + "call, or use WdfDeviceInitSetIoInCallerContextCallback " + "to probe and lock user mode memory"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + *pMdl = NULL; + Unlock(irql); + + return status; + } + else { + status = STATUS_INTERNAL_ERROR; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Unrecognized I/O Type %d on WDFDEVICE 0x%p, WDFREQUEST 0x%p, " + "%!STATUS!", + ioType, GetDevice()->GetHandle(), GetHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + *pMdl = NULL; + Unlock(irql); + + return status; + } + } + + // + // if pBuffer != NULL, attempt to generate an MDL for it + // + if( (pBuffer == NULL) || (length == 0) ) { + *pMdl = NULL; + Unlock(irql); + + status = STATUS_BUFFER_TOO_SMALL; + + if (pBuffer == NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, SystemBuffer is NULL, %!STATUS!", + GetHandle(), status); + } + else if (length == 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, SystemBuffer length is 0, %!STATUS!", + GetHandle(), status); + } + + return status; + } + + // + // See if we have already allocated an MDL for this + // + if( m_AllocatedMdl != NULL ) { + *pMdl = m_AllocatedMdl; + Unlock(irql); + return STATUS_SUCCESS; + } + + pNewMdl = FxMdlAllocate(pFxDriverGlobals, + this, + pBuffer, + length, + FALSE, + FALSE); + + if (pNewMdl == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Could not allocate MDL for buffer 0x%p Length %d, %!STATUS!", + pBuffer, length, status); + *pMdl = NULL; + Unlock(irql); + + return status; + } + + Mx::MxBuildMdlForNonPagedPool(pNewMdl); + + // + // We associated the Mdl with the request object + // so it can be freed when completed. + // + m_AllocatedMdl = pNewMdl; + + *pMdl = pNewMdl; + + Unlock(irql); + + return STATUS_SUCCESS; +} + + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetDeviceControlOutputMdl( + __out PMDL *pMdl + ) +/*++ + +Routine Description: + + Return the IRP_MJ_DEVICE_CONTROL OutputBuffer as an MDL + + The MDL is automatically released when the request is completed. + + The MDL is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or for any request other than IRP_MJ_DEVICE_CONTROL. + + The MDL is as follows for each buffering mode: + + METHOD_BUFFERED: + + MmBuildMdlForNonPagedPool(IoAllocateMdl(Irp->UserBuffer, ... )) + + METHOD_IN_DIRECT: + + Irp->MdlAddress + + METHOD_OUT_DIRECT: + + Irp->MdlAddress + + METHOD_NEITHER: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The MDL is only valid until the request is completed. + +Arguments: + + pMdl- Pointer location to return MDL ptr + +Returns: + + NTSTATUS + +--*/ +{ + ULONG length; + PVOID pBuffer; + KIRQL irql; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + PMDL pNewMdl; + UCHAR majorFunction; + + length = 0; + pBuffer = NULL; + pFxDriverGlobals = GetDriverGlobals(); + + Lock(&irql); + + // Verifier + if (pFxDriverGlobals->FxVerifierIO) { + + status = VerifyRequestIsNotCompleted(pFxDriverGlobals); + if (!NT_SUCCESS(status)) { + Unlock(irql); + return status; + } + } + + // + // See if we have an IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL + // + majorFunction = m_Irp.GetMajorFunction(); + + if( !((majorFunction == IRP_MJ_DEVICE_CONTROL) || + (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL)) ) { + status = STATUS_INVALID_DEVICE_REQUEST; + + // + // It's a non-Device Control request, which is an error for this call + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p (MajorFunction is 0x%x) this call is only valid for " + "IOCTLs, %!STATUS!", GetHandle(), majorFunction, status); + *pMdl = NULL; + + Unlock(irql); + + return status; + } + + switch (m_Irp.GetParameterIoctlCodeBufferMethod()) { + case METHOD_BUFFERED: + + pBuffer = m_Irp.GetSystemBuffer(); + length = m_Irp.GetParameterIoctlOutputBufferLength(); + + // Fall through to common buffer handler + break; + + case METHOD_IN_DIRECT: + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with read access + // + *pMdl = m_Irp.GetMdl(); + + if (*pMdl == NULL) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, METHOD_IN_DIRECT IOCTL, PMDL is NULL, " + "%!STATUS!", GetHandle(), status); + } + else { + status = STATUS_SUCCESS; + } + Unlock(irql); + + return status; + + case METHOD_OUT_DIRECT: + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with write access + // + *pMdl = m_Irp.GetMdl(); + + if (*pMdl == NULL) { + status = STATUS_BUFFER_TOO_SMALL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, METHOD_OUT_DIRECT IOCTL, PMDL is NULL, " + "%!STATUS!", GetHandle(), status); + } + else { + status = STATUS_SUCCESS; + } + Unlock(irql); + + return status; + + case METHOD_NEITHER: + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Attempt to get UserMode Buffer Pointer for METHOD_NEITHER " + "DeviceControl 0x%x, WDFDEVICE 0x%p, WDFREQUEST 0x%p, %!STATUS!", + m_Irp.GetParameterIoctlCode(), + GetDevice()->GetHandle(), GetHandle(), status); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Driver must use METHOD_BUFFERED or METHOD_xx_DIRECT I/O for this " + "call, or use WdfDeviceInitSetIoInCallerContextCallback to probe " + "and lock user mode memory"); + + *pMdl = NULL; + Unlock(irql); + + return status; + } + + // + // if pBuffer != NULL, attempt to generate an MDL for it + // + if( (pBuffer == NULL) || (length == 0) ) { + *pMdl = NULL; + + Unlock(irql); + + status = STATUS_BUFFER_TOO_SMALL; + + if (pBuffer == NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, SystemBuffer is NULL, %!STATUS!", + GetHandle(), status); + } + else if (length == 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, SystemBuffer length is 0, %!STATUS!", + GetHandle(), status); + } + + return status; + } + + // + // See if we have already allocated an MDL for this + // + if( m_AllocatedMdl != NULL ) { + *pMdl = m_AllocatedMdl; + Unlock(irql); + + return STATUS_SUCCESS; + } + + pNewMdl= FxMdlAllocate(pFxDriverGlobals, + this, + pBuffer, + length, + FALSE, + FALSE); + + if (pNewMdl == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p could not allocate MDL for buffer 0x%p Length %d, " + "%!STATUS!", GetHandle(), pBuffer, length, status); + *pMdl = NULL; + Unlock(irql); + + return status; + } + + Mx::MxBuildMdlForNonPagedPool(pNewMdl); + + // + // We associated the Mdl with the request object + // so it can be freed when completed. + // + m_AllocatedMdl = pNewMdl; + + *pMdl = pNewMdl; + + Unlock(irql); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::ProbeAndLockForRead( + __in PVOID Buffer, + __in ULONG Length, + __deref_out FxRequestMemory** MemoryObject + ) + +/*++ + +Routine Description: + + Probe and lock a memory buffer for reading. + + This is to be called in the proper process context, and + will generate an FxRequestMemory object if successful. + + The FxRequestMemory object will be associated with the FxRequest + object, and is automatically released when the FxRequest is completed. + + This function performs validation to ensure that the current + thread is in the same process as the thread that originated + the I/O request. + +Arguments: + + + Buffer - Buffer to lock down + + Length - Length of buffer + + MemoryObject - FxRequestMemory object to return + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + PMDL pMdl; + PIRP irp; + PVOID pVA; + FxRequestMemory* pMemory; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pMdl = NULL; + pMemory = NULL; + pFxDriverGlobals = GetDriverGlobals(); + + if (Length == 0) { + status = STATUS_INVALID_USER_BUFFER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Length of zero not allowed, %!STATUS!", status); + + return status; + } + + irp = m_Irp.GetIrp(); + + if (irp == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + // Error, completed request + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p has already been completed or has no PIRP assignment," + " %!STATUS!", GetObjectHandle(), status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return status; + } + + // + // Look at the Irp, and if there is a thread field, validate we are + // actually in the correct process! + // + status = VerifyProbeAndLock(pFxDriverGlobals); + if(!NT_SUCCESS(status) ) { + return status; + } + + pMdl = FxMdlAllocate(pFxDriverGlobals, this, Buffer, Length, FALSE, TRUE); + + if (pMdl == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Failed to allocate MDL %!STATUS!", status); + return status; + } + + // Use a C utility function for the probe due to C++ exception handling issues + status = FxProbeAndLockForRead(pMdl, UserMode); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Exception is raised for Address 0x%p, Length %d %!STATUS!", + Buffer, Length, status); + FxMdlFree(pFxDriverGlobals, pMdl); + return status; + } + + // + // Get a system address for the MDL + // + pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority); + if (pVA == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // Build an FxRequestMemory object now + status = FxRequestMemory::Create(pFxDriverGlobals, NULL, &pMemory); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // Associate the FxRequestMemory object with the FxRequest + status = pMemory->Commit(NULL, NULL, this); + if (!NT_SUCCESS(status)) { + goto Done; + } + +Done: + if (NT_SUCCESS(status)) { + // + // If we re-define the WDFMEMORY interfaces to allow + // failure for get buffer, we could delay the assignment + // of SystemAddressForMdl and its PTE's until the driver + // actually requests a double buffer mapping. + // + // Some DMA drivers may just retrieve the MDL from the WDFMEMORY + // and not even attempt to access the underlying bytes, other + // than through hardware DMA. + // + pMemory->SetMdl( + this, + pMdl, + pVA, + Length, + TRUE // Readonly + ); + + *MemoryObject = pMemory; + } + else { + if (pMemory != NULL) { + pMemory->DeleteFromFailedCreate(); + } + + Mx::MxUnlockPages(pMdl); + FxMdlFree(pFxDriverGlobals, pMdl); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::ProbeAndLockForWrite( + __in PVOID Buffer, + __in ULONG Length, + __deref_out FxRequestMemory** MemoryObject + ) + +/*++ + +Routine Description: + + Probe and lock a memory buffer for writing. + + This is to be called in the proper process context, and + will generate an FxRequestMemory object if successful. + + The FxRequestMemory object will be associated with the FxRequest + object, and is automatically released when the FxRequest is completed. + + This function performs validation to ensure that the current + thread is in the same process as the thread that originated + the I/O request. + +Arguments: + + + Buffer - Buffer to lock down + + Length - Length of buffer + + MemoryObject - FxRequestMemory object to return + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + PMDL pMdl; + PIRP irp; + PVOID pVA; + FxRequestMemory* pMemory; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pMdl = NULL; + pMemory = NULL; + pFxDriverGlobals = GetDriverGlobals(); + + if (Length == 0) { + status = STATUS_INVALID_USER_BUFFER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Length of zero not allowed, %!STATUS!", status); + + return status; + } + + irp = m_Irp.GetIrp(); + + if (irp == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + // Error, completed request + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST %p has already been completed or has no PIRP assignment," + " %!STATUS!", GetObjectHandle(), status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return status; + } + + // + // Look at the Irp, and if there is a thread field, validate we are + // actually in the correct process! + // + status = VerifyProbeAndLock(pFxDriverGlobals); + if(!NT_SUCCESS(status) ) { + return status; + } + + pMdl = FxMdlAllocate(pFxDriverGlobals, this, Buffer, Length, FALSE, TRUE); + if (pMdl == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Failed to allocate MDL %!STATUS!", status); + return status; + } + + // Use a C utility function for the probe due to C++ exception handling issues + status = FxProbeAndLockForWrite(pMdl, UserMode); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "Exception is raised for Address 0x%p, Length %d %!STATUS!", + Buffer, Length, status); + FxMdlFree(pFxDriverGlobals, pMdl); + return status; + } + + // + // Get a system address for the MDL + // + pVA = Mx::MxGetSystemAddressForMdlSafe(pMdl, NormalPagePriority); + if (pVA == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // Build an FxRequestMemory object now + status = FxRequestMemory::Create(pFxDriverGlobals, NULL, &pMemory); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // Associate the FxRequestMemory object with the FxRequest + status = pMemory->Commit(NULL, NULL, this); + if (!NT_SUCCESS(status)) { + goto Done; + } + +Done: + if (NT_SUCCESS(status)) { + // + // If we re-define the WDFMEMORY interfaces to allow + // failure for get buffer, we could delay the assignment + // of SystemAddressForMdl and its PTE's until the driver + // actually requests a double buffer mapping. + // + // Some DMA drivers may just retrieve the MDL from the WDFMEMORY + // and not even attempt to access the underlying bytes, other + // than through hardware DMA. + // + pMemory->SetMdl( + this, + pMdl, + pVA, + Length, + FALSE // FALSE indicates not a readonly buffer + ); + + *MemoryObject = pMemory; + } + else { + if (pMemory != NULL) { + pMemory->DeleteFromFailedCreate(); + } + + Mx::MxUnlockPages(pMdl); + FxMdlFree(pFxDriverGlobals, pMdl); + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/km/fxrequestsystembufferkm.cpp b/sdk/lib/drivers/wdf/shared/core/km/fxrequestsystembufferkm.cpp new file mode 100644 index 00000000000..56d62483608 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/km/fxrequestsystembufferkm.cpp @@ -0,0 +1,93 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestSystemBuffer.cpp + +Abstract: + + This module implements class representing the system buffer in an FxRequest + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestSystemBufferKm.tmh" +} + +_Must_inspect_result_ +PVOID +FxRequestSystemBuffer::GetBuffer( + VOID + ) +/*++ + +Routine Description: + Returns the system buffer that has been cached away by the call to SetBuffer() + +Arguments: + None + +Return Value: + Valid memory or NULL on error + + --*/ +{ + FxDevice* pDevice; + FxIrp* irp = GetRequest()->GetFxIrp(); + WDF_DEVICE_IO_TYPE ioType; + + switch (irp->GetMajorFunction()) { + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + return m_Buffer; + + case IRP_MJ_READ: + case IRP_MJ_WRITE: + pDevice = FxDevice::GetFxDevice(irp->GetDeviceObject()); + ioType = pDevice->GetIoType(); + + switch (ioType) { + case WdfDeviceIoBuffered: + return m_Buffer; + + case WdfDeviceIoDirect: + // + // FxRequest::GetMemoryObject has already called MmGetSystemAddressForMdlSafe + // and returned success, so we know that we can safely call + // MmGetSystemAddressForMdlSafe again to get a valid VA pointer. + // + return Mx::MxGetSystemAddressForMdlSafe(m_Mdl, NormalPagePriority); + + case WdfDeviceIoNeither: + return m_Buffer; + + default: + ASSERT(FALSE); + return NULL; + } + + default: + ASSERT(FALSE); + return NULL; + } +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdeviceapium.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceapium.cpp new file mode 100644 index 00000000000..4ab562e3408 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceapium.cpp @@ -0,0 +1,1462 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceApiUm.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" +#include "fxiotarget.hpp" +#include + +extern "C" { +#include "FxDeviceApiUm.tmh" +} + +// +// extern "C" the entire file +// +extern "C" { + +// +// Verifier Functions +// +// Do not specify argument names +FX_DECLARE_VF_FUNCTION_P4( +NTSTATUS, +VerifyWdfDeviceWdmDispatchIrpToIoQueue, + _In_ FxDevice*, + _In_ MdIrp, + _In_ FxIoQueue*, + _In_ ULONG + ); + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDevicePostEvent)( + _In_ PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ WDFDEVICE Device, + _In_ REFGUID EventGuid, + _In_ WDF_EVENT_TYPE WdfEventType, + _In_reads_bytes_(DataSizeCb) BYTE * Data, + _In_ ULONG DataSizeCb + ) +/*++ + +Routine Description: + + This method asynchronously notifies applications that are waiting for the + specified event from a driver. + +Arguments: + Device - WDF Device handle. + + EventGuid: The GUID for the event. The GUID is determined by the application + and the driver and is opaque to the framework. + + EventType: A WDF_EVENT_TYPE-typed value that identifies the type of + event. In the current version of UMDF, the driver must set EventType + to WdfEventBroadcast (1). WdfEventBroadcast indicates that the event + is broadcast. Applications can subscribe to WdfEventBroadcast-type + events. To receive broadcast events, the application must register + for notification through the Microsoft Win32 + RegisterDeviceNotification function. WdfEventBroadcast-type events + are exposed as DBT_CUSTOMEVENT-type events to applications. + + Data: A pointer to a buffer that contains data that is associated with the + event. NULL is a valid value. + + DataSizeCb : The size, in bytes, of data that Data points to. Zero is a + valid size value if Data is set to NULL. + +Return Value: + An NTSTATUS value that denotes success or failure of the DDI + +--*/ +{ + DDI_ENTRY(); + + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + HRESULT hr; + + // + // 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); + + if (DataSizeCb > 0) { + FxPointerNotNull(pFxDriverGlobals, Data); + } + + // + // Currently only broadcast events are supported. + // + if (WdfEventType != WdfEventBroadcast) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p WdfEventType %d not expected %!STATUS!", + Device, WdfEventType, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // post the event + // + hr = pDevice->GetDeviceStack()->PostEvent(EventGuid, + WdfEventType, + Data, + DataSizeCb); + + if (FAILED(hr)) { + status = FxDevice::NtStatusFromHr(pDevice->GetDeviceStack(), hr); + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE 0x%p Failed to post event %!STATUS!", + Device, status); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceMapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PHYSICAL_ADDRESS PhysicalAddress, + _In_ + SIZE_T NumberOfBytes, + _In_ + MEMORY_CACHING_TYPE CacheType, + _Out_ + PVOID* PseudoBaseAddress + ) +/*++ + +Routine Description: + + This routine maps given physical address of a device register into + system address space and optionally into user-mode address space. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PhysicalAddress - Address of MMIO register to be mapped + + NumberOfBytes - Length of resource to be mapped in bytes. + + CacheType - supplies type of caching desired + + PseudoBaseAddress - Pseudo base address (opaque base address) of the + mapped resource. + +Return Value: + + HRESULT + +--*/ +{ + DDI_ENTRY(); + + FxCmResList* transResources; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + HRESULT hr; + + // + // 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); + + // + // Is direct hardware access allowed? + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, + (pDevice->IsDirectHardwareAccessAllowed() == TRUE)), + DriverGlobals->DriverName); + + // + // Validate input parameters. + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(PhysicalAddress.QuadPart), + DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("NumberOfBytes should be > 0", + (NumberOfBytes > 0)), DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("CacheType incorrect", + (CacheType >= MmNonCached && + CacheType < MmMaximumCacheType)), + DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(PseudoBaseAddress), + DriverGlobals->DriverName); + + *PseudoBaseAddress = NULL; + transResources = pDevice->GetTranslatedResources(); + hr = transResources->MapIoSpaceWorker(PhysicalAddress, + NumberOfBytes, + CacheType, + PseudoBaseAddress); + if (FAILED(hr)) { + status = pDevice->NtStatusFromHr(hr); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceUnmapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress, + _In_ + SIZE_T NumberOfBytes + ) +/*++ + +Routine Description: + + This routine unmaps a previously mapped register resource. + +Arguments: + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PseudoBaseAddress - Address to be unmapped + + NumberOfBytes - Length of resource to be mapped in bytes. + +Return Value: + + VOID + +--*/ +{ + DDI_ENTRY(); + + IWudfDeviceStack *deviceStack; + HRESULT hr; + FxCmResList* resources; + PVOID systemBaseAddress; + 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); + + // + // Is direct hardware access allowed? + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, + (pDevice->IsDirectHardwareAccessAllowed() == TRUE)), + DriverGlobals->DriverName); + + // + // Validate input parameters. + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(PseudoBaseAddress), + DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("NumberOfBytes should be > 0", + (NumberOfBytes > 0)), DriverGlobals->DriverName); + // + // Get system address. + // + systemBaseAddress = pDevice->GetSystemAddressFromPseudoAddress(PseudoBaseAddress); + + // + // Validate that caller has given correct base address and length, and if + // so clear the mapping from resource table + // + resources = pDevice->GetTranslatedResources(); + hr = resources->ValidateAndClearMapping(systemBaseAddress, + NumberOfBytes); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Driver attempted to unmap " + "incorrect register address, or provided incorrect size", + SUCCEEDED(hr)), DriverGlobals->DriverName); + + // + // call host + // + if SUCCEEDED(hr) { + deviceStack = pDevice->GetDeviceStack(); + + deviceStack->UnmapIoSpace(systemBaseAddress, NumberOfBytes); + } + + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PVOID +WDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress + ) +/*++ + +Routine Description: + + This routine returns user-mode base address where registers corresponing + to supplied pseudo base address have been mapped.. + +Arguments: + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PseudoBaseAddress - Pseudo base address for which the caller needs to get + user-mode mapped address. + +Return Value: + + User-mode mapped base address. + +--*/ +{ + DDI_ENTRY(); + + HRESULT hr; + FxCmResList* transResources; + PVOID usermodeBaseAddress; + PVOID systemBaseAddress; + 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); + + // + // Is direct hardware access allowed? + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, + (pDevice->IsDirectHardwareAccessAllowed() == TRUE)), + DriverGlobals->DriverName); + + // + // Is user-mode mapping of registers enabled + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Incorrect register access mode." + " Register mapping to user-mode is not enabled. Set the INF directive" + " UmdfRegisterAccessMode to RegisterAccessUsingUserModeMapping" + " in driver's INF file to enable Register mapping to user-mode", + (pDevice->AreRegistersMappedToUsermode() == TRUE)), DriverGlobals->DriverName); + + // + // Validate input parameters. + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(PseudoBaseAddress), + DriverGlobals->DriverName); + + // + // check if this base address is valid. + // + usermodeBaseAddress = NULL; + transResources = pDevice->GetTranslatedResources(); + systemBaseAddress = pDevice->GetSystemAddressFromPseudoAddress(PseudoBaseAddress); + + hr = transResources->ValidateRegisterSystemBaseAddress(systemBaseAddress, + &usermodeBaseAddress); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Driver provided incorrect base " + "address", SUCCEEDED(hr)), DriverGlobals->DriverName); + + return usermodeBaseAddress; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +SIZE_T +WDFAPI +WDFEXPORT(WdfDeviceReadFromHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _Out_writes_all_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ) +/*++ + +Routine Description: + + This routine does read from a device port or register. + +Arguments: + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + Type - Specified whether it is port or register + + Size - Supplies size of read in bytes. + + TargetAddress - Supplies address of port or register to read from + + Buffer - Supplies optionally a buffer to receive the read data + + Count - Size of buffer in bytes + +Return Value: + + Returns the read value if it is non-buffered port or register. + Otherwise zero. + +--*/ +{ + DDI_ENTRY(); + + SIZE_T value = 0; + PVOID systemAddress = NULL; + HRESULT hr = S_OK; + SIZE_T length = 0; + FxCmResList* resources; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + + // + // ETW event for perf measurement + // + EventWriteEVENT_UMDF_FX_DDI_READ_FROM_HARDWARE_START(Type, Size, Count); + + // + // 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); + + // + // See if direct hwaccess is allowed + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, + (pDevice->IsDirectHardwareAccessAllowed() == TRUE)), + DriverGlobals->DriverName); + + // + // validate parameters + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Incorrect Type parameter", + (Type > WdfDeviceHwAccessTargetTypeInvalid && + Type < WdfDeviceHwAccessTargetTypeMaximum)), + DriverGlobals->DriverName); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Incorrect Size parameter", + (Size > WdfDeviceHwAccessTargetSizeInvalid && + Size < WdfDeviceHwAccessTargetSizeMaximum)), + DriverGlobals->DriverName); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(TargetAddress), + DriverGlobals->DriverName); + + if (pDevice->IsBufferType(Type)) { + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(Buffer), DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Count should be > 0", (Count > 0)), + DriverGlobals->DriverName); + } + else { + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NULL(Buffer), DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Count should be 0", (Count == 0)), + DriverGlobals->DriverName); + } + +#if !defined(_WIN64) + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("ULONG64 write is allowed only" + "on 64-bit platform", (Size != WdfDeviceHwAccessTargetSizeUlong64)), + DriverGlobals->DriverName); +#endif + + // + // get system address from pseudo address for registers + // + if (pDevice->IsRegister(Type)){ + systemAddress = pDevice->GetSystemAddressFromPseudoAddress(TargetAddress); + } + + length = pDevice->GetLength(Size); + + // + // For buffer access for registers, compute the length of buffer using Count. + // Count is the element count in the buffer (of UCHAR/USHORT/ULONG/ULONG64). + // Note that Port is accessed differently than registers - the buffer is + // written into the port address of specified size (UCHAR/USHORT/ULONG). + // + if (pDevice->IsBufferType(Type) && pDevice->IsRegister(Type)) { + size_t tmp; + + hr = SizeTMult(Count, length, &tmp); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred " + "when computing length of read access", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + + length = tmp; + } + + resources = pDevice->GetTranslatedResources(); + + // + // Port access is always handled through system call. + // Register access can be handled in usermode if driver enabled + // mapping registers to usermode. + // + if (pDevice->AreRegistersMappedToUsermode() && pDevice->IsRegister(Type)) { + PVOID umAddress = NULL; + + // + // Acquire the resource validation table lock for read/write as well + // since a driver's thread accessing hardware register/port and + // race with Map/Unmap operations. + // + resources->LockResourceTable(); + + hr = resources->ValidateRegisterSystemAddressRange(systemAddress, + length, + &umAddress); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Driver attempted to read from invalid register address or " + "address range", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + + if (pDevice->IsBufferType(Type)) { + pDevice->ReadRegisterBuffer(Size, umAddress, Buffer, Count); + } + else { + value = pDevice->ReadRegister(Size, umAddress); + } + + resources->UnlockResourceTable(); + } + else { + // + // Registers are not mapped to user-mode address space so send + // message to reflector to use system HAL routines to access register. + // Acquire validation table lock here as well since some read/write + // thread might race with PrepareHardware/ReleaseHardware that may be + // building/deleting the table. + // + IWudfDeviceStack *deviceStack; + + resources->LockResourceTable(); + + if (pDevice->IsRegister(Type)) { + hr = resources->ValidateRegisterSystemAddressRange(systemAddress, + length, + NULL); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Driver attempted to read from invalid register address " + "or address range", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + } + else { + hr = resources->ValidatePortAddressRange(TargetAddress, + length); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Driver attempted to read from invalid port address or " + "address range", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + } + + resources->UnlockResourceTable(); + + deviceStack = pDevice->GetDeviceStack(); + deviceStack->ReadFromHardware((UMINT::WDF_DEVICE_HWACCESS_TARGET_TYPE)Type, + (UMINT::WDF_DEVICE_HWACCESS_TARGET_SIZE)Size, + TargetAddress, + &value, + Buffer, + Count); + } + + // + // ETW event for perf measurement + // + EventWriteEVENT_UMDF_FX_DDI_READ_FROM_HARDWARE_END(Type, Size, Count); + + return value; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfDeviceWriteToHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _In_ + SIZE_T Value, + _In_reads_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ) +/*++ + +Routine Description: + + This routine does writes to a device port or register. + +Arguments: + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + Type - Specified whether it is port or register + + Size - Supplies size of read in bytes. + + TargetAddress - Supplies address of port or register to read from + + Value - value to write + + Buffer - Supplies optionally a buffer that has data that needs to be + written. + + Count - Size of buffer in bytes + +Return Value: + + void + +--*/ +{ + DDI_ENTRY(); + + PVOID systemAddress = NULL; + FxCmResList* resources; + HRESULT hr = S_OK; + SIZE_T length = 0; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + + // + // ETW event for perf measurement + // + EventWriteEVENT_UMDF_FX_DDI_WRITE_TO_HARDWARE_START(Type, Size, Count); + + // + // 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); + + // + // See if direct hwaccess is allowed + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, + (pDevice->IsDirectHardwareAccessAllowed() == TRUE)), + DriverGlobals->DriverName); + + // + // validate parameters + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Incorrect Type parameter", + (Type > WdfDeviceHwAccessTargetTypeInvalid && + Type < WdfDeviceHwAccessTargetTypeMaximum)), + DriverGlobals->DriverName); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Incorrect Size parameter", + (Size > WdfDeviceHwAccessTargetSizeInvalid && + Size < WdfDeviceHwAccessTargetSizeMaximum)), + DriverGlobals->DriverName); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(TargetAddress), + DriverGlobals->DriverName); + + if (pDevice->IsBufferType(Type)) { + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(Buffer), + DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Count should be > 0", (Count > 0)), + DriverGlobals->DriverName); + } + else { + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NULL(Buffer), DriverGlobals->DriverName); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Count should be 0", (Count == 0)), + DriverGlobals->DriverName); + } + +#if !defined(_WIN64) + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("ULONG64 write is allowed only" + "on 64-bit platform", (Size != WdfDeviceHwAccessTargetSizeUlong64)), + DriverGlobals->DriverName); +#endif + + // + // get system address from pseudo address for registers + // + if (pDevice->IsRegister(Type)){ + systemAddress = pDevice->GetSystemAddressFromPseudoAddress(TargetAddress); + } + + length = pDevice->GetLength(Size); + + // + // For buffer access for registers, compute the length of buffer using Count. + // Count is the element count in the buffer (of UCHAR/USHORT/ULONG/ULONG64). + // Note that Port is accessed differently than registers - the buffer is + // written into the port address of specified size (UCHAR/USHORT/ULONG). + // + if (pDevice->IsBufferType(Type) && pDevice->IsRegister(Type)) { + size_t tmp; + + hr = SizeTMult(Count, length, &tmp); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred " + "when computing length of write access", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + + length = tmp; + } + + resources = pDevice->GetTranslatedResources(); + + // + // Port access is always handled through system call. + // Register access can be handled in usermode if driver enabled + // mapping registers to usermode. + // + if (pDevice->AreRegistersMappedToUsermode() && pDevice->IsRegister(Type)) { + PVOID umAddress = NULL; + + // + // Acquire the resource validation table lock for read/write as well + // since a driver's thread accessing hardware register/port and + // race with Map/Unmap operations. + // + resources->LockResourceTable(); + + + hr = resources->ValidateRegisterSystemAddressRange(systemAddress, + length, + &umAddress); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Driver attempted to write to invalid register address or " + "address range", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + + if (pDevice->IsBufferType(Type)) { + pDevice->WriteRegisterBuffer(Size, umAddress, Buffer, Count); + } + else { + pDevice->WriteRegister(Size, umAddress, Value); + } + + resources->UnlockResourceTable(); + } + else { + // + // Registers are not mapped to user-mode address space so send + // message to reflector to use system HAL routines to access register. + // Acquire validation table lock here as well since some read/write + // thread might race with PrepareHardware/ReleaseHardware that may be + // building/deleting the table. + // + IWudfDeviceStack *deviceStack; + + resources->LockResourceTable(); + + if (pDevice->IsRegister(Type)) { + hr = resources->ValidateRegisterSystemAddressRange(systemAddress, + length, + NULL); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Driver attempted to write to invalid register address " + "or address range", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + + } + else { + hr = resources->ValidatePortAddressRange(TargetAddress, + length); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Driver attempted to write to invalid port address or " + "address range", (SUCCEEDED(hr))), + DriverGlobals->DriverName); + } + + resources->UnlockResourceTable(); + + deviceStack = pDevice->GetDeviceStack(); + deviceStack->WriteToHardware((UMINT::WDF_DEVICE_HWACCESS_TARGET_TYPE)Type, + (UMINT::WDF_DEVICE_HWACCESS_TARGET_SIZE)Size, + TargetAddress, + Value, + Buffer, + Count); + } + + // + // ETW event for perf measurement + // + EventWriteEVENT_UMDF_FX_DDI_WRITE_TO_HARDWARE_END(Type, Size, Count); + + return; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignInterfaceProperty) ( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG BufferLength, + _In_opt_ + PVOID PropertyBuffer + ) +/*++ + +Routine Description: + + This routine assigns interface property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PropertyData - A pointer to WDF_DEVICE_INTERFACE_PROPERTY_ DATA structure. + + Type - Set this parameter to the DEVPROPTYPE value that specifies the type + of the data that is supplied in the Data buffer. + + BufferLength - Specifies the length, in bytes, of the buffer that + PropertyBuffer points to. + + PropertyBuffer - optional, A pointer to the device interface property data. + Set this parameter to NULL to delete the specified property. + +Return Value: + + Mthod returns an NTSTATUS value. This routine might return one of the + following values. It might return other NTSTATUS-codes as well. + + STATUS_SUCCESS - The operation succeeded. + STATUS_INVALID_PARAMETER - One of the parameters is incorrect. + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice *pDevice; + NTSTATUS status; + + // + // 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); + + // + // Validate PropertyData + // + status = pDevice->FxValidateInterfacePropertyData(PropertyData); + if (!NT_SUCCESS(status)) { + return status; + } + + if (BufferLength == 0 && PropertyBuffer != NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Property buffer size is zero, while the buffer is non-NULL" + ", %!STATUS!", status); + return status; + } + + status = pDevice->AssignProperty(PropertyData, + FxInterfaceProperty, + Type, + BufferLength, + PropertyBuffer + ); + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty) ( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +/*++ + +Routine Description: + + This routine queries interface property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PropertyData - A pointer to WDF_DEVICE_INTERFACE_PROPERTY_ DATA structure. + + PoolType - A POOL_TYPE-typed enumerator that specifies the type of memory + to be allocated. + + PropertyMemoryAttributes - optional, A pointer to a caller-allocated + WDF_OBJECT_ATTRIBUTES structure that describes object attributes + for the memory object that the function will allocate. This + parameter is optional and can be WDF_NO_OBJECT_ATTRIBUTES. + + PropertyMemory - A pointer to a WDFMEMORY-typed location that receives a + handle to a framework memory object. + + Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves + the property data, the routine writes the property type value to + this variable. This value indicates the type of property data + that is in the Data buffer. + + +Return Value: + + Method returns an NTSTATUS value. This routine might return one of the + following values. It might return other NTSTATUS-codes as well. + + STATUS_SUCCESS The operation succeeded. + STATUS_INVALID_PARAMETER One of the parameters is incorrect. + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + // + // Validate PropertyData + // + status = pDevice->FxValidateInterfacePropertyData(PropertyData); + if (!NT_SUCCESS(status)) { + return status; + } + + FxPointerNotNull(pFxDriverGlobals, PropertyMemory); + FxPointerNotNull(pFxDriverGlobals, Type); + + *PropertyMemory = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxDevice::_AllocAndQueryPropertyEx(pFxDriverGlobals, + NULL, + pDevice, + PropertyData, + FxInterfaceProperty, + PoolType, + PropertyMemoryAttributes, + PropertyMemory, + Type); + return status; +} + + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryInterfaceProperty) ( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE PropertyType + ) +/*++ + +Routine Description: + + This routine queries interface property. + +Arguments: + + DriverGlobals - DriverGlobals pointer + + Device - WDF Device handle. + + PropertyData - A pointer to WDF_DEVICE_INTERFACE_PROPERTY_ DATA structure. + + BufferLength - The size, in bytes, of the buffer that is pointed to by + PropertyBuffer. + + PropertyBuffer - A caller-supplied pointer to a caller-allocated buffer that + receives the requested information. The pointer can be NULL + if the BufferLength parameter is zero. + + ResultLength - A caller-supplied location that, on return, contains the + size, in bytes, of the information that the method stored in + PropertyBuffer. If the function's return value is + STATUS_BUFFER_TOO_SMALL, this location receives the required + buffer size. + + Type - A pointer to a DEVPROPTYPE variable. If method successfully retrieves + the property data, the routine writes the property type value + to this variable. This value indicates the type of property + data that is in the Data buffer. + +Return Value: + + Method returns an NTSTATUS value. This routine might return one of the + following values. + + STATUS_BUFFER_TOO_SMALL - The supplied buffer is too small to receive the + information. The ResultLength member receives the + size of buffer required. + STATUS_SUCCESS - The operation succeeded. + STATUS_INVALID_PARAMETER - One of the parameters is incorrect. + + The method might return other NTSTATUS values. + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + // + // Validate PropertyData + // + status = pDevice->FxValidateInterfacePropertyData(PropertyData); + if (!NT_SUCCESS(status)) { + return status; + } + + FxPointerNotNull(pFxDriverGlobals, ResultLength); + FxPointerNotNull(pFxDriverGlobals, PropertyType); + + if (BufferLength != 0 && PropertyBuffer == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Property buffer size is non-zero, while the buffer is NULL" + ", %!STATUS!", status); + return status; + } + + if (BufferLength == 0 && PropertyBuffer != NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Property buffer size is zero, while the buffer is non-NULL" + ", %!STATUS!", status); + return status; + } + + status = FxDevice::_QueryPropertyEx(pFxDriverGlobals, + NULL, + pDevice, + PropertyData, + FxInterfaceProperty, + BufferLength, + PropertyBuffer, + ResultLength, + PropertyType); + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceGetDeviceStackIoType) ( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + WDF_DEVICE_IO_TYPE* ReadWriteIoType, + _Out_ + WDF_DEVICE_IO_TYPE* IoControlIoType + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ReadWriteIoType); + FxPointerNotNull(pFxDriverGlobals, IoControlIoType); + + pDevice->GetDeviceStackIoType( + ReadWriteIoType, + IoControlIoType + ); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceHidNotifyPresence)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN IsPresent + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + HRESULT hr; + FxDevice* pDevice; + IWudfDeviceStack* pDevStack; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *)&pDevice, + &pFxDriverGlobals); + + pDevStack = pDevice->m_DevStack; + + hr = pDevStack->HidNotifyPresence(IsPresent); + status = FxDevice::NtStatusFromHr(pDevStack, hr); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "HidNotifyPresence(%s) failed, %!STATUS! - Make sure to call " + "WdfDeviceInitEnableHidInterface in EvtDriverDeviceAdd " + "before calling WdfDeviceHidNotifyPresence.", + IsPresent ? "TRUE" : "FALSE", status); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFFILEOBJECT +WDFEXPORT(WdfDeviceGetFileObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + MdFileObject FileObject + ) +/*++ + +Routine Description: + + This functions returns the WDFFILEOBJECT corresponding to the WDM fileobject. + +Arguments: + + Device - Handle to the device to which the WDM fileobject is related to. + + FileObject - WDM FILE_OBJECT structure. + +Return Value: + +--*/ + +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(FileObject); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + TRAPMSG("The DDI WdfDeviceGetFileObject is not supported for UMDF"), + DriverGlobals->DriverName); + + return NULL; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + MdIrp Irp, + __in + WDFQUEUE Queue, + __in + ULONG Flags + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDevice* pDevice; + FxIoQueue* pQueue; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + FxPointerNotNull(pFxDriverGlobals, Irp); + + FxIrp fxIrp(Irp); + + // + // Unlike in KMDF, It's not possible for UMDF to forward to a parent queue. + // + ASSERT(pDevice->m_ParentDevice != pQueue->GetDevice()); + + status = VerifyWdfDeviceWdmDispatchIrpToIoQueue(pFxDriverGlobals, + pDevice, + Irp, + pQueue, + Flags); + if (!NT_SUCCESS(status)) { + + fxIrp.SetStatus(status); + fxIrp.SetInformation(0x0); + fxIrp.CompleteRequest(IO_NO_INCREMENT); + + return status; + } + + // + // DispatchStep2 will convert the IRP to a WDFRequest and queue it, dispatching + // the request to the driver if possible. + // + return pDevice->m_PkgIo->DispatchStep2(reinterpret_cast(Irp), + NULL, + pQueue); +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP pIrp, + _In_ + WDFCONTEXT DispatchContext + ) + +/*++ + +Routine Description: + + This DDI returns control of the IRP to the framework. + This must only be called from the dispatch callback passed to + WdfDeviceConfigureWdmIrpDispatchCallback + + +Arguments: + + Device - Handle to the I/O device. + + pIrp - Opaque handle to a _WUDF_IRP_WITH_VALIDATION structure. + + DispatchContext - Framework dispatch context passed as a parameter to the + dispatch callback. + +Returns: + + IRP's status. + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID *) &pDevice, + &pFxDriverGlobals); + + // + // Validate parameters and dispatch state. DispatchContext has already been + // validated in DispatchStep1. + // + FxPointerNotNull(pFxDriverGlobals, pIrp); + FxPointerNotNull(pFxDriverGlobals, DispatchContext); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("This function must be called from within a " + "EVT_WDFDEVICE_WDM_IRP_DISPATCH callback", + ((UCHAR)DispatchContext & FX_IN_DISPATCH_CALLBACK)), + DriverGlobals->DriverName); + + // + // Adjust this context + // + DispatchContext = (WDFCONTEXT)((ULONG_PTR)DispatchContext & ~FX_IN_DISPATCH_CALLBACK); + + // + // Cast this pIrp back to its composite parts and dispatch it again + // + return pDevice->m_PkgIo->DispatchStep1(reinterpret_cast(pIrp), + DispatchContext); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdevicebaseum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdevicebaseum.cpp new file mode 100644 index 00000000000..18952013d8a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdevicebaseum.cpp @@ -0,0 +1,81 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceBaseUm.cpp + +Abstract: + + This is the class implementation for the base device class. + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceBaseUm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceBase::QueryForInterface( + __in const GUID* InterfaceType, + __out PINTERFACE Interface, + __in USHORT Size, + __in USHORT Version, + __in PVOID InterfaceSpecificData, + __in_opt MdDeviceObject TargetDevice + ) +/*++ + +Routine Description: + Send an IRP_MJPNP/IRP_MN_QUERY_INTERFACE irp to a device object and its + attached stack. + +Arguments: + InterfaceType - The type of interface to query for + + Interface - The interface to fill out + + Size - Size of Interface in bytes + + Version - Version of the interface to be queried + + InterfaceSpecificData - Addtional interface data to be queried + + TargetDevice - device in the stack to send the query to. If NULL, the top + of the stack will receive the query. + +Return Value: + NTSTATUS as indicated by the handler of the QI with in the device stack, + STATUS_NOT_SUPPORTED if the QI is not handled. + + --*/ +{ + UNREFERENCED_PARAMETER(InterfaceType); + UNREFERENCED_PARAMETER(Interface); + UNREFERENCED_PARAMETER(Size); + UNREFERENCED_PARAMETER(Version); + UNREFERENCED_PARAMETER(InterfaceSpecificData); + UNREFERENCED_PARAMETER(TargetDevice); + + // + // Query interface is not implemented for UMDF yet + // + return STATUS_NOT_IMPLEMENTED; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdeviceinitapium.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceinitapium.cpp new file mode 100644 index 00000000000..aac1d75f37e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceinitapium.cpp @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInitApiUm.cpp + +Abstract: + + This module exposes the "C" interface to the FxDevice object. + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceInitApiUm.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfDeviceInitEnableHidInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), DeviceInit); + + DeviceInit->DevStack->SetHidInterfaceSupport(); +} + +} // extern "C" + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdeviceinitum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceinitum.cpp new file mode 100644 index 00000000000..4a267cef3f2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceinitum.cpp @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInitUm.cpp + +Abstract: + Internals for WDFDEVICE_INIT + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceInitUm.tmh" +} + +VOID +WDFDEVICE_INIT::SetPdo( + __in FxDevice* Parent + ) +{ + UNREFERENCED_PARAMETER(Parent); + + UfxVerifierTrapNotImpl(); +} + +VOID +WDFDEVICE_INIT::AssignIoType( + _In_ PWDF_IO_TYPE_CONFIG IoTypeConfig + ) +{ + NTSTATUS status; + + if (IoTypeConfig->ReadWriteIoType == WdfDeviceIoUndefined || + IoTypeConfig->ReadWriteIoType > WdfDeviceIoBufferedOrDirect) { + status= STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Out of range ReadWriteIoType %d, %!status!", + IoTypeConfig->ReadWriteIoType, status); + FxVerifierDbgBreakPoint(DriverGlobals); + return; + } + + if (IoTypeConfig->DeviceControlIoType == WdfDeviceIoUndefined || + IoTypeConfig->DeviceControlIoType > WdfDeviceIoBufferedOrDirect) { + status= STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Out of range DeviceControlIoType %d, %!status!", + IoTypeConfig->DeviceControlIoType, status); + FxVerifierDbgBreakPoint(DriverGlobals); + return; + } + + if (IoTypeConfig->ReadWriteIoType == WdfDeviceIoNeither || + IoTypeConfig->DeviceControlIoType == WdfDeviceIoNeither) { + status= STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WdfDeviceIoNeither not supported for ReadWriteIoType or " + "DeviceControlIoType, %!status!", status); + FxVerifierDbgBreakPoint(DriverGlobals); + return; + } + + ReadWriteIoType = IoTypeConfig->ReadWriteIoType; + DeviceControlIoType = IoTypeConfig->DeviceControlIoType; + DirectTransferThreshold = IoTypeConfig->DirectTransferThreshold; + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdeviceum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceum.cpp new file mode 100644 index 00000000000..5f4438c2553 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdeviceum.cpp @@ -0,0 +1,1972 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceUm.cpp + +Abstract: + + This is the KM specific class implementation for the base Device class. + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +extern "C" { +#include "FxDeviceUm.tmh" +} + +VOID +FxDevice::DispatchUm( + _In_ MdDeviceObject DeviceObject, + _In_ MdIrp Irp, + _In_opt_ IUnknown* Context + ) +{ + UNREFERENCED_PARAMETER(Context); + + + + + + (void) Dispatch(DeviceObject, Irp); +} + +VOID +FxDevice::DispatchWithLockUm( + _In_ MdDeviceObject DeviceObject, + _In_ MdIrp Irp, + _In_opt_ IUnknown* Context + ) +{ + UNREFERENCED_PARAMETER(Context); + + (void) DispatchWithLock(DeviceObject, Irp); +} + +FxDevice* +FxDevice::GetFxDevice( + __in MdDeviceObject DeviceObject + ) +{ + IWudfDevice2* device2; + + + + + device2 = static_cast (DeviceObject); + + return (FxDevice *)device2->GetContext(); +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::FdoInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + PFX_DRIVER_GLOBALS pGlobals; + NTSTATUS status; + FxPkgFdo * pkgFdo; + HRESULT hr; + BOOLEAN bAttached = FALSE; + + pGlobals = GetDriverGlobals(); + + if (DeviceInit->Fdo.EventCallbacks.EvtDeviceFilterAddResourceRequirements != NULL && + DeviceInit->Fdo.EventCallbacks.EvtDeviceRemoveAddedResources == NULL) { + // + // Not allowed to add resources without filtering them out later + // + DoTraceLevelMessage( + pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Must set EvtDeviceRemoveAddedResources if " + "EvtDeviceFilterAddResourceRequirements (%p) is set", + DeviceInit->Fdo.EventCallbacks.EvtDeviceFilterAddResourceRequirements); + + FxVerifierDbgBreakPoint(pGlobals); + + return STATUS_INVALID_DEVICE_STATE; + } + + // + // All FDOs cannot be deleted through the driver calling WdfObjectDelete + // + MarkNoDeleteDDI(); + + m_PhysicalDevice.SetObject((MdDeviceObject)DeviceInit->Fdo.PhysicalDevice); + + // + // The PDO is known because it was used to bring up this FDO. + // + m_PdoKnown = TRUE; + + // + // Try to create and install the default packages that an FDO contains. + // + + // PnP + status = FxPkgFdo::_Create(pGlobals, (CfxDevice*)this, &pkgFdo); + + if (!NT_SUCCESS(status)) { + return status; + } + else { + m_PkgPnp = pkgFdo; + } + + InstallPackage(m_PkgPnp); + + status = SetFilter(DeviceInit->Fdo.Filter); + if (!NT_SUCCESS(status)) { + return status; + } + + status = GetFdoPkg()->Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + + // + // Should be done after invoking Initialize so that FxPkgFdo::m_EnumInfo is + // already allocated. + // + if (DeviceInit->Fdo.ListConfig.Size > 0) { + status = GetFdoPkg()->CreateDefaultDeviceList( + &DeviceInit->Fdo.ListConfig, + DeviceInit->Fdo.ListConfigAttributes.Size > 0 + ? &DeviceInit->Fdo.ListConfigAttributes + : NULL); + + if (!NT_SUCCESS(status)) { + return status; + } + + SetDeviceTelemetryInfoFlags(DeviceInfoHasDynamicChildren); + } + + // + // If the Size is zero then the driver writer never set any callbacks so we + // can skip this call. + // + if (DeviceInit->Fdo.EventCallbacks.Size != 0) { + status = GetFdoPkg()->RegisterCallbacks(&DeviceInit->Fdo.EventCallbacks); + if (!NT_SUCCESS(status)) { + return status; + } + } + + status = CreateDevice(DeviceInit); + if (NT_SUCCESS(status)) { + MdDeviceObject attachedDevice = NULL; + + // + // If this is an FDO then the PhysicalDevice field will be initialized, + // and we need to attach to the device stack. + // + // + // Attach the newly created host device object to existing stack. + // Insert the host device in the device chain for this device stack. + // + hr = DeviceInit->DevStack->AttachDevice( + m_DeviceObject.GetObject(), + &attachedDevice + ); + if (S_OK == hr) { + status = STATUS_SUCCESS; + } + else { + // + // Catch if the host isn't obeying the COM contract that requires + // a NULL interface when FAILED(hr). + // Note that AttachDevice can return success with a NULL interface + // for the attached device when this device is the first in the + // stack. + // + FX_VERIFY(DRIVER(BadArgument, TODO), CHECK_NULL(attachedDevice)); + status = FxDevice::NtStatusFromHr(DeviceInit->DevStack, hr); + goto exit; + } + + m_AttachedDevice.SetObject(attachedDevice); + bAttached = TRUE; + + if (m_AttachedDevice.GetObject() == NULL) { + // + // Note that AttachDevice can return success with a NULL interface + // for the attached device when this device is the first in the + // stack. + // + + + + + // + DO_NOTHING(); + } + + if (NT_SUCCESS(status)) { + // + // If PPO, save newly created device as PPO in device stack + // + if (DeviceInit->IsPwrPolOwner()) { + GetDeviceStack()->SetPPO(m_DeviceObject.GetObject()); + } + + // + // If we are a filter device, inherit some state from the + // attached device. + // + if (m_Filter) { + // + // Set the IO type and power pageable status on our device based + // on the attached device's settings. + // + SetFilterIoType(); + + if (m_AttachedDevice.GetObject() != NULL) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | + (m_AttachedDevice.GetFlags() & (DO_POWER_PAGABLE | DO_POWER_INRUSH))); + } + + // + // For devices other then filters, m_PowerPageableCapable gets + // set in CreateDevice, but since this is determined for filters + // by the device they have attached to, we must set this value + // later as a special case only for filters. + // + if (m_DeviceObject.GetFlags() & DO_POWER_PAGABLE) { + m_PowerPageableCapable = TRUE; + } + } + else { + // + // We are not a filter, we dictate our own DO flags + // + + // + // Power pageable and inrush are mutually exclusive + // + if (DeviceInit->PowerPageable) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_PAGABLE); + } + else if (DeviceInit->Inrush) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_POWER_INRUSH); + } + } + } + } + + // + // Set buffer retrieval and I/O type values + // + m_RetrievalMode = UMINT::WdfDeviceIoBufferRetrievalDeferred; + m_ReadWriteIoType = DeviceInit->ReadWriteIoType; + m_IoctlIoType = DeviceInit->DeviceControlIoType;; + m_DirectTransferThreshold = DeviceInit->DirectTransferThreshold; + + // + // Read HwAccess settings from registry + // + RetrieveDeviceRegistrySettings(); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_PkgGeneral->PostCreateDeviceInitialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + status = GetFdoPkg()->PostCreateDeviceInitialize(); + + if (NT_SUCCESS(status)) { + // + // Do not clear the DO_DEVICE_INITIALIZING bit here. Instead, either + // let the caller do it in their AddDevice or do it after the AddDevice + // callback returns. + // + // FinishInitializing(); + } + + exit: + + // + // Let the device stack object hold the only reference to + // the host devices. The infrastructure guarantees that the device + // stack's lifetime is greater than the this object's lifetime. + // If the Attach failed, the object will be destroyed. + // + if (NULL != m_DeviceObject.GetObject()) { + m_DeviceObject.GetObject()->Release(); + } + + if (NULL != m_AttachedDevice.GetObject()) { + m_AttachedDevice.GetObject()->Release(); + } + + if (!NT_SUCCESS(status)) { + if (bAttached) { + DetachDevice(); + bAttached = FALSE; + } + + // + // NULL out m_pIWudfDevice so that d'tor doesn't try to detach again. + // + m_DeviceObject.SetObject(NULL); // weak ref. + m_AttachedDevice.SetObject(NULL); // weak ref. + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::CreateDevice( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + MdDeviceObject pNewDeviceObject = NULL; + ULONG characteristics; + NTSTATUS status; + DEVICE_TYPE devType; + HRESULT hr; + IWudfDevice2* pNewDeviceObject2; + IWudfDeviceStack2* pDevStack2; + + status = m_PkgGeneral->Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + + + + + + + + + + UNREFERENCED_PARAMETER(devType); + + characteristics = DeviceInit->Characteristics; + + status = FxMessageDispatch::_CreateAndInitialize(GetDriverGlobals(), + this, + &m_Dispatcher); + if (!NT_SUCCESS(status)) { + return status; + } + + hr = DeviceInit->DevStack->QueryInterface(IID_IWudfDeviceStack2, + (PVOID*)&pDevStack2); + FX_VERIFY(INTERNAL, CHECK_QI(hr, pDevStack2)); + if (FAILED(hr)) { + status = FxDevice::NtStatusFromHr(DeviceInit->DevStack, hr); + return status; + } + pDevStack2->Release(); // weak ref. is sufficient. + + // + // Create IWudfDevice + // + hr = pDevStack2->CreateDevice2(DeviceInit->DriverID, + static_cast(m_Dispatcher), + sizeof(FxWdmDeviceExtension), + &pNewDeviceObject2); + if (FAILED(hr)) { + status = FxDevice::NtStatusFromHr(DeviceInit->DevStack, hr); + return status; + } + + hr = pNewDeviceObject2->QueryInterface(IID_IWudfDevice, + (PVOID*)&pNewDeviceObject); + FX_VERIFY(INTERNAL, CHECK_QI(hr, pNewDeviceObject)); + if (FAILED(hr)) { + status = FxDevice::NtStatusFromHr(DeviceInit->DevStack, hr); + return status; + } + pNewDeviceObject->Release(); // weak ref. is sufficient. + + if (NT_SUCCESS(status)) { + + // + // Initialize the remove lock and the event for use with the remove lock + // The event is initiatalized via IWudfDevice so the host can close the + // handle before destroying the allocated "WDM extension" + // In the KMDF implementation the "WDM device extension" is allocated by + // IoCreateDevice and destroyed when the WDM device object is deleted. + // In the kernel implementation the allocated extension only needs to be freed, + // where-as with UM the event handle needs to be closed as well. + // + FxWdmDeviceExtension* pWdmExt; + pWdmExt = _GetFxWdmExtension(pNewDeviceObject); + + Mx::MxInitializeRemoveLock(&pWdmExt->IoRemoveLock, + GetDriverGlobals()->Tag, + 0, // max min + 0); // highwater mark + + status = pNewDeviceObject2->InitializeEventForRemoveLock( + &(pWdmExt->IoRemoveLock.RemoveEvent)); + if (!NT_SUCCESS(status)) { + return status; + } + ASSERT(pWdmExt->IoRemoveLock.RemoveEvent); + + m_DeviceObject.SetObject(pNewDeviceObject); + + // + // Set the context + // + pNewDeviceObject2->SetContext(this); + + // + // capture input info + // + m_DevStack = DeviceInit->DevStack; + + // + // Hijack from deviceinit + // + m_PdoDevKey = DeviceInit->PdoKey; + DeviceInit->PdoKey = NULL; + + m_DeviceKeyPath = DeviceInit->ConfigRegistryPath; + DeviceInit->ConfigRegistryPath = NULL; + + m_KernelDeviceName = DeviceInit->KernelDeviceName; + DeviceInit->KernelDeviceName = NULL; + + m_DeviceInstanceId = DeviceInit->DevInstanceID; + DeviceInit->DevInstanceID = NULL; + + // + // Set some device object flags based on properties of DeviceInit. + // + // If we are a filter, we will set these flags later + // (in FxDevice::FdoInitialize) based on the device we are attached to. + // + if (m_Filter == FALSE) { + if (DeviceInit->ReadWriteIoType == WdfDeviceIoBuffered) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_BUFFERED_IO); + } + else if (DeviceInit->ReadWriteIoType == WdfDeviceIoDirect) { + m_DeviceObject.SetFlags(m_DeviceObject.GetFlags() | DO_DIRECT_IO); + } + + m_ReadWriteIoType = DeviceInit->ReadWriteIoType; + m_PowerPageableCapable = DeviceInit->PowerPageable; + } + + // + // Note: In case of UMDF the StackSize of the MdDeviceObject must + // be incremented prior to calling AttachDevice. It is because at the + // time of attaching the device the CWudfDevStack caches the stack + // size of devnode. + // This is unlike KMDF where it must be done after AttachDevice. + // Though the UMDF design can be modified to match KMDF solution, it + // seems simpler to adjust the stack size of UMDF prior to AttachDevice + // + if (m_SelfIoTargetNeeded) { + SetStackSize(GetStackSize()+1); + } + } + + return status; +} + +VOID +FxDevice::Destroy( + VOID + ) +{ + // + // If there was a failure during create (AddDevice), we need to detach + // from stack so that we don't receive remove irp from host (since fx sm + // uses a simulated remove event to do remove related cleanup). + // + if (m_CleanupFromFailedCreate) { + if (m_DeviceObject.GetObject() != NULL) { + DeleteSymbolicLink(); + + // + // The device object may not go away right away if there are pending + // references on it. But we can't look up our FxDevice anymore, so + // lets clear the DeviceExtension pointer. + // + m_DeviceObject.SetDeviceExtension(NULL); + } + + // + // Since this can be called in the context of the destructor when the ref + // count is zero, use GetObjectHandleUnchecked() to get the handle value. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGDEVICE, + "Deleting !devobj %p, WDFDEVICE %p, attached to !devobj %p", + m_DeviceObject.GetObject(), GetObjectHandleUnchecked(), + m_AttachedDevice.GetObject()); + + // + // This will detach the device from stack. Note that detach may cause + // the last ref on device object (IWudfDevice) to be released and + // therefore delete the device object. + // + DetachDevice(); + } +} + +VOID +FxDevice::DestructorInternal( + VOID + ) +{ + if (m_DeviceObject.GetObject() != NULL) { + // + // The device object may not go away right away if there are pending + // references on it. But we can't look up our FxDevice anymore, so + // lets clear the DeviceExtension pointer. + // + m_DeviceObject.SetDeviceExtension(NULL); + } + + // + // Since this can be called in the context of the destructor when the ref + // count is zero, use GetObjectHandleUnchecked() to get the handle value. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGDEVICE, + "Deleting !devobj %p, WDFDEVICE %p, attached to !devobj %p", + m_DeviceObject.GetObject(), GetObjectHandleUnchecked(), + m_AttachedDevice.GetObject()); + + // + // This will detach the device from stack. Note that detach may cause + // the last ref on device object (IWudfDevice) to be released and + // therefore delete the device object. + // + DetachDevice(); + + if (m_InteruptThreadpool) { + delete m_InteruptThreadpool; + m_InteruptThreadpool = NULL; + } + + delete [] m_KernelDeviceName; + m_KernelDeviceName = NULL; + + delete [] m_DeviceKeyPath; + m_DeviceKeyPath = NULL; + + delete [] m_DeviceInstanceId; + m_DeviceInstanceId = NULL; + + if (m_PdoDevKey) { + RegCloseKey(m_PdoDevKey); + this->m_PdoDevKey = NULL; + } + + if (m_Dispatcher) { + delete m_Dispatcher; + m_Dispatcher = NULL; + } +} + +VOID +FxDevice::GetPreferredTransferMode( + _In_ MdDeviceObject DeviceObject, + _Out_ UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL *RetrievalMode, + _Out_ WDF_DEVICE_IO_TYPE *RWPreference, + _Out_ WDF_DEVICE_IO_TYPE *IoctlPreference + ) +/*++ + + Routine Description: + + This method returns the i/o type information for the device to the + caller. + + Arguments: + + RetrievalMode - the retrival mode desired by this device + + RWPreference - the preferred r/w mode for the device + + IoctlPreference - the preferred ioctl mode for the device + + Return Value: + + None + +--*/ +{ + FxDevice* device; + + device = GetFxDevice(DeviceObject); + + *RetrievalMode = device->GetRetrievalMode(); + *RWPreference = device->GetPreferredRWTransferMode(); + *IoctlPreference = device->GetPreferredIoctlTransferMode(); +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::PdoInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + UNREFERENCED_PARAMETER(DeviceInit); + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return STATUS_NOT_IMPLEMENTED; +} + + +_Must_inspect_result_ +NTSTATUS +FxDevice::ControlDeviceInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + UNREFERENCED_PARAMETER(DeviceInit); + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxDevice::AddChildList( + __inout FxChildList* List + ) +{ + UNREFERENCED_PARAMETER(List); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +FxDevice::RemoveChildList( + __inout FxChildList* List + ) +{ + UNREFERENCED_PARAMETER(List); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::AllocateDmaEnablerList( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxDevice::AddDmaEnabler( + __inout FxDmaEnabler* Enabler + ) +{ + UNREFERENCED_PARAMETER(Enabler); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +FxDevice::RemoveDmaEnabler( + __inout FxDmaEnabler* Enabler + ) +{ + UNREFERENCED_PARAMETER(Enabler); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +NTSTATUS +FxDevice::ProcessWmiPowerQueryOrSetData ( + _In_ RdWmiPowerAction Action, + _Out_ BOOLEAN * QueryResult + ) +/*++ + + Routine Description: + + This method is called to process WMI set/Query data received from + reflector. Reflector sends this message when it receives a WMI Query or + Set Irp for this device for power guids. + + Arguments: + + Action - Enumeration of Set and Query actions for S0Idle and SxWake + + *QueryResult - receives the query result. + + Return Value: + + STATUS_SUCCESS if successful + + STATUS_INVALID_PARAMETER if the parameter values are invalid + +--*/ +{ + if (Action == ActionInvalid) { + return STATUS_INVALID_PARAMETER; + } + + if ((Action == QueryS0Idle || Action == QuerySxWake) && QueryResult == NULL) { + return STATUS_INVALID_PARAMETER; + } + + switch(Action) + { + case SetS0IdleEnable: + m_PkgPnp->PowerPolicySetS0IdleState(TRUE); + break; + case SetS0IdleDisable: + m_PkgPnp->PowerPolicySetS0IdleState(FALSE); + break; + case SetSxWakeEnable: + m_PkgPnp->PowerPolicySetSxWakeState(TRUE); + break; + case SetSxWakeDisable: + m_PkgPnp->PowerPolicySetSxWakeState(FALSE); + break; + case QueryS0Idle: + *QueryResult = m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; + break; + case QuerySxWake: + *QueryResult = m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; + break; + default: + ASSERT(FALSE); + break; + } + + return STATUS_SUCCESS; +} + +WUDF_INTERFACE_CONTEXT +FxDevice::RemoteInterfaceArrival ( + _In_ IWudfDevice * DeviceObject, + _In_ LPCGUID DeviceInterfaceGuid, + _In_ PCWSTR SymbolicLink + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(DeviceInterfaceGuid); + UNREFERENCED_PARAMETER(SymbolicLink); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +void +FxDevice::RemoteInterfaceRemoval ( + _In_ IWudfDevice * DeviceObject, + _In_ WUDF_INTERFACE_CONTEXT RemoteInterfaceID + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(RemoteInterfaceID); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +BOOL +FxDevice::TransportQueryId ( + _In_ IWudfDevice * DeviceObject, + _In_ DWORD Id, + _In_ PVOID DataBuffer, + _In_ SIZE_T cbDataBufferSize + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Id); + UNREFERENCED_PARAMETER(DataBuffer); + UNREFERENCED_PARAMETER(cbDataBufferSize); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return FALSE; +} + +void +FxDevice::PoFxDevicePowerRequired ( + _In_ MdDeviceObject DeviceObject + ) +{ + GetFxDevice(DeviceObject)->m_PkgPnp->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.PowerRequiredCallbackInvoked(); +} + +void +FxDevice::PoFxDevicePowerNotRequired ( + _In_ MdDeviceObject DeviceObject + ) +{ + GetFxDevice(DeviceObject)->m_PkgPnp->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.PowerNotRequiredCallbackInvoked(); +} + +NTSTATUS +FxDevice::NtStatusFromHr ( + _In_ IWudfDeviceStack * DevStack, + _In_ HRESULT Hr + ) +{ + PUMDF_VERSION_DATA driverVersion = DevStack->GetMinDriverVersion(); + BOOL preserveCompat = + DevStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + return CHostFxUtil::NtStatusFromHr(Hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat + ); +} + +NTSTATUS +FxDevice::NtStatusFromHr ( + _In_ HRESULT Hr + ) +{ + return FxDevice::NtStatusFromHr(GetDeviceStack(), Hr); +} + +VOID +FxDevice::RetrieveDeviceRegistrySettings( + VOID + ) +{ + DWORD err; + HKEY wudfKey = NULL; + DWORD data; + DWORD dataSize; + + err = RegOpenKeyEx(m_PdoDevKey, + WUDF_SUB_KEY, + 0, + KEY_READ, + &wudfKey); + if (ERROR_SUCCESS != err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to open hw registry key to read hw access settings"); + goto clean0; + } + + // + // Read FX_DIRECT_HARDWARE_ACCESS value + // + dataSize = sizeof(data); + data = 0; + err = RegQueryValueEx(wudfKey, + FX_DIRECT_HARDWARE_ACCESS, + NULL, + NULL, + (BYTE*) &data, + &dataSize); + + if (ERROR_SUCCESS == err) { + if (((WDF_DIRECT_HARDWARE_ACCESS_TYPE)data) < WdfDirectHardwareAccessMax) { + // + // save the setting only if it is valid + // + m_DirectHardwareAccess = (WDF_DIRECT_HARDWARE_ACCESS_TYPE)data; + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "invalid direct hardware access value in registry %u", + (WDF_DIRECT_HARDWARE_ACCESS_TYPE)data); + } + } + else if (ERROR_FILE_NOT_FOUND != err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read direct hardware access value in registry"); + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "DirectHardwareAccess = %u", m_DirectHardwareAccess); + + + // + // Read FX_REGISTER_ACCESS_MODE value + // + dataSize = sizeof(data); + data = 0; + err = RegQueryValueEx(wudfKey, + FX_REGISTER_ACCESS_MODE, + NULL, + NULL, + (BYTE*) &data, + &dataSize); + if (ERROR_SUCCESS == err) { + if (((WDF_REGISTER_ACCESS_MODE_TYPE)data) < WdfRegisterAccessMax) { + // + // save the setting only if it is valid + // + m_RegisterAccessMode = (WDF_REGISTER_ACCESS_MODE_TYPE)data; + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid Register Access mode value in registry %u", + (WDF_REGISTER_ACCESS_MODE_TYPE)data); + } + } + else if (ERROR_FILE_NOT_FOUND != err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read Register Access mode value in registry"); + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "RegisterAccessMode = %u", m_RegisterAccessMode); + + // + // Read FX_FILE_OBJECT_POLICY + // + dataSize = sizeof(data); + data = 0; + err = RegQueryValueEx(wudfKey, + FX_FILE_OBJECT_POLICY, + NULL, + NULL, + (BYTE*) &data, + &dataSize); + if (ERROR_SUCCESS == err) { + if (((WDF_FILE_OBJECT_POLICY_TYPE)data) < WdfFileObjectPolicyMax) { + // + // save the setting only if it is valid + // + m_FileObjectPolicy = (WDF_FILE_OBJECT_POLICY_TYPE)data; + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid File object Policy value in registry %u", + (WDF_FILE_OBJECT_POLICY_TYPE)data); + } + } + else if (ERROR_FILE_NOT_FOUND != err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read File Object Policy value in registry"); + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "FileObjectPolicy = %u", m_FileObjectPolicy); + + // + // Read FX_FS_CONTEXT_USE_POLICY + // + dataSize = sizeof(data); + data = 0; + err = RegQueryValueEx(wudfKey, + FX_FS_CONTEXT_USE_POLICY, + NULL, + NULL, + (BYTE*) &data, + &dataSize); + if (ERROR_SUCCESS == err) { + if (((WDF_FS_CONTEXT_USE_POLICY_TYPE)data) < WdfFsContextUsePolicyMax) { + // + // save the setting only if it is valid + // + m_FsContextUsePolicy = (WDF_FS_CONTEXT_USE_POLICY_TYPE)data; + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid Fs Context Use Policy value in registry %u", + (WDF_FILE_OBJECT_POLICY_TYPE)data); + } + } + else if (ERROR_FILE_NOT_FOUND != err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read Fs Context Use Policy value in registry"); + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "FsContextUsePolicy = %u", m_FsContextUsePolicy); + + +clean0: + + if (NULL != wudfKey) { + RegCloseKey(wudfKey); + } + + return; +} + +NTSTATUS +FxDevice::_OpenDeviceRegistryKey( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ IWudfDeviceStack* DeviceStack, + _In_ PWSTR DriverName, + _In_ ULONG DevInstKeyType, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE DevInstRegKey + ) +{ + NTSTATUS status; + HRESULT hr; + + UMINT::WDF_PROPERTY_STORE_ROOT root; + UMINT::WDF_PROPERTY_STORE_RETRIEVE_FLAGS flags = UMINT::WdfPropertyStoreNormal; + PWSTR subpath = NULL; + + + + + #define WDF_REGKEY_DEVICE_SUBKEY 256 + #define WDF_REGKEY_DRIVER_SUBKEY 256 + + root.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + + if (DevInstKeyType & PLUGPLAY_REGKEY_CURRENT_HWPROFILE) + { + ASSERTMSG("Not available in UMDF\n", FALSE); + } + else if (DevInstKeyType & PLUGPLAY_REGKEY_DEVICE) + { + root.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; + + if (DevInstKeyType & WDF_REGKEY_DEVICE_SUBKEY) + { + root.Qualifier.HardwareKey.ServiceName = DriverName; + flags = UMINT::WdfPropertyStoreCreateIfMissing; + } + else + { + root.Qualifier.HardwareKey.ServiceName = WDF_PROPERTY_STORE_HARDWARE_KEY_ROOT; + } + } + else if (DevInstKeyType & PLUGPLAY_REGKEY_DRIVER) + { + root.RootClass = UMINT::WdfPropertyStoreRootClassSoftwareKey; + + if (DevInstKeyType & WDF_REGKEY_DRIVER_SUBKEY) + { + subpath = DriverName; + flags = UMINT::WdfPropertyStoreCreateIfMissing; + } + else + { + subpath = L"\\"; + } + } + else if (DevInstKeyType & FX_PLUGPLAY_REGKEY_DEVICEMAP) + { + root.RootClass = UMINT::WdfPropertyStoreRootClassLegacyHardwareKey; + + // + // Legacy keys must always be opened volatile for UMDF + // + flags = UMINT::WdfPropertyStoreCreateVolatile; + + subpath = NULL; + root.Qualifier.LegacyHardwareKey.LegacyMapName = DriverName; + } + + hr = ((IWudfDeviceStack*)DeviceStack)->CreateRegistryEntry(&root, + flags, + DesiredAccess, + subpath, + (PHKEY)DevInstRegKey, + NULL); + status = FxDevice::NtStatusFromHr(DeviceStack, hr); + + return status; +} + +NTSTATUS +FxDevice::_GetDeviceProperty( + _In_ PVOID DeviceStack, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_opt_ PULONG ResultLength + ) +{ + HRESULT hr; + NTSTATUS status; + + DEVPROPTYPE propType; + const DEVPROPKEY *propKey = NULL; + + // + // {cccccccc-cccc-cccc-cccc-cccccccccccc} + // 2 brackets + 4 dashes + 32 characters + UNICODE_NULL + // + GUID guidBuffer = {0}; + ULONG guidChLen = 2 + 4 + 32 + 1; + ULONG guidCbLen = guidChLen * sizeof(WCHAR); + BOOLEAN convertGuidToString = FALSE; + + PVOID buffer = PropertyBuffer; + ULONG bufferLen = BufferLength; + ULONG resultLen = 0; + + UMINT::WDF_PROPERTY_STORE_ROOT rootSpecifier; + rootSpecifier.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + rootSpecifier.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; + rootSpecifier.Qualifier.HardwareKey.ServiceName = NULL; + + // + // Map DEVICE_REGISTRY_PROPERTY enums to DEVPROPKEYs + // + switch (DeviceProperty) + { + case DevicePropertyDeviceDescription: + propKey = &DEVPKEY_Device_DeviceDesc; + break; + case DevicePropertyHardwareID: + propKey = &DEVPKEY_Device_HardwareIds; + break; + case DevicePropertyCompatibleIDs: + propKey = &DEVPKEY_Device_CompatibleIds; + break; + case DevicePropertyBootConfiguration: + ASSERTMSG("Not available in UMDF\n", FALSE); + break; + case DevicePropertyBootConfigurationTranslated: + ASSERTMSG("Not available in UMDF\n", FALSE); + break; + case DevicePropertyClassName: + propKey = &DEVPKEY_Device_Class; + break; + case DevicePropertyClassGuid: + propKey = &DEVPKEY_Device_ClassGuid; + convertGuidToString = TRUE; + break; + case DevicePropertyDriverKeyName: + propKey = &DEVPKEY_NAME; + break; + case DevicePropertyManufacturer: + propKey = &DEVPKEY_Device_Manufacturer; + break; + case DevicePropertyFriendlyName: + propKey = &DEVPKEY_Device_FriendlyName; + break; + case DevicePropertyLocationInformation: + propKey = &DEVPKEY_Device_LocationInfo; + break; + case DevicePropertyPhysicalDeviceObjectName: + propKey = &DEVPKEY_Device_PDOName; + break; + case DevicePropertyBusTypeGuid: + propKey = &DEVPKEY_Device_BusTypeGuid; + break; + case DevicePropertyLegacyBusType: + propKey = &DEVPKEY_Device_LegacyBusType; + break; + case DevicePropertyBusNumber: + propKey = &DEVPKEY_Device_BusNumber; + break; + case DevicePropertyEnumeratorName: + propKey = &DEVPKEY_Device_EnumeratorName; + break; + case DevicePropertyAddress: + propKey = &DEVPKEY_Device_Address; + break; + case DevicePropertyUINumber: + propKey = &DEVPKEY_Device_UINumber; + break; + case DevicePropertyInstallState: + propKey = &DEVPKEY_Device_InstallState; + break; + case DevicePropertyRemovalPolicy: + propKey = &DEVPKEY_Device_RemovalPolicy; + break; + case DevicePropertyResourceRequirements: + ASSERTMSG("Not available in UMDF\n", FALSE); + break; + case DevicePropertyAllocatedResources: + ASSERTMSG("Not available in UMDF\n", FALSE); + break; + case DevicePropertyContainerID: + propKey = &DEVPKEY_Device_ContainerId; + convertGuidToString = TRUE; + break; + } + + FX_VERIFY(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(propKey)); + + if (convertGuidToString) + { + buffer = &guidBuffer; + bufferLen = sizeof(GUID); + } + + hr = ((IWudfDeviceStack*)DeviceStack)->GetUnifiedPropertyData(&rootSpecifier, + propKey, + 0, + 0, + bufferLen, + &propType, + &resultLen, + buffer); + if (S_OK == hr) + { + status = STATUS_SUCCESS; + + // + // Some DEVICE_REGISTRY_PROPERTY values are GUID strings, + // while their DEVPROPKEY equivalents are GUID structs. To preserve + // KMDF-UMDF DDI parity, we convert select GUID structs to wchar strings. + // + if (convertGuidToString) + { + if (PropertyBuffer == NULL || BufferLength < guidCbLen) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + hr = StringCchPrintf((PWSTR)PropertyBuffer, + guidChLen, + L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + guidBuffer.Data1, guidBuffer.Data2, guidBuffer.Data3, + guidBuffer.Data4[0], guidBuffer.Data4[1], + guidBuffer.Data4[2], guidBuffer.Data4[3], + guidBuffer.Data4[4], guidBuffer.Data4[5], + guidBuffer.Data4[6], guidBuffer.Data4[7]); + if (hr != S_OK) + { + status = STATUS_UNSUCCESSFUL; + } + } + } + } + else if (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) == hr) + { + status = STATUS_BUFFER_TOO_SMALL; + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + if (ResultLength) + { + *ResultLength = convertGuidToString ? guidCbLen : resultLen; + } + + return status; +} + +VOID +FxDevice::DetachDevice( + VOID + ) +{ + // + // Note that UMDF host's DetachDevice has a different interface than + // IoDetachDevice. DetachDevice takes the current device object as parameter + // instead of target device. + // + if (m_DevStack != NULL && m_DeviceObject.GetObject() != NULL) { + Mx::MxDetachDevice(m_DeviceObject.GetObject()); + m_AttachedDevice.SetObject(NULL); + + // + // This was a weak ref. Set it to NULL. m_DeviceObject (IWudfDevice)'s + // lifetime is managed by host through a ref taken during Attach. + // + m_DeviceObject.SetObject(NULL); + } +} + +VOID +FxDevice::InvalidateDeviceState( + VOID + ) +{ + GetMxDeviceObject()->InvalidateDeviceState(GetDeviceObject()); +} + +NTSTATUS +FxDevice::CreateSymbolicLink( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ PCUNICODE_STRING SymbolicLinkName + ) +{ + HRESULT hr; + NTSTATUS status; + + status = FxDuplicateUnicodeString(FxDriverGlobals, + SymbolicLinkName, + &m_SymbolicLinkName); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p allocate buffer for symbolic name failed, %!STATUS!", + GetHandle(), status); + + return status; + } + + hr = GetDeviceStack()->CreateSymbolicLink(SymbolicLinkName->Buffer, NULL); + if (SUCCEEDED(hr)) { + status = STATUS_SUCCESS; + } + else { + status = NtStatusFromHr(hr); + ASSERT(NT_SUCCESS(status) == FALSE); + + FxPoolFree(m_SymbolicLinkName.Buffer); + + RtlZeroMemory(&m_SymbolicLinkName, + sizeof(m_SymbolicLinkName)); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDFDEVICE %p create symbolic link failed, %!STATUS!", + GetHandle(), status); + } + + return status; +} + +VOID +FxDevice::DeleteSymbolicLink( + VOID + ) +{ + if (m_SymbolicLinkName.Buffer != NULL) { + // + // There is no IoDeleteSymbolicLink equivalent exposed by UMDF host. + // Reflector takes care of deleteing the symbolic link on removal. + // So just free the string now. + // + FxPoolFree(m_SymbolicLinkName.Buffer); + RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName)); + } +} + +NTSTATUS +FxDevice::AssignProperty ( + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ DEVPROPTYPE Type, + _In_ ULONG BufferLength, + _In_opt_ PVOID PropertyBuffer + ) +{ + NTSTATUS status; + HRESULT hr; + const DEVPROPKEY * propertyKey; + LCID lcid; + ULONG flags; + + // + // call into host to assign the property + // + UMINT::WDF_PROPERTY_STORE_ROOT rootSpecifier = {0}; + + if (FxPropertyType == FxInterfaceProperty) { + PWDF_DEVICE_INTERFACE_PROPERTY_DATA interfaceData = + (PWDF_DEVICE_INTERFACE_PROPERTY_DATA) PropertyData; + + rootSpecifier.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + rootSpecifier.RootClass = UMINT::WdfPropertyStoreRootClassDeviceInterfaceKey; + rootSpecifier.Qualifier.DeviceInterfaceKey.InterfaceGUID = + interfaceData->InterfaceClassGUID; + if (interfaceData->ReferenceString != NULL) { + rootSpecifier.Qualifier.DeviceInterfaceKey.ReferenceString = + interfaceData->ReferenceString->Buffer; + } + propertyKey = interfaceData->PropertyKey; + lcid = interfaceData->Lcid; + flags = interfaceData->Flags; + } + else { + PWDF_DEVICE_PROPERTY_DATA deviceData = + (PWDF_DEVICE_PROPERTY_DATA) PropertyData; + + ASSERT(FxPropertyType == FxDeviceProperty); + + rootSpecifier.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + rootSpecifier.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; + propertyKey = deviceData->PropertyKey; + lcid = deviceData->Lcid; + flags = deviceData->Flags; + } + + hr = GetDeviceStack()->SetUnifiedPropertyData(&rootSpecifier, + propertyKey, + lcid, + flags, + Type, + BufferLength, + PropertyBuffer); + if (S_OK == hr) { + status = STATUS_SUCCESS; + } + else { + status = NtStatusFromHr(hr); + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p failed to assign interface property, %!STATUS!", + GetHandle(), status); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_OpenKey( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ ULONG DeviceInstanceKeyType, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ WDFKEY* Key + ) +{ + FxRegKey* pKey; + WDFKEY keyHandle; + HANDLE hKey = NULL; + NTSTATUS status; + IWudfDeviceStack* deviceStack; + PWSTR driverName; + + status = FxValidateObjectAttributes(FxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = _ValidateOpenKeyParams(FxDriverGlobals, DeviceInit, Device); + if (!NT_SUCCESS(status)) { + return status; + } + + _Analysis_assume_(DeviceInit != NULL || Device != NULL); + + if (DeviceInit != NULL) { + deviceStack = DeviceInit->DevStack; + driverName = DeviceInit->ConfigRegistryPath; + } + else { + deviceStack = Device->m_DevStack; + driverName = Device->m_DeviceKeyPath; + } + + pKey = new(FxDriverGlobals, KeyAttributes) FxRegKey(FxDriverGlobals); + + if (pKey == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (Device != NULL) { + pKey->SetDeviceBase(Device); + } + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + + if (NT_SUCCESS(status)) { + status = _OpenDeviceRegistryKey(FxDriverGlobals, + deviceStack, + driverName, + DeviceInstanceKeyType, + DesiredAccess, + &hKey); + if (NT_SUCCESS(status)) { + pKey->SetHandle(hKey); + *Key = keyHandle; + } + } + + if (!NT_SUCCESS(status)) { + // + // No object is being returned, make sure the destroy callback will not + // be called. + // + pKey->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::OpenSettingsKey( + __out HANDLE* Key, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + FxAutoRegKey parent; + MdDeviceObject pdo; + + // + // We need a PDO to open this reg key. in the case of failure to create + // a static PDO, we will go down this path in the pnp state machine, so we + // must check for validity always. + // + pdo = GetSafePhysicalDevice(); + + if (pdo == NULL) { + return STATUS_INVALID_DEVICE_STATE; + } + + status = _OpenDeviceRegistryKey(GetDriverGlobals(), + m_DevStack, + m_DeviceKeyPath, + PLUGPLAY_REGKEY_DEVICE, + DesiredAccess, + &parent.m_Key); + if (NT_SUCCESS(status)) { + DECLARE_CONST_UNICODE_STRING(wdf, L"WDF"); + + // + // Create the key if it does not already exist + // + status = FxRegKey::_Create(parent.m_Key, + &wdf, + Key, + DesiredAccess); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_QueryPropertyEx ( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ ULONG BufferLength, + _Out_ PVOID PropertyBuffer, + _Out_ PULONG ResultLength, + _Out_ PDEVPROPTYPE PropertyType + ) +{ + NTSTATUS status; + HRESULT hr; + DEVPROPTYPE propType; + ULONG requiredLength = 0; + const DEVPROPKEY * propertyKey; + LCID lcid; + ULONG flags; + IWudfDeviceStack* devStack; + + *ResultLength = 0; + *PropertyType = 0; + + status = FxDevice::_ValidateOpenKeyParams(DriverGlobals, + DeviceInit, + Device); + if (!NT_SUCCESS(status)) { + return status; + } + + _Analysis_assume_(DeviceInit != NULL || Device != NULL); + + if (DeviceInit != NULL) { + devStack = DeviceInit->DevStack; + } + else { + devStack = Device->m_DevStack; + } + + UMINT::WDF_PROPERTY_STORE_ROOT rootSpecifier = {0}; + + if (FxPropertyType == FxInterfaceProperty) { + PWDF_DEVICE_INTERFACE_PROPERTY_DATA interfaceData = + (PWDF_DEVICE_INTERFACE_PROPERTY_DATA) PropertyData; + + rootSpecifier.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + rootSpecifier.RootClass = UMINT::WdfPropertyStoreRootClassDeviceInterfaceKey; + rootSpecifier.Qualifier.DeviceInterfaceKey.InterfaceGUID = + interfaceData->InterfaceClassGUID; + if (interfaceData->ReferenceString != NULL) { + rootSpecifier.Qualifier.DeviceInterfaceKey.ReferenceString = + interfaceData->ReferenceString->Buffer; + } + propertyKey = interfaceData->PropertyKey; + lcid = interfaceData->Lcid; + flags = interfaceData->Flags; + } + else { + PWDF_DEVICE_PROPERTY_DATA deviceData = + (PWDF_DEVICE_PROPERTY_DATA) PropertyData; + + ASSERT(FxPropertyType == FxDeviceProperty); + + rootSpecifier.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + rootSpecifier.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; + propertyKey = deviceData->PropertyKey; + lcid = deviceData->Lcid; + flags = deviceData->Flags; + } + + hr = devStack->GetUnifiedPropertyData(&rootSpecifier, + propertyKey, + lcid, + flags, + BufferLength, + &propType, + &requiredLength, + PropertyBuffer); + + if (hr == (HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))) { + status = STATUS_BUFFER_TOO_SMALL; + *ResultLength = requiredLength; + *PropertyType = propType; + } + else if (hr == S_OK) { + status = STATUS_SUCCESS; + *ResultLength = requiredLength; + *PropertyType = propType; + } + else { + status = NtStatusFromHr(devStack, hr); + ASSERT(NT_SUCCESS(status) == FALSE); + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Query for unified property buffer failed, %!STATUS!", + status); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::_QueryProperty( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_opt_ MdDeviceObject RemotePdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_opt_ PULONG ResultLength + ) +{ + NTSTATUS status; + IWudfDeviceStack* deviceStack; + + UNREFERENCED_PARAMETER(RemotePdo); + + status = FxDevice::_ValidateOpenKeyParams(FxDriverGlobals, + DeviceInit, + Device); + if (!NT_SUCCESS(status)) { + return status; + } + + _Analysis_assume_(DeviceInit != NULL || Device != NULL); + + if (DeviceInit != NULL) { + deviceStack = DeviceInit->DevStack; + } + else { + deviceStack = Device->m_DevStack; + } + + status = _GetDeviceProperty(deviceStack, + DeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength); + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::FxValidateInterfacePropertyData( + _In_ PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + if (PropertyData->Size != sizeof(WDF_DEVICE_INTERFACE_PROPERTY_DATA)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "PropertyData size (%d) incorrect, expected %d, %!STATUS!", + PropertyData->Size, + sizeof(WDF_DEVICE_INTERFACE_PROPERTY_DATA), status); + return status; + } + + FxPointerNotNull(pFxDriverGlobals, PropertyData->InterfaceClassGUID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (PropertyData->ReferenceString != NULL) { + status = FxValidateUnicodeString(pFxDriverGlobals, + PropertyData->ReferenceString); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + } + + // + // check if the interface has been registered with WDF + // + if (IsInterfaceRegistered(PropertyData->InterfaceClassGUID, + PropertyData->ReferenceString) == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p cannot assign interface property for an interface not" + " yet registered with WDF, %!STATUS!", + GetHandle(), status); + return status; + } + + return status; +} + +VOID +FxDevice::GetDeviceStackIoType ( + _Out_ WDF_DEVICE_IO_TYPE* ReadWriteIoType, + _Out_ WDF_DEVICE_IO_TYPE* IoControlIoType + ) +{ + UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL retrievalMode; + + GetDeviceStack()->GetDeviceStackPreferredTransferMode( + &retrievalMode, + (UMINT::WDF_DEVICE_IO_TYPE*)ReadWriteIoType, + (UMINT::WDF_DEVICE_IO_TYPE*)IoControlIoType + ); +} + +VOID +FxDevice::RetrieveDeviceInfoRegistrySettings( + _Out_ PCWSTR* GroupId, + _Out_ PUMDF_DRIVER_REGSITRY_INFO DeviceRegInfo + ) +{ + DWORD Err; + DWORD Data; + HKEY wudfKey = NULL; + DWORD DataSize; + DWORD type; + PWSTR buffer; + DWORD bufferSize; + + ASSERT(GroupId != NULL); + ASSERT(DeviceRegInfo != NULL); + + ZeroMemory(DeviceRegInfo, sizeof(UMDF_DRIVER_REGSITRY_INFO)); + type = REG_NONE; + + if (m_PdoDevKey == NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Handle to hardware key not yet available"); + return; + } + + Err = RegOpenKeyEx(m_PdoDevKey, + WUDF_SUB_KEY, + 0, + KEY_READ, + &wudfKey); + if (ERROR_SUCCESS != Err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to open hw registry key to read hw access settings"); + goto clean0; + } + + // + // Read WDF_KERNEL_MODE_CLIENT_POLICY value + // + DataSize = sizeof(Data); + Data = 0; + Err = RegQueryValueEx(wudfKey, + FX_KERNEL_MODE_CLIENT_POLICY, + NULL, + NULL, + (BYTE*) &Data, + &DataSize); + + if (ERROR_SUCCESS == Err) { + if (((WDF_KERNEL_MODE_CLIENT_POLICY_TYPE)Data) == WdfAllowKernelModeClients) { + DeviceRegInfo->IsKernelModeClientAllowed = TRUE; + } + } + else if (ERROR_FILE_NOT_FOUND != Err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read kernel mode client policy value in registry"); + } + + // + // Read WDF_FILE_OBJECT_POLICY value + // + DataSize = sizeof(Data); + Data = 0; + Err = RegQueryValueEx(wudfKey, + FX_FILE_OBJECT_POLICY, + NULL, + NULL, + (BYTE*) &Data, + &DataSize); + if (ERROR_SUCCESS == Err) { + if (((WDF_FILE_OBJECT_POLICY_TYPE)Data) == WdfAllowNullAndUnknownFileObjects) { + DeviceRegInfo->IsNullFileObjectAllowed = TRUE; + } + } + else if (ERROR_FILE_NOT_FOUND != Err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read file object policy value in registry"); + } + + // + // Read WDF_METHOD_NEITHER_ACTION value + // + DataSize = sizeof(Data); + Data = 0; + Err = RegQueryValueEx(wudfKey, + FX_METHOD_NEITHER_ACTION, + NULL, + NULL, + (BYTE*) &Data, + &DataSize); + if (ERROR_SUCCESS == Err) { + if (((WDF_METHOD_NEITHER_ACTION_TYPE)Data) == WdfMethodNeitherAction_Copy) { + DeviceRegInfo->IsMethodNeitherActionCopy = TRUE; + } + } + else if (ERROR_FILE_NOT_FOUND != Err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read method neither action value in registry"); + } + + // + // Read WDF_PROCESS_SHARING_ENABLED value + // + DataSize = sizeof(Data); + Data = 0; + Err = RegQueryValueEx(wudfKey, + FX_PROCESS_SHARING_ENABLED, + NULL, + NULL, + (BYTE*) &Data, + &DataSize); + if (ERROR_SUCCESS == Err) { + if (((WDF_PROCESS_SHARING_TYPE)Data) == WdfProcessSharingDisabled) { + DeviceRegInfo->IsHostProcessSharingDisabled = TRUE; + } + } + else if (ERROR_FILE_NOT_FOUND != Err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read method neither action value in registry"); + } + + // + // Read Group ID + // + buffer = NULL; + bufferSize = 0; + *GroupId = NULL; + + Err = RegQueryValueEx(wudfKey, + FX_DEVICE_GROUP_ID, + 0, + &type, + (LPBYTE) buffer, + &bufferSize); + if (ERROR_MORE_DATA == Err) { + + buffer = new WCHAR[bufferSize/sizeof(buffer[0])]; + if (buffer == NULL) { + Err = ERROR_NOT_ENOUGH_MEMORY; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to allocate memory for string buffer"); + } + else { + + buffer[0] = L'\0'; + Err = RegQueryValueEx(wudfKey, + FX_DEVICE_GROUP_ID, + 0, + &type, + (LPBYTE) buffer, + &bufferSize); + if (Err == ERROR_SUCCESS) { + if (type != REG_SZ) { + Err = ERROR_INVALID_PARAMETER; + } + else { + // + // according to the string data returned by RegQueryValueEx() + // is not always null terminated. + // + buffer[bufferSize/sizeof(buffer[0]) - 1] = L'\0'; + } + } + + if (Err == ERROR_SUCCESS) { + *GroupId = buffer; + } + else { + delete [] buffer; + buffer = NULL; + } + } + } + else if (ERROR_FILE_NOT_FOUND != Err) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to read Group id value in registry"); + } + + +clean0: + + if (NULL != wudfKey) { + RegCloseKey(wudfKey); + } + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxDevice::OpenDevicemapKeyWorker( + _In_ PFX_DRIVER_GLOBALS pFxDriverGlobals, + _In_ PCUNICODE_STRING KeyName, + _In_ ACCESS_MASK DesiredAccess, + _In_ FxRegKey* pKey + ) +{ + + NTSTATUS status; + HANDLE hKey = NULL; + + status = _OpenDeviceRegistryKey(pFxDriverGlobals, + m_DevStack, + KeyName->Buffer, + FX_PLUGPLAY_REGKEY_DEVICEMAP, + DesiredAccess, + &hKey); + if (NT_SUCCESS(status)) { + pKey->SetHandle(hKey); + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdriverapium.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdriverapium.cpp new file mode 100644 index 00000000000..b21a741e242 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdriverapium.cpp @@ -0,0 +1,244 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriverApiKm.cpp + +Abstract: + + This module contains the "C" interface for the FxDriver object. + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include +#include "FxDriverApiUm.tmh" +} + +// +// extern the whole file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDriverOpenParametersRegistryKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in + ACCESS_MASK DesiredAccess, + __in_opt + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + __out + WDFKEY* Key + ) +{ + NTSTATUS status; + LONG result; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDriver* pDriver; + FxRegKey* pKey; + HKEY hKey = NULL; + WDFKEY keyHandle; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + Driver, + FX_TYPE_DRIVER, + (PVOID*) &pDriver); + + pKey = new(pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals); + if (pKey == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + if (NT_SUCCESS(status)) { + if (DesiredAccess & (GENERIC_WRITE | KEY_CREATE_SUB_KEY | WRITE_DAC)) { + // + // These access rights are not allowed. This restriction is + // imposed by the host process and the reflector driver. + // + // Even though the maximum-permissions handle is already opened, + // we fail so that the caller knows not to assume it has the + // GENERIC_WRITE, KEY_CREATE_SUB_KEY, or WRITE_DAC permissions. + // + status = STATUS_ACCESS_DENIED; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Could not open '%s' service parameters key " + "with access rights 0x%x, %!STATUS!", + pFxDriverGlobals->Public.DriverName, + DesiredAccess, status); + } else if ((DesiredAccess & ~(KEY_READ | GENERIC_READ)) == 0) { + // + // If caller requested read-only access, open a new handle + // to the parameters key, no reason to give more privileges + // than needed. + // + result = RegOpenKeyEx(pDriver->GetDriverParametersKey(), + L"", + 0, + DesiredAccess, + &hKey); + status = WinErrorToNtStatus(result); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Could not open '%s' service parameters key " + "with access rights 0x%x, %!STATUS!", + pFxDriverGlobals->Public.DriverName, + DesiredAccess, status); + } + } else { + // + // If caller requested write access, give it the pre-opened + // handle, since we do not have permission to open this key + // with write access rights from user mode. + // + hKey = pDriver->GetDriverParametersKey(); + + // + // Mark the registry key handle such that it won't be closed + // when this FxRegKey is deleted. We might need the handle again + // for future calls to WdfDriverOpenParametersRegistryKey. + // + pKey->SetCanCloseHandle(FALSE); + } + + if (NT_SUCCESS(status)) { + pKey->SetHandle((HANDLE)hKey); + *Key = keyHandle; + } + } + + if (!NT_SUCCESS(status)) { + pKey->DeleteFromFailedCreate(); + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PDRIVER_OBJECT +WDFEXPORT(WdfDriverWdmGetDriverObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver + ) +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(Driver); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDRIVER +WDFEXPORT(WdfWdmDriverGetWdfDriverHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + PDRIVER_OBJECT DriverObject + ) +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(DriverObject); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +VOID +WDFEXPORT(WdfDriverMiniportUnload)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver + ) +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(Driver); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceMiniportCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDRIVER Driver, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __in + PDEVICE_OBJECT DeviceObject, + __in_opt + PDEVICE_OBJECT AttachedDeviceObject, + __in_opt + PDEVICE_OBJECT Pdo, + __out + WDFDEVICE* Device + ) +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(Driver); + UNREFERENCED_PARAMETER(Attributes); + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(AttachedDeviceObject); + UNREFERENCED_PARAMETER(Pdo); + UNREFERENCED_PARAMETER(Device); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxdriverum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxdriverum.cpp new file mode 100644 index 00000000000..efe9952fab3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxdriverum.cpp @@ -0,0 +1,352 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriverUm.cpp + +Abstract: + + This is the main driver framework. + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" +#include "fxiotarget.hpp" +#include "fxldrum.h" + +// Tracing support +extern "C" { +#include "FxDriverUm.tmh" +} + + +_Must_inspect_result_ +NTSTATUS +FxDriver::AddDevice ( + _In_ PDRIVER_OBJECT_UM DriverObject, + _In_ PVOID Context, + _In_ IWudfDeviceStack * DevStack, + _In_ LPCWSTR KernelDeviceName, + _In_opt_ HKEY PdoKey, + _In_ LPCWSTR ServiceName, + _In_ LPCWSTR DevInstanceID, + _In_ ULONG DriverID + ) +{ + FxDriver *pDriver; + + // + // Context parameter is CWudfDriverGlobals in legacy UMDF. Not used in + // UMDF 2.0 + // + UNREFERENCED_PARAMETER(Context); + + pDriver = FxDriver::GetFxDriver(DriverObject); + + + + if (pDriver != NULL) { + return pDriver->AddDevice(DevStack, + KernelDeviceName, + PdoKey, + ServiceName, + DevInstanceID, + DriverID + ); + } + + return STATUS_UNSUCCESSFUL; +} + +_Must_inspect_result_ +NTSTATUS +FxDriver::AddDevice( + _In_ IWudfDeviceStack * DevStack, + _In_ LPCWSTR KernelDeviceName, + _In_opt_ HKEY PdoKey, + _In_ LPCWSTR ServiceName, + _In_ LPCWSTR DevInstanceID, + _In_ ULONG DriverID + ) +{ + WDFDEVICE_INIT init(this); + FxDevice* pDevice; + NTSTATUS status; + HRESULT hr = S_OK; + LONG lRetVal = -1; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Enter AddDevice DevStack %p", DevStack); + + //FX_VERIFY(INTERNAL, CHECK_NOT_NULL(DevStack)); + //FX_VERIFY(INTERNAL, CHECK_NOT_NULL(KernelDeviceName)); + //FX_VERIFY(INTERNAL, CHECK_HANDLE(PdoKey)); + //FX_VERIFY(INTERNAL, CHECK_NOT_NULL(ServiceName)); + //FX_VERIFY(INTERNAL, CHECK_NOT_NULL(DevInstanceID)); + + pDevice = NULL; + init.CreatedOnStack = TRUE; + init.InitType = FxDeviceInitTypeFdo; + init.Fdo.PhysicalDevice = NULL; + + // + // Capture the input parameters + // + init.DevStack = DevStack; + init.DriverID = DriverID; + + lRetVal = RegOpenKeyEx( + PdoKey, + NULL, + 0, + KEY_READ, + &init.PdoKey + ); + + if (ERROR_SUCCESS != lRetVal) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Registry key open failed for the PDO key, " + "winerror %!WINERROR!", lRetVal); + + hr = HRESULT_FROM_WIN32(lRetVal); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + size_t len = 0; + hr = StringCchLengthW(ServiceName, STRSAFE_MAX_CCH, &len); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Registry path string too long or badly formed " + "path. Invalid configuration HRESULT %!hresult!", + hr); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + len += 1; // Add one for the string termination character + init.ConfigRegistryPath = new WCHAR[len]; + if (NULL == init.ConfigRegistryPath) { + hr = E_OUTOFMEMORY; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Failed to allocate memory for Config path" + " HRESULT %!hresult!", hr); + + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + hr = StringCchCopyW(init.ConfigRegistryPath, len, ServiceName); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Failed to copy the configuration path status " + "%!hresult!", hr); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + // + // Capture the PDO device instance ID. + // + len = 0; + hr = StringCchLengthW(DevInstanceID, STRSAFE_MAX_CCH, &len); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Device Instance ID string too long or badly formed" + " path. Invalid configuration %!hresult!", hr); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + len += 1; // Add one for the string termination character + init.DevInstanceID = new WCHAR[len]; + if (NULL == init.DevInstanceID) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Failed to allocate memory for DevInstanceID " + "%!hresult!", hr); + hr = E_OUTOFMEMORY; + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + hr = StringCchCopyW(init.DevInstanceID, len, DevInstanceID); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Unable to copy DevInstanceID %!hresult!", hr); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + // + // Capture Kernel device name. + // + len = 0; + hr = StringCchLengthW(KernelDeviceName, STRSAFE_MAX_CCH, &len); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Unable to determine KernelDeviceName length" + "%!hresult!", hr); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + len += 1; // Add one for string termination character. + init.KernelDeviceName = new WCHAR[len]; + if (init.KernelDeviceName == NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Failed to allocate memory for KernelDeviceName " + "%!hresult!", hr); + hr = E_OUTOFMEMORY; + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + hr = StringCchCopyW(init.KernelDeviceName, len, KernelDeviceName); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Unable to copy kernel device name KernelDeviceName" + " %!hresult!", hr); + return FxDevice::NtStatusFromHr(DevStack, hr); + } + + // + // Invoke driver's AddDevice callback + // + status = m_DriverDeviceAdd.Invoke(GetHandle(), &init); + + // + // Caller returned w/out creating a device, we are done. Returning + // STATUS_SUCCESS w/out creating a device and attaching to the stack is OK, + // especially for filter drivers which selectively attach to devices. + // + if (init.CreatedDevice == NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Driver did not create a device in " + "EvtDriverAddDevice, status %!STATUS!", status); + + // + // We do not let filters affect the building of the rest of the stack. + // If they return error, we convert it to STATUS_SUCCESS. + // + if (init.Fdo.Filter && !NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Filter returned %!STATUS! without creating a WDFDEVICE, " + "converting to STATUS_SUCCESS", status); + status = STATUS_SUCCESS; + } + + return status; + } + + pDevice = init.CreatedDevice; + + if (NT_SUCCESS(status)) { + // + // Make sure that DO_DEVICE_INITIALIZING is cleared. + // FxDevice::FdoInitialize does not do this b/c the driver writer may + // want the bit set until sometime after WdfDeviceCreate returns + // + pDevice->FinishInitializing(); + } + else { + // + // Created a device, but returned error. + // + ASSERT(pDevice->IsPnp()); + ASSERT(pDevice->m_CurrentPnpState == WdfDevStatePnpInit); + + status = pDevice->DeleteDeviceFromFailedCreate(status, TRUE); + pDevice = NULL; + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit, status %!STATUS!", status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDriver::AllocateDriverObjectExtensionAndStoreFxDriver( + VOID + ) +{ + // + // No allocation needed for user-mode, just store FxDriver in driver object. + // + m_DriverObject.GetObject()->FxDriver = this; + + return STATUS_SUCCESS; +} + +FxDriver* +FxDriver::GetFxDriver( + __in MdDriverObject DriverObject + ) +{ + return DriverObject->FxDriver; +} + +VOID +FxDriver::ClearDriverObjectFxDriver( + VOID + ) +{ + PDRIVER_OBJECT_UM pDriverObj = m_DriverObject.GetObject(); + + if (pDriverObj != NULL) { + pDriverObj->FxDriver = NULL; + } +} + +NTSTATUS +FxDriver::OpenParametersKey( + VOID + ) +{ + HRESULT hr; + NTSTATUS status; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + PDRIVER_OBJECT_UM pDrvObj = GetDriverObject(); + IWudfDeviceStack* pDevStack = (IWudfDeviceStack*)pDrvObj->WudfDevStack; + + UMINT::WDF_PROPERTY_STORE_ROOT rootSpecifier; + UMINT::WDF_PROPERTY_STORE_RETRIEVE_FLAGS flags; + CANSI_STRING serviceNameA; + DECLARE_UNICODE_STRING_SIZE(serviceNameW, WDF_DRIVER_GLOBALS_NAME_LEN); + HKEY hKey; + + RtlInitAnsiString(&serviceNameA, FxDriverGlobals->Public.DriverName); + status = RtlAnsiStringToUnicodeString(&serviceNameW, + &serviceNameA, + FALSE); + if (NT_SUCCESS(status)) { + rootSpecifier.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + rootSpecifier.RootClass = UMINT::WdfPropertyStoreRootDriverParametersKey; + rootSpecifier.Qualifier.ParametersKey.ServiceName = serviceNameW.Buffer; + + flags = UMINT::WdfPropertyStoreCreateIfMissing; + + hr = pDevStack->CreateRegistryEntry(&rootSpecifier, + flags, + GENERIC_ALL & ~(GENERIC_WRITE | KEY_CREATE_SUB_KEY | WRITE_DAC), + NULL, + &hKey, + NULL); + status = FxDevice::NtStatusFromHr(pDevStack, hr); + if (NT_SUCCESS(status)) { + m_DriverParametersKey = hKey; + } + } + + return status; +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxfileobjectapium.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxfileobjectapium.cpp new file mode 100644 index 00000000000..99a38688d85 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxfileobjectapium.cpp @@ -0,0 +1,180 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectApiUm.cpp + +Abstract: + + This modules implements the C API's for the FxFileObject. + +Author: + + + +Environment: + + User mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" +#include "FxFileObject.hpp" + +extern "C" { +#include "FxFileObjectApiUm.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFileObjectClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(FileObject); + + FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("Not implemented"), DriverGlobals->DriverName); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfFileObjectGetInitiatorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + DDI_ENTRY(); + + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + if (pFO->GetWdmFileObject() != NULL) { + return pFO->GetWdmFileObject()->GetInitiatorProcessId(); + } + else { + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), TRAPMSG("Cannot get initiator " + "process ID from a file object that doesn't have a WDM file object"), + DriverGlobals->DriverName); + return 0; + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDFFILEOBJECT +WDFEXPORT(WdfFileObjectGetRelatedFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + DDI_ENTRY(); + + FxFileObject* pFO; + FxFileObject* pFoRelated; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + pFoRelated = pFO->GetRelatedFileObject(); + + if (pFoRelated != NULL) { + return pFoRelated->GetHandle(); + } + else { + return NULL; + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFileObjectIncrementProcessKeepAliveCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + // + // This DDI is expected to be called per WDFREQUEST + // and the caller may be impersonated at that time. + // + DDI_ENTRY_IMPERSONATION_OK(); + + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + return pFO->UpdateProcessKeepAliveCount(TRUE /*Increment*/); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFileObjectDecrementProcessKeepAliveCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + // + // This DDI is expected to be called per WDFREQUEST + // and the caller may be impersonated at that time. + // + DDI_ENTRY_IMPERSONATION_OK(); + + FxFileObject* pFO; + + // + // Validate the FileObject object handle, and get its FxFileObject* + // + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + return pFO->UpdateProcessKeepAliveCount(FALSE /*Increment*/); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxfileobjectum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxfileobjectum.cpp new file mode 100644 index 00000000000..65c58e32831 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxfileobjectum.cpp @@ -0,0 +1,119 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectUm.hpp + +Abstract: + + This module implements a frameworks managed FileObject + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxFileObjectUm.tmh" +} + +VOID +FxFileObject::SetFileObjectContext( + _In_ MdFileObject WdmFileObject, + _In_ WDF_FILEOBJECT_CLASS NormalizedFileClass, + _In_ MdIrp Irp, + _In_ FxDevice* Device + ) +{ + IWudfIoIrp* pIoIrp; + HRESULT hrQi; + + UNREFERENCED_PARAMETER(WdmFileObject); + UNREFERENCED_PARAMETER(NormalizedFileClass); + + ASSERT(NormalizedFileClass == WdfFileObjectWdfCannotUseFsContexts); + + // + // In UMDF, fx file object is stored by host. Host passes it back to + // framework as a parameter to irp dispatch routine. + // + hrQi = Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQi, pIoIrp)); + pIoIrp->Release(); + + pIoIrp->SetFrameworkFileObjectContext(Device->GetDeviceObject(), + (IUnknown *) this); +} + +VOID +FxFileObject::Initialize( + _In_ MdIrp CreateIrp + ) +{ + FxIrp irp(CreateIrp); + IWudfIoIrp* ioIrp = irp.GetIoIrp(); + IUnknown* pCxtFramework = NULL; + FxFileObject* pRelatedFileObj = NULL; + + // + // Get framework related file object. + // + ioIrp->GetFrameworkRelatedFileObjectContext( + m_Device->GetDeviceObject(), + &pCxtFramework + ); + if (pCxtFramework != NULL) { + pRelatedFileObj = (FxFileObject*) pCxtFramework; + + pRelatedFileObj->AddRef(); + this->m_RelatedFileObject = pRelatedFileObj; + } + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxFileObject::UpdateProcessKeepAliveCount( + _In_ BOOLEAN Increment + ) +{ + MdFileObject pWdmFO = GetWdmFileObject(); + FxDevice* pDevice = GetDevice(); + + if (pWdmFO == NULL) { + FX_VERIFY(DRIVER(BadArgument, TODO), TRAPMSG("Cannot increment " + "process keep alive count from a file object that doesn't " + "have a WDM file object")); + return STATUS_INVALID_PARAMETER; + } + + // + // Validate that driver set UmdfFsContextUsePolicy = CannotUseFsContexts + // + if (pDevice->m_FsContextUsePolicy != WdfCannotUseFsContexts) { + FX_VERIFY(DRIVER(BadArgument, TODO), TRAPMSG("Cannot increment " + "process keep alive count unless UmdfFsContextUsePolicy INF " + "directive is set to WdfCannotUseFsContexts")); + return STATUS_INVALID_DEVICE_REQUEST; + } + + return pDevice->NtStatusFromHr( + pDevice->GetDeviceStack2()-> + UpdateProcessKeepAliveCount(pWdmFO, Increment)); +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxirpum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxirpum.cpp new file mode 100644 index 00000000000..8f9b25c4dca --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxirpum.cpp @@ -0,0 +1,1814 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "fxmin.hpp" + +extern "C" { +#include "FxIrpUm.tmh" + +extern IWudfHost2 *g_IWudfHost2; +} + +#define TraceEvents(a,b,c,d,e) UNREFERENCED_PARAMETER(d); + +MdIrp +FxIrp::GetIrp( + VOID + ) +{ + return m_Irp; +} + + +VOID +FxIrp::CompleteRequest( + __in_opt CCHAR PriorityBoost + ) +{ + UNREFERENCED_PARAMETER(PriorityBoost); + + m_Irp->CompleteRequest(); + m_Irp = NULL; +} + + +NTSTATUS +FxIrp::CallDriver( + __in MdDeviceObject DeviceObject + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + + m_Irp->Forward(); + return STATUS_SUCCESS; +} + + +NTSTATUS +FxIrp::PoCallDriver( + __in MdDeviceObject DeviceObject + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + + m_Irp->Forward(); + return STATUS_SUCCESS; +} + + + +VOID +FxIrp::StartNextPowerIrp( + ) +{ + + + + DO_NOTHING(); +} + + +VOID +FxIrp::SetCompletionRoutine( + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess, + __in BOOLEAN InvokeOnError, + __in BOOLEAN InvokeOnCancel + ) +{ + UNREFERENCED_PARAMETER(InvokeOnSuccess); + UNREFERENCED_PARAMETER(InvokeOnError); + UNREFERENCED_PARAMETER(InvokeOnCancel); + + // + // In UMDF completion callback is invoked in all three cases, there isn't an option + // to invoke it selectively + + + + + FX_VERIFY(INTERNAL, CHECK( + "UMDF completion routine can't be invoked selectively on Success/Error/Cancel", + (TRUE == InvokeOnSuccess) && + (TRUE == InvokeOnError) && + (TRUE == InvokeOnCancel))); + + m_Irp->SetCompletionRoutine( + CompletionRoutine, + Context + ); +} + +VOID +FxIrp::SetCompletionRoutineEx( + __in MdDeviceObject DeviceObject, + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess, + __in BOOLEAN InvokeOnError, + __in BOOLEAN InvokeOnCancel + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + + SetCompletionRoutine( + CompletionRoutine, + Context, + InvokeOnSuccess, + InvokeOnError, + InvokeOnCancel); +} + +MdCancelRoutine +FxIrp::SetCancelRoutine( + __in_opt MdCancelRoutine CancelRoutine + ) +{ + return m_Irp->SetCancelRoutine(CancelRoutine); +} + + +NTSTATUS +FxIrp::_IrpSynchronousCompletion( + __in MdDeviceObject DeviceObject, + __in MdIrp /*OriginalIrp*/, + __in PVOID Context + ) +{ + HANDLE event = (HANDLE) Context; + + UNREFERENCED_PARAMETER(DeviceObject); + + SetEvent(event); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + + +_Must_inspect_result_ +NTSTATUS +FxIrp::SendIrpSynchronously( + __in MdDeviceObject DeviceObject + ) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE event; + + UNREFERENCED_PARAMETER(DeviceObject); + + event = CreateEvent( + NULL, + TRUE, //bManualReset + FALSE, //bInitialState + NULL //Name + ); + + if (NULL == event) + { +#pragma prefast(suppress:__WARNING_MUST_USE, "we convert all Win32 errors into a generic failure currently") + DWORD err = GetLastError(); + + // + // As such event creation would fail only for resource reasons if we pass + // correct parameters + // + + status = STATUS_INSUFFICIENT_RESOURCES; + + TraceEvents( TRACE_LEVEL_ERROR, + FX_TRACE_IO, + "Failed to create event, error: %!WINERROR!, " + "returning %!STATUS!", + err, status); + + } + + if (NT_SUCCESS(status)) + { + SetCompletionRoutine(_IrpSynchronousCompletion, + event, + TRUE, + TRUE, + TRUE); + + m_Irp->Forward(); + + DWORD retval = WaitForSingleObject(event, INFINITE); + FX_VERIFY(INTERNAL, CHECK("INFNITE wait failed", + (retval == WAIT_OBJECT_0))); + + status = this->GetStatus(); + } + + return status; +} + + +VOID +FxIrp::CopyCurrentIrpStackLocationToNext( + VOID + ) +{ + m_Irp->CopyCurrentIrpStackLocationToNext(); +} + +UCHAR +FxIrp::GetMajorFunction( + VOID + ) +{ + UCHAR majorFunction = IRP_MJ_MAXIMUM_FUNCTION; + IWudfIoIrp * pIoIrp = NULL; + IWudfPnpIrp * pPnpIrp = NULL; + + // + // IWudfIrp does not expose a method to get major function code. So we + // find out if it's an I/O irp or pnp irp. If I/O irp then we use GetType + // method to retrieve request tyoe and then map it to major function code, + // otherwise if it is pnp irp then we just use GetMajorFunction method + // exposed by IWudfPnpIrp. + // + HRESULT hrQI = m_Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + if (SUCCEEDED(hrQI)) { + UMINT::WDF_REQUEST_TYPE type; + + // + // for Io irp, map request type to major funcction + // + type = (UMINT::WDF_REQUEST_TYPE) pIoIrp->GetType(); + switch(type) { + case UMINT::WdfRequestCreate: + majorFunction = IRP_MJ_CREATE; + break; + case UMINT::WdfRequestCleanup: + majorFunction = IRP_MJ_CLEANUP; + break; + case UMINT::WdfRequestRead: + majorFunction = IRP_MJ_READ; + break; + case UMINT::WdfRequestWrite: + majorFunction = IRP_MJ_WRITE; + break; + case UMINT::WdfRequestDeviceIoControl: + majorFunction = IRP_MJ_DEVICE_CONTROL; + break; + case UMINT::WdfRequestClose: + majorFunction = IRP_MJ_CLOSE; + break; + case UMINT::WdfRequestInternalIoctl: + majorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + break; + case UMINT::WdfRequestFlushBuffers: + majorFunction = IRP_MJ_FLUSH_BUFFERS; + break; + case UMINT::WdfRequestQueryInformation: + majorFunction = IRP_MJ_QUERY_INFORMATION; + break; + case UMINT::WdfRequestSetInformation: + majorFunction = IRP_MJ_SET_INFORMATION; + break; + case UMINT::WdfRequestUsb: + case UMINT::WdfRequestOther: + // fall through + default: + FX_VERIFY(INTERNAL, TRAPMSG("The request type is not expected")); + } + + pIoIrp->Release(); + } + else { + FX_VERIFY(INTERNAL, CHECK_NULL(pIoIrp)); + + // + // see if it is a pnp irp + // + hrQI = m_Irp->QueryInterface(IID_IWudfPnpIrp, (PVOID*)&pPnpIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pPnpIrp)); + + majorFunction = pPnpIrp->GetMajorFunction(); + pPnpIrp->Release(); + } + + return majorFunction; +} + +UCHAR +FxIrp::GetMinorFunction( + VOID + ) +{ + UCHAR minorFunction; + IWudfPnpIrp * pPnpIrp = NULL; + IWudfIoIrp * pIoIrp = NULL; + + HRESULT hrQI = m_Irp->QueryInterface(IID_IWudfPnpIrp, (PVOID*)&pPnpIrp); + if (SUCCEEDED(hrQI)) { + minorFunction = pPnpIrp->GetMinorFunction(); + pPnpIrp->Release(); + } + else { + // + // If this is not PnP irp then this must be Io irp. + // + hrQI = m_Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pIoIrp)); + pIoIrp->Release(); + + // + // Minor function is 0 for I/O irps (create/cleanup/close/read/write/ + // ioctl). + // + minorFunction = 0; + } + + return minorFunction; +} + +KPROCESSOR_MODE +FxIrp::GetRequestorMode( + VOID + ) +{ + IWudfIoIrp * pIoIrp = NULL; + + HRESULT hrQI = m_Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + + if (SUCCEEDED(hrQI)) { + KPROCESSOR_MODE requestorMode; + + requestorMode = pIoIrp->GetRequestorMode(); + pIoIrp->Release(); + + return requestorMode; + } + else { + return KernelMode; + } +} + +VOID +FxIrp::SetContext( + __in ULONG Index, + __in PVOID Value + ) +{ + m_Irp->SetContext(Index, Value); +} + + +PVOID +FxIrp::GetContext( + __in ULONG Index + ) +{ + return m_Irp->GetContext(Index); +} + + +PIO_STACK_LOCATION +FxIrp::GetCurrentIrpStackLocation( + VOID + ) +{ + + + + + // The Km implementation does some verifier checks in this function so + // mode agnostic code uses it and therefore we provide the um version as a + // stub. The return value is NULL and is not used by the caller. + // + return NULL; +} + + +PIO_STACK_LOCATION +FxIrp::GetNextIrpStackLocation( + VOID + ) +{ + + + + + FX_VERIFY(INTERNAL, TRAPMSG("Common code using io stack location directly")); + return NULL; +} + +VOID +FxIrp::SkipCurrentIrpStackLocation( + VOID + ) +{ + // + // Earler we always used to copy because the framework always set a + // completion routine to notify other packages that we completed. However, + // since some I/O paths relied on Skip to revert the action taken by + // SetNextStackLocation in failure paths, we now skip instead of copy. The + // same behavior applies to KMDF as well. + // + m_Irp->SkipCurrentIrpStackLocation(); +} + +VOID +FxIrp::MarkIrpPending( + VOID + ) +{ + + + + + + m_Irp->MarkIrpPending(); +} + + +BOOLEAN +FxIrp::PendingReturned( + VOID + ) +{ + + + + + + return m_Irp->PendingReturned(); +} + + +VOID +FxIrp::PropagatePendingReturned( + VOID + ) +{ + + + + + + m_Irp->PropagatePendingReturned(); +} + + +VOID +FxIrp::SetStatus( + __in NTSTATUS Status + ) +{ + m_Irp->SetStatus(Status); +} + + +NTSTATUS +FxIrp::GetStatus( + VOID + ) +{ + return m_Irp->GetStatus(); +} + + +BOOLEAN +FxIrp::Cancel( + VOID + ) +{ + return (m_Irp->Cancel() ? TRUE: FALSE); +} + + +BOOLEAN +FxIrp::IsCanceled( + ) +{ + return (m_Irp->IsCanceled() ? TRUE: FALSE); +} + + +KIRQL +FxIrp::GetCancelIrql( + ) +{ + // + // CancelIrql is used to pass in to IoReleaseCancelSpinLock + // hence it is not applicable to UMDF. + // + return PASSIVE_LEVEL; +} + + +VOID +FxIrp::SetInformation( + __in ULONG_PTR Information + ) +{ + m_Irp->SetInformation(Information); +} + + +ULONG_PTR +FxIrp::GetInformation( + ) +{ + return m_Irp->GetInformation(); +} + + +CCHAR +FxIrp::GetCurrentIrpStackLocationIndex( + ) +{ + + + + + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + + return -1; +} + + +PLIST_ENTRY +FxIrp::ListEntry( + ) +{ + return m_Irp->GetListEntry(); +} + + +PVOID +FxIrp::GetSystemBuffer( + ) +{ + IWudfIoIrp * ioIrp = NULL; + PVOID systemBuffer = NULL; + HRESULT hr; + + ioIrp = GetIoIrp(); + + switch (GetMajorFunction()) { + case IRP_MJ_WRITE: + // + // For write host provides the buffer as input buffer + // + hr = ioIrp->RetrieveBuffers(NULL, // InputBufferCb + &systemBuffer,// InputBuffer + NULL, // OutputBufferCb + NULL // OutputBuffer + ); + break; + case IRP_MJ_READ: + // + // For read host provides the buffer as output buffer + // + hr = ioIrp->RetrieveBuffers(NULL, // InputBufferCb + NULL, // InputBuffer + NULL, // OutputBufferCb + &systemBuffer // OutputBuffer + ); + break; + case IRP_MJ_DEVICE_CONTROL: + hr = ioIrp->RetrieveBuffers(NULL, // InputBufferCb + &systemBuffer,// InputBuffer + NULL, // OutputBufferCb + NULL // OutputBuffer + ); + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + hr = E_NOTIMPL; + break; + } + + if (FAILED(hr)) { + systemBuffer = NULL; + } + + return systemBuffer; +} + +PVOID +FxIrp::GetOutputBuffer( + ) +{ + IWudfIoIrp * ioIrp = NULL; + PVOID outputBuffer = NULL; + HRESULT hr; + + ioIrp = GetIoIrp(); + + switch (GetMajorFunction()) { + case IRP_MJ_DEVICE_CONTROL: + hr = ioIrp->RetrieveBuffers(NULL, // InputBufferCb + NULL, // InputBuffer + NULL, // OutputBufferCb + &outputBuffer // OutputBuffer + ); + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + hr = E_NOTIMPL; + break; + } + + if (FAILED(hr)) { + outputBuffer = NULL; + } + + return outputBuffer; +} + +PMDL +FxIrp::GetMdl( + ) +{ + return NULL; +} + + +PVOID +FxIrp::GetUserBuffer( + ) +{ + // + // UserBuffer is used with METHOD_NEITHER + // For METHOD_NEITHER reflector still makes a copy of the buffer + // in common buffer (if METHOD_NEITHER is enabled via regkey) + // + + IWudfIoIrp * ioIrp = GetIoIrp(); + PVOID userBuffer; + HRESULT hr; + + hr = ioIrp->RetrieveBuffers(NULL, // InputBufferCb + NULL, // InputBuffer + NULL, // OutputBufferCb + &userBuffer // OutputBuffer + ); + if (FAILED(hr)) + { + userBuffer = NULL; + } + + return userBuffer; +} + + +VOID +FxIrp::Reuse( + __in NTSTATUS Status + ) +{ + GetIoIrp()->Reuse(Status); + return; +} + + +SYSTEM_POWER_STATE_CONTEXT +FxIrp::GetParameterPowerSystemPowerStateContext( + ) +{ + SYSTEM_POWER_STATE_CONTEXT systemPwrStateContext = {0}; + + systemPwrStateContext.ContextAsUlong = GetPnpIrp()->GetSystemPowerStateContext(); + + return systemPwrStateContext; +} + + +POWER_STATE_TYPE +FxIrp::GetParameterPowerType( + ) +{ + POWER_STATE_TYPE powerType; + + powerType = GetPnpIrp()->GetPowerType(); + + return powerType; +} + + +DEVICE_POWER_STATE +FxIrp::GetParameterPowerStateDeviceState( + ) +{ + DEVICE_POWER_STATE devicePowerState; + + devicePowerState = GetPnpIrp()->GetPowerStateDeviceState(); + + return devicePowerState; +} + + +SYSTEM_POWER_STATE +FxIrp::GetParameterPowerStateSystemState( + ) +{ + SYSTEM_POWER_STATE systemPowerState; + + systemPowerState = GetPnpIrp()->GetPowerStateSystemState(); + + return systemPowerState; +} + + +POWER_ACTION +FxIrp::GetParameterPowerShutdownType( + ) +{ + POWER_ACTION powerAction; + + powerAction = GetPnpIrp()->GetPowerAction(); + + return powerAction; +} + + +DEVICE_RELATION_TYPE +FxIrp::GetParameterQDRType( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return BusRelations; +} + +// +// Get Methods for IO_STACK_LOCATION.Parameters.QueryInterface + + + + +PINTERFACE +FxIrp::GetParameterQueryInterfaceInterface( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return NULL; +} + +const GUID* +FxIrp::GetParameterQueryInterfaceType( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return NULL; +} + + +USHORT +FxIrp::GetParameterQueryInterfaceVersion( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return 0; +} + + +USHORT +FxIrp::GetParameterQueryInterfaceSize( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return 0; +} + + +PVOID +FxIrp::GetParameterQueryInterfaceInterfaceSpecificData( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return NULL; +} + +// +// Get Method for IO_STACK_LOCATION.Parameters.UsageNotification + + + + + +DEVICE_USAGE_NOTIFICATION_TYPE +FxIrp::GetParameterUsageNotificationType( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return DeviceUsageTypeUndefined; +} + + +BOOLEAN +FxIrp::GetParameterUsageNotificationInPath( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return FALSE; +} + + +VOID +FxIrp::SetParameterUsageNotificationInPath( + __in BOOLEAN /*InPath*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + + +BOOLEAN +FxIrp::GetNextStackParameterUsageNotificationInPath( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + + return FALSE; +} + +// +// Get/Set Methods for IO_STACK_LOCATION.Parameters.StartDevice +// + +PCM_RESOURCE_LIST +FxIrp::GetParameterAllocatedResources( + ) +{ + IWudfPnpIrp * pnpIrp = NULL; + PCM_RESOURCE_LIST res = NULL; + + + + + + + pnpIrp = static_cast(m_Irp); + + res = pnpIrp->GetParameterAllocatedResources(); + + // + // Release the ref even though we are returning a memory pointer from + // IWudfIrp object. This is fine because we know irp is valid for the + // lifetime of the caller who is calling this interface). + // + + + return res; +} + +VOID +FxIrp::SetParameterAllocatedResources( + __in PCM_RESOURCE_LIST /*AllocatedResources*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); +} + +PCM_RESOURCE_LIST +FxIrp::GetParameterAllocatedResourcesTranslated( + ) +{ + IWudfPnpIrp * pnpIrp = NULL; + PCM_RESOURCE_LIST res = NULL; + + + + + + + pnpIrp = static_cast(m_Irp); + + res = pnpIrp->GetParameterAllocatedResourcesTranslated(); + + + return res; +} + +VOID +FxIrp::SetParameterAllocatedResourcesTranslated( + __in PCM_RESOURCE_LIST /*AllocatedResourcesTranslated*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); +} + +VOID +FxIrp::SetMajorFunction( + __in UCHAR MajorFunction + ) +{ + IWudfIoIrp * pIoIrp = NULL; + + // + // IWudfIrp does not expose a method to set major function code directly so + // map it to WdfRequestType. + // + HRESULT hrQI = m_Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + if (SUCCEEDED(hrQI)) { + UMINT::WDF_REQUEST_TYPE type; + + // + // for Io irp, map major function to request type + // + switch(MajorFunction) { + case IRP_MJ_CREATE: + type = UMINT::WdfRequestCreate; + break; + case IRP_MJ_CLEANUP: + type = UMINT::WdfRequestCleanup; + break; + case IRP_MJ_READ: + type = UMINT::WdfRequestRead; + break; + case IRP_MJ_WRITE: + type = UMINT::WdfRequestWrite; + break; + case IRP_MJ_DEVICE_CONTROL: + type = UMINT::WdfRequestDeviceIoControl; + break; + case IRP_MJ_CLOSE: + type = UMINT::WdfRequestClose; + break; + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + type = UMINT::WdfRequestInternalIoctl; + break; + case IRP_MJ_FLUSH_BUFFERS: + type = UMINT::WdfRequestFlushBuffers; + break; + case IRP_MJ_QUERY_INFORMATION: + type = UMINT::WdfRequestQueryInformation; + break; + case IRP_MJ_SET_INFORMATION: + type = UMINT::WdfRequestSetInformation; + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("The request type is not expected")); + type = UMINT::WdfRequestUndefined; + } + + pIoIrp->SetTypeForNextStackLocation(type); + pIoIrp->Release(); + } + else { + FX_VERIFY(INTERNAL, TRAPMSG("Not expected")); + } +} + +VOID +FxIrp::SetMinorFunction( + __in UCHAR /*MinorFunction*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not supported")); +} + +LCID +FxIrp::GetParameterQueryDeviceTextLocaleId( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + + return (LCID)(-1); +} + +DEVICE_TEXT_TYPE +FxIrp::GetParameterQueryDeviceTextType( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + + return (DEVICE_TEXT_TYPE)(-1); +} + +BOOLEAN +FxIrp::GetParameterSetLockLock( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + + return FALSE; +} + +// +// Get Method for IO_STACK_LOCATION.Parameters.QueryId +// + +BUS_QUERY_ID_TYPE +FxIrp::GetParameterQueryIdType( + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); + + return (BUS_QUERY_ID_TYPE)(-1); +} + +POWER_STATE +FxIrp::GetParameterPowerState( + ) +{ + IWudfPnpIrp * pnpIrp = NULL; + POWER_STATE powerState; + + + + + + + pnpIrp = static_cast(m_Irp); + + powerState = pnpIrp->GetPowerState(); + + + return powerState; +} + +VOID +FxIrp::InitNextStackUsingStack( + __in FxIrp* /*Irp*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); +} + + + + +_Must_inspect_result_ +NTSTATUS +FxIrp::RequestPowerIrp( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in PREQUEST_POWER_COMPLETE CompletionFunction, + __in PVOID Context + ) +{ + HRESULT hr; + IWudfDevice* deviceObject; + IWudfDeviceStack *deviceStack; + + deviceObject = DeviceObject; + deviceStack = deviceObject->GetDeviceStackInterface(); + + hr = deviceStack->RequestPowerIrp(MinorFunction, + PowerState, + CompletionFunction, + Context); + + if (S_OK == hr) + { + return STATUS_SUCCESS; + } + else + { + PUMDF_VERSION_DATA driverVersion = deviceStack->GetMinDriverVersion(); + + BOOL preserveCompat = + deviceStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + return CHostFxUtil::NtStatusFromHr( + hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat + ); + } +} + +_Must_inspect_result_ +MdIrp +FxIrp::AllocateIrp( + _In_ CCHAR StackSize, + _In_opt_ FxDevice* Device + ) +{ + IWudfIoIrp* ioIrp; + HRESULT hr; + NTSTATUS status; + + ioIrp = NULL; + + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(Device)); + + // + // UMDF currently support allocating of I/O Irps only + // + hr = Device->GetDeviceStack()->AllocateIoIrp(Device->GetDeviceObject(), + StackSize, + &ioIrp); + + if (FAILED(hr)) { + status = Device->NtStatusFromHr(hr); + DoTraceLevelMessage( + Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "WDFDEVICE 0x%p Failed to allocate I/O request %!STATUS!", + Device->GetHandle(), status); + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(ioIrp), + Device->GetDriverGlobals()->Public.DriverName); + } + else { + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(ioIrp), + Device->GetDriverGlobals()->Public.DriverName); + } + + return ioIrp; +} + +// +// Get/Set Methods for IO_STACK_LOCATION.Parameters.DeviceCapabilities +// + +PDEVICE_CAPABILITIES +FxIrp::GetParameterDeviceCapabilities( + ) +{ + IWudfPnpIrp * pQueryCapsIrp = GetPnpIrp(); + PDEVICE_CAPABILITIES deviceCapabilities; + + deviceCapabilities = pQueryCapsIrp->GetDeviceCapabilities(); + + return deviceCapabilities; +} + + +VOID +FxIrp::SetParameterDeviceCapabilities( + __in PDEVICE_CAPABILITIES /*DeviceCapabilities*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); +} + + + + + +VOID +FxIrp::SetParameterIoctlCode( + __in ULONG /*DeviceIoControlCode*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + + +VOID +FxIrp::SetParameterIoctlInputBufferLength( + __in ULONG /*InputBufferLength*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + + +VOID +FxIrp::SetParameterIoctlType3InputBuffer( + __in PVOID /*Type3InputBuffer*/ + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +VOID +FxIrp::ClearNextStack( + ) +{ + m_Irp->ClearNextStackLocation(); +} + +MdIrp +FxIrp::GetIrpFromListEntry( + __in PLIST_ENTRY ListEntry + ) +{ + return g_IWudfHost2->GetIrpFromListEntry(ListEntry); +} + +FxAutoIrp::~FxAutoIrp() +{ + if (m_Irp != NULL) { + m_Irp->Release(); + m_Irp = NULL; + } +} + +MdCompletionRoutine +FxIrp::GetNextCompletionRoutine( + VOID + ) +{ + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +VOID +FxIrp::CopyToNextIrpStackLocation( + __in PIO_STACK_LOCATION Stack + ) +{ + UNREFERENCED_PARAMETER(Stack); + + + + + + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + +} + +VOID +FxIrp::SetNextIrpStackLocation( + VOID + ) +{ + m_Irp->SetNextIrpStackLocation(); +} + +UCHAR +FxIrp::GetCurrentStackFlags( + VOID + ) +{ + + + + + + + + return 0; +} + +MdFileObject +FxIrp::GetCurrentStackFileObject( + VOID + ) +{ + return GetIoIrp()->GetFile(); +} + +VOID +FxIrp::SetFlags( + __in ULONG Flags + ) +{ + UNREFERENCED_PARAMETER(Flags); + + + + + + + FX_VERIFY(INTERNAL, CHECK_TODO(Flags == 0)); +} + +ULONG +FxIrp::GetFlags( + VOID + ) +{ + + + + + + return 0; +} + +VOID +FxIrp::SetCancel( + __in BOOLEAN Cancel + ) +{ + UNREFERENCED_PARAMETER(Cancel); + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +CCHAR +FxIrp::GetStackCount( + ) +{ + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return 0; +} + +VOID +FxIrp::SetSystemBuffer( + __in PVOID Value + ) +{ + UNREFERENCED_PARAMETER(Value); + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +PMDL* +FxIrp::GetMdlAddressPointer( + ) +{ + return NULL; +} + +VOID +FxIrp::SetMdlAddress( + __in PMDL Value + ) +{ + // + // MDL is not supported in UMDF so must be NULL. + // + FX_VERIFY(INTERNAL, CHECK_NULL(Value)); +} + +VOID +FxIrp::SetUserBuffer( + __in PVOID Value + ) +{ + UNREFERENCED_PARAMETER(Value); + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +MdDeviceObject +FxIrp::GetDeviceObject( + VOID + ) +{ + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +VOID +FxIrp::SetCurrentDeviceObject( + __in MdDeviceObject DeviceObject + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +LONGLONG +FxIrp::GetParameterWriteByteOffsetQuadPart( + ) +{ + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return 0; +} + +VOID +FxIrp::SetNextParameterWriteByteOffsetQuadPart( + __in LONGLONG DeviceOffset + ) +{ + UNREFERENCED_PARAMETER(DeviceOffset); + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +VOID +FxIrp::SetNextParameterWriteLength( + __in ULONG IoLength + ) +{ + UNREFERENCED_PARAMETER(IoLength); + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +VOID +FxIrp::SetNextStackParameterOthersArgument1( + __in PVOID Argument1 + ) +{ + UNREFERENCED_PARAMETER(Argument1); + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +PVOID* +FxIrp::GetNextStackParameterOthersArgument1Pointer( + ) +{ + + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +PVOID* +FxIrp::GetNextStackParameterOthersArgument2Pointer( + ) +{ + + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +PVOID* +FxIrp::GetNextStackParameterOthersArgument4Pointer( + ) +{ + + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +MdFileObject +FxIrp::GetFileObject( + VOID + ) +{ + IWudfIoIrp * pIoIrp = NULL; + + HRESULT hrQI = m_Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pIoIrp)); + pIoIrp->Release(); + + return pIoIrp->GetFile(); +} + +ULONG +FxIrp::GetParameterIoctlCode( + VOID + ) +{ + IWudfIoIrp * ioIrp = NULL; + ULONG ioControlCode = 0; + + if (GetMajorFunction() == IRP_MJ_DEVICE_CONTROL) { + ioIrp = GetIoIrp(); + ioIrp->GetDeviceIoControlParameters(&ioControlCode, NULL, NULL); + } + + return ioControlCode; +} + +ULONG +FxIrp::GetParameterIoctlCodeBufferMethod( + VOID + ) +{ + // + // For UMDF, always return METHOD_BUFFERED. This is because merged code + // uses this info to decide how and where to fetch the buffers from, from + // inside the irp, and for UMDF, the buffers are always fetched from host in + // same manner irrespective of IOCTL type. + // + return METHOD_BUFFERED; +} + +ULONG +FxIrp::GetParameterIoctlOutputBufferLength( + VOID + ) +{ + IWudfIoIrp * ioIrp = NULL; + ULONG outputBufferLength; + + ioIrp = GetIoIrp(); + ioIrp->GetDeviceIoControlParameters(NULL, NULL, &outputBufferLength); + + return outputBufferLength; +} + +ULONG +FxIrp::GetParameterIoctlInputBufferLength( + VOID + ) +{ + IWudfIoIrp * ioIrp = NULL; + ULONG inputBufferLength; + + ioIrp = GetIoIrp(); + ioIrp->GetDeviceIoControlParameters(NULL, &inputBufferLength, NULL); + + return inputBufferLength; +} + +VOID +FxIrp::SetParameterIoctlOutputBufferLength( + __in ULONG OutputBufferLength + ) +{ + UNREFERENCED_PARAMETER(OutputBufferLength); + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); +} + +PVOID +FxIrp::GetParameterIoctlType3InputBuffer( + VOID + ) +{ + + + + + + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +VOID +FxIrp::SetNextStackFlags( + __in UCHAR Flags + ) +{ + UNREFERENCED_PARAMETER(Flags); + + + + + + + + + DO_NOTHING(); +} + +VOID +FxIrp::SetNextStackFileObject( + _In_ MdFileObject FileObject + ) +{ + GetIoIrp()->SetFileForNextIrpStackLocation(FileObject); +} + +VOID +FxIrp::ClearNextStackLocation( + VOID + ) +{ + m_Irp->ClearNextStackLocation(); +} + +ULONG +FxIrp::GetParameterReadLength( + VOID + ) +{ + ULONG length; + + GetIoIrp()->GetReadParameters(&length, NULL, NULL); + + return length; +} + +ULONG +FxIrp::GetParameterWriteLength( + VOID + ) +{ + ULONG length; + + GetIoIrp()->GetWriteParameters(&length, NULL, NULL); + + return length; +} + +ULONG +FxIrp::GetCurrentFlags( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return 0; +} + +PVOID +FxIrp::GetCurrentParametersPointer( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +MdEThread +FxIrp::GetThread( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +BOOLEAN +FxIrp::Is32bitProcess( + VOID + ) +{ + return (GetIoIrp()->IsFrom32BitProcess() ? TRUE : FALSE); +} + +VOID +FxIrp::FreeIrp( + VOID + ) +{ + // + // Release the um com irp creation ref + // + m_Irp->Release(); + + // + // This is equivalent to IoFreeIrp in km. + // + GetIoIrp()->Deallocate(); +} + +PIO_STATUS_BLOCK +FxIrp::GetStatusBlock( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +PVOID +FxIrp::GetDriverContext( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return NULL; +} + +ULONG +FxIrp::GetDriverContextSize( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("To be implemented")); + return 0; +} + +VOID +FxIrp::CopyParameters( + _Out_ PWDF_REQUEST_PARAMETERS Parameters + ) +{ + IWudfIoIrp* ioIrp; + UCHAR majorFunction; + + ioIrp = GetIoIrp(); + majorFunction = GetMajorFunction(); + + switch (majorFunction) { + case IRP_MJ_CREATE: + ioIrp->GetCreateParameters( + &Parameters->Parameters.Create.Options, + &Parameters->Parameters.Create.FileAttributes, + &Parameters->Parameters.Create.ShareAccess, + NULL // ACCESS_MASK* + ); + break; + case IRP_MJ_READ: + ioIrp->GetReadParameters((ULONG*)&Parameters->Parameters.Read.Length, + &Parameters->Parameters.Read.DeviceOffset, + &Parameters->Parameters.Read.Key); + break; + case IRP_MJ_WRITE: + ioIrp->GetWriteParameters((ULONG*)&Parameters->Parameters.Write.Length, + &Parameters->Parameters.Write.DeviceOffset, + &Parameters->Parameters.Write.Key); + break; + case IRP_MJ_DEVICE_CONTROL: + ioIrp->GetDeviceIoControlParameters( + &Parameters->Parameters.DeviceIoControl.IoControlCode, + (ULONG*)&Parameters->Parameters.DeviceIoControl.InputBufferLength, + (ULONG*)&Parameters->Parameters.DeviceIoControl.OutputBufferLength + ); + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Not expected")); + break; + } + + return; +} + +VOID +FxIrp::CopyStatus( + _Out_ PIO_STATUS_BLOCK StatusBlock + ) +{ + StatusBlock->Status = GetStatus(); + StatusBlock->Information = GetInformation(); +} + +BOOLEAN +FxIrp::HasStack( + _In_ UCHAR StackCount + ) +{ + UNREFERENCED_PARAMETER(StackCount); + + + + + + + + return TRUE; +} + +BOOLEAN +FxIrp::IsCurrentIrpStackLocationValid( + VOID + ) +{ + + + + + + + + + return TRUE; +} + +IWudfIoIrp* +FxIrp::GetIoIrp( + VOID + ) +{ + IWudfIoIrp* pIoIrp; + HRESULT hrQI; + + hrQI = m_Irp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pIoIrp)); + pIoIrp->Release(); + + // + // Now that we confirmed the irp is an io irp, just return the underlying + // irp. + // + return static_cast(m_Irp); +} + + +IWudfPnpIrp* +FxIrp::GetPnpIrp( + VOID + ) +{ + IWudfPnpIrp* pPnpIrp; + HRESULT hrQI; + + hrQI = m_Irp->QueryInterface(IID_IWudfPnpIrp, (PVOID*)&pPnpIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pPnpIrp)); + pPnpIrp->Release(); + + // + // Now that we confirmed the irp is a pnp irp, just return the underlying + // irp. + // + return static_cast(m_Irp); +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxmessagedispatchum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxmessagedispatchum.cpp new file mode 100644 index 00000000000..51c21a4a89c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxmessagedispatchum.cpp @@ -0,0 +1,386 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxMessageDispatchUm.cpp + +Abstract: + + Implements the host process dispatcher object. See header file for + details. + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ + +#include "fxmin.hpp" +#include "fxldrum.h" + +extern "C" +{ +#include "FxMessageDispatchUm.tmh" +} + +// {cba20727-0910-4a8a-aada-c31d5cf5bf20} +extern const GUID IID_FxMessageDispatch = +{0xcba20727, 0x0910, 0x4a8a, { 0xaa, 0xda, 0xc3, 0x1d, 0x5c, 0xf5, 0xbf, 0x20 }}; + +// +// Manager functions. +// +NTSTATUS +FxMessageDispatch::_CreateAndInitialize( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_ FxDevice* Device, + _Out_ FxMessageDispatch ** ppWudfDispatcher + ) +{ + HRESULT hr = S_OK; + FxMessageDispatch * pWudfDispatcher = NULL; + NTSTATUS status; + + *ppWudfDispatcher = NULL; + + pWudfDispatcher = new (DriverGlobals) FxMessageDispatch(Device); + if (NULL == pWudfDispatcher) { + hr = E_OUTOFMEMORY; + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Memory allocation failure. Cannot create Dispatcher object.\n"); + goto Done; + } + + *ppWudfDispatcher = pWudfDispatcher; + +Done: + + if (FAILED(hr)) { + status = Device->NtStatusFromHr(hr); + } + else { + status = STATUS_SUCCESS; + } + + return status; +} + +// +// IUnknown +// +ULONG +FxMessageDispatch::AddRef() +{ + LONG cRefs = InterlockedIncrement( &m_cRefs ); + + // + // This allows host to manage the lifetime of FxDevice. + // + m_Device->ADDREF(this); + + return cRefs; +} + + +ULONG +FxMessageDispatch::Release() +{ + LONG cRefs = InterlockedDecrement( &m_cRefs ); + + if (0 == cRefs) { + // + // The lifetime of this object is controlled by FxDevice + // object (the container object), and not by this ref count. FxDevice + // will delete this object in its destructior. + // + DO_NOTHING(); + } + + // + // This allows host to manage the lifetime of FxDevice. If this is the last + // release on FxDevice, FxDevice will e deleted and this object will be + // deleted as part of FxDevice destructor. + // + m_Device->RELEASE(this); + + return cRefs; +} + +HRESULT +FxMessageDispatch::QueryInterface( + _In_ const IID& iid, + _Out_ void ** ppv + ) +{ + if ( NULL == ppv ) { + return E_INVALIDARG; + } + + if ( iid == IID_IUnknown) { + *ppv = static_cast (this); + } + else if ( iid == IID_IFxMessageDispatch ) { + *ppv = static_cast (this); + } + else if ( iid == IID_IFxMessageDispatch2 ) { + *ppv = static_cast (this); + } + else if ( iid == IID_FxMessageDispatch ) { + *ppv = this; + } + else { + *ppv = NULL; + return E_NOINTERFACE; + } + + this->AddRef(); + return S_OK; +} + +// +// IFxMessageDispatch +// +void +FxMessageDispatch::DispatchPnP( + _In_ IWudfIrp * pIrp + ) +{ + IWudfPnpIrp * pIPnpIrp = NULL; + + HRESULT hrQI = pIrp->QueryInterface(IID_IWudfPnpIrp, (PVOID*)&pIPnpIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pIPnpIrp)); + + if (IRP_MJ_POWER == pIPnpIrp->GetMajorFunction()) { + GetDriverObject()->MajorFunction[IRP_MJ_POWER](GetDeviceObject(), + pIrp, + NULL); + } + else { + GetDriverObject()->MajorFunction[IRP_MJ_PNP](GetDeviceObject(), + pIrp, + NULL); + } + + SAFE_RELEASE(pIPnpIrp); +} + +void +FxMessageDispatch::CreateFile( + _In_ IWudfIoIrp * pCreateIrp + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_CREATE](GetDeviceObject(), + pCreateIrp, + NULL); +} + +void +FxMessageDispatch::DeviceControl( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_DEVICE_CONTROL](GetDeviceObject(), + pIrp, + pFxContext); +} + +void +FxMessageDispatch::ReadFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_READ](GetDeviceObject(), pIrp, pFxContext); +} + +void +FxMessageDispatch::WriteFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_WRITE](GetDeviceObject(), pIrp, pFxContext); +} + +void +FxMessageDispatch::CleanupFile( + _In_ IWudfIoIrp * pIrp, + _In_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_CLEANUP](GetDeviceObject(), pIrp, pFxContext); +} + +void +FxMessageDispatch::CloseFile( + _In_ IWudfIoIrp * pIrp, + _In_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_CLOSE](GetDeviceObject(), pIrp, pFxContext); +} + +void +FxMessageDispatch::FlushBuffers( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_FLUSH_BUFFERS](GetDeviceObject(), + pIrp, + pFxContext); +} + +void +FxMessageDispatch::QueryInformationFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_QUERY_INFORMATION]( + GetDeviceObject(), + pIrp, + pFxContext + ); +} + +void +FxMessageDispatch::SetInformationFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ) +{ + GetDriverObject()->MajorFunction[IRP_MJ_SET_INFORMATION](GetDeviceObject(), + pIrp, + pFxContext); +} + +VOID +FxMessageDispatch::GetPreferredTransferMode( + _Out_ UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL *RetrievalMode, + _Out_ UMINT::WDF_DEVICE_IO_TYPE *RWPreference, + _Out_ UMINT::WDF_DEVICE_IO_TYPE *IoctlPreference + ) +{ + FxDevice::GetPreferredTransferMode(GetDeviceObject(), + RetrievalMode, + (WDF_DEVICE_IO_TYPE*)RWPreference, + (WDF_DEVICE_IO_TYPE*)IoctlPreference); +} + +ULONG +FxMessageDispatch::GetDirectTransferThreshold( + VOID + ) +{ + return m_Device->GetDirectTransferThreshold(); +} + +NTSTATUS +FxMessageDispatch::ProcessWmiPowerQueryOrSetData( + _In_ RdWmiPowerAction Action, + _Out_ BOOLEAN *QueryResult + ) +{ + return m_Device->ProcessWmiPowerQueryOrSetData(Action, QueryResult); +} + +WUDF_INTERFACE_CONTEXT +FxMessageDispatch::RemoteInterfaceArrival( + _In_ LPCGUID pDeviceInterfaceGuid, + _In_ PCWSTR pSymbolicLink + ) +{ + return FxDevice::RemoteInterfaceArrival(GetDeviceObject(), + pDeviceInterfaceGuid, + pSymbolicLink); +} + +void +FxMessageDispatch::RemoteInterfaceRemoval( + _In_ WUDF_INTERFACE_CONTEXT RemoteInterfaceID + ) +{ + FxDevice::RemoteInterfaceRemoval(GetDeviceObject(), + RemoteInterfaceID); +} + +BOOL +FxMessageDispatch::TransportQueryID( + _In_ DWORD Id, + _In_ PVOID DataBuffer, + _In_ SIZE_T cbDataBufferSize + ) +{ + return FxDevice::TransportQueryId(GetDeviceObject(), + Id, + DataBuffer, + cbDataBufferSize); +} + +void +FxMessageDispatch::PoFxDevicePowerRequired( + void + ) +{ + FxDevice::PoFxDevicePowerRequired(GetDeviceObject()); +} + +void +FxMessageDispatch::PoFxDevicePowerNotRequired( + void + ) +{ + FxDevice::PoFxDevicePowerNotRequired(GetDeviceObject()); +} + +// +// Additional public functions. +// + +// +// Returns the Dispatcher object from the given interface without +// incrementing the refcount. +// +FxMessageDispatch* +FxMessageDispatch::_GetObjFromItf( + _In_ IFxMessageDispatch* pIFxMessageDispatch + ) +{ + FxMessageDispatch * pWudfDispatcher = NULL; + HRESULT hrQI = pIFxMessageDispatch->QueryInterface( + IID_FxMessageDispatch, + reinterpret_cast(&pWudfDispatcher) + ); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pWudfDispatcher)); + pWudfDispatcher->Release(); //release the reference taken by QI + return pWudfDispatcher; +} + +// +// Returns the specified interface from the given object without +// incrementing the refcount. +// +IFxMessageDispatch* +FxMessageDispatch::_GetDispatcherItf( + _In_ FxMessageDispatch* pWudfDispatcher + ) +{ + IFxMessageDispatch * pIFxMessageDispatch = NULL; + HRESULT hrQI = pWudfDispatcher->QueryInterface(IID_IFxMessageDispatch, + (PVOID*)&pIFxMessageDispatch); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pIFxMessageDispatch)); + pIFxMessageDispatch->Release(); //release the reference taken by QI + return pIFxMessageDispatch; +} diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxnpagedlookasidelistum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxnpagedlookasidelistum.cpp new file mode 100644 index 00000000000..f3d84c7f14c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxnpagedlookasidelistum.cpp @@ -0,0 +1,149 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxNPagedLookasideListUm.cpp + +Abstract: + + This module implements a frameworks managed FxNPagedLookasideList + +Author: + +Environment: + + user mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +#include "FxNPagedLookasideList.hpp" +#include "FxMemoryBufferFromLookaside.hpp" + +FxNPagedLookasideList::FxNPagedLookasideList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag + ) : + FxLookasideList(FxDriverGlobals, sizeof(*this), PoolTag) +{ +} + +FxNPagedLookasideList::~FxNPagedLookasideList() +{ +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideList::Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) +{ + NTSTATUS status; + + status = InitializeLookaside((USHORT) BufferSize, + sizeof(FxMemoryBufferFromLookaside), + MemoryAttributes); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideList::Allocate( + __out FxMemoryObject** PPMemory + ) +{ + FxMemoryBufferFromLookaside *pBuffer; + PVOID p; + + if (PPMemory == NULL) { + return STATUS_INVALID_PARAMETER; + } + + *PPMemory = NULL; + + // + // Get the raw memory allocation. + // + p = FxAllocateFromNPagedLookasideList(NULL, m_MemoryObjectSize); + if (p == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + p = InitObjectAlloc(p); + + // + // Construct new FxMemoryBufferFromLookaside + // + pBuffer = new(GetDriverGlobals(), p, m_BufferSize, &m_MemoryAttributes) + FxMemoryBufferFromLookaside(GetDriverGlobals(), this, m_BufferSize); + + // + // pBuffer might be displaced if there is a debug extension + // + ASSERT(_GetBase(pBuffer) == p); + + *PPMemory = pBuffer; + + return STATUS_SUCCESS; +} + +VOID +FxNPagedLookasideList::Reclaim( + __in FxMemoryBufferFromLookaside * Memory + ) +{ + _Reclaim(GetDriverGlobals(), &m_ObjectLookaside, Memory); +} + +FxNPagedLookasideListFromPool::FxNPagedLookasideListFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag + ) : FxLookasideListFromPool(FxDriverGlobals, sizeof(*this), PoolTag) +{ + UfxVerifierTrapNotImpl(); +} + +FxNPagedLookasideListFromPool::~FxNPagedLookasideListFromPool( + VOID + ) +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideListFromPool::Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_UNSUCCESSFUL; +} + +_Must_inspect_result_ +NTSTATUS +FxNPagedLookasideListFromPool::Allocate( + __out FxMemoryObject** PPMemory + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_UNSUCCESSFUL; +} + +VOID +FxNPagedLookasideListFromPool::Reclaim( + __in FxMemoryBufferFromLookaside * Memory + ) +{ + UfxVerifierTrapNotImpl(); +} + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxrequestapium.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxrequestapium.cpp new file mode 100644 index 00000000000..4a8aa359228 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxrequestapium.cpp @@ -0,0 +1,449 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestApiUm.cpp + +Abstract: + + This module implements FxRequest object + +Author: + +Environment: + + User mode only + +Revision History: + + +--*/ +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestApiUm.tmh" + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestImpersonate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_ + PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate, + _In_opt_ + PVOID Context + ) + +/*++ + +Routine Description: + + The WdfRequestImpersonate method registers the event that the framework + should call for impersonation. + +Arguments: + + Request : Request object + + ImpersonationLevel : A SECURITY_IMPERSONATION_LEVEL-typed value that identifies + the level of impersonation. + + EvtRequestImpersonate : A pointer to the IImpersonateCallback interface whose + method the framework calls for impersonation. + +Returns: + + Impersonate returns STATUS_SUCCESS if the operation succeeds. Otherwise, + this method returns one of the error codes that are defined in ntstatus.h. + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + if (VALID_IMPERSONATION_LEVEL(ImpersonationLevel) == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "ImpersonationLevel is not a valid level, %!STATUS!", + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (EvtRequestImpersonate == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "EvtRequestImpersonate must not be NULL, %!STATUS!", + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->Impersonate(ImpersonationLevel, + EvtRequestImpersonate, + Context); + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfRequestGetRequestorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +/*++ + +Routine Description: + + This routine returns the identifier of the process that sent the I/O request. + + The WDM IRP is invalid once WdfRequestComplete is called, regardless + of any reference counts on the WDFREQUEST object. + +Arguments: + + Request - Handle to the Request object + +Returns: + + Process ID + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return 0; + } + + return irp->GetRequestorProcessId(); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsFromUserModeDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return FALSE; + } + + return (pRequest->GetFxIrp()->GetIoIrp()->IsDriverCreated() ? TRUE : FALSE); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN IsUserModeDriverInitiated + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pRequest->GetFxIrp()->GetIoIrp()->SetUserModeDriverInitiatedIo( + IsUserModeDriverInitiated + ); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return FALSE; + } + + return (pRequest->GetFxIrp()->GetIoIrp()->GetUserModeDriverInitiatedIo() + ? TRUE : FALSE); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + LPGUID ActivityId + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pRequest->GetFxIrp()->GetIoIrp()->SetActivityId(ActivityId); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + LPGUID ActivityId + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ActivityId); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (pRequest->GetFxIrp()->GetIoIrp()->IsActivityIdSet() == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p Activity ID is not set for the " + "request, %!STATUS!", Request, status); + return status; + } + + *ActivityId = *(pRequest->GetFxIrp()->GetIoIrp()->GetActivityId()); + status = STATUS_SUCCESS; + + return status; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDF_DEVICE_IO_TYPE +WDFEXPORT(WdfRequestGetEffectiveIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest *pRequest; + MdIrp irp; + + // + // Validate the request handle, and get the FxRequest* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Request, + FX_TYPE_REQUEST, + (PVOID*)&pRequest, + &pFxDriverGlobals); + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Enter: WDFREQUEST 0x%p", Request); +#endif // FX_VERBOSE_TRACE + + status = pRequest->GetIrp(&irp); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + Request, status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return WdfDeviceIoUndefined; + } + + return (WDF_DEVICE_IO_TYPE)(pRequest->GetFxIrp()->GetIoIrp()->GetTransferMode()); +} + +} // extern "C" the whole file diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxrequestsystembufferum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxrequestsystembufferum.cpp new file mode 100644 index 00000000000..90bfb4e0175 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxrequestsystembufferum.cpp @@ -0,0 +1,72 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestSystemBuffer.cpp + +Abstract: + + This module implements class representing the system buffer in an FxRequest + +Author: + + + + +Environment: + + User mode only + +Revision History: + + + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestSystemBufferUm.tmh" +} + +_Must_inspect_result_ +PVOID +FxRequestSystemBuffer::GetBuffer( + VOID + ) +/*++ + +Routine Description: + Returns the system buffer that has been cached away by the call to SetBuffer() + +Arguments: + None + +Return Value: + Valid memory or NULL on error + + --*/ +{ + FxIrp* irp = GetRequest()->GetFxIrp(); + + // + // For UMDF, the buffer is always stored in m_Buffer. + // + switch (irp->GetMajorFunction()) { + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + case IRP_MJ_READ: + case IRP_MJ_WRITE: + return m_Buffer; + + default: + ASSERT(FALSE); + return NULL; + } +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/um/fxrequestum.cpp b/sdk/lib/drivers/wdf/shared/core/um/fxrequestum.cpp new file mode 100644 index 00000000000..9c87b9abea4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/um/fxrequestum.cpp @@ -0,0 +1,264 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestUm.cpp + +Abstract: + + This module implements KM specific FxRequest object routines + +Author: + + + +Environment: + + User mode only + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// Tracing support +extern "C" { +#include "FxRequestUm.tmh" +} + +VOID +FxRequest::CheckAssumptions( + VOID + ) +/*++ + +Routine Description: + This routine is never actually called by running code, it just has + WDFCASSERTs who upon failure, would not allow this file to be compiled. + + DO NOT REMOVE THIS FUNCTION just because it is not called by any running + code. + +Arguments: + None + +Return Value: + None + + --*/ +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetMdl( + __out PMDL *pMdl + ) +{ + UNREFERENCED_PARAMETER(pMdl); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + + +_Must_inspect_result_ +NTSTATUS +FxRequest::GetDeviceControlOutputMdl( + __out PMDL *pMdl + ) +/*++ + +Routine Description: + + Return the IRP_MJ_DEVICE_CONTROL OutputBuffer as an MDL + + The MDL is automatically released when the request is completed. + + The MDL is not valid for a METHOD_NEITHER IRP_MJ_DEVICE_CONTROL, + or for any request other than IRP_MJ_DEVICE_CONTROL. + + The MDL is as follows for each buffering mode: + + METHOD_BUFFERED: + + MmBuildMdlForNonPagedPool(IoAllocateMdl(Irp->UserBuffer, ... )) + + METHOD_IN_DIRECT: + + Irp->MdlAddress + + METHOD_OUT_DIRECT: + + Irp->MdlAddress + + METHOD_NEITHER: + + NULL. Must use WdfDeviceInitSetIoInCallerContextCallback in order + to access the request in the calling threads address space before + it is placed into any I/O Queues. + + The MDL is only valid until the request is completed. + +Arguments: + + pMdl- Pointer location to return MDL ptr + +Returns: + + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(pMdl); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::ProbeAndLockForRead( + __in PVOID Buffer, + __in ULONG Length, + __deref_out FxRequestMemory** MemoryObject + ) + +/*++ + +Routine Description: + + Probe and lock a memory buffer for reading. + + This is to be called in the proper process context, and + will generate an FxRequestMemory object if successful. + + The FxRequestMemory object will be associated with the FxRequest + object, and is automatically released when the FxRequest is completed. + + This function performs validation to ensure that the current + thread is in the same process as the thread that originated + the I/O request. + +Arguments: + + + Buffer - Buffer to lock down + + Length - Length of buffer + + MemoryObject - FxRequestMemory object to return + +Returns: + + NTSTATUS + +--*/ + +{ + UNREFERENCED_PARAMETER(Buffer); + UNREFERENCED_PARAMETER(Length); + UNREFERENCED_PARAMETER(MemoryObject); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxRequest::ProbeAndLockForWrite( + __in PVOID Buffer, + __in ULONG Length, + __deref_out FxRequestMemory** MemoryObject + ) + +/*++ + +Routine Description: + + Probe and lock a memory buffer for writing. + + This is to be called in the proper process context, and + will generate an FxRequestMemory object if successful. + + The FxRequestMemory object will be associated with the FxRequest + object, and is automatically released when the FxRequest is completed. + + This function performs validation to ensure that the current + thread is in the same process as the thread that originated + the I/O request. + +Arguments: + + + Buffer - Buffer to lock down + + Length - Length of buffer + + MemoryObject - FxRequestMemory object to return + +Returns: + + NTSTATUS + +--*/ + +{ + UNREFERENCED_PARAMETER(Buffer); + UNREFERENCED_PARAMETER(Length); + UNREFERENCED_PARAMETER(MemoryObject); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +NTSTATUS +FxRequest::Impersonate( + _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_ PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate, + _In_opt_ PVOID Context + ) +{ + DDI_ENTRY(); + + NTSTATUS status; + HRESULT hr; + MdIrp irp; + + status = GetIrp(&irp); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST is already completed 0x%p, %!STATUS!", + GetHandle(), status); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return status; + } + + hr = irp->ImpersonateRequestorProcess(ImpersonationLevel); + + if (SUCCEEDED(hr)) { + status = STATUS_SUCCESS; + EvtRequestImpersonate(GetHandle(), Context); + irp->RevertImpersonation(); + } + else { + status = GetDevice()->NtStatusFromHr(hr); + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WDFREQUEST 0x%p, Could not impersonate, %!STATUS!", + GetHandle(), status); + } + + return status; +} + + diff --git a/sdk/lib/drivers/wdf/shared/core/verifierapi.cpp b/sdk/lib/drivers/wdf/shared/core/verifierapi.cpp new file mode 100644 index 00000000000..0ea1bfaf474 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/core/verifierapi.cpp @@ -0,0 +1,269 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + VerifierApi.c + +Abstract: + + This module implements various global verifier worker routines + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "coreprivshared.hpp" + +// +// extern "C" all APIs +// +extern "C" { + +// +// Global triage Info for dbgeng and 0x9F work +// +extern WDF_TRIAGE_INFO g_WdfTriageInfo; + + +VOID +WDFEXPORT(WdfVerifierDbgBreakPoint)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals + ) + +/*++ + +Routine Description: + + Common Driver Frameworks DbgBreakPoint() function. + + This will only break point if WdfVerifierDbgBreakOnError is defined, so + it's safe to call for production systems. + +Arguments: + + DriverGlobals - + +Return Value: + + None. + +--*/ + +{ + DDI_ENTRY_IMPERSONATION_OK(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + if (pFxDriverGlobals->FxVerifierDbgBreakOnError) { + DbgBreakPoint(); + } +} + + +VOID +WDFEXPORT(WdfVerifierKeBugCheck)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + ULONG BugCheckCode, + __in + ULONG_PTR BugCheckParameter1, + __in + ULONG_PTR BugCheckParameter2, + __in + ULONG_PTR BugCheckParameter3, + __in + ULONG_PTR BugCheckParameter4 + ) + +/*++ + +Routine Description: + + Common Driver Frameworks KeBugCheckEx() function. Use this function rather + than the system one. This routine will indicate to the bugcheck callbacks + that the IFR data for this driver needs to be copied to the minidump file. + +Arguments: + + DriverGlobals - + + BugCheckCode - Specifies a value that indicates the reason for the bug check. + + BugCheckParameter1 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + + BugCheckParameter2 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + + BugCheckParameter3 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + + BugCheckParameter4 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + +Return Value: + + None. + +--*/ + +{ + DDI_ENTRY_IMPERSONATION_OK(); + + // + // Indicate to the BugCheck callback filter which IFR to dump. + // + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + pFxDriverGlobals->FxForceLogsInMiniDump = TRUE; + +#pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "WDF wrapper to KeBugCheckEx."); + Mx::MxBugCheckEx(BugCheckCode, + BugCheckParameter1, + BugCheckParameter2, + BugCheckParameter3, + BugCheckParameter4); +} + +VOID +WDFEXPORT(WdfCxVerifierKeBugCheck)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + WDFOBJECT Object, + __in + ULONG BugCheckCode, + __in + ULONG_PTR BugCheckParameter1, + __in + ULONG_PTR BugCheckParameter2, + __in + ULONG_PTR BugCheckParameter3, + __in + ULONG_PTR BugCheckParameter4 + ) + +/*++ + +Routine Description: + + Common Driver Frameworks KeBugCheckEx() function. Cx should use this + function rather than the system one or WdfVerifierKeBugCheck. This routine + will indicate to the bugcheck callbacks that the IFR data for this driver or its + client driver needs to be copied to the minidump file. + +Arguments: + + DriverGlobals - + + Object - WDF uses this object to select which logs to write in the minidump. + Cx can pass an object from the client driver's hierarchy to force + the client driver's logs in the minidump. + + BugCheckCode - Specifies a value that indicates the reason for the bug check. + + BugCheckParameter1 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + + BugCheckParameter2 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + + BugCheckParameter3 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + + BugCheckParameter4 - Supply additional information, such as the address and + data where a memory-corruption error occurred, depending on the value of + BugCheckCode. + +Return Value: + + None. + +--*/ + +{ + DDI_ENTRY_IMPERSONATION_OK(); + + FxObject* pObject; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + if (NULL == Object) { + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + } + else { + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Object, + FX_TYPE_OBJECT, + (PVOID*)&pObject, + &pFxDriverGlobals); + } + + UNREFERENCED_PARAMETER(pObject); + + // + // Indicate to the BugCheck callback filter which IFR to dump. + // + pFxDriverGlobals->FxForceLogsInMiniDump = TRUE; + +#pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "WDF wrapper to KeBugCheckEx."); + Mx::MxBugCheckEx(BugCheckCode, + BugCheckParameter1, + BugCheckParameter2, + BugCheckParameter3, + BugCheckParameter4); +} + + +PVOID +WDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ) + +/*++ + +Routine Description: + + Returns a pointer to the WDF triage info for dbgeng and 0x9F work. + +Arguments: + + DriverGlobals - + +Return Value: + + None. + +--*/ + +{ + DDI_ENTRY(); + + UNREFERENCED_PARAMETER(DriverGlobals); + return &g_WdfTriageInfo; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/km/vfprivkm.hpp b/sdk/lib/drivers/wdf/shared/enhancedverif/km/vfprivkm.hpp new file mode 100644 index 00000000000..cd7aaabb477 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/km/vfprivkm.hpp @@ -0,0 +1,357 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + vfpriv.hpp + +Abstract: + + common header file for verifier + +Author: + + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#pragma once +extern "C" { +#include +} + +#include "fx.hpp" + +extern "C" { + +__inline +VOID +VerifyIrqlEntry( + __out KIRQL *Irql + ) +{ + *Irql = KeGetCurrentIrql(); +} + +__inline +VOID +VerifyIrqlExit( + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in KIRQL PrevIrql + ) +{ + KIRQL currIrql; + + currIrql = KeGetCurrentIrql(); + if (PrevIrql != currIrql) { + KdPrint(("WDF VERIFIER: Irql at entry of event is not same as at exit.\n")); + FxVerifierBugCheck(GetFxDriverGlobals(DriverGlobals), + WDF_VERIFIER_IRQL_MISMATCH, + PrevIrql, + currIrql + ); + } +} + +__inline +VOID +VerifyCriticalRegionEntry( + __out BOOLEAN *CritRegion + ) +{ + if (KeGetCurrentIrql() <= APC_LEVEL) { + *CritRegion = KeAreApcsDisabled(); + } +} + +__inline +VOID +VerifyCriticalRegionExit( + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in BOOLEAN OldCritRegion, + __in PVOID Pfn + ) +{ + if (KeGetCurrentIrql() <= APC_LEVEL) { + if (OldCritRegion != KeAreApcsDisabled()) { + KdPrint(("WDF VERIFIER: Critical section entry and exit around event callback incorrect\n")); + FxVerifierBugCheck(GetFxDriverGlobals(DriverGlobals), + WDF_VERIFIER_CRITICAL_REGION_MISMATCH, + (ULONG_PTR)Pfn, + 0 + ); + } + } +} +} // extern "C" + +FORCEINLINE +VOID +PerformanceAnalysisIOProcess( + __in PFX_DRIVER_GLOBALS pFxDriverGlobals, + __in WDFREQUEST Handle, + __out FxRequest** ppReq, + __inout GUID* pActivityId + ) +{ + + FxObjectHandleGetPtr(pFxDriverGlobals, + Handle, + FX_TYPE_REQUEST, + (PVOID *) ppReq); + + if (IoGetActivityIdIrp((*ppReq)->GetFxIrp()->GetIrp(), pActivityId) == STATUS_NOT_FOUND) + { + EtwActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + IoSetActivityIdIrp((*ppReq)->GetFxIrp()->GetIrp(), pActivityId); + } +} + +FORCEINLINE +BOOLEAN +PerfIoStart( + __in WDFREQUEST Handle +) +{ + FxRequest* pReq; + GUID activityId = { 0 }; + WDFOBJECT_OFFSET offset = 0; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) + { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + PerformanceAnalysisIOProcess(pFxDriverGlobals, Handle, &pReq, + &activityId); + + EventWriteFX_REQUEST_START(&activityId, pReq->GetFxIrp()->GetMajorFunction(), + pDriverDeviceAdd, pReq->GetCurrentQueue()->GetDevice()->GetHandle()); + } + return status; +} + +FORCEINLINE +BOOLEAN +PerfIoComplete( + __in WDFREQUEST Handle +) +{ + FxRequest* pReq; + GUID activityId = { 0 }; + WDFOBJECT_OFFSET offset = 0; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) + { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + PerformanceAnalysisIOProcess(pFxDriverGlobals, Handle, &pReq, + &activityId); + + EventWriteFX_REQUEST_COMPLETE(&activityId, pReq->GetFxIrp()->GetMajorFunction(), + pDriverDeviceAdd, pReq->GetCurrentQueue()->GetDevice()->GetHandle()); + } + return status; +} + +FORCEINLINE +PFN_WDF_DRIVER_DEVICE_ADD +PerformanceGetDriverDeviceAdd( + __in WDFOBJECT Handle +) +{ + WDFOBJECT_OFFSET offset = 0; + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + + return pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); +} + +__inline +BOOLEAN +PerfEvtDeviceD0EntryStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + WDFOBJECT_OFFSET offset = 0; + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + EtwActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + EventWriteFX_POWER_D0_ENTRY_START(pActivityId, pDriverDeviceAdd, Handle); + } + + return status; +} + +__inline +VOID +PerfEvtDeviceD0EntryStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + EventWriteFX_POWER_D0_ENTRY_STOP(pActivityId, PerformanceGetDriverDeviceAdd(Handle), Handle); +} + +__inline +BOOLEAN +PerfEvtDeviceD0ExitStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + WDFOBJECT_OFFSET offset = 0; + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + EtwActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + EventWriteFX_POWER_D0_EXIT_START(pActivityId, pDriverDeviceAdd, Handle); + } + return status; +} + +__inline +VOID +PerfEvtDeviceD0ExitStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + EventWriteFX_POWER_D0_EXIT_STOP(pActivityId, PerformanceGetDriverDeviceAdd(Handle), Handle); +} + +__inline +BOOLEAN +PerfEvtDevicePrepareHardwareStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + + WDFOBJECT_OFFSET offset = 0; + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + EtwActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + EventWriteFX_POWER_HW_PREPARE_START(pActivityId, pDriverDeviceAdd, Handle); + } + return status; +} + +__inline +VOID +PerfEvtDevicePrepareHardwareStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + EventWriteFX_POWER_HW_PREPARE_STOP(pActivityId, PerformanceGetDriverDeviceAdd(Handle), Handle); +} + +__inline +BOOLEAN +PerfEvtDeviceReleaseHardwareStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + WDFOBJECT_OFFSET offset = 0; + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + EtwActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + EventWriteFX_POWER_HW_RELEASE_START(pActivityId, pDriverDeviceAdd, Handle); + } + return status; +} + +__inline +VOID +PerfEvtDeviceReleaseHardwareStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + EventWriteFX_POWER_HW_RELEASE_STOP(pActivityId, PerformanceGetDriverDeviceAdd(Handle), Handle); +} + +// EvtIoStop callback started. +__inline +BOOLEAN +PerfEvtIoStopStart( + __in WDFQUEUE Queue, + __inout GUID* pActivityId +) +{ + WDFOBJECT_OFFSET offset = 0; + WDFDEVICE device; + FxIoQueue* pQueue; + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Queue, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + FxObjectHandleGetPtr(pFxDriverGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*) &pQueue); + device = (WDFDEVICE) pQueue->GetDevice()->GetHandle(); + pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + EtwActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + EventWriteFX_EVTIOSTOP_START(pActivityId, pDriverDeviceAdd, device); + } + return status; +} + +// EvtIoStop callback returned. +__inline +VOID +PerfEvtIoStopStop( + __in WDFQUEUE Queue, + __in GUID* pActivityId +) +{ + WDFOBJECT_OFFSET offset = 0; + WDFDEVICE device; + FxIoQueue* pQueue; + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Queue, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + FxObjectHandleGetPtr(pFxDriverGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*) &pQueue); + device = (WDFDEVICE) pQueue->GetDevice()->GetHandle(); + pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + + EventWriteFX_EVTIOSTOP_STOP(pActivityId, pDriverDeviceAdd, device); +} diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/km/vfwdfdynamics.cpp b/sdk/lib/drivers/wdf/shared/enhancedverif/km/vfwdfdynamics.cpp new file mode 100644 index 00000000000..8699c8a53f6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/km/vfwdfdynamics.cpp @@ -0,0 +1,8313 @@ +/*++ + +Module Name: VfWdfDynamics.cpp + +Abstract: + Generated implementation for WDF API Verifier hooks + +Environment: + kernel mode only + +--*/ + + +extern "C" { +#include +} +#include "vfpriv.hpp" + + +extern "C" { +extern WDFVERSION WdfVersion; +} + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(FX_ENHANCED_VERIFIER_SECTION_NAME, \ + VFWDFEXPORT(WdfChildListCreate), \ + VFWDFEXPORT(WdfChildListGetDevice), \ + VFWDFEXPORT(WdfChildListRetrievePdo), \ + VFWDFEXPORT(WdfChildListRetrieveAddressDescription), \ + VFWDFEXPORT(WdfChildListBeginScan), \ + VFWDFEXPORT(WdfChildListEndScan), \ + VFWDFEXPORT(WdfChildListBeginIteration), \ + VFWDFEXPORT(WdfChildListRetrieveNextDevice), \ + VFWDFEXPORT(WdfChildListEndIteration), \ + VFWDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent), \ + VFWDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing), \ + VFWDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent), \ + VFWDFEXPORT(WdfChildListRequestChildEject), \ + VFWDFEXPORT(WdfCollectionCreate), \ + VFWDFEXPORT(WdfCollectionGetCount), \ + VFWDFEXPORT(WdfCollectionAdd), \ + VFWDFEXPORT(WdfCollectionRemove), \ + VFWDFEXPORT(WdfCollectionRemoveItem), \ + VFWDFEXPORT(WdfCollectionGetItem), \ + VFWDFEXPORT(WdfCollectionGetFirstItem), \ + VFWDFEXPORT(WdfCollectionGetLastItem), \ + VFWDFEXPORT(WdfCommonBufferCreate), \ + VFWDFEXPORT(WdfCommonBufferCreateWithConfig), \ + VFWDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress), \ + VFWDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress), \ + VFWDFEXPORT(WdfCommonBufferGetLength), \ + VFWDFEXPORT(WdfControlDeviceInitAllocate), \ + VFWDFEXPORT(WdfControlDeviceInitSetShutdownNotification), \ + VFWDFEXPORT(WdfControlFinishInitializing), \ + VFWDFEXPORT(WdfCxDeviceInitAllocate), \ + VFWDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback), \ + VFWDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback), \ + VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes), \ + VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig), \ + VFWDFEXPORT(WdfCxVerifierKeBugCheck), \ + VFWDFEXPORT(WdfDeviceGetDeviceState), \ + VFWDFEXPORT(WdfDeviceSetDeviceState), \ + VFWDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle), \ + VFWDFEXPORT(WdfDeviceWdmGetDeviceObject), \ + VFWDFEXPORT(WdfDeviceWdmGetAttachedDevice), \ + VFWDFEXPORT(WdfDeviceWdmGetPhysicalDevice), \ + VFWDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp), \ + VFWDFEXPORT(WdfDeviceWdmDispatchIrp), \ + VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue), \ + VFWDFEXPORT(WdfDeviceAddDependentUsageDeviceObject), \ + VFWDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject), \ + VFWDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice), \ + VFWDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice), \ + VFWDFEXPORT(WdfDeviceClearRemovalRelationsDevices), \ + VFWDFEXPORT(WdfDeviceGetDriver), \ + VFWDFEXPORT(WdfDeviceRetrieveDeviceName), \ + VFWDFEXPORT(WdfDeviceAssignMofResourceName), \ + VFWDFEXPORT(WdfDeviceGetIoTarget), \ + VFWDFEXPORT(WdfDeviceGetDevicePnpState), \ + VFWDFEXPORT(WdfDeviceGetDevicePowerState), \ + VFWDFEXPORT(WdfDeviceGetDevicePowerPolicyState), \ + VFWDFEXPORT(WdfDeviceAssignS0IdleSettings), \ + VFWDFEXPORT(WdfDeviceAssignSxWakeSettings), \ + VFWDFEXPORT(WdfDeviceOpenRegistryKey), \ + VFWDFEXPORT(WdfDeviceOpenDevicemapKey), \ + VFWDFEXPORT(WdfDeviceSetSpecialFileSupport), \ + VFWDFEXPORT(WdfDeviceSetCharacteristics), \ + VFWDFEXPORT(WdfDeviceGetCharacteristics), \ + VFWDFEXPORT(WdfDeviceGetAlignmentRequirement), \ + VFWDFEXPORT(WdfDeviceSetAlignmentRequirement), \ + VFWDFEXPORT(WdfDeviceInitFree), \ + VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks), \ + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks), \ + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership), \ + VFWDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback), \ + VFWDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback), \ + VFWDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback), \ + VFWDFEXPORT(WdfDeviceInitSetExclusive), \ + VFWDFEXPORT(WdfDeviceInitSetIoType), \ + VFWDFEXPORT(WdfDeviceInitSetPowerNotPageable), \ + VFWDFEXPORT(WdfDeviceInitSetPowerPageable), \ + VFWDFEXPORT(WdfDeviceInitSetPowerInrush), \ + VFWDFEXPORT(WdfDeviceInitSetDeviceType), \ + VFWDFEXPORT(WdfDeviceInitAssignName), \ + VFWDFEXPORT(WdfDeviceInitAssignSDDLString), \ + VFWDFEXPORT(WdfDeviceInitSetDeviceClass), \ + VFWDFEXPORT(WdfDeviceInitSetCharacteristics), \ + VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig), \ + VFWDFEXPORT(WdfDeviceInitSetRequestAttributes), \ + VFWDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback), \ + VFWDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback), \ + VFWDFEXPORT(WdfDeviceInitSetRemoveLockOptions), \ + VFWDFEXPORT(WdfDeviceCreate), \ + VFWDFEXPORT(WdfDeviceSetStaticStopRemove), \ + VFWDFEXPORT(WdfDeviceCreateDeviceInterface), \ + VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState), \ + VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString), \ + VFWDFEXPORT(WdfDeviceCreateSymbolicLink), \ + VFWDFEXPORT(WdfDeviceQueryProperty), \ + VFWDFEXPORT(WdfDeviceAllocAndQueryProperty), \ + VFWDFEXPORT(WdfDeviceSetPnpCapabilities), \ + VFWDFEXPORT(WdfDeviceSetPowerCapabilities), \ + VFWDFEXPORT(WdfDeviceSetBusInformationForChildren), \ + VFWDFEXPORT(WdfDeviceIndicateWakeStatus), \ + VFWDFEXPORT(WdfDeviceSetFailed), \ + VFWDFEXPORT(WdfDeviceStopIdleNoTrack), \ + VFWDFEXPORT(WdfDeviceResumeIdleNoTrack), \ + VFWDFEXPORT(WdfDeviceStopIdleActual), \ + VFWDFEXPORT(WdfDeviceResumeIdleActual), \ + VFWDFEXPORT(WdfDeviceGetFileObject), \ + VFWDFEXPORT(WdfDeviceEnqueueRequest), \ + VFWDFEXPORT(WdfDeviceGetDefaultQueue), \ + VFWDFEXPORT(WdfDeviceConfigureRequestDispatching), \ + VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback), \ + VFWDFEXPORT(WdfDeviceGetSystemPowerAction), \ + VFWDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings), \ + VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure), \ + VFWDFEXPORT(WdfDeviceInitSetIoTypeEx), \ + VFWDFEXPORT(WdfDeviceQueryPropertyEx), \ + VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx), \ + VFWDFEXPORT(WdfDeviceAssignProperty), \ + VFWDFEXPORT(WdfDeviceGetSelfIoTarget), \ + VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget), \ + VFWDFEXPORT(WdfDmaEnablerCreate), \ + VFWDFEXPORT(WdfDmaEnablerConfigureSystemProfile), \ + VFWDFEXPORT(WdfDmaEnablerGetMaximumLength), \ + VFWDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements), \ + VFWDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements), \ + VFWDFEXPORT(WdfDmaEnablerGetFragmentLength), \ + VFWDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter), \ + VFWDFEXPORT(WdfDmaTransactionCreate), \ + VFWDFEXPORT(WdfDmaTransactionInitialize), \ + VFWDFEXPORT(WdfDmaTransactionInitializeUsingOffset), \ + VFWDFEXPORT(WdfDmaTransactionInitializeUsingRequest), \ + VFWDFEXPORT(WdfDmaTransactionExecute), \ + VFWDFEXPORT(WdfDmaTransactionRelease), \ + VFWDFEXPORT(WdfDmaTransactionDmaCompleted), \ + VFWDFEXPORT(WdfDmaTransactionDmaCompletedWithLength), \ + VFWDFEXPORT(WdfDmaTransactionDmaCompletedFinal), \ + VFWDFEXPORT(WdfDmaTransactionGetBytesTransferred), \ + VFWDFEXPORT(WdfDmaTransactionSetMaximumLength), \ + VFWDFEXPORT(WdfDmaTransactionGetRequest), \ + VFWDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength), \ + VFWDFEXPORT(WdfDmaTransactionGetDevice), \ + VFWDFEXPORT(WdfDmaTransactionGetTransferInfo), \ + VFWDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback), \ + VFWDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback), \ + VFWDFEXPORT(WdfDmaTransactionSetImmediateExecution), \ + VFWDFEXPORT(WdfDmaTransactionAllocateResources), \ + VFWDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset), \ + VFWDFEXPORT(WdfDmaTransactionFreeResources), \ + VFWDFEXPORT(WdfDmaTransactionCancel), \ + VFWDFEXPORT(WdfDmaTransactionWdmGetTransferContext), \ + VFWDFEXPORT(WdfDmaTransactionStopSystemTransfer), \ + VFWDFEXPORT(WdfDpcCreate), \ + VFWDFEXPORT(WdfDpcEnqueue), \ + VFWDFEXPORT(WdfDpcCancel), \ + VFWDFEXPORT(WdfDpcGetParentObject), \ + VFWDFEXPORT(WdfDpcWdmGetDpc), \ + VFWDFEXPORT(WdfDriverCreate), \ + VFWDFEXPORT(WdfDriverGetRegistryPath), \ + VFWDFEXPORT(WdfDriverWdmGetDriverObject), \ + VFWDFEXPORT(WdfDriverOpenParametersRegistryKey), \ + VFWDFEXPORT(WdfWdmDriverGetWdfDriverHandle), \ + VFWDFEXPORT(WdfDriverRegisterTraceInfo), \ + VFWDFEXPORT(WdfDriverRetrieveVersionString), \ + VFWDFEXPORT(WdfDriverIsVersionAvailable), \ + VFWDFEXPORT(WdfFdoInitWdmGetPhysicalDevice), \ + VFWDFEXPORT(WdfFdoInitOpenRegistryKey), \ + VFWDFEXPORT(WdfFdoInitQueryProperty), \ + VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty), \ + VFWDFEXPORT(WdfFdoInitQueryPropertyEx), \ + VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx), \ + VFWDFEXPORT(WdfFdoInitSetEventCallbacks), \ + VFWDFEXPORT(WdfFdoInitSetFilter), \ + VFWDFEXPORT(WdfFdoInitSetDefaultChildListConfig), \ + VFWDFEXPORT(WdfFdoQueryForInterface), \ + VFWDFEXPORT(WdfFdoGetDefaultChildList), \ + VFWDFEXPORT(WdfFdoAddStaticChild), \ + VFWDFEXPORT(WdfFdoLockStaticChildListForIteration), \ + VFWDFEXPORT(WdfFdoRetrieveNextStaticChild), \ + VFWDFEXPORT(WdfFdoUnlockStaticChildListFromIteration), \ + VFWDFEXPORT(WdfFileObjectGetFileName), \ + VFWDFEXPORT(WdfFileObjectGetFlags), \ + VFWDFEXPORT(WdfFileObjectGetDevice), \ + VFWDFEXPORT(WdfFileObjectWdmGetFileObject), \ + VFWDFEXPORT(WdfInterruptCreate), \ + VFWDFEXPORT(WdfInterruptQueueDpcForIsr), \ + VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr), \ + VFWDFEXPORT(WdfInterruptSynchronize), \ + VFWDFEXPORT(WdfInterruptAcquireLock), \ + VFWDFEXPORT(WdfInterruptReleaseLock), \ + VFWDFEXPORT(WdfInterruptEnable), \ + VFWDFEXPORT(WdfInterruptDisable), \ + VFWDFEXPORT(WdfInterruptWdmGetInterrupt), \ + VFWDFEXPORT(WdfInterruptGetInfo), \ + VFWDFEXPORT(WdfInterruptSetPolicy), \ + VFWDFEXPORT(WdfInterruptSetExtendedPolicy), \ + VFWDFEXPORT(WdfInterruptGetDevice), \ + VFWDFEXPORT(WdfInterruptTryToAcquireLock), \ + VFWDFEXPORT(WdfInterruptReportActive), \ + VFWDFEXPORT(WdfInterruptReportInactive), \ + VFWDFEXPORT(WdfIoQueueCreate), \ + VFWDFEXPORT(WdfIoQueueGetState), \ + VFWDFEXPORT(WdfIoQueueStart), \ + VFWDFEXPORT(WdfIoQueueStop), \ + VFWDFEXPORT(WdfIoQueueStopSynchronously), \ + VFWDFEXPORT(WdfIoQueueGetDevice), \ + VFWDFEXPORT(WdfIoQueueRetrieveNextRequest), \ + VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject), \ + VFWDFEXPORT(WdfIoQueueFindRequest), \ + VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest), \ + VFWDFEXPORT(WdfIoQueueDrainSynchronously), \ + VFWDFEXPORT(WdfIoQueueDrain), \ + VFWDFEXPORT(WdfIoQueuePurgeSynchronously), \ + VFWDFEXPORT(WdfIoQueuePurge), \ + VFWDFEXPORT(WdfIoQueueReadyNotify), \ + VFWDFEXPORT(WdfIoQueueAssignForwardProgressPolicy), \ + VFWDFEXPORT(WdfIoQueueStopAndPurge), \ + VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously), \ + VFWDFEXPORT(WdfIoTargetCreate), \ + VFWDFEXPORT(WdfIoTargetOpen), \ + VFWDFEXPORT(WdfIoTargetCloseForQueryRemove), \ + VFWDFEXPORT(WdfIoTargetClose), \ + VFWDFEXPORT(WdfIoTargetStart), \ + VFWDFEXPORT(WdfIoTargetStop), \ + VFWDFEXPORT(WdfIoTargetPurge), \ + VFWDFEXPORT(WdfIoTargetGetState), \ + VFWDFEXPORT(WdfIoTargetGetDevice), \ + VFWDFEXPORT(WdfIoTargetQueryTargetProperty), \ + VFWDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty), \ + VFWDFEXPORT(WdfIoTargetQueryForInterface), \ + VFWDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject), \ + VFWDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice), \ + VFWDFEXPORT(WdfIoTargetWdmGetTargetFileObject), \ + VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle), \ + VFWDFEXPORT(WdfIoTargetSendReadSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForRead), \ + VFWDFEXPORT(WdfIoTargetSendWriteSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForWrite), \ + VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl), \ + VFWDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl), \ + VFWDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers), \ + VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue), \ + VFWDFEXPORT(WdfMemoryCreate), \ + VFWDFEXPORT(WdfMemoryCreatePreallocated), \ + VFWDFEXPORT(WdfMemoryGetBuffer), \ + VFWDFEXPORT(WdfMemoryAssignBuffer), \ + VFWDFEXPORT(WdfMemoryCopyToBuffer), \ + VFWDFEXPORT(WdfMemoryCopyFromBuffer), \ + VFWDFEXPORT(WdfLookasideListCreate), \ + VFWDFEXPORT(WdfMemoryCreateFromLookaside), \ + VFWDFEXPORT(WdfDeviceMiniportCreate), \ + VFWDFEXPORT(WdfDriverMiniportUnload), \ + VFWDFEXPORT(WdfObjectGetTypedContextWorker), \ + VFWDFEXPORT(WdfObjectAllocateContext), \ + VFWDFEXPORT(WdfObjectContextGetObject), \ + VFWDFEXPORT(WdfObjectReferenceActual), \ + VFWDFEXPORT(WdfObjectDereferenceActual), \ + VFWDFEXPORT(WdfObjectCreate), \ + VFWDFEXPORT(WdfObjectDelete), \ + VFWDFEXPORT(WdfObjectQuery), \ + VFWDFEXPORT(WdfPdoInitAllocate), \ + VFWDFEXPORT(WdfPdoInitSetEventCallbacks), \ + VFWDFEXPORT(WdfPdoInitAssignDeviceID), \ + VFWDFEXPORT(WdfPdoInitAssignInstanceID), \ + VFWDFEXPORT(WdfPdoInitAddHardwareID), \ + VFWDFEXPORT(WdfPdoInitAddCompatibleID), \ + VFWDFEXPORT(WdfPdoInitAssignContainerID), \ + VFWDFEXPORT(WdfPdoInitAddDeviceText), \ + VFWDFEXPORT(WdfPdoInitSetDefaultLocale), \ + VFWDFEXPORT(WdfPdoInitAssignRawDevice), \ + VFWDFEXPORT(WdfPdoInitAllowForwardingRequestToParent), \ + VFWDFEXPORT(WdfPdoMarkMissing), \ + VFWDFEXPORT(WdfPdoRequestEject), \ + VFWDFEXPORT(WdfPdoGetParent), \ + VFWDFEXPORT(WdfPdoRetrieveIdentificationDescription), \ + VFWDFEXPORT(WdfPdoRetrieveAddressDescription), \ + VFWDFEXPORT(WdfPdoUpdateAddressDescription), \ + VFWDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice), \ + VFWDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice), \ + VFWDFEXPORT(WdfPdoClearEjectionRelationsDevices), \ + VFWDFEXPORT(WdfDeviceAddQueryInterface), \ + VFWDFEXPORT(WdfRegistryOpenKey), \ + VFWDFEXPORT(WdfRegistryCreateKey), \ + VFWDFEXPORT(WdfRegistryClose), \ + VFWDFEXPORT(WdfRegistryWdmGetHandle), \ + VFWDFEXPORT(WdfRegistryRemoveKey), \ + VFWDFEXPORT(WdfRegistryRemoveValue), \ + VFWDFEXPORT(WdfRegistryQueryValue), \ + VFWDFEXPORT(WdfRegistryQueryMemory), \ + VFWDFEXPORT(WdfRegistryQueryMultiString), \ + VFWDFEXPORT(WdfRegistryQueryUnicodeString), \ + VFWDFEXPORT(WdfRegistryQueryString), \ + VFWDFEXPORT(WdfRegistryQueryULong), \ + VFWDFEXPORT(WdfRegistryAssignValue), \ + VFWDFEXPORT(WdfRegistryAssignMemory), \ + VFWDFEXPORT(WdfRegistryAssignMultiString), \ + VFWDFEXPORT(WdfRegistryAssignUnicodeString), \ + VFWDFEXPORT(WdfRegistryAssignString), \ + VFWDFEXPORT(WdfRegistryAssignULong), \ + VFWDFEXPORT(WdfRequestCreate), \ + VFWDFEXPORT(WdfRequestCreateFromIrp), \ + VFWDFEXPORT(WdfRequestReuse), \ + VFWDFEXPORT(WdfRequestChangeTarget), \ + VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType), \ + VFWDFEXPORT(WdfRequestWdmFormatUsingStackLocation), \ + VFWDFEXPORT(WdfRequestSend), \ + VFWDFEXPORT(WdfRequestGetStatus), \ + VFWDFEXPORT(WdfRequestMarkCancelable), \ + VFWDFEXPORT(WdfRequestMarkCancelableEx), \ + VFWDFEXPORT(WdfRequestUnmarkCancelable), \ + VFWDFEXPORT(WdfRequestIsCanceled), \ + VFWDFEXPORT(WdfRequestCancelSentRequest), \ + VFWDFEXPORT(WdfRequestIsFrom32BitProcess), \ + VFWDFEXPORT(WdfRequestSetCompletionRoutine), \ + VFWDFEXPORT(WdfRequestGetCompletionParams), \ + VFWDFEXPORT(WdfRequestAllocateTimer), \ + VFWDFEXPORT(WdfRequestComplete), \ + VFWDFEXPORT(WdfRequestCompleteWithPriorityBoost), \ + VFWDFEXPORT(WdfRequestCompleteWithInformation), \ + VFWDFEXPORT(WdfRequestGetParameters), \ + VFWDFEXPORT(WdfRequestRetrieveInputMemory), \ + VFWDFEXPORT(WdfRequestRetrieveOutputMemory), \ + VFWDFEXPORT(WdfRequestRetrieveInputBuffer), \ + VFWDFEXPORT(WdfRequestRetrieveOutputBuffer), \ + VFWDFEXPORT(WdfRequestRetrieveInputWdmMdl), \ + VFWDFEXPORT(WdfRequestRetrieveOutputWdmMdl), \ + VFWDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer), \ + VFWDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer), \ + VFWDFEXPORT(WdfRequestSetInformation), \ + VFWDFEXPORT(WdfRequestGetInformation), \ + VFWDFEXPORT(WdfRequestGetFileObject), \ + VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForRead), \ + VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite), \ + VFWDFEXPORT(WdfRequestGetRequestorMode), \ + VFWDFEXPORT(WdfRequestForwardToIoQueue), \ + VFWDFEXPORT(WdfRequestGetIoQueue), \ + VFWDFEXPORT(WdfRequestRequeue), \ + VFWDFEXPORT(WdfRequestStopAcknowledge), \ + VFWDFEXPORT(WdfRequestWdmGetIrp), \ + VFWDFEXPORT(WdfRequestIsReserved), \ + VFWDFEXPORT(WdfRequestForwardToParentDeviceIoQueue), \ + VFWDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber), \ + VFWDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType), \ + VFWDFEXPORT(WdfIoResourceRequirementsListAppendIoResList), \ + VFWDFEXPORT(WdfIoResourceRequirementsListInsertIoResList), \ + VFWDFEXPORT(WdfIoResourceRequirementsListGetCount), \ + VFWDFEXPORT(WdfIoResourceRequirementsListGetIoResList), \ + VFWDFEXPORT(WdfIoResourceRequirementsListRemove), \ + VFWDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList), \ + VFWDFEXPORT(WdfIoResourceListCreate), \ + VFWDFEXPORT(WdfIoResourceListAppendDescriptor), \ + VFWDFEXPORT(WdfIoResourceListInsertDescriptor), \ + VFWDFEXPORT(WdfIoResourceListUpdateDescriptor), \ + VFWDFEXPORT(WdfIoResourceListGetCount), \ + VFWDFEXPORT(WdfIoResourceListGetDescriptor), \ + VFWDFEXPORT(WdfIoResourceListRemove), \ + VFWDFEXPORT(WdfIoResourceListRemoveByDescriptor), \ + VFWDFEXPORT(WdfCmResourceListAppendDescriptor), \ + VFWDFEXPORT(WdfCmResourceListInsertDescriptor), \ + VFWDFEXPORT(WdfCmResourceListGetCount), \ + VFWDFEXPORT(WdfCmResourceListGetDescriptor), \ + VFWDFEXPORT(WdfCmResourceListRemove), \ + VFWDFEXPORT(WdfCmResourceListRemoveByDescriptor), \ + VFWDFEXPORT(WdfStringCreate), \ + VFWDFEXPORT(WdfStringGetUnicodeString), \ + VFWDFEXPORT(WdfObjectAcquireLock), \ + VFWDFEXPORT(WdfObjectReleaseLock), \ + VFWDFEXPORT(WdfWaitLockCreate), \ + VFWDFEXPORT(WdfWaitLockAcquire), \ + VFWDFEXPORT(WdfWaitLockRelease), \ + VFWDFEXPORT(WdfSpinLockCreate), \ + VFWDFEXPORT(WdfSpinLockAcquire), \ + VFWDFEXPORT(WdfSpinLockRelease), \ + VFWDFEXPORT(WdfTimerCreate), \ + VFWDFEXPORT(WdfTimerStart), \ + VFWDFEXPORT(WdfTimerStop), \ + VFWDFEXPORT(WdfTimerGetParentObject), \ + VFWDFEXPORT(WdfUsbTargetDeviceCreate), \ + VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters), \ + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation), \ + VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor), \ + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor), \ + VFWDFEXPORT(WdfUsbTargetDeviceQueryString), \ + VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString), \ + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString), \ + VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces), \ + VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig), \ + VFWDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle), \ + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber), \ + VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously), \ + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer), \ + VFWDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous), \ + VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously), \ + VFWDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously), \ + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort), \ + VFWDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously), \ + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb), \ + VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability), \ + VFWDFEXPORT(WdfUsbTargetDeviceCreateUrb), \ + VFWDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb), \ + VFWDFEXPORT(WdfUsbTargetPipeGetInformation), \ + VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint), \ + VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint), \ + VFWDFEXPORT(WdfUsbTargetPipeGetType), \ + VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck), \ + VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite), \ + VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead), \ + VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader), \ + VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort), \ + VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset), \ + VFWDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb), \ + VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber), \ + VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints), \ + VFWDFEXPORT(WdfUsbInterfaceGetDescriptor), \ + VFWDFEXPORT(WdfUsbInterfaceGetNumSettings), \ + VFWDFEXPORT(WdfUsbInterfaceSelectSetting), \ + VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation), \ + VFWDFEXPORT(WdfUsbTargetDeviceGetInterface), \ + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex), \ + VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes), \ + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe), \ + VFWDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle), \ + VFWDFEXPORT(WdfVerifierDbgBreakPoint), \ + VFWDFEXPORT(WdfVerifierKeBugCheck), \ + VFWDFEXPORT(WdfGetTriageInfo), \ + VFWDFEXPORT(WdfWmiProviderCreate), \ + VFWDFEXPORT(WdfWmiProviderGetDevice), \ + VFWDFEXPORT(WdfWmiProviderIsEnabled), \ + VFWDFEXPORT(WdfWmiProviderGetTracingHandle), \ + VFWDFEXPORT(WdfWmiInstanceCreate), \ + VFWDFEXPORT(WdfWmiInstanceRegister), \ + VFWDFEXPORT(WdfWmiInstanceDeregister), \ + VFWDFEXPORT(WdfWmiInstanceGetDevice), \ + VFWDFEXPORT(WdfWmiInstanceGetProvider), \ + VFWDFEXPORT(WdfWmiInstanceFireEvent), \ + VFWDFEXPORT(WdfWorkItemCreate), \ + VFWDFEXPORT(WdfWorkItemEnqueue), \ + VFWDFEXPORT(WdfWorkItemGetParentObject), \ + VFWDFEXPORT(WdfWorkItemFlush), \ + ) +#endif // #pragma alloc_text + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_CHILD_LIST_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES ChildListAttributes, + _Out_ + WDFCHILDLIST* ChildList + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTCREATE) WdfVersion.Functions.pfnWdfChildListCreate)(DriverGlobals, Device, Config, ChildListAttributes, ChildList); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfChildListGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTGETDEVICE) WdfVersion.Functions.pfnWdfChildListGetDevice)(DriverGlobals, ChildList); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfChildListRetrievePdo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _Inout_ + PWDF_CHILD_RETRIEVE_INFO RetrieveInfo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTRETRIEVEPDO) WdfVersion.Functions.pfnWdfChildListRetrievePdo)(DriverGlobals, ChildList, RetrieveInfo); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListRetrieveAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTRETRIEVEADDRESSDESCRIPTION) WdfVersion.Functions.pfnWdfChildListRetrieveAddressDescription)(DriverGlobals, ChildList, IdentificationDescription, AddressDescription); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListBeginScan)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCHILDLISTBEGINSCAN) WdfVersion.Functions.pfnWdfChildListBeginScan)(DriverGlobals, ChildList); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListEndScan)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCHILDLISTENDSCAN) WdfVersion.Functions.pfnWdfChildListEndScan)(DriverGlobals, ChildList); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListBeginIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCHILDLISTBEGINITERATION) WdfVersion.Functions.pfnWdfChildListBeginIteration)(DriverGlobals, ChildList, Iterator); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListRetrieveNextDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator, + _Out_ + WDFDEVICE* Device, + _Inout_opt_ + PWDF_CHILD_RETRIEVE_INFO Info + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTRETRIEVENEXTDEVICE) WdfVersion.Functions.pfnWdfChildListRetrieveNextDevice)(DriverGlobals, ChildList, Iterator, Device, Info); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListEndIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCHILDLISTENDITERATION) WdfVersion.Functions.pfnWdfChildListEndIteration)(DriverGlobals, ChildList, Iterator); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListAddOrUpdateChildDescriptionAsPresent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + _In_opt_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTADDORUPDATECHILDDESCRIPTIONASPRESENT) WdfVersion.Functions.pfnWdfChildListAddOrUpdateChildDescriptionAsPresent)(DriverGlobals, ChildList, IdentificationDescription, AddressDescription); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfChildListUpdateChildDescriptionAsMissing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTUPDATECHILDDESCRIPTIONASMISSING) WdfVersion.Functions.pfnWdfChildListUpdateChildDescriptionAsMissing)(DriverGlobals, ChildList, IdentificationDescription); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfChildListUpdateAllChildDescriptionsAsPresent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCHILDLISTUPDATEALLCHILDDESCRIPTIONSASPRESENT) WdfVersion.Functions.pfnWdfChildListUpdateAllChildDescriptionsAsPresent)(DriverGlobals, ChildList); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfChildListRequestChildEject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCHILDLIST ChildList, + _In_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCHILDLISTREQUESTCHILDEJECT) WdfVersion.Functions.pfnWdfChildListRequestChildEject)(DriverGlobals, ChildList, IdentificationDescription); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + _Out_ + WDFCOLLECTION* Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONCREATE) WdfVersion.Functions.pfnWdfCollectionCreate)(DriverGlobals, CollectionAttributes, Collection); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCollectionGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETCOUNT) WdfVersion.Functions.pfnWdfCollectionGetCount)(DriverGlobals, Collection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionAdd)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONADD) WdfVersion.Functions.pfnWdfCollectionAdd)(DriverGlobals, Collection, Object); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Item + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCOLLECTIONREMOVE) WdfVersion.Functions.pfnWdfCollectionRemove)(DriverGlobals, Collection, Item); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemoveItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCOLLECTIONREMOVEITEM) WdfVersion.Functions.pfnWdfCollectionRemoveItem)(DriverGlobals, Collection, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETITEM) WdfVersion.Functions.pfnWdfCollectionGetItem)(DriverGlobals, Collection, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetFirstItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETFIRSTITEM) WdfVersion.Functions.pfnWdfCollectionGetFirstItem)(DriverGlobals, Collection); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetLastItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETLASTITEM) WdfVersion.Functions.pfnWdfCollectionGetLastItem)(DriverGlobals, Collection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCommonBufferCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFCOMMONBUFFER* CommonBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOMMONBUFFERCREATE) WdfVersion.Functions.pfnWdfCommonBufferCreate)(DriverGlobals, DmaEnabler, Length, Attributes, CommonBuffer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCommonBufferCreateWithConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length, + _In_ + PWDF_COMMON_BUFFER_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFCOMMONBUFFER* CommonBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOMMONBUFFERCREATEWITHCONFIG) WdfVersion.Functions.pfnWdfCommonBufferCreateWithConfig)(DriverGlobals, DmaEnabler, Length, Config, Attributes, CommonBuffer); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfCommonBufferGetAlignedVirtualAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOMMONBUFFERGETALIGNEDVIRTUALADDRESS) WdfVersion.Functions.pfnWdfCommonBufferGetAlignedVirtualAddress)(DriverGlobals, CommonBuffer); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PHYSICAL_ADDRESS +VFWDFEXPORT(WdfCommonBufferGetAlignedLogicalAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOMMONBUFFERGETALIGNEDLOGICALADDRESS) WdfVersion.Functions.pfnWdfCommonBufferGetAlignedLogicalAddress)(DriverGlobals, CommonBuffer); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfCommonBufferGetLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOMMONBUFFER CommonBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOMMONBUFFERGETLENGTH) WdfVersion.Functions.pfnWdfCommonBufferGetLength)(DriverGlobals, CommonBuffer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFDEVICE_INIT +VFWDFEXPORT(WdfControlDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + CONST UNICODE_STRING* SDDLString + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCONTROLDEVICEINITALLOCATE) WdfVersion.Functions.pfnWdfControlDeviceInitAllocate)(DriverGlobals, Driver, SDDLString); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfControlDeviceInitSetShutdownNotification)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDF_DEVICE_SHUTDOWN_NOTIFICATION Notification, + _In_ + UCHAR Flags + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCONTROLDEVICEINITSETSHUTDOWNNOTIFICATION) WdfVersion.Functions.pfnWdfControlDeviceInitSetShutdownNotification)(DriverGlobals, DeviceInit, Notification, Flags); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfControlFinishInitializing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCONTROLFINISHINITIALIZING) WdfVersion.Functions.pfnWdfControlFinishInitializing)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFCXDEVICE_INIT +VFWDFEXPORT(WdfCxDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCXDEVICEINITALLOCATE) WdfVersion.Functions.pfnWdfCxDeviceInitAllocate)(DriverGlobals, DeviceInit); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCxDeviceInitAssignWdmIrpPreprocessCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDeviceWdmIrpPreprocess, + _In_ + UCHAR MajorFunction, + _When_(NumMinorFunctions > 0, _In_reads_bytes_(NumMinorFunctions)) + _When_(NumMinorFunctions == 0, _In_opt_) + PUCHAR MinorFunctions, + _In_ + ULONG NumMinorFunctions + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCXDEVICEINITASSIGNWDMIRPPREPROCESSCALLBACK) WdfVersion.Functions.pfnWdfCxDeviceInitAssignWdmIrpPreprocessCallback)(DriverGlobals, CxDeviceInit, EvtCxDeviceWdmIrpPreprocess, MajorFunction, MinorFunctions, NumMinorFunctions); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetIoInCallerContextCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXDEVICEINITSETIOINCALLERCONTEXTCALLBACK) WdfVersion.Functions.pfnWdfCxDeviceInitSetIoInCallerContextCallback)(DriverGlobals, CxDeviceInit, EvtIoInCallerContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXDEVICEINITSETREQUESTATTRIBUTES) WdfVersion.Functions.pfnWdfCxDeviceInitSetRequestAttributes)(DriverGlobals, CxDeviceInit, RequestAttributes); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXDEVICEINITSETFILEOBJECTCONFIG) WdfVersion.Functions.pfnWdfCxDeviceInitSetFileObjectConfig)(DriverGlobals, CxDeviceInit, CxFileObjectConfig, FileObjectAttributes); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfCxVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFOBJECT Object, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXVERIFIERKEBUGCHECK) WdfVersion.Functions.pfnWdfCxVerifierKeBugCheck)(DriverGlobals, Object, BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceGetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + PWDF_DEVICE_STATE DeviceState + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEGETDEVICESTATE) WdfVersion.Functions.pfnWdfDeviceGetDeviceState)(DriverGlobals, Device, DeviceState); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_STATE DeviceState + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETDEVICESTATE) WdfVersion.Functions.pfnWdfDeviceSetDeviceState)(DriverGlobals, Device, DeviceState); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfWdmDeviceGetWdfDeviceHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDEVICE_OBJECT DeviceObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWDMDEVICEGETWDFDEVICEHANDLE) WdfVersion.Functions.pfnWdfWdmDeviceGetWdfDeviceHandle)(DriverGlobals, DeviceObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfDeviceWdmGetDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMGETDEVICEOBJECT) WdfVersion.Functions.pfnWdfDeviceWdmGetDeviceObject)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfDeviceWdmGetAttachedDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMGETATTACHEDDEVICE) WdfVersion.Functions.pfnWdfDeviceWdmGetAttachedDevice)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfDeviceWdmGetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMGETPHYSICALDEVICE) WdfVersion.Functions.pfnWdfDeviceWdmGetPhysicalDevice)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchPreprocessedIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMDISPATCHPREPROCESSEDIRP) WdfVersion.Functions.pfnWdfDeviceWdmDispatchPreprocessedIrp)(DriverGlobals, Device, Irp); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFCONTEXT DispatchContext + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMDISPATCHIRP) WdfVersion.Functions.pfnWdfDeviceWdmDispatchIrp)(DriverGlobals, Device, Irp, DispatchContext); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFQUEUE Queue, + _In_ + ULONG Flags + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMDISPATCHIRPTOIOQUEUE) WdfVersion.Functions.pfnWdfDeviceWdmDispatchIrpToIoQueue)(DriverGlobals, Device, Irp, Queue, Flags); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAddDependentUsageDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT DependentDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEADDDEPENDENTUSAGEDEVICEOBJECT) WdfVersion.Functions.pfnWdfDeviceAddDependentUsageDeviceObject)(DriverGlobals, Device, DependentDevice); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceRemoveDependentUsageDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT DependentDevice + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEREMOVEDEPENDENTUSAGEDEVICEOBJECT) WdfVersion.Functions.pfnWdfDeviceRemoveDependentUsageDeviceObject)(DriverGlobals, Device, DependentDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAddRemovalRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEADDREMOVALRELATIONSPHYSICALDEVICE) WdfVersion.Functions.pfnWdfDeviceAddRemovalRelationsPhysicalDevice)(DriverGlobals, Device, PhysicalDevice); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceRemoveRemovalRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEREMOVEREMOVALRELATIONSPHYSICALDEVICE) WdfVersion.Functions.pfnWdfDeviceRemoveRemovalRelationsPhysicalDevice)(DriverGlobals, Device, PhysicalDevice); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceClearRemovalRelationsDevices)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICECLEARREMOVALRELATIONSDEVICES) WdfVersion.Functions.pfnWdfDeviceClearRemovalRelationsDevices)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +VFWDFEXPORT(WdfDeviceGetDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDRIVER) WdfVersion.Functions.pfnWdfDeviceGetDriver)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceRetrieveDeviceName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICERETRIEVEDEVICENAME) WdfVersion.Functions.pfnWdfDeviceRetrieveDeviceName)(DriverGlobals, Device, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignMofResourceName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING MofResourceName + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNMOFRESOURCENAME) WdfVersion.Functions.pfnWdfDeviceAssignMofResourceName)(DriverGlobals, Device, MofResourceName); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETIOTARGET) WdfVersion.Functions.pfnWdfDeviceGetIoTarget)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_PNP_STATE +VFWDFEXPORT(WdfDeviceGetDevicePnpState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDEVICEPNPSTATE) WdfVersion.Functions.pfnWdfDeviceGetDevicePnpState)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_POWER_STATE +VFWDFEXPORT(WdfDeviceGetDevicePowerState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDEVICEPOWERSTATE) WdfVersion.Functions.pfnWdfDeviceGetDevicePowerState)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_DEVICE_POWER_POLICY_STATE +VFWDFEXPORT(WdfDeviceGetDevicePowerPolicyState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDEVICEPOWERPOLICYSTATE) WdfVersion.Functions.pfnWdfDeviceGetDevicePowerPolicyState)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignS0IdleSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNS0IDLESETTINGS) WdfVersion.Functions.pfnWdfDeviceAssignS0IdleSettings)(DriverGlobals, Device, Settings); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignSxWakeSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNSXWAKESETTINGS) WdfVersion.Functions.pfnWdfDeviceAssignSxWakeSettings)(DriverGlobals, Device, Settings); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEOPENREGISTRYKEY) WdfVersion.Functions.pfnWdfDeviceOpenRegistryKey)(DriverGlobals, Device, DeviceInstanceKeyType, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenDevicemapKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEOPENDEVICEMAPKEY) WdfVersion.Functions.pfnWdfDeviceOpenDevicemapKey)(DriverGlobals, Device, KeyName, DesiredAccess, KeyAttributes, Key); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetSpecialFileSupport)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_SPECIAL_FILE_TYPE FileType, + _In_ + BOOLEAN FileTypeIsSupported + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETSPECIALFILESUPPORT) WdfVersion.Functions.pfnWdfDeviceSetSpecialFileSupport)(DriverGlobals, Device, FileType, FileTypeIsSupported); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceCharacteristics + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETCHARACTERISTICS) WdfVersion.Functions.pfnWdfDeviceSetCharacteristics)(DriverGlobals, Device, DeviceCharacteristics); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfDeviceGetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETCHARACTERISTICS) WdfVersion.Functions.pfnWdfDeviceGetCharacteristics)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfDeviceGetAlignmentRequirement)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETALIGNMENTREQUIREMENT) WdfVersion.Functions.pfnWdfDeviceGetAlignmentRequirement)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetAlignmentRequirement)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG AlignmentRequirement + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETALIGNMENTREQUIREMENT) WdfVersion.Functions.pfnWdfDeviceSetAlignmentRequirement)(DriverGlobals, Device, AlignmentRequirement); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitFree)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITFREE) WdfVersion.Functions.pfnWdfDeviceInitFree)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPNPPOWEREVENTCALLBACKS) WdfVersion.Functions.pfnWdfDeviceInitSetPnpPowerEventCallbacks)(DriverGlobals, DeviceInit, PnpPowerEventCallbacks); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERPOLICYEVENTCALLBACKS) WdfVersion.Functions.pfnWdfDeviceInitSetPowerPolicyEventCallbacks)(DriverGlobals, DeviceInit, PowerPolicyEventCallbacks); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsPowerPolicyOwner + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERPOLICYOWNERSHIP) WdfVersion.Functions.pfnWdfDeviceInitSetPowerPolicyOwnership)(DriverGlobals, DeviceInit, IsPowerPolicyOwner); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitRegisterPnpStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_PNP_STATE PnpState, + _In_ + PFN_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION EvtDevicePnpStateChange, + _In_ + ULONG CallbackTypes + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEINITREGISTERPNPSTATECHANGECALLBACK) WdfVersion.Functions.pfnWdfDeviceInitRegisterPnpStateChangeCallback)(DriverGlobals, DeviceInit, PnpState, EvtDevicePnpStateChange, CallbackTypes); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitRegisterPowerStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_POWER_STATE PowerState, + _In_ + PFN_WDF_DEVICE_POWER_STATE_CHANGE_NOTIFICATION EvtDevicePowerStateChange, + _In_ + ULONG CallbackTypes + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEINITREGISTERPOWERSTATECHANGECALLBACK) WdfVersion.Functions.pfnWdfDeviceInitRegisterPowerStateChangeCallback)(DriverGlobals, DeviceInit, PowerState, EvtDevicePowerStateChange, CallbackTypes); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitRegisterPowerPolicyStateChangeCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState, + _In_ + PFN_WDF_DEVICE_POWER_POLICY_STATE_CHANGE_NOTIFICATION EvtDevicePowerPolicyStateChange, + _In_ + ULONG CallbackTypes + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEINITREGISTERPOWERPOLICYSTATECHANGECALLBACK) WdfVersion.Functions.pfnWdfDeviceInitRegisterPowerPolicyStateChangeCallback)(DriverGlobals, DeviceInit, PowerPolicyState, EvtDevicePowerPolicyStateChange, CallbackTypes); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetExclusive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsExclusive + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETEXCLUSIVE) WdfVersion.Functions.pfnWdfDeviceInitSetExclusive)(DriverGlobals, DeviceInit, IsExclusive); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_IO_TYPE IoType + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETIOTYPE) WdfVersion.Functions.pfnWdfDeviceInitSetIoType)(DriverGlobals, DeviceInit, IoType); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerNotPageable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERNOTPAGEABLE) WdfVersion.Functions.pfnWdfDeviceInitSetPowerNotPageable)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPageable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERPAGEABLE) WdfVersion.Functions.pfnWdfDeviceInitSetPowerPageable)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerInrush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERINRUSH) WdfVersion.Functions.pfnWdfDeviceInitSetPowerInrush)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetDeviceType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_TYPE DeviceType + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETDEVICETYPE) WdfVersion.Functions.pfnWdfDeviceInitSetDeviceType)(DriverGlobals, DeviceInit, DeviceType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitAssignName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_opt_ + PCUNICODE_STRING DeviceName + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEINITASSIGNNAME) WdfVersion.Functions.pfnWdfDeviceInitAssignName)(DriverGlobals, DeviceInit, DeviceName); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitAssignSDDLString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_opt_ + PCUNICODE_STRING SDDLString + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEINITASSIGNSDDLSTRING) WdfVersion.Functions.pfnWdfDeviceInitAssignSDDLString)(DriverGlobals, DeviceInit, SDDLString); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetDeviceClass)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + CONST GUID* DeviceClassGuid + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETDEVICECLASS) WdfVersion.Functions.pfnWdfDeviceInitSetDeviceClass)(DriverGlobals, DeviceInit, DeviceClassGuid); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetCharacteristics)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceCharacteristics, + _In_ + BOOLEAN OrInValues + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETCHARACTERISTICS) WdfVersion.Functions.pfnWdfDeviceInitSetCharacteristics)(DriverGlobals, DeviceInit, DeviceCharacteristics, OrInValues); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETFILEOBJECTCONFIG) WdfVersion.Functions.pfnWdfDeviceInitSetFileObjectConfig)(DriverGlobals, DeviceInit, FileObjectConfig, FileObjectAttributes); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETREQUESTATTRIBUTES) WdfVersion.Functions.pfnWdfDeviceInitSetRequestAttributes)(DriverGlobals, DeviceInit, RequestAttributes); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceInitAssignWdmIrpPreprocessCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmIrpPreprocess, + _In_ + UCHAR MajorFunction, + _When_(NumMinorFunctions > 0, _In_reads_bytes_(NumMinorFunctions)) + _When_(NumMinorFunctions == 0, _In_opt_) + PUCHAR MinorFunctions, + _In_ + ULONG NumMinorFunctions + ) +{ + PAGED_CODE_LOCKED(); +#pragma prefast(suppress: __WARNING_INVALID_PARAM_VALUE_3,"This is a verifier DDI hook routine. It just passes the caller parameters to original routine") + return ((PFN_WDFDEVICEINITASSIGNWDMIRPPREPROCESSCALLBACK) WdfVersion.Functions.pfnWdfDeviceInitAssignWdmIrpPreprocessCallback)(DriverGlobals, DeviceInit, EvtDeviceWdmIrpPreprocess, MajorFunction, MinorFunctions, NumMinorFunctions); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoInCallerContextCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETIOINCALLERCONTEXTCALLBACK) WdfVersion.Functions.pfnWdfDeviceInitSetIoInCallerContextCallback)(DriverGlobals, DeviceInit, EvtIoInCallerContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetRemoveLockOptions)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_REMOVE_LOCK_OPTIONS Options + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETREMOVELOCKOPTIONS) WdfVersion.Functions.pfnWdfDeviceInitSetRemoveLockOptions)(DriverGlobals, DeviceInit, Options); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT* DeviceInit, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + _Out_ + WDFDEVICE* Device + ) +{ + VF_HOOK_PROCESS_INFO hookInfo; + NTSTATUS status; + + PAGED_CODE_LOCKED(); + RtlZeroMemory(&hookInfo, sizeof(VF_HOOK_PROCESS_INFO)); + + status = AddEventHooksWdfDeviceCreate( + &hookInfo, + DriverGlobals, + DeviceInit, + DeviceAttributes, + Device); + + UNREFERENCED_PARAMETER(status); + + if (hookInfo.DonotCallKmdfLib) { + return hookInfo.DdiCallStatus; + } + + return ((PFN_WDFDEVICECREATE) WdfVersion.Functions.pfnWdfDeviceCreate)(DriverGlobals, DeviceInit, DeviceAttributes, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetStaticStopRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN Stoppable + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETSTATICSTOPREMOVE) WdfVersion.Functions.pfnWdfDeviceSetStaticStopRemove)(DriverGlobals, Device, Stoppable); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateDeviceInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECREATEDEVICEINTERFACE) WdfVersion.Functions.pfnWdfDeviceCreateDeviceInterface)(DriverGlobals, Device, InterfaceClassGUID, ReferenceString); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + BOOLEAN IsInterfaceEnabled + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETDEVICEINTERFACESTATE) WdfVersion.Functions.pfnWdfDeviceSetDeviceInterfaceState)(DriverGlobals, Device, InterfaceClassGUID, ReferenceString, IsInterfaceEnabled); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICERETRIEVEDEVICEINTERFACESTRING) WdfVersion.Functions.pfnWdfDeviceRetrieveDeviceInterfaceString)(DriverGlobals, Device, InterfaceClassGUID, ReferenceString, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateSymbolicLink)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING SymbolicLinkName + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECREATESYMBOLICLINK) WdfVersion.Functions.pfnWdfDeviceCreateSymbolicLink)(DriverGlobals, Device, SymbolicLinkName); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEQUERYPROPERTY) WdfVersion.Functions.pfnWdfDeviceQueryProperty)(DriverGlobals, Device, DeviceProperty, BufferLength, PropertyBuffer, ResultLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEALLOCANDQUERYPROPERTY) WdfVersion.Functions.pfnWdfDeviceAllocAndQueryProperty)(DriverGlobals, Device, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPnpCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETPNPCAPABILITIES) WdfVersion.Functions.pfnWdfDeviceSetPnpCapabilities)(DriverGlobals, Device, PnpCapabilities); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPowerCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETPOWERCAPABILITIES) WdfVersion.Functions.pfnWdfDeviceSetPowerCapabilities)(DriverGlobals, Device, PowerCapabilities); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetBusInformationForChildren)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PPNP_BUS_INFORMATION BusInformation + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETBUSINFORMATIONFORCHILDREN) WdfVersion.Functions.pfnWdfDeviceSetBusInformationForChildren)(DriverGlobals, Device, BusInformation); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceIndicateWakeStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + NTSTATUS WaitWakeStatus + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEINDICATEWAKESTATUS) WdfVersion.Functions.pfnWdfDeviceIndicateWakeStatus)(DriverGlobals, Device, WaitWakeStatus); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetFailed)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_FAILED_ACTION FailedAction + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETFAILED) WdfVersion.Functions.pfnWdfDeviceSetFailed)(DriverGlobals, Device, FailedAction); +} + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0 + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICESTOPIDLENOTRACK) WdfVersion.Functions.pfnWdfDeviceStopIdleNoTrack)(DriverGlobals, Device, WaitForD0); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICERESUMEIDLENOTRACK) WdfVersion.Functions.pfnWdfDeviceResumeIdleNoTrack)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICESTOPIDLEACTUAL) WdfVersion.Functions.pfnWdfDeviceStopIdleActual)(DriverGlobals, Device, WaitForD0, Tag, Line, File); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICERESUMEIDLEACTUAL) WdfVersion.Functions.pfnWdfDeviceResumeIdleActual)(DriverGlobals, Device, Tag, Line, File); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfDeviceGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PFILE_OBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETFILEOBJECT) WdfVersion.Functions.pfnWdfDeviceGetFileObject)(DriverGlobals, Device, FileObject); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceEnqueueRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEENQUEUEREQUEST) WdfVersion.Functions.pfnWdfDeviceEnqueueRequest)(DriverGlobals, Device, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfDeviceGetDefaultQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDEFAULTQUEUE) WdfVersion.Functions.pfnWdfDeviceGetDefaultQueue)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureRequestDispatching)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFQUEUE Queue, + _In_ + _Strict_type_match_ + WDF_REQUEST_TYPE RequestType + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECONFIGUREREQUESTDISPATCHING) WdfVersion.Functions.pfnWdfDeviceConfigureRequestDispatching)(DriverGlobals, Device, Queue, RequestType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDisptach, + _In_opt_ + WDFCONTEXT DriverContext + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECONFIGUREWDMIRPDISPATCHCALLBACK) WdfVersion.Functions.pfnWdfDeviceConfigureWdmIrpDispatchCallback)(DriverGlobals, Device, Driver, MajorFunction, EvtDeviceWdmIrpDisptach, DriverContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +POWER_ACTION +VFWDFEXPORT(WdfDeviceGetSystemPowerAction)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETSYSTEMPOWERACTION) WdfVersion.Functions.pfnWdfDeviceGetSystemPowerAction)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmAssignPowerFrameworkSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMASSIGNPOWERFRAMEWORKSETTINGS) WdfVersion.Functions.pfnWdfDeviceWdmAssignPowerFrameworkSettings)(DriverGlobals, Device, PowerFrameworkSettings); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETRELEASEHARDWAREORDERONFAILURE) WdfVersion.Functions.pfnWdfDeviceInitSetReleaseHardwareOrderOnFailure)(DriverGlobals, DeviceInit, ReleaseHardwareOrderOnFailure); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETIOTYPEEX) WdfVersion.Functions.pfnWdfDeviceInitSetIoTypeEx)(DriverGlobals, DeviceInit, IoTypeConfig); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfDeviceQueryPropertyEx)(DriverGlobals, Device, DeviceProperty, BufferLength, PropertyBuffer, RequiredSize, Type); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEALLOCANDQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfDeviceAllocAndQueryPropertyEx)(DriverGlobals, Device, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory, Type); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG Size, + _In_opt_ + PVOID Data + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNPROPERTY) WdfVersion.Functions.pfnWdfDeviceAssignProperty)(DriverGlobals, Device, DeviceProperty, Type, Size, Data); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETSELFIOTARGET) WdfVersion.Functions.pfnWdfDeviceGetSelfIoTarget)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITALLOWSELFIOTARGET) WdfVersion.Functions.pfnWdfDeviceInitAllowSelfIoTarget)(DriverGlobals, DeviceInit); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaEnablerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DMA_ENABLER_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDMAENABLER* DmaEnablerHandle + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMAENABLERCREATE) WdfVersion.Functions.pfnWdfDmaEnablerCreate)(DriverGlobals, Device, Config, Attributes, DmaEnablerHandle); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaEnablerConfigureSystemProfile)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + PWDF_DMA_SYSTEM_PROFILE_CONFIG ProfileConfig, + _In_ + WDF_DMA_DIRECTION ConfigDirection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMAENABLERCONFIGURESYSTEMPROFILE) WdfVersion.Functions.pfnWdfDmaEnablerConfigureSystemProfile)(DriverGlobals, DmaEnabler, ProfileConfig, ConfigDirection); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaEnablerGetMaximumLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMAENABLERGETMAXIMUMLENGTH) WdfVersion.Functions.pfnWdfDmaEnablerGetMaximumLength)(DriverGlobals, DmaEnabler); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaEnablerGetMaximumScatterGatherElements)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMAENABLERGETMAXIMUMSCATTERGATHERELEMENTS) WdfVersion.Functions.pfnWdfDmaEnablerGetMaximumScatterGatherElements)(DriverGlobals, DmaEnabler); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaEnablerSetMaximumScatterGatherElements)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + _When_(MaximumFragments == 0, __drv_reportError(MaximumFragments cannot be zero)) + size_t MaximumFragments + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMAENABLERSETMAXIMUMSCATTERGATHERELEMENTS) WdfVersion.Functions.pfnWdfDmaEnablerSetMaximumScatterGatherElements)(DriverGlobals, DmaEnabler, MaximumFragments); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaEnablerGetFragmentLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + WDF_DMA_DIRECTION DmaDirection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMAENABLERGETFRAGMENTLENGTH) WdfVersion.Functions.pfnWdfDmaEnablerGetFragmentLength)(DriverGlobals, DmaEnabler, DmaDirection); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDMA_ADAPTER +VFWDFEXPORT(WdfDmaEnablerWdmGetDmaAdapter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_ + WDF_DMA_DIRECTION DmaDirection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMAENABLERWDMGETDMAADAPTER) WdfVersion.Functions.pfnWdfDmaEnablerWdmGetDmaAdapter)(DriverGlobals, DmaEnabler, DmaDirection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMAENABLER DmaEnabler, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDMATRANSACTION* DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONCREATE) WdfVersion.Functions.pfnWdfDmaTransactionCreate)(DriverGlobals, DmaEnabler, Attributes, DmaTransaction); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionInitialize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + PMDL Mdl, + _In_ + PVOID VirtualAddress, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONINITIALIZE) WdfVersion.Functions.pfnWdfDmaTransactionInitialize)(DriverGlobals, DmaTransaction, EvtProgramDmaFunction, DmaDirection, Mdl, VirtualAddress, Length); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionInitializeUsingOffset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + PMDL Mdl, + _In_ + size_t Offset, + _In_ + _When_(Length == 0, __drv_reportError(Length cannot be zero)) + size_t Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONINITIALIZEUSINGOFFSET) WdfVersion.Functions.pfnWdfDmaTransactionInitializeUsingOffset)(DriverGlobals, DmaTransaction, EvtProgramDmaFunction, DmaDirection, Mdl, Offset, Length); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionInitializeUsingRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_PROGRAM_DMA EvtProgramDmaFunction, + _In_ + WDF_DMA_DIRECTION DmaDirection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONINITIALIZEUSINGREQUEST) WdfVersion.Functions.pfnWdfDmaTransactionInitializeUsingRequest)(DriverGlobals, DmaTransaction, Request, EvtProgramDmaFunction, DmaDirection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionExecute)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONEXECUTE) WdfVersion.Functions.pfnWdfDmaTransactionExecute)(DriverGlobals, DmaTransaction, Context); +} + +_Success_(TRUE) +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONRELEASE) WdfVersion.Functions.pfnWdfDmaTransactionRelease)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionDmaCompleted)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _Out_ + NTSTATUS* Status + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONDMACOMPLETED) WdfVersion.Functions.pfnWdfDmaTransactionDmaCompleted)(DriverGlobals, DmaTransaction, Status); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionDmaCompletedWithLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t TransferredLength, + _Out_ + NTSTATUS* Status + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONDMACOMPLETEDWITHLENGTH) WdfVersion.Functions.pfnWdfDmaTransactionDmaCompletedWithLength)(DriverGlobals, DmaTransaction, TransferredLength, Status); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionDmaCompletedFinal)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t FinalTransferredLength, + _Out_ + NTSTATUS* Status + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONDMACOMPLETEDFINAL) WdfVersion.Functions.pfnWdfDmaTransactionDmaCompletedFinal)(DriverGlobals, DmaTransaction, FinalTransferredLength, Status); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaTransactionGetBytesTransferred)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONGETBYTESTRANSFERRED) WdfVersion.Functions.pfnWdfDmaTransactionGetBytesTransferred)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetMaximumLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + size_t MaximumLength + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONSETMAXIMUMLENGTH) WdfVersion.Functions.pfnWdfDmaTransactionSetMaximumLength)(DriverGlobals, DmaTransaction, MaximumLength); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFREQUEST +VFWDFEXPORT(WdfDmaTransactionGetRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONGETREQUEST) WdfVersion.Functions.pfnWdfDmaTransactionGetRequest)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +size_t +VFWDFEXPORT(WdfDmaTransactionGetCurrentDmaTransferLength)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONGETCURRENTDMATRANSFERLENGTH) WdfVersion.Functions.pfnWdfDmaTransactionGetCurrentDmaTransferLength)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfDmaTransactionGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONGETDEVICE) WdfVersion.Functions.pfnWdfDmaTransactionGetDevice)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionGetTransferInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _Out_opt_ + ULONG* MapRegisterCount, + _Out_opt_ + ULONG* ScatterGatherElementCount + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONGETTRANSFERINFO) WdfVersion.Functions.pfnWdfDmaTransactionGetTransferInfo)(DriverGlobals, DmaTransaction, MapRegisterCount, ScatterGatherElementCount); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetChannelConfigurationCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + PFN_WDF_DMA_TRANSACTION_CONFIGURE_DMA_CHANNEL ConfigureRoutine, + _In_opt_ + PVOID ConfigureContext + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONSETCHANNELCONFIGURATIONCALLBACK) WdfVersion.Functions.pfnWdfDmaTransactionSetChannelConfigurationCallback)(DriverGlobals, DmaTransaction, ConfigureRoutine, ConfigureContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetTransferCompleteCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_opt_ + PFN_WDF_DMA_TRANSACTION_DMA_TRANSFER_COMPLETE DmaCompletionRoutine, + _In_opt_ + PVOID DmaCompletionContext + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONSETTRANSFERCOMPLETECALLBACK) WdfVersion.Functions.pfnWdfDmaTransactionSetTransferCompleteCallback)(DriverGlobals, DmaTransaction, DmaCompletionRoutine, DmaCompletionContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetImmediateExecution)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + BOOLEAN UseImmediateExecution + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONSETIMMEDIATEEXECUTION) WdfVersion.Functions.pfnWdfDmaTransactionSetImmediateExecution)(DriverGlobals, DmaTransaction, UseImmediateExecution); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDmaTransactionAllocateResources)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + WDF_DMA_DIRECTION DmaDirection, + _In_ + ULONG RequiredMapRegisters, + _In_ + PFN_WDF_RESERVE_DMA EvtReserveDmaFunction, + _In_ + PVOID EvtReserveDmaContext + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONALLOCATERESOURCES) WdfVersion.Functions.pfnWdfDmaTransactionAllocateResources)(DriverGlobals, DmaTransaction, DmaDirection, RequiredMapRegisters, EvtReserveDmaFunction, EvtReserveDmaContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionSetDeviceAddressOffset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction, + _In_ + ULONG Offset + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONSETDEVICEADDRESSOFFSET) WdfVersion.Functions.pfnWdfDmaTransactionSetDeviceAddressOffset)(DriverGlobals, DmaTransaction, Offset); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionFreeResources)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONFREERESOURCES) WdfVersion.Functions.pfnWdfDmaTransactionFreeResources)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDmaTransactionCancel)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONCANCEL) WdfVersion.Functions.pfnWdfDmaTransactionCancel)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfDmaTransactionWdmGetTransferContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDMATRANSACTIONWDMGETTRANSFERCONTEXT) WdfVersion.Functions.pfnWdfDmaTransactionWdmGetTransferContext)(DriverGlobals, DmaTransaction); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDmaTransactionStopSystemTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDMATRANSACTION DmaTransaction + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDMATRANSACTIONSTOPSYSTEMTRANSFER) WdfVersion.Functions.pfnWdfDmaTransactionStopSystemTransfer)(DriverGlobals, DmaTransaction); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDpcCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_DPC_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFDPC* Dpc + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDPCCREATE) WdfVersion.Functions.pfnWdfDpcCreate)(DriverGlobals, Config, Attributes, Dpc); +} + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDpcEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDPCENQUEUE) WdfVersion.Functions.pfnWdfDpcEnqueue)(DriverGlobals, Dpc); +} + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(HIGH_LEVEL)) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDpcCancel)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc, + _In_ + BOOLEAN Wait + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDPCCANCEL) WdfVersion.Functions.pfnWdfDpcCancel)(DriverGlobals, Dpc, Wait); +} + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfDpcGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDPCGETPARENTOBJECT) WdfVersion.Functions.pfnWdfDpcGetParentObject)(DriverGlobals, Dpc); +} + +_IRQL_requires_max_(HIGH_LEVEL) +WDFAPI +PKDPC +VFWDFEXPORT(WdfDpcWdmGetDpc)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDPC Dpc + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDPCWDMGETDPC) WdfVersion.Functions.pfnWdfDpcWdmGetDpc)(DriverGlobals, Dpc); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PCUNICODE_STRING RegistryPath, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + _In_ + PWDF_DRIVER_CONFIG DriverConfig, + _Out_opt_ + WDFDRIVER* Driver + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERCREATE) WdfVersion.Functions.pfnWdfDriverCreate)(DriverGlobals, DriverObject, RegistryPath, DriverAttributes, DriverConfig, Driver); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWSTR +VFWDFEXPORT(WdfDriverGetRegistryPath)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERGETREGISTRYPATH) WdfVersion.Functions.pfnWdfDriverGetRegistryPath)(DriverGlobals, Driver); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDRIVER_OBJECT +VFWDFEXPORT(WdfDriverWdmGetDriverObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERWDMGETDRIVEROBJECT) WdfVersion.Functions.pfnWdfDriverWdmGetDriverObject)(DriverGlobals, Driver); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverOpenParametersRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVEROPENPARAMETERSREGISTRYKEY) WdfVersion.Functions.pfnWdfDriverOpenParametersRegistryKey)(DriverGlobals, Driver, DesiredAccess, KeyAttributes, Key); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +VFWDFEXPORT(WdfWdmDriverGetWdfDriverHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWDMDRIVERGETWDFDRIVERHANDLE) WdfVersion.Functions.pfnWdfWdmDriverGetWdfDriverHandle)(DriverGlobals, DriverObject); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverRegisterTraceInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PFN_WDF_TRACE_CALLBACK EvtTraceCallback, + _In_ + PVOID ControlBlock + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERREGISTERTRACEINFO) WdfVersion.Functions.pfnWdfDriverRegisterTraceInfo)(DriverGlobals, DriverObject, EvtTraceCallback, ControlBlock); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverRetrieveVersionString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERRETRIEVEVERSIONSTRING) WdfVersion.Functions.pfnWdfDriverRetrieveVersionString)(DriverGlobals, Driver, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDriverIsVersionAvailable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERISVERSIONAVAILABLE) WdfVersion.Functions.pfnWdfDriverIsVersionAvailable)(DriverGlobals, Driver, VersionAvailableParams); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfFdoInitWdmGetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITWDMGETPHYSICALDEVICE) WdfVersion.Functions.pfnWdfFdoInitWdmGetPhysicalDevice)(DriverGlobals, DeviceInit); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITOPENREGISTRYKEY) WdfVersion.Functions.pfnWdfFdoInitOpenRegistryKey)(DriverGlobals, DeviceInit, DeviceInstanceKeyType, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITQUERYPROPERTY) WdfVersion.Functions.pfnWdfFdoInitQueryProperty)(DriverGlobals, DeviceInit, DeviceProperty, BufferLength, PropertyBuffer, ResultLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITALLOCANDQUERYPROPERTY) WdfVersion.Functions.pfnWdfFdoInitAllocAndQueryProperty)(DriverGlobals, DeviceInit, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfFdoInitQueryPropertyEx)(DriverGlobals, DeviceInit, DeviceProperty, BufferLength, PropertyBuffer, ResultLength, Type); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITALLOCANDQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfFdoInitAllocAndQueryPropertyEx)(DriverGlobals, DeviceInit, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory, Type); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FDO_EVENT_CALLBACKS FdoEventCallbacks + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFFDOINITSETEVENTCALLBACKS) WdfVersion.Functions.pfnWdfFdoInitSetEventCallbacks)(DriverGlobals, DeviceInit, FdoEventCallbacks); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetFilter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFFDOINITSETFILTER) WdfVersion.Functions.pfnWdfFdoInitSetFilter)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetDefaultChildListConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_CHILD_LIST_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DefaultChildListAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFFDOINITSETDEFAULTCHILDLISTCONFIG) WdfVersion.Functions.pfnWdfFdoInitSetDefaultChildListConfig)(DriverGlobals, DeviceInit, Config, DefaultChildListAttributes); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoQueryForInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_ + LPCGUID InterfaceType, + _Out_ + PINTERFACE Interface, + _In_ + USHORT Size, + _In_ + USHORT Version, + _In_opt_ + PVOID InterfaceSpecificData + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOQUERYFORINTERFACE) WdfVersion.Functions.pfnWdfFdoQueryForInterface)(DriverGlobals, Fdo, InterfaceType, Interface, Size, Version, InterfaceSpecificData); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFCHILDLIST +VFWDFEXPORT(WdfFdoGetDefaultChildList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOGETDEFAULTCHILDLIST) WdfVersion.Functions.pfnWdfFdoGetDefaultChildList)(DriverGlobals, Fdo); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoAddStaticChild)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_ + WDFDEVICE Child + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOADDSTATICCHILD) WdfVersion.Functions.pfnWdfFdoAddStaticChild)(DriverGlobals, Fdo, Child); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoLockStaticChildListForIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFFDOLOCKSTATICCHILDLISTFORITERATION) WdfVersion.Functions.pfnWdfFdoLockStaticChildListForIteration)(DriverGlobals, Fdo); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfFdoRetrieveNextStaticChild)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo, + _In_opt_ + WDFDEVICE PreviousChild, + _In_ + ULONG Flags + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDORETRIEVENEXTSTATICCHILD) WdfVersion.Functions.pfnWdfFdoRetrieveNextStaticChild)(DriverGlobals, Fdo, PreviousChild, Flags); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoUnlockStaticChildListFromIteration)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Fdo + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFFDOUNLOCKSTATICCHILDLISTFROMITERATION) WdfVersion.Functions.pfnWdfFdoUnlockStaticChildListFromIteration)(DriverGlobals, Fdo); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PUNICODE_STRING +VFWDFEXPORT(WdfFileObjectGetFileName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETFILENAME) WdfVersion.Functions.pfnWdfFileObjectGetFileName)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfFileObjectGetFlags)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETFLAGS) WdfVersion.Functions.pfnWdfFileObjectGetFlags)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfFileObjectGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETDEVICE) WdfVersion.Functions.pfnWdfFileObjectGetDevice)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PFILE_OBJECT +VFWDFEXPORT(WdfFileObjectWdmGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTWDMGETFILEOBJECT) WdfVersion.Functions.pfnWdfFileObjectWdmGetFileObject)(DriverGlobals, FileObject); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfInterruptCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_INTERRUPT_CONFIG Configuration, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFINTERRUPT* Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTCREATE) WdfVersion.Functions.pfnWdfInterruptCreate)(DriverGlobals, Device, Configuration, Attributes, Interrupt); +} + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueDpcForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTQUEUEDPCFORISR) WdfVersion.Functions.pfnWdfInterruptQueueDpcForIsr)(DriverGlobals, Interrupt); +} + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTQUEUEWORKITEMFORISR) WdfVersion.Functions.pfnWdfInterruptQueueWorkItemForIsr)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptSynchronize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + _In_ + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTSYNCHRONIZE) WdfVersion.Functions.pfnWdfInterruptSynchronize)(DriverGlobals, Interrupt, Callback, Context); +} + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTACQUIRELOCK) WdfVersion.Functions.pfnWdfInterruptAcquireLock)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTRELEASELOCK) WdfVersion.Functions.pfnWdfInterruptReleaseLock)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptEnable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTENABLE) WdfVersion.Functions.pfnWdfInterruptEnable)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptDisable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTDISABLE) WdfVersion.Functions.pfnWdfInterruptDisable)(DriverGlobals, Interrupt); +} + +_Must_inspect_result_ +WDFAPI +PKINTERRUPT +VFWDFEXPORT(WdfInterruptWdmGetInterrupt)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTWDMGETINTERRUPT) WdfVersion.Functions.pfnWdfInterruptWdmGetInterrupt)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptGetInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _Out_ + PWDF_INTERRUPT_INFO Info + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTGETINFO) WdfVersion.Functions.pfnWdfInterruptGetInfo)(DriverGlobals, Interrupt, Info); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + WDF_INTERRUPT_POLICY Policy, + _In_ + WDF_INTERRUPT_PRIORITY Priority, + _In_ + KAFFINITY TargetProcessorSet + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTSETPOLICY) WdfVersion.Functions.pfnWdfInterruptSetPolicy)(DriverGlobals, Interrupt, Policy, Priority, TargetProcessorSet); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetExtendedPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTSETEXTENDEDPOLICY) WdfVersion.Functions.pfnWdfInterruptSetExtendedPolicy)(DriverGlobals, Interrupt, PolicyAndGroup); +} + +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfInterruptGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTGETDEVICE) WdfVersion.Functions.pfnWdfInterruptGetDevice)(DriverGlobals, Interrupt); +} + +_Must_inspect_result_ +_Post_satisfies_(return == 1 || return == 0) +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptTryToAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTTRYTOACQUIRELOCK) WdfVersion.Functions.pfnWdfInterruptTryToAcquireLock)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReportActive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTREPORTACTIVE) WdfVersion.Functions.pfnWdfInterruptReportActive)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReportInactive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTREPORTINACTIVE) WdfVersion.Functions.pfnWdfInterruptReportInactive)(DriverGlobals, Interrupt); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_IO_QUEUE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + _Out_opt_ + WDFQUEUE* Queue + ) +{ + VF_HOOK_PROCESS_INFO hookInfo; + NTSTATUS status; + + PAGED_CODE_LOCKED(); + RtlZeroMemory(&hookInfo, sizeof(VF_HOOK_PROCESS_INFO)); + + status = AddEventHooksWdfIoQueueCreate( + &hookInfo, + DriverGlobals, + Device, + Config, + QueueAttributes, + Queue); + + UNREFERENCED_PARAMETER(status); + + if (hookInfo.DonotCallKmdfLib) { + return hookInfo.DdiCallStatus; + } + + return ((PFN_WDFIOQUEUECREATE) WdfVersion.Functions.pfnWdfIoQueueCreate)(DriverGlobals, Device, Config, QueueAttributes, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_QUEUE_STATE +VFWDFEXPORT(WdfIoQueueGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_opt_ + PULONG QueueRequests, + _Out_opt_ + PULONG DriverRequests + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEGETSTATE) WdfVersion.Functions.pfnWdfIoQueueGetState)(DriverGlobals, Queue, QueueRequests, DriverRequests); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTART) WdfVersion.Functions.pfnWdfIoQueueStart)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopComplete, + _When_(StopComplete != 0, _In_) + _When_(StopComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOP) WdfVersion.Functions.pfnWdfIoQueueStop)(DriverGlobals, Queue, StopComplete, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOPSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueueStopSynchronously)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoQueueGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEGETDEVICE) WdfVersion.Functions.pfnWdfIoQueueGetDevice)(DriverGlobals, Queue); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveNextRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + NTSTATUS rtn = ((PFN_WDFIOQUEUERETRIEVENEXTREQUEST) WdfVersion.Functions.pfnWdfIoQueueRetrieveNextRequest)(DriverGlobals, Queue, OutRequest); + if (rtn == STATUS_SUCCESS) { + PerfIoStart(*OutRequest); + } + return rtn; +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFFILEOBJECT FileObject, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + NTSTATUS rtn = ((PFN_WDFIOQUEUERETRIEVEREQUESTBYFILEOBJECT) WdfVersion.Functions.pfnWdfIoQueueRetrieveRequestByFileObject)(DriverGlobals, Queue, FileObject, OutRequest); + if (rtn == STATUS_SUCCESS) { + PerfIoStart(*OutRequest); + } + return rtn; +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueFindRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + WDFREQUEST FoundRequest, + _In_opt_ + WDFFILEOBJECT FileObject, + _Inout_opt_ + PWDF_REQUEST_PARAMETERS Parameters, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEFINDREQUEST) WdfVersion.Functions.pfnWdfIoQueueFindRequest)(DriverGlobals, Queue, FoundRequest, FileObject, Parameters, OutRequest); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFREQUEST FoundRequest, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + NTSTATUS rtn = ((PFN_WDFIOQUEUERETRIEVEFOUNDREQUEST) WdfVersion.Functions.pfnWdfIoQueueRetrieveFoundRequest)(DriverGlobals, Queue, FoundRequest, OutRequest); + if (rtn == STATUS_SUCCESS) { + PerfIoStart(*OutRequest); + } + return rtn; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrainSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEDRAINSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueueDrainSynchronously)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrain)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + _When_(DrainComplete != 0, _In_) + _When_(DrainComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEDRAIN) WdfVersion.Functions.pfnWdfIoQueueDrain)(DriverGlobals, Queue, DrainComplete, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEPURGESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueuePurgeSynchronously)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + _When_(PurgeComplete != 0, _In_) + _When_(PurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEPURGE) WdfVersion.Functions.pfnWdfIoQueuePurge)(DriverGlobals, Queue, PurgeComplete, Context); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueReadyNotify)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + PFN_WDF_IO_QUEUE_STATE QueueReady, + _In_opt_ + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEREADYNOTIFY) WdfVersion.Functions.pfnWdfIoQueueReadyNotify)(DriverGlobals, Queue, QueueReady, Context); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueAssignForwardProgressPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY ForwardProgressPolicy + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEASSIGNFORWARDPROGRESSPOLICY) WdfVersion.Functions.pfnWdfIoQueueAssignForwardProgressPolicy)(DriverGlobals, Queue, ForwardProgressPolicy); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + _When_(StopAndPurgeComplete != 0, _In_) + _When_(StopAndPurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOPANDPURGE) WdfVersion.Functions.pfnWdfIoQueueStopAndPurge)(DriverGlobals, Queue, StopAndPurgeComplete, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOPANDPURGESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueueStopAndPurgeSynchronously)(DriverGlobals, Queue); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + _Out_ + WDFIOTARGET* IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETCREATE) WdfVersion.Functions.pfnWdfIoTargetCreate)(DriverGlobals, Device, IoTargetAttributes, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetOpen)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETOPEN) WdfVersion.Functions.pfnWdfIoTargetOpen)(DriverGlobals, IoTarget, OpenParams); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetCloseForQueryRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETCLOSEFORQUERYREMOVE) WdfVersion.Functions.pfnWdfIoTargetCloseForQueryRemove)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETCLOSE) WdfVersion.Functions.pfnWdfIoTargetClose)(DriverGlobals, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSTART) WdfVersion.Functions.pfnWdfIoTargetStart)(DriverGlobals, IoTarget); +} + +_When_(Action == 3, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1 || Action == 2, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_SENT_IO_ACTION Action + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETSTOP) WdfVersion.Functions.pfnWdfIoTargetStop)(DriverGlobals, IoTarget, Action); +} + +_When_(Action == 2, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_PURGE_IO_ACTION Action + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETPURGE) WdfVersion.Functions.pfnWdfIoTargetPurge)(DriverGlobals, IoTarget, Action); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_TARGET_STATE +VFWDFEXPORT(WdfIoTargetGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETGETSTATE) WdfVersion.Functions.pfnWdfIoTargetGetState)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoTargetGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETGETDEVICE) WdfVersion.Functions.pfnWdfIoTargetGetDevice)(DriverGlobals, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetQueryTargetProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _When_(BufferLength != 0, _Out_writes_bytes_to_opt_(BufferLength, *ResultLength)) + _When_(BufferLength == 0, _Out_opt_) + PVOID PropertyBuffer, + _Deref_out_range_(<=,BufferLength) + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); +#pragma prefast(suppress: __WARNING_HIGH_PRIORITY_OVERFLOW_POSTCONDITION, "This is a verifier DDI hook routine and all it does is call original routine.") + return ((PFN_WDFIOTARGETQUERYTARGETPROPERTY) WdfVersion.Functions.pfnWdfIoTargetQueryTargetProperty)(DriverGlobals, IoTarget, DeviceProperty, BufferLength, PropertyBuffer, ResultLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETALLOCANDQUERYTARGETPROPERTY) WdfVersion.Functions.pfnWdfIoTargetAllocAndQueryTargetProperty)(DriverGlobals, IoTarget, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetQueryForInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + LPCGUID InterfaceType, + _Out_ + PINTERFACE Interface, + _In_ + USHORT Size, + _In_ + USHORT Version, + _In_opt_ + PVOID InterfaceSpecificData + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETQUERYFORINTERFACE) WdfVersion.Functions.pfnWdfIoTargetQueryForInterface)(DriverGlobals, IoTarget, InterfaceType, Interface, Size, Version, InterfaceSpecificData); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETWDMGETTARGETDEVICEOBJECT) WdfVersion.Functions.pfnWdfIoTargetWdmGetTargetDeviceObject)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PDEVICE_OBJECT +VFWDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETWDMGETTARGETPHYSICALDEVICE) WdfVersion.Functions.pfnWdfIoTargetWdmGetTargetPhysicalDevice)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PFILE_OBJECT +VFWDFEXPORT(WdfIoTargetWdmGetTargetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETWDMGETTARGETFILEOBJECT) WdfVersion.Functions.pfnWdfIoTargetWdmGetTargetFileObject)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETWDMGETTARGETFILEHANDLE) WdfVersion.Functions.pfnWdfIoTargetWdmGetTargetFileHandle)(DriverGlobals, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesRead + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDREADSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendReadSynchronously)(DriverGlobals, IoTarget, Request, OutputBuffer, DeviceOffset, RequestOptions, BytesRead); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORREAD) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForRead)(DriverGlobals, IoTarget, Request, OutputBuffer, OutputBufferOffset, DeviceOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesWritten + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDWRITESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendWriteSynchronously)(DriverGlobals, IoTarget, Request, InputBuffer, DeviceOffset, RequestOptions, BytesWritten); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORWRITE) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForWrite)(DriverGlobals, IoTarget, Request, InputBuffer, InputBufferOffset, DeviceOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDIOCTLSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendIoctlSynchronously)(DriverGlobals, IoTarget, Request, IoctlCode, InputBuffer, OutputBuffer, RequestOptions, BytesReturned); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORIOCTL) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForIoctl)(DriverGlobals, IoTarget, Request, IoctlCode, InputBuffer, InputBufferOffset, OutputBuffer, OutputBufferOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDINTERNALIOCTLSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendInternalIoctlSynchronously)(DriverGlobals, IoTarget, Request, IoctlCode, InputBuffer, OutputBuffer, RequestOptions, BytesReturned); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORINTERNALIOCTL) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForInternalIoctl)(DriverGlobals, IoTarget, Request, IoctlCode, InputBuffer, InputBufferOffset, OutputBuffer, OutputBufferOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg1, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg2, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OtherArg4, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDINTERNALIOCTLOTHERSSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendInternalIoctlOthersSynchronously)(DriverGlobals, IoTarget, Request, IoctlCode, OtherArg1, OtherArg2, OtherArg4, RequestOptions, BytesReturned); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY OtherArg1, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg1Offset, + _In_opt_ + WDFMEMORY OtherArg2, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg2Offset, + _In_opt_ + WDFMEMORY OtherArg4, + _In_opt_ + PWDFMEMORY_OFFSET OtherArg4Offset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORINTERNALIOCTLOTHERS) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForInternalIoctlOthers)(DriverGlobals, IoTarget, Request, IoctlCode, OtherArg1, OtherArg1Offset, OtherArg2, OtherArg2Offset, OtherArg4, OtherArg4Offset); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSELFASSIGNDEFAULTIOQUEUE) WdfVersion.Functions.pfnWdfIoTargetSelfAssignDefaultIoQueue)(DriverGlobals, IoTarget, Queue); +} + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + ULONG PoolTag, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory, + _Outptr_opt_result_bytebuffer_(BufferSize) + PVOID* Buffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCREATE) WdfVersion.Functions.pfnWdfMemoryCreate)(DriverGlobals, Attributes, PoolType, PoolTag, BufferSize, Memory, Buffer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreatePreallocated)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ __drv_aliasesMem + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCREATEPREALLOCATED) WdfVersion.Functions.pfnWdfMemoryCreatePreallocated)(DriverGlobals, Attributes, Buffer, BufferSize, Memory); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfMemoryGetBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Out_opt_ + size_t* BufferSize + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYGETBUFFER) WdfVersion.Functions.pfnWdfMemoryGetBuffer)(DriverGlobals, Memory, BufferSize); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYASSIGNBUFFER) WdfVersion.Functions.pfnWdfMemoryAssignBuffer)(DriverGlobals, Memory, Buffer, BufferSize); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyToBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY SourceMemory, + _In_ + size_t SourceOffset, + _Out_writes_bytes_( NumBytesToCopyTo ) + PVOID Buffer, + _In_ + _When_(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCOPYTOBUFFER) WdfVersion.Functions.pfnWdfMemoryCopyToBuffer)(DriverGlobals, SourceMemory, SourceOffset, Buffer, NumBytesToCopyTo); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyFromBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY DestinationMemory, + _In_ + size_t DestinationOffset, + _In_ + PVOID Buffer, + _In_ + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCOPYFROMBUFFER) WdfVersion.Functions.pfnWdfMemoryCopyFromBuffer)(DriverGlobals, DestinationMemory, DestinationOffset, Buffer, NumBytesToCopyFrom); +} + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfLookasideListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LookasideAttributes, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _In_opt_ + ULONG PoolTag, + _Out_ + WDFLOOKASIDE* Lookaside + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFLOOKASIDELISTCREATE) WdfVersion.Functions.pfnWdfLookasideListCreate)(DriverGlobals, LookasideAttributes, BufferSize, PoolType, MemoryAttributes, PoolTag, Lookaside); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreateFromLookaside)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFLOOKASIDE Lookaside, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCREATEFROMLOOKASIDE) WdfVersion.Functions.pfnWdfMemoryCreateFromLookaside)(DriverGlobals, Lookaside, Memory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceMiniportCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + PDEVICE_OBJECT DeviceObject, + _In_opt_ + PDEVICE_OBJECT AttachedDeviceObject, + _In_opt_ + PDEVICE_OBJECT Pdo, + _Out_ + WDFDEVICE* Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEMINIPORTCREATE) WdfVersion.Functions.pfnWdfDeviceMiniportCreate)(DriverGlobals, Driver, Attributes, DeviceObject, AttachedDeviceObject, Pdo, Device); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfDriverMiniportUnload)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDRIVERMINIPORTUNLOAD) WdfVersion.Functions.pfnWdfDriverMiniportUnload)(DriverGlobals, Driver); +} + +WDFAPI +PVOID +FASTCALL +VFWDFEXPORT(WdfObjectGetTypedContextWorker)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTGETTYPEDCONTEXTWORKER) WdfVersion.Functions.pfnWdfObjectGetTypedContextWorker)(DriverGlobals, Handle, TypeInfo); +} + +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectAllocateContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PWDF_OBJECT_ATTRIBUTES ContextAttributes, + _Outptr_opt_ + PVOID* Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTALLOCATECONTEXT) WdfVersion.Functions.pfnWdfObjectAllocateContext)(DriverGlobals, Handle, ContextAttributes, Context); +} + +WDFAPI +WDFOBJECT +FASTCALL +VFWDFEXPORT(WdfObjectContextGetObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PVOID ContextPointer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTCONTEXTGETOBJECT) WdfVersion.Functions.pfnWdfObjectContextGetObject)(DriverGlobals, ContextPointer); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTREFERENCEACTUAL) WdfVersion.Functions.pfnWdfObjectReferenceActual)(DriverGlobals, Handle, Tag, Line, File); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDereferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTDEREFERENCEACTUAL) WdfVersion.Functions.pfnWdfObjectDereferenceActual)(DriverGlobals, Handle, Tag, Line, File); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFOBJECT* Object + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTCREATE) WdfVersion.Functions.pfnWdfObjectCreate)(DriverGlobals, Attributes, Object); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDelete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTDELETE) WdfVersion.Functions.pfnWdfObjectDelete)(DriverGlobals, Object); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectQuery)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object, + _In_ + CONST GUID* Guid, + _In_ + ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTQUERY) WdfVersion.Functions.pfnWdfObjectQuery)(DriverGlobals, Object, Guid, QueryBufferLength, QueryBuffer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFDEVICE_INIT +VFWDFEXPORT(WdfPdoInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE ParentDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITALLOCATE) WdfVersion.Functions.pfnWdfPdoInitAllocate)(DriverGlobals, ParentDevice); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoInitSetEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PDO_EVENT_CALLBACKS DispatchTable + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFPDOINITSETEVENTCALLBACKS) WdfVersion.Functions.pfnWdfPdoInitSetEventCallbacks)(DriverGlobals, DeviceInit, DispatchTable); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignDeviceID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING DeviceID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITASSIGNDEVICEID) WdfVersion.Functions.pfnWdfPdoInitAssignDeviceID)(DriverGlobals, DeviceInit, DeviceID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignInstanceID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING InstanceID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITASSIGNINSTANCEID) WdfVersion.Functions.pfnWdfPdoInitAssignInstanceID)(DriverGlobals, DeviceInit, InstanceID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAddHardwareID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING HardwareID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITADDHARDWAREID) WdfVersion.Functions.pfnWdfPdoInitAddHardwareID)(DriverGlobals, DeviceInit, HardwareID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAddCompatibleID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING CompatibleID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITADDCOMPATIBLEID) WdfVersion.Functions.pfnWdfPdoInitAddCompatibleID)(DriverGlobals, DeviceInit, CompatibleID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignContainerID)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING ContainerID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITASSIGNCONTAINERID) WdfVersion.Functions.pfnWdfPdoInitAssignContainerID)(DriverGlobals, DeviceInit, ContainerID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAddDeviceText)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PCUNICODE_STRING DeviceDescription, + _In_ + PCUNICODE_STRING DeviceLocation, + _In_ + LCID LocaleId + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITADDDEVICETEXT) WdfVersion.Functions.pfnWdfPdoInitAddDeviceText)(DriverGlobals, DeviceInit, DeviceDescription, DeviceLocation, LocaleId); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoInitSetDefaultLocale)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + LCID LocaleId + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFPDOINITSETDEFAULTLOCALE) WdfVersion.Functions.pfnWdfPdoInitSetDefaultLocale)(DriverGlobals, DeviceInit, LocaleId); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoInitAssignRawDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + CONST GUID* DeviceClassGuid + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOINITASSIGNRAWDEVICE) WdfVersion.Functions.pfnWdfPdoInitAssignRawDevice)(DriverGlobals, DeviceInit, DeviceClassGuid); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoInitAllowForwardingRequestToParent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFPDOINITALLOWFORWARDINGREQUESTTOPARENT) WdfVersion.Functions.pfnWdfPdoInitAllowForwardingRequestToParent)(DriverGlobals, DeviceInit); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoMarkMissing)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOMARKMISSING) WdfVersion.Functions.pfnWdfPdoMarkMissing)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoRequestEject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFPDOREQUESTEJECT) WdfVersion.Functions.pfnWdfPdoRequestEject)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfPdoGetParent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOGETPARENT) WdfVersion.Functions.pfnWdfPdoGetParent)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoRetrieveIdentificationDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDORETRIEVEIDENTIFICATIONDESCRIPTION) WdfVersion.Functions.pfnWdfPdoRetrieveIdentificationDescription)(DriverGlobals, Device, IdentificationDescription); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoRetrieveAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDORETRIEVEADDRESSDESCRIPTION) WdfVersion.Functions.pfnWdfPdoRetrieveAddressDescription)(DriverGlobals, Device, AddressDescription); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoUpdateAddressDescription)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Inout_ + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOUPDATEADDRESSDESCRIPTION) WdfVersion.Functions.pfnWdfPdoUpdateAddressDescription)(DriverGlobals, Device, AddressDescription); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfPdoAddEjectionRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFPDOADDEJECTIONRELATIONSPHYSICALDEVICE) WdfVersion.Functions.pfnWdfPdoAddEjectionRelationsPhysicalDevice)(DriverGlobals, Device, PhysicalDevice); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoRemoveEjectionRelationsPhysicalDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PDEVICE_OBJECT PhysicalDevice + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFPDOREMOVEEJECTIONRELATIONSPHYSICALDEVICE) WdfVersion.Functions.pfnWdfPdoRemoveEjectionRelationsPhysicalDevice)(DriverGlobals, Device, PhysicalDevice); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfPdoClearEjectionRelationsDevices)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFPDOCLEAREJECTIONRELATIONSDEVICES) WdfVersion.Functions.pfnWdfPdoClearEjectionRelationsDevices)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAddQueryInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_QUERY_INTERFACE_CONFIG InterfaceConfig + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEADDQUERYINTERFACE) WdfVersion.Functions.pfnWdfDeviceAddQueryInterface)(DriverGlobals, Device, InterfaceConfig); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryOpenKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYOPENKEY) WdfVersion.Functions.pfnWdfRegistryOpenKey)(DriverGlobals, ParentKey, KeyName, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryCreateKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_ + ULONG CreateOptions, + _Out_opt_ + PULONG CreateDisposition, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYCREATEKEY) WdfVersion.Functions.pfnWdfRegistryCreateKey)(DriverGlobals, ParentKey, KeyName, DesiredAccess, CreateOptions, CreateDisposition, KeyAttributes, Key); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRegistryClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREGISTRYCLOSE) WdfVersion.Functions.pfnWdfRegistryClose)(DriverGlobals, Key); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfRegistryWdmGetHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYWDMGETHANDLE) WdfVersion.Functions.pfnWdfRegistryWdmGetHandle)(DriverGlobals, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYREMOVEKEY) WdfVersion.Functions.pfnWdfRegistryRemoveKey)(DriverGlobals, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYREMOVEVALUE) WdfVersion.Functions.pfnWdfRegistryRemoveValue)(DriverGlobals, Key, ValueName); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueLength, + _Out_writes_bytes_opt_( ValueLength) + PVOID Value, + _Out_opt_ + PULONG ValueLengthQueried, + _Out_opt_ + PULONG ValueType + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYVALUE) WdfVersion.Functions.pfnWdfRegistryQueryValue)(DriverGlobals, Key, ValueName, ValueLength, Value, ValueLengthQueried, ValueType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _Out_ + WDFMEMORY* Memory, + _Out_opt_ + PULONG ValueType + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYMEMORY) WdfVersion.Functions.pfnWdfRegistryQueryMemory)(DriverGlobals, Key, ValueName, PoolType, MemoryAttributes, Memory, ValueType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYMULTISTRING) WdfVersion.Functions.pfnWdfRegistryQueryMultiString)(DriverGlobals, Key, ValueName, StringsAttributes, Collection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_opt_ + PUSHORT ValueByteLength, + _Inout_opt_ + PUNICODE_STRING Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYUNICODESTRING) WdfVersion.Functions.pfnWdfRegistryQueryUnicodeString)(DriverGlobals, Key, ValueName, ValueByteLength, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYSTRING) WdfVersion.Functions.pfnWdfRegistryQueryString)(DriverGlobals, Key, ValueName, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_ + PULONG Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYULONG) WdfVersion.Functions.pfnWdfRegistryQueryULong)(DriverGlobals, Key, ValueName, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + ULONG ValueLength, + _In_reads_( ValueLength) + PVOID Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNVALUE) WdfVersion.Functions.pfnWdfRegistryAssignValue)(DriverGlobals, Key, ValueName, ValueType, ValueLength, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET MemoryOffsets + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNMEMORY) WdfVersion.Functions.pfnWdfRegistryAssignMemory)(DriverGlobals, Key, ValueName, ValueType, Memory, MemoryOffsets); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFCOLLECTION StringsCollection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNMULTISTRING) WdfVersion.Functions.pfnWdfRegistryAssignMultiString)(DriverGlobals, Key, ValueName, StringsCollection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + PCUNICODE_STRING Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNUNICODESTRING) WdfVersion.Functions.pfnWdfRegistryAssignUnicodeString)(DriverGlobals, Key, ValueName, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNSTRING) WdfVersion.Functions.pfnWdfRegistryAssignString)(DriverGlobals, Key, ValueName, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNULONG) WdfVersion.Functions.pfnWdfRegistryAssignULong)(DriverGlobals, Key, ValueName, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_opt_ + WDFIOTARGET IoTarget, + _Out_ + WDFREQUEST* Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCREATE) WdfVersion.Functions.pfnWdfRequestCreate)(DriverGlobals, RequestAttributes, IoTarget, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestCreateFromIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_ + PIRP Irp, + _In_ + BOOLEAN RequestFreesIrp, + _Out_ + WDFREQUEST* Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCREATEFROMIRP) WdfVersion.Functions.pfnWdfRequestCreateFromIrp)(DriverGlobals, RequestAttributes, Irp, RequestFreesIrp, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestReuse)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTREUSE) WdfVersion.Functions.pfnWdfRequestReuse)(DriverGlobals, Request, ReuseParams); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestChangeTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCHANGETARGET) WdfVersion.Functions.pfnWdfRequestChangeTarget)(DriverGlobals, Request, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTFORMATREQUESTUSINGCURRENTTYPE) WdfVersion.Functions.pfnWdfRequestFormatRequestUsingCurrentType)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestWdmFormatUsingStackLocation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PIO_STACK_LOCATION Stack + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTWDMFORMATUSINGSTACKLOCATION) WdfVersion.Functions.pfnWdfRequestWdmFormatUsingStackLocation)(DriverGlobals, Request, Stack); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS == 0, _Must_inspect_result_) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestSend)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET Target, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS Options + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTSEND) WdfVersion.Functions.pfnWdfRequestSend)(DriverGlobals, Request, Target, Options); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestGetStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETSTATUS) WdfVersion.Functions.pfnWdfRequestGetStatus)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestMarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTMARKCANCELABLE) WdfVersion.Functions.pfnWdfRequestMarkCancelable)(DriverGlobals, Request, EvtRequestCancel); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestMarkCancelableEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTMARKCANCELABLEEX) WdfVersion.Functions.pfnWdfRequestMarkCancelableEx)(DriverGlobals, Request, EvtRequestCancel); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestUnmarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTUNMARKCANCELABLE) WdfVersion.Functions.pfnWdfRequestUnmarkCancelable)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsCanceled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTISCANCELED) WdfVersion.Functions.pfnWdfRequestIsCanceled)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestCancelSentRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCANCELSENTREQUEST) WdfVersion.Functions.pfnWdfRequestCancelSentRequest)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsFrom32BitProcess)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTISFROM32BITPROCESS) WdfVersion.Functions.pfnWdfRequestIsFrom32BitProcess)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetCompletionRoutine)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_opt_ + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ __drv_aliasesMem + WDFCONTEXT CompletionContext + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSETCOMPLETIONROUTINE) WdfVersion.Functions.pfnWdfRequestSetCompletionRoutine)(DriverGlobals, Request, CompletionRoutine, CompletionContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetCompletionParams)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_COMPLETION_PARAMS Params + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTGETCOMPLETIONPARAMS) WdfVersion.Functions.pfnWdfRequestGetCompletionParams)(DriverGlobals, Request, Params); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestAllocateTimer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTALLOCATETIMER) WdfVersion.Functions.pfnWdfRequestAllocateTimer)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestComplete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status + ) +{ + PAGED_CODE_LOCKED(); + PerfIoComplete(Request); + ((PFN_WDFREQUESTCOMPLETE) WdfVersion.Functions.pfnWdfRequestComplete)(DriverGlobals, Request, Status); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestCompleteWithPriorityBoost)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + CCHAR PriorityBoost + ) +{ + PAGED_CODE_LOCKED(); + PerfIoComplete(Request); + ((PFN_WDFREQUESTCOMPLETEWITHPRIORITYBOOST) WdfVersion.Functions.pfnWdfRequestCompleteWithPriorityBoost)(DriverGlobals, Request, Status, PriorityBoost); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestCompleteWithInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + ULONG_PTR Information + ) +{ + PAGED_CODE_LOCKED(); + PerfIoComplete(Request); + ((PFN_WDFREQUESTCOMPLETEWITHINFORMATION) WdfVersion.Functions.pfnWdfRequestCompleteWithInformation)(DriverGlobals, Request, Status, Information); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_PARAMETERS Parameters + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTGETPARAMETERS) WdfVersion.Functions.pfnWdfRequestGetParameters)(DriverGlobals, Request, Parameters); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEINPUTMEMORY) WdfVersion.Functions.pfnWdfRequestRetrieveInputMemory)(DriverGlobals, Request, Memory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEOUTPUTMEMORY) WdfVersion.Functions.pfnWdfRequestRetrieveOutputMemory)(DriverGlobals, Request, Memory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEINPUTBUFFER) WdfVersion.Functions.pfnWdfRequestRetrieveInputBuffer)(DriverGlobals, Request, MinimumRequiredLength, Buffer, Length); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredSize, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEOUTPUTBUFFER) WdfVersion.Functions.pfnWdfRequestRetrieveOutputBuffer)(DriverGlobals, Request, MinimumRequiredSize, Buffer, Length); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputWdmMdl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Outptr_ + PMDL* Mdl + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEINPUTWDMMDL) WdfVersion.Functions.pfnWdfRequestRetrieveInputWdmMdl)(DriverGlobals, Request, Mdl); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputWdmMdl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Outptr_ + PMDL* Mdl + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEOUTPUTWDMMDL) WdfVersion.Functions.pfnWdfRequestRetrieveOutputWdmMdl)(DriverGlobals, Request, Mdl); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveUnsafeUserInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_maybenull_(*Length) + PVOID* InputBuffer, + _Out_opt_ + size_t* Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEUNSAFEUSERINPUTBUFFER) WdfVersion.Functions.pfnWdfRequestRetrieveUnsafeUserInputBuffer)(DriverGlobals, Request, MinimumRequiredLength, InputBuffer, Length); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveUnsafeUserOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_maybenull_(*Length) + PVOID* OutputBuffer, + _Out_opt_ + size_t* Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEUNSAFEUSEROUTPUTBUFFER) WdfVersion.Functions.pfnWdfRequestRetrieveUnsafeUserOutputBuffer)(DriverGlobals, Request, MinimumRequiredLength, OutputBuffer, Length); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + ULONG_PTR Information + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSETINFORMATION) WdfVersion.Functions.pfnWdfRequestSetInformation)(DriverGlobals, Request, Information); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG_PTR +VFWDFEXPORT(WdfRequestGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETINFORMATION) WdfVersion.Functions.pfnWdfRequestGetInformation)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfRequestGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETFILEOBJECT) WdfVersion.Functions.pfnWdfRequestGetFileObject)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_reads_bytes_(Length) + PVOID Buffer, + _In_ + size_t Length, + _Out_ + WDFMEMORY* MemoryObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTPROBEANDLOCKUSERBUFFERFORREAD) WdfVersion.Functions.pfnWdfRequestProbeAndLockUserBufferForRead)(DriverGlobals, Request, Buffer, Length, MemoryObject); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestProbeAndLockUserBufferForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_reads_bytes_(Length) + PVOID Buffer, + _In_ + size_t Length, + _Out_ + WDFMEMORY* MemoryObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTPROBEANDLOCKUSERBUFFERFORWRITE) WdfVersion.Functions.pfnWdfRequestProbeAndLockUserBufferForWrite)(DriverGlobals, Request, Buffer, Length, MemoryObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +KPROCESSOR_MODE +VFWDFEXPORT(WdfRequestGetRequestorMode)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETREQUESTORMODE) WdfVersion.Functions.pfnWdfRequestGetRequestorMode)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestForwardToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE DestinationQueue + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTFORWARDTOIOQUEUE) WdfVersion.Functions.pfnWdfRequestForwardToIoQueue)(DriverGlobals, Request, DestinationQueue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfRequestGetIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETIOQUEUE) WdfVersion.Functions.pfnWdfRequestGetIoQueue)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRequeue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTREQUEUE) WdfVersion.Functions.pfnWdfRequestRequeue)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestStopAcknowledge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN Requeue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSTOPACKNOWLEDGE) WdfVersion.Functions.pfnWdfRequestStopAcknowledge)(DriverGlobals, Request, Requeue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PIRP +VFWDFEXPORT(WdfRequestWdmGetIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTWDMGETIRP) WdfVersion.Functions.pfnWdfRequestWdmGetIrp)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsReserved)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTISRESERVED) WdfVersion.Functions.pfnWdfRequestIsReserved)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestForwardToParentDeviceIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE ParentDeviceQueue, + _In_ + PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTFORWARDTOPARENTDEVICEIOQUEUE) WdfVersion.Functions.pfnWdfRequestForwardToParentDeviceIoQueue)(DriverGlobals, Request, ParentDeviceQueue, ForwardOptions); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG SlotNumber + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCEREQUIREMENTSLISTSETSLOTNUMBER) WdfVersion.Functions.pfnWdfIoResourceRequirementsListSetSlotNumber)(DriverGlobals, RequirementsList, SlotNumber); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + _Strict_type_match_ + INTERFACE_TYPE InterfaceType + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCEREQUIREMENTSLISTSETINTERFACETYPE) WdfVersion.Functions.pfnWdfIoResourceRequirementsListSetInterfaceType)(DriverGlobals, RequirementsList, InterfaceType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceRequirementsListAppendIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCEREQUIREMENTSLISTAPPENDIORESLIST) WdfVersion.Functions.pfnWdfIoResourceRequirementsListAppendIoResList)(DriverGlobals, RequirementsList, IoResList); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceRequirementsListInsertIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCEREQUIREMENTSLISTINSERTIORESLIST) WdfVersion.Functions.pfnWdfIoResourceRequirementsListInsertIoResList)(DriverGlobals, RequirementsList, IoResList, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfIoResourceRequirementsListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCEREQUIREMENTSLISTGETCOUNT) WdfVersion.Functions.pfnWdfIoResourceRequirementsListGetCount)(DriverGlobals, RequirementsList); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIORESLIST +VFWDFEXPORT(WdfIoResourceRequirementsListGetIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCEREQUIREMENTSLISTGETIORESLIST) WdfVersion.Functions.pfnWdfIoResourceRequirementsListGetIoResList)(DriverGlobals, RequirementsList, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCEREQUIREMENTSLISTREMOVE) WdfVersion.Functions.pfnWdfIoResourceRequirementsListRemove)(DriverGlobals, RequirementsList, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_ + WDFIORESLIST IoResList + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCEREQUIREMENTSLISTREMOVEBYIORESLIST) WdfVersion.Functions.pfnWdfIoResourceRequirementsListRemoveByIoResList)(DriverGlobals, RequirementsList, IoResList); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceListCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESREQLIST RequirementsList, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFIORESLIST* ResourceList + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCELISTCREATE) WdfVersion.Functions.pfnWdfIoResourceListCreate)(DriverGlobals, RequirementsList, Attributes, ResourceList); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceListAppendDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCELISTAPPENDDESCRIPTOR) WdfVersion.Functions.pfnWdfIoResourceListAppendDescriptor)(DriverGlobals, ResourceList, Descriptor); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoResourceListInsertDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCELISTINSERTDESCRIPTOR) WdfVersion.Functions.pfnWdfIoResourceListInsertDescriptor)(DriverGlobals, ResourceList, Descriptor, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceListUpdateDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCELISTUPDATEDESCRIPTOR) WdfVersion.Functions.pfnWdfIoResourceListUpdateDescriptor)(DriverGlobals, ResourceList, Descriptor, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfIoResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCELISTGETCOUNT) WdfVersion.Functions.pfnWdfIoResourceListGetCount)(DriverGlobals, ResourceList); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PIO_RESOURCE_DESCRIPTOR +VFWDFEXPORT(WdfIoResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIORESOURCELISTGETDESCRIPTOR) WdfVersion.Functions.pfnWdfIoResourceListGetDescriptor)(DriverGlobals, ResourceList, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCELISTREMOVE) WdfVersion.Functions.pfnWdfIoResourceListRemove)(DriverGlobals, ResourceList, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoResourceListRemoveByDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIORESLIST ResourceList, + _In_ + PIO_RESOURCE_DESCRIPTOR Descriptor + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIORESOURCELISTREMOVEBYDESCRIPTOR) WdfVersion.Functions.pfnWdfIoResourceListRemoveByDescriptor)(DriverGlobals, ResourceList, Descriptor); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCmResourceListAppendDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCMRESOURCELISTAPPENDDESCRIPTOR) WdfVersion.Functions.pfnWdfCmResourceListAppendDescriptor)(DriverGlobals, List, Descriptor); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCmResourceListInsertDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCMRESOURCELISTINSERTDESCRIPTOR) WdfVersion.Functions.pfnWdfCmResourceListInsertDescriptor)(DriverGlobals, List, Descriptor, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCmResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCMRESOURCELISTGETCOUNT) WdfVersion.Functions.pfnWdfCmResourceListGetCount)(DriverGlobals, List); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PCM_PARTIAL_RESOURCE_DESCRIPTOR +VFWDFEXPORT(WdfCmResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCMRESOURCELISTGETDESCRIPTOR) WdfVersion.Functions.pfnWdfCmResourceListGetDescriptor)(DriverGlobals, List, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCmResourceListRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCMRESOURCELISTREMOVE) WdfVersion.Functions.pfnWdfCmResourceListRemove)(DriverGlobals, List, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCmResourceListRemoveByDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCMRESOURCELISTREMOVEBYDESCRIPTOR) WdfVersion.Functions.pfnWdfCmResourceListRemoveByDescriptor)(DriverGlobals, List, Descriptor); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfStringCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PCUNICODE_STRING UnicodeString, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringAttributes, + _Out_ + WDFSTRING* String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFSTRINGCREATE) WdfVersion.Functions.pfnWdfStringCreate)(DriverGlobals, UnicodeString, StringAttributes, String); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfStringGetUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFSTRING String, + _Out_ + PUNICODE_STRING UnicodeString + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFSTRINGGETUNICODESTRING) WdfVersion.Functions.pfnWdfStringGetUnicodeString)(DriverGlobals, String, UnicodeString); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTACQUIRELOCK) WdfVersion.Functions.pfnWdfObjectAcquireLock)(DriverGlobals, Object); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTRELEASELOCK) WdfVersion.Functions.pfnWdfObjectReleaseLock)(DriverGlobals, Object); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LockAttributes, + _Out_ + WDFWAITLOCK* Lock + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWAITLOCKCREATE) WdfVersion.Functions.pfnWdfWaitLockCreate)(DriverGlobals, LockAttributes, Lock); +} + +_When_(Timeout == NULL, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Timeout != NULL && *Timeout == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Timeout != NULL && *Timeout != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +_Always_(_When_(Timeout == NULL, _Acquires_lock_(Lock))) +_When_(Timeout != NULL && return == STATUS_SUCCESS, _Acquires_lock_(Lock)) +_When_(Timeout != NULL, _Must_inspect_result_) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + WDFWAITLOCK Lock, + _In_opt_ + PLONGLONG Timeout + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWAITLOCKACQUIRE) WdfVersion.Functions.pfnWdfWaitLockAcquire)(DriverGlobals, Lock, Timeout); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWaitLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFWAITLOCK Lock + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWAITLOCKRELEASE) WdfVersion.Functions.pfnWdfWaitLockRelease)(DriverGlobals, Lock); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfSpinLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + _Out_ + WDFSPINLOCK* SpinLock + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFSPINLOCKCREATE) WdfVersion.Functions.pfnWdfSpinLockCreate)(DriverGlobals, SpinLockAttributes, SpinLock); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + _IRQL_saves_ + WDFSPINLOCK SpinLock + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFSPINLOCKACQUIRE) WdfVersion.Functions.pfnWdfSpinLockAcquire)(DriverGlobals, SpinLock); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_min_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + _IRQL_restores_ + WDFSPINLOCK SpinLock + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFSPINLOCKRELEASE) WdfVersion.Functions.pfnWdfSpinLockRelease)(DriverGlobals, SpinLock); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfTimerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_TIMER_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFTIMER* Timer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERCREATE) WdfVersion.Functions.pfnWdfTimerCreate)(DriverGlobals, Config, Attributes, Timer); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + LONGLONG DueTime + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERSTART) WdfVersion.Functions.pfnWdfTimerStart)(DriverGlobals, Timer, DueTime); +} + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + BOOLEAN Wait + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERSTOP) WdfVersion.Functions.pfnWdfTimerStop)(DriverGlobals, Timer, Wait); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfTimerGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERGETPARENTOBJECT) WdfVersion.Functions.pfnWdfTimerGetParentObject)(DriverGlobals, Timer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECREATE) WdfVersion.Functions.pfnWdfUsbTargetDeviceCreate)(DriverGlobals, Device, Attributes, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_USB_DEVICE_CREATE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECREATEWITHPARAMETERS) WdfVersion.Functions.pfnWdfUsbTargetDeviceCreateWithParameters)(DriverGlobals, Device, Config, Attributes, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PWDF_USB_DEVICE_INFORMATION Information + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICERETRIEVEINFORMATION) WdfVersion.Functions.pfnWdfUsbTargetDeviceRetrieveInformation)(DriverGlobals, UsbDevice, Information); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBTARGETDEVICEGETDEVICEDESCRIPTOR) WdfVersion.Functions.pfnWdfUsbTargetDeviceGetDeviceDescriptor)(DriverGlobals, UsbDevice, UsbDeviceDescriptor); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_writes_bytes_to_opt_(*ConfigDescriptorLength,*ConfigDescriptorLength) + PVOID ConfigDescriptor, + _Inout_ + PUSHORT ConfigDescriptorLength + ) +{ + PAGED_CODE_LOCKED(); +#pragma prefast(suppress: __WARNING_HIGH_PRIORITY_OVERFLOW_POSTCONDITION, "This is a verifier DDI hook routine and all it does is call original routine.") + return ((PFN_WDFUSBTARGETDEVICERETRIEVECONFIGDESCRIPTOR) WdfVersion.Functions.pfnWdfUsbTargetDeviceRetrieveConfigDescriptor)(DriverGlobals, UsbDevice, ConfigDescriptor, ConfigDescriptorLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_writes_opt_(*NumCharacters) + PUSHORT String, + _Inout_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEQUERYSTRING) WdfVersion.Functions.pfnWdfUsbTargetDeviceQueryString)(DriverGlobals, UsbDevice, Request, RequestOptions, String, NumCharacters, StringIndex, LangID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + _Out_ + WDFMEMORY* StringMemory, + _Out_opt_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEALLOCANDQUERYSTRING) WdfVersion.Functions.pfnWdfUsbTargetDeviceAllocAndQueryString)(DriverGlobals, UsbDevice, StringMemoryAttributes, StringMemory, NumCharacters, StringIndex, LangID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET Offset, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORSTRING) WdfVersion.Functions.pfnWdfUsbTargetDeviceFormatRequestForString)(DriverGlobals, UsbDevice, Request, Memory, Offset, StringIndex, LangID); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +UCHAR +VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEGETNUMINTERFACES) WdfVersion.Functions.pfnWdfUsbTargetDeviceGetNumInterfaces)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipeAttributes, + _Inout_ + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICESELECTCONFIG) WdfVersion.Functions.pfnWdfUsbTargetDeviceSelectConfig)(DriverGlobals, UsbDevice, PipeAttributes, Params); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +USBD_CONFIGURATION_HANDLE +VFWDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEWDMGETCONFIGURATIONHANDLE) WdfVersion.Functions.pfnWdfUsbTargetDeviceWdmGetConfigurationHandle)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PULONG CurrentFrameNumber + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICERETRIEVECURRENTFRAMENUMBER) WdfVersion.Functions.pfnWdfUsbTargetDeviceRetrieveCurrentFrameNumber)(DriverGlobals, UsbDevice, CurrentFrameNumber); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesTransferred + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICESENDCONTROLTRANSFERSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetDeviceSendControlTransferSynchronously)(DriverGlobals, UsbDevice, Request, RequestOptions, SetupPacket, MemoryDescriptor, BytesTransferred); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + WDFMEMORY TransferMemory, + _In_opt_ + PWDFMEMORY_OFFSET TransferOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORCONTROLTRANSFER) WdfVersion.Functions.pfnWdfUsbTargetDeviceFormatRequestForControlTransfer)(DriverGlobals, UsbDevice, Request, SetupPacket, TransferMemory, TransferOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEISCONNECTEDSYNCHRONOUS) WdfVersion.Functions.pfnWdfUsbTargetDeviceIsConnectedSynchronous)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICERESETPORTSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetDeviceResetPortSynchronously)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECYCLEPORTSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetDeviceCyclePortSynchronously)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORCYCLEPORT) WdfVersion.Functions.pfnWdfUsbTargetDeviceFormatRequestForCyclePort)(DriverGlobals, UsbDevice, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_reads_(_Inexpressible_("union bug in SAL")) + PURB Urb + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICESENDURBSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetDeviceSendUrbSynchronously)(DriverGlobals, UsbDevice, Request, RequestOptions, Urb); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY UrbMemory, + _In_opt_ + PWDFMEMORY_OFFSET UrbMemoryOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORURB) WdfVersion.Functions.pfnWdfUsbTargetDeviceFormatRequestForUrb)(DriverGlobals, UsbDevice, Request, UrbMemory, UrbMemoryOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + CONST GUID* CapabilityType, + _In_ + ULONG CapabilityBufferLength, + _When_(CapabilityBufferLength == 0, _Out_opt_) + _When_(CapabilityBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(CapabilityBufferLength)) + _When_(CapabilityBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + _Out_opt_ + _When_(ResultLength != NULL,_Deref_out_range_(<=,CapabilityBufferLength)) + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEQUERYUSBCAPABILITY) WdfVersion.Functions.pfnWdfUsbTargetDeviceQueryUsbCapability)(DriverGlobals, UsbDevice, CapabilityType, CapabilityBufferLength, CapabilityBuffer, ResultLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFMEMORY* UrbMemory, + _Outptr_opt_result_bytebuffer_(sizeof(URB)) + PURB* Urb + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECREATEURB) WdfVersion.Functions.pfnWdfUsbTargetDeviceCreateUrb)(DriverGlobals, UsbDevice, Attributes, UrbMemory, Urb); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + ULONG NumberOfIsochPackets, + _Out_ + WDFMEMORY* UrbMemory, + _Outptr_opt_result_bytebuffer_(GET_ISO_URB_SIZE(NumberOfIsochPackets)) + PURB* Urb + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECREATEISOCHURB) WdfVersion.Functions.pfnWdfUsbTargetDeviceCreateIsochUrb)(DriverGlobals, UsbDevice, Attributes, NumberOfIsochPackets, UrbMemory, Urb); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _Out_ + PWDF_USB_PIPE_INFORMATION PipeInformation + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBTARGETPIPEGETINFORMATION) WdfVersion.Functions.pfnWdfUsbTargetPipeGetInformation)(DriverGlobals, Pipe, PipeInformation); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEISINENDPOINT) WdfVersion.Functions.pfnWdfUsbTargetPipeIsInEndpoint)(DriverGlobals, Pipe); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEISOUTENDPOINT) WdfVersion.Functions.pfnWdfUsbTargetPipeIsOutEndpoint)(DriverGlobals, Pipe); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_USB_PIPE_TYPE +VFWDFEXPORT(WdfUsbTargetPipeGetType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEGETTYPE) WdfVersion.Functions.pfnWdfUsbTargetPipeGetType)(DriverGlobals, Pipe); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBTARGETPIPESETNOMAXIMUMPACKETSIZECHECK) WdfVersion.Functions.pfnWdfUsbTargetPipeSetNoMaximumPacketSizeCheck)(DriverGlobals, Pipe); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesWritten + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEWRITESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeWriteSynchronously)(DriverGlobals, Pipe, Request, RequestOptions, MemoryDescriptor, BytesWritten); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY WriteMemory, + _In_opt_ + PWDFMEMORY_OFFSET WriteOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORWRITE) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForWrite)(DriverGlobals, Pipe, Request, WriteMemory, WriteOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesRead + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEREADSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeReadSynchronously)(DriverGlobals, Pipe, Request, RequestOptions, MemoryDescriptor, BytesRead); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY ReadMemory, + _In_opt_ + PWDFMEMORY_OFFSET ReadOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORREAD) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForRead)(DriverGlobals, Pipe, Request, ReadMemory, ReadOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPECONFIGCONTINUOUSREADER) WdfVersion.Functions.pfnWdfUsbTargetPipeConfigContinuousReader)(DriverGlobals, Pipe, Config); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEABORTSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeAbortSynchronously)(DriverGlobals, Pipe, Request, RequestOptions); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORABORT) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForAbort)(DriverGlobals, Pipe, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPERESETSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeResetSynchronously)(DriverGlobals, Pipe, Request, RequestOptions); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORRESET) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForReset)(DriverGlobals, Pipe, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_reads_(_Inexpressible_("union bug in SAL")) + PURB Urb + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPESENDURBSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeSendUrbSynchronously)(DriverGlobals, Pipe, Request, RequestOptions, Urb); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE PIPE, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY UrbMemory, + _In_opt_ + PWDFMEMORY_OFFSET UrbMemoryOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORURB) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForUrb)(DriverGlobals, PIPE, Request, UrbMemory, UrbMemoryOffset); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETINTERFACENUMBER) WdfVersion.Functions.pfnWdfUsbInterfaceGetInterfaceNumber)(DriverGlobals, UsbInterface); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETNUMENDPOINTS) WdfVersion.Functions.pfnWdfUsbInterfaceGetNumEndpoints)(DriverGlobals, UsbInterface, SettingIndex); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _Out_ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBINTERFACEGETDESCRIPTOR) WdfVersion.Functions.pfnWdfUsbInterfaceGetDescriptor)(DriverGlobals, UsbInterface, SettingIndex, InterfaceDescriptor); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETNUMSETTINGS) WdfVersion.Functions.pfnWdfUsbInterfaceGetNumSettings)(DriverGlobals, UsbInterface); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbInterfaceSelectSetting)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + _In_ + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACESELECTSETTING) WdfVersion.Functions.pfnWdfUsbInterfaceSelectSetting)(DriverGlobals, UsbInterface, PipesAttributes, Params); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _In_ + UCHAR EndpointIndex, + _Out_ + PWDF_USB_PIPE_INFORMATION EndpointInfo + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBINTERFACEGETENDPOINTINFORMATION) WdfVersion.Functions.pfnWdfUsbInterfaceGetEndpointInformation)(DriverGlobals, UsbInterface, SettingIndex, EndpointIndex, EndpointInfo); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBINTERFACE +VFWDFEXPORT(WdfUsbTargetDeviceGetInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + UCHAR InterfaceIndex + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEGETINTERFACE) WdfVersion.Functions.pfnWdfUsbTargetDeviceGetInterface)(DriverGlobals, UsbDevice, InterfaceIndex); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE Interface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETCONFIGUREDSETTINGINDEX) WdfVersion.Functions.pfnWdfUsbInterfaceGetConfiguredSettingIndex)(DriverGlobals, Interface); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETNUMCONFIGUREDPIPES) WdfVersion.Functions.pfnWdfUsbInterfaceGetNumConfiguredPipes)(DriverGlobals, UsbInterface); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBPIPE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR PipeIndex, + _Out_opt_ + PWDF_USB_PIPE_INFORMATION PipeInfo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETCONFIGUREDPIPE) WdfVersion.Functions.pfnWdfUsbInterfaceGetConfiguredPipe)(DriverGlobals, UsbInterface, PipeIndex, PipeInfo); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +USBD_PIPE_HANDLE +VFWDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE UsbPipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEWDMGETPIPEHANDLE) WdfVersion.Functions.pfnWdfUsbTargetPipeWdmGetPipeHandle)(DriverGlobals, UsbPipe); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierDbgBreakPoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFVERIFIERDBGBREAKPOINT) WdfVersion.Functions.pfnWdfVerifierDbgBreakPoint)(DriverGlobals); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFVERIFIERKEBUGCHECK) WdfVersion.Functions.pfnWdfVerifierKeBugCheck)(DriverGlobals, BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4); +} + +WDFAPI +PVOID +VFWDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFGETTRIAGEINFO) WdfVersion.Functions.pfnWdfGetTriageInfo)(DriverGlobals); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiProviderCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + _Out_ + WDFWMIPROVIDER* WmiProvider + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIPROVIDERCREATE) WdfVersion.Functions.pfnWdfWmiProviderCreate)(DriverGlobals, Device, WmiProviderConfig, ProviderAttributes, WmiProvider); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfWmiProviderGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIPROVIDERGETDEVICE) WdfVersion.Functions.pfnWdfWmiProviderGetDevice)(DriverGlobals, WmiProvider); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfWmiProviderIsEnabled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider, + _In_ + WDF_WMI_PROVIDER_CONTROL ProviderControl + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIPROVIDERISENABLED) WdfVersion.Functions.pfnWdfWmiProviderIsEnabled)(DriverGlobals, WmiProvider, ProviderControl); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONGLONG +VFWDFEXPORT(WdfWmiProviderGetTracingHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIPROVIDER WmiProvider + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIPROVIDERGETTRACINGHANDLE) WdfVersion.Functions.pfnWdfWmiProviderGetTracingHandle)(DriverGlobals, WmiProvider); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiInstanceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_WMI_INSTANCE_CONFIG InstanceConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES InstanceAttributes, + _Out_opt_ + WDFWMIINSTANCE* Instance + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIINSTANCECREATE) WdfVersion.Functions.pfnWdfWmiInstanceCreate)(DriverGlobals, Device, InstanceConfig, InstanceAttributes, Instance); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiInstanceRegister)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIINSTANCEREGISTER) WdfVersion.Functions.pfnWdfWmiInstanceRegister)(DriverGlobals, WmiInstance); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWmiInstanceDeregister)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWMIINSTANCEDEREGISTER) WdfVersion.Functions.pfnWdfWmiInstanceDeregister)(DriverGlobals, WmiInstance); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfWmiInstanceGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIINSTANCEGETDEVICE) WdfVersion.Functions.pfnWdfWmiInstanceGetDevice)(DriverGlobals, WmiInstance); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFWMIPROVIDER +VFWDFEXPORT(WdfWmiInstanceGetProvider)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIINSTANCEGETPROVIDER) WdfVersion.Functions.pfnWdfWmiInstanceGetProvider)(DriverGlobals, WmiInstance); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWmiInstanceFireEvent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWMIINSTANCE WmiInstance, + _In_opt_ + ULONG EventDataSize, + _In_reads_bytes_opt_(EventDataSize) + PVOID EventData + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWMIINSTANCEFIREEVENT) WdfVersion.Functions.pfnWdfWmiInstanceFireEvent)(DriverGlobals, WmiInstance, EventDataSize, EventData); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWorkItemCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_WORKITEM_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFWORKITEM* WorkItem + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWORKITEMCREATE) WdfVersion.Functions.pfnWdfWorkItemCreate)(DriverGlobals, Config, Attributes, WorkItem); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWORKITEMENQUEUE) WdfVersion.Functions.pfnWdfWorkItemEnqueue)(DriverGlobals, WorkItem); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfWorkItemGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWORKITEMGETPARENTOBJECT) WdfVersion.Functions.pfnWdfWorkItemGetParentObject)(DriverGlobals, WorkItem); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemFlush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWORKITEMFLUSH) WdfVersion.Functions.pfnWdfWorkItemFlush)(DriverGlobals, WorkItem); +} + + diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/um/vfprivum.hpp b/sdk/lib/drivers/wdf/shared/enhancedverif/um/vfprivum.hpp new file mode 100644 index 00000000000..fd638ae3396 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/um/vfprivum.hpp @@ -0,0 +1,325 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + vfpriv.hpp + +Abstract: + + common header file for verifier + +Author: + + +Environment: + + User mode only + +Revision History: + +--*/ + +#pragma once + +#include "fxmin.hpp" + +FORCEINLINE +VOID +PerformanceAnalysisIOProcess( + __in PFX_DRIVER_GLOBALS pFxDriverGlobals, + __in WDFREQUEST Handle, + __inout FxRequest** ppReq, + __inout GUID* pActivityId + ) +{ + FxObjectHandleGetPtr(pFxDriverGlobals, + Handle, + FX_TYPE_REQUEST, + (PVOID *) ppReq); + + if ((*ppReq)->GetFxIrp()->GetIoIrp()->IsActivityIdSet() == FALSE) { + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + (*ppReq)->GetFxIrp()->GetIoIrp()->SetActivityId(pActivityId); + } + else { + *pActivityId = *(*ppReq)->GetFxIrp()->GetIoIrp()->GetActivityId(); + } +} + +FORCEINLINE +BOOLEAN +PerfIoStart( + __in WDFREQUEST Handle +) +{ + FxRequest* pReq; + GUID activityId = { 0 }; + WDFOBJECT_OFFSET offset = 0; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + PerformanceAnalysisIOProcess(pFxDriverGlobals, Handle, &pReq, + &activityId); + + UCHAR Type = pReq->GetFxIrp()->GetMajorFunction(); + WDFDEVICE Device = pReq->GetCurrentQueue()->GetDevice()->GetHandle(); + EVENT_DATA_DESCRIPTOR EventData[3]; + EventDataDescCreate(&EventData[0], &Type, sizeof(const UCHAR)); + EventDataDescCreate(&EventData[1], &pDriverDeviceAdd, sizeof(PVOID)); + EventDataDescCreate(&EventData[2], &Device, sizeof(PVOID)); + + EventWriteTransfer(Microsoft_Windows_DriverFrameworks_UserMode_PerformanceHandle, + &FX_REQUEST_START, + &activityId, + NULL, + 3, + &EventData[0]); + } + return status; +} + +FORCEINLINE +BOOLEAN +PerfIoComplete( + __in WDFREQUEST Handle +) +{ + FxRequest* pReq; + GUID activityId = { 0 }; + WDFOBJECT_OFFSET offset = 0; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + PerformanceAnalysisIOProcess(pFxDriverGlobals, Handle, &pReq, + &activityId); + + UCHAR Type = pReq->GetFxIrp()->GetMajorFunction(); + WDFDEVICE Device = pReq->GetCurrentQueue()->GetDevice()->GetHandle(); + EVENT_DATA_DESCRIPTOR EventData[3]; + EventDataDescCreate(&EventData[0], &Type, sizeof(const UCHAR)); + EventDataDescCreate(&EventData[1], &pDriverDeviceAdd, sizeof(PVOID)); + EventDataDescCreate(&EventData[2], &Device, sizeof(PVOID)); + + EventWriteTransfer(Microsoft_Windows_DriverFrameworks_UserMode_PerformanceHandle, + &FX_REQUEST_COMPLETE, + &activityId, + NULL, + 3, + &EventData[0]); + } + return status; +} + +__inline +BOOLEAN +PerformanceAnalysisPowerProcess( + __in PCEVENT_DESCRIPTOR EventDescriptor, + __in GUID* pActivityId, + __in WDFDEVICE Handle +) +{ + WDFOBJECT_OFFSET offset = 0; + FxObject *pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + BOOLEAN status = IsFxPerformanceAnalysis(pFxDriverGlobals); + + if(status) { + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + + EVENT_DATA_DESCRIPTOR EventData[2]; + EventDataDescCreate(&EventData[0], &pDriverDeviceAdd, sizeof(PVOID)); + EventDataDescCreate(&EventData[1], &Handle, sizeof(PVOID)); + + EventWriteTransfer(Microsoft_Windows_DriverFrameworks_UserMode_PerformanceHandle, + EventDescriptor, + pActivityId, + NULL, + 2, + &EventData[0]); + } + + return status; +} + +__inline +BOOLEAN +PerfEvtDeviceD0EntryStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + return PerformanceAnalysisPowerProcess(&FX_POWER_D0_ENTRY_START, pActivityId, Handle); +} + +__inline +VOID +PerfEvtDeviceD0EntryStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + PerformanceAnalysisPowerProcess(&FX_POWER_D0_ENTRY_STOP, pActivityId, Handle); +} + +__inline +BOOLEAN +PerfEvtDeviceD0ExitStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + return PerformanceAnalysisPowerProcess(&FX_POWER_D0_EXIT_START, pActivityId, Handle); +} + +__inline +VOID +PerfEvtDeviceD0ExitStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + PerformanceAnalysisPowerProcess(&FX_POWER_D0_EXIT_STOP, pActivityId, Handle); +} + +__inline +BOOLEAN +PerfEvtDevicePrepareHardwareStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + return PerformanceAnalysisPowerProcess(&FX_POWER_HW_PREPARE_START, pActivityId, Handle); +} + +__inline +VOID +PerfEvtDevicePrepareHardwareStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + PerformanceAnalysisPowerProcess(&FX_POWER_HW_PREPARE_STOP, pActivityId, Handle); +} + +__inline +BOOLEAN +PerfEvtDeviceReleaseHardwareStart( + __in WDFDEVICE Handle, + __inout GUID* pActivityId +) +{ + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + return PerformanceAnalysisPowerProcess(&FX_POWER_HW_RELEASE_START, pActivityId, Handle); +} + +__inline +VOID +PerfEvtDeviceReleaseHardwareStop( + __in WDFDEVICE Handle, + __in GUID* pActivityId +) +{ + PerformanceAnalysisPowerProcess(&FX_POWER_HW_RELEASE_STOP, pActivityId, Handle); +} + +// EvtIoStop callback started. +__inline +BOOLEAN +PerfEvtIoStopStart( + __in WDFQUEUE Queue, + __inout GUID* pActivityId +) +{ + FxIoQueue* pQueue; + WDFOBJECT_OFFSET offset = 0; + WDFDEVICE device; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Queue, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*) &pQueue); + device = (WDFDEVICE) pQueue->GetDevice()->GetHandle(); + + EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, pActivityId); + return PerformanceAnalysisPowerProcess(&FX_EVTIOSTOP_START, pActivityId, device); +} + +// EvtIoStop callback returned. +__inline +VOID +PerfEvtIoStopStop( + __in WDFQUEUE Queue, + __in GUID* pActivityId +) +{ + FxIoQueue* pQueue; + WDFOBJECT_OFFSET offset = 0; + WDFDEVICE device; + + FxObject *pObject = FxObject::_GetObjectFromHandle(Queue, &offset); + PFX_DRIVER_GLOBALS pFxDriverGlobals = pObject->GetDriverGlobals(); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*) &pQueue); + device = (WDFDEVICE) pQueue->GetDevice()->GetHandle(); + + PerformanceAnalysisPowerProcess(&FX_EVTIOSTOP_STOP, pActivityId, device); +} + +__inline +VOID +VerifyIrqlEntry( + __out KIRQL *Irql + ) +{ + DO_NOTHING(); +} + +__inline +VOID +VerifyIrqlExit( + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in KIRQL PrevIrql + ) +{ + DO_NOTHING(); +} + +__inline +VOID +VerifyCriticalRegionEntry( + __out BOOLEAN *CritRegion + ) +{ + DO_NOTHING(); +} + +__inline +VOID +VerifyCriticalRegionExit( + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in BOOLEAN OldCritRegion, + __in PVOID Pfn + ) +{ + DO_NOTHING(); +} + diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/um/vfwdfdynamics.cpp b/sdk/lib/drivers/wdf/shared/enhancedverif/um/vfwdfdynamics.cpp new file mode 100644 index 00000000000..1eae86b7a70 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/um/vfwdfdynamics.cpp @@ -0,0 +1,5002 @@ +/*++ + +Module Name: VfWdfDynamics.cpp + +Abstract: + Generated implementation for WDF API Verifier hooks + +Environment: + user mode only + +--*/ + +#include "fxmin.hpp" +#include "vfpriv.hpp" + +extern "C" { +#include "FxDynamics.h" +} + + +extern "C" { +extern WDFVERSION WdfVersion; +} + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(FX_ENHANCED_VERIFIER_SECTION_NAME, \ + VFWDFEXPORT(WdfCollectionCreate), \ + VFWDFEXPORT(WdfCollectionGetCount), \ + VFWDFEXPORT(WdfCollectionAdd), \ + VFWDFEXPORT(WdfCollectionRemove), \ + VFWDFEXPORT(WdfCollectionRemoveItem), \ + VFWDFEXPORT(WdfCollectionGetItem), \ + VFWDFEXPORT(WdfCollectionGetFirstItem), \ + VFWDFEXPORT(WdfCollectionGetLastItem), \ + VFWDFEXPORT(WdfCxDeviceInitAllocate), \ + VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes), \ + VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig), \ + VFWDFEXPORT(WdfCxVerifierKeBugCheck), \ + VFWDFEXPORT(WdfDeviceGetDeviceState), \ + VFWDFEXPORT(WdfDeviceSetDeviceState), \ + VFWDFEXPORT(WdfDeviceWdmDispatchIrp), \ + VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue), \ + VFWDFEXPORT(WdfDeviceGetDriver), \ + VFWDFEXPORT(WdfDeviceGetIoTarget), \ + VFWDFEXPORT(WdfDeviceAssignS0IdleSettings), \ + VFWDFEXPORT(WdfDeviceAssignSxWakeSettings), \ + VFWDFEXPORT(WdfDeviceOpenRegistryKey), \ + VFWDFEXPORT(WdfDeviceOpenDevicemapKey), \ + VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks), \ + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks), \ + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership), \ + VFWDFEXPORT(WdfDeviceInitSetIoType), \ + VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig), \ + VFWDFEXPORT(WdfDeviceInitSetRequestAttributes), \ + VFWDFEXPORT(WdfDeviceCreate), \ + VFWDFEXPORT(WdfDeviceSetStaticStopRemove), \ + VFWDFEXPORT(WdfDeviceCreateDeviceInterface), \ + VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState), \ + VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString), \ + VFWDFEXPORT(WdfDeviceCreateSymbolicLink), \ + VFWDFEXPORT(WdfDeviceQueryProperty), \ + VFWDFEXPORT(WdfDeviceAllocAndQueryProperty), \ + VFWDFEXPORT(WdfDeviceSetPnpCapabilities), \ + VFWDFEXPORT(WdfDeviceSetPowerCapabilities), \ + VFWDFEXPORT(WdfDeviceSetFailed), \ + VFWDFEXPORT(WdfDeviceStopIdleNoTrack), \ + VFWDFEXPORT(WdfDeviceResumeIdleNoTrack), \ + VFWDFEXPORT(WdfDeviceStopIdleActual), \ + VFWDFEXPORT(WdfDeviceResumeIdleActual), \ + VFWDFEXPORT(WdfDeviceGetFileObject), \ + VFWDFEXPORT(WdfDeviceGetDefaultQueue), \ + VFWDFEXPORT(WdfDeviceConfigureRequestDispatching), \ + VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback), \ + VFWDFEXPORT(WdfDeviceGetSystemPowerAction), \ + VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure), \ + VFWDFEXPORT(WdfDeviceInitSetIoTypeEx), \ + VFWDFEXPORT(WdfDevicePostEvent), \ + VFWDFEXPORT(WdfDeviceMapIoSpace), \ + VFWDFEXPORT(WdfDeviceUnmapIoSpace), \ + VFWDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress), \ + VFWDFEXPORT(WdfDeviceReadFromHardware), \ + VFWDFEXPORT(WdfDeviceWriteToHardware), \ + VFWDFEXPORT(WdfDeviceAssignInterfaceProperty), \ + VFWDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty), \ + VFWDFEXPORT(WdfDeviceQueryInterfaceProperty), \ + VFWDFEXPORT(WdfDeviceGetDeviceStackIoType), \ + VFWDFEXPORT(WdfDeviceQueryPropertyEx), \ + VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx), \ + VFWDFEXPORT(WdfDeviceAssignProperty), \ + VFWDFEXPORT(WdfDeviceGetSelfIoTarget), \ + VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget), \ + VFWDFEXPORT(WdfDriverCreate), \ + VFWDFEXPORT(WdfDriverGetRegistryPath), \ + VFWDFEXPORT(WdfDriverOpenParametersRegistryKey), \ + VFWDFEXPORT(WdfDriverRetrieveVersionString), \ + VFWDFEXPORT(WdfDriverIsVersionAvailable), \ + VFWDFEXPORT(WdfFdoInitOpenRegistryKey), \ + VFWDFEXPORT(WdfFdoInitQueryProperty), \ + VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty), \ + VFWDFEXPORT(WdfFdoInitQueryPropertyEx), \ + VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx), \ + VFWDFEXPORT(WdfFdoInitSetFilter), \ + VFWDFEXPORT(WdfFileObjectGetFileName), \ + VFWDFEXPORT(WdfFileObjectGetDevice), \ + VFWDFEXPORT(WdfFileObjectGetInitiatorProcessId), \ + VFWDFEXPORT(WdfFileObjectGetRelatedFileObject), \ + VFWDFEXPORT(WdfDeviceInitEnableHidInterface), \ + VFWDFEXPORT(WdfDeviceHidNotifyPresence), \ + VFWDFEXPORT(WdfInterruptCreate), \ + VFWDFEXPORT(WdfInterruptQueueDpcForIsr), \ + VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr), \ + VFWDFEXPORT(WdfInterruptSynchronize), \ + VFWDFEXPORT(WdfInterruptAcquireLock), \ + VFWDFEXPORT(WdfInterruptReleaseLock), \ + VFWDFEXPORT(WdfInterruptEnable), \ + VFWDFEXPORT(WdfInterruptDisable), \ + VFWDFEXPORT(WdfInterruptGetInfo), \ + VFWDFEXPORT(WdfInterruptSetPolicy), \ + VFWDFEXPORT(WdfInterruptSetExtendedPolicy), \ + VFWDFEXPORT(WdfInterruptGetDevice), \ + VFWDFEXPORT(WdfInterruptTryToAcquireLock), \ + VFWDFEXPORT(WdfIoQueueCreate), \ + VFWDFEXPORT(WdfIoQueueGetState), \ + VFWDFEXPORT(WdfIoQueueStart), \ + VFWDFEXPORT(WdfIoQueueStop), \ + VFWDFEXPORT(WdfIoQueueStopSynchronously), \ + VFWDFEXPORT(WdfIoQueueGetDevice), \ + VFWDFEXPORT(WdfIoQueueRetrieveNextRequest), \ + VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject), \ + VFWDFEXPORT(WdfIoQueueFindRequest), \ + VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest), \ + VFWDFEXPORT(WdfIoQueueDrainSynchronously), \ + VFWDFEXPORT(WdfIoQueueDrain), \ + VFWDFEXPORT(WdfIoQueuePurgeSynchronously), \ + VFWDFEXPORT(WdfIoQueuePurge), \ + VFWDFEXPORT(WdfIoQueueReadyNotify), \ + VFWDFEXPORT(WdfIoQueueStopAndPurge), \ + VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously), \ + VFWDFEXPORT(WdfIoTargetCreate), \ + VFWDFEXPORT(WdfIoTargetOpen), \ + VFWDFEXPORT(WdfIoTargetCloseForQueryRemove), \ + VFWDFEXPORT(WdfIoTargetClose), \ + VFWDFEXPORT(WdfIoTargetStart), \ + VFWDFEXPORT(WdfIoTargetStop), \ + VFWDFEXPORT(WdfIoTargetPurge), \ + VFWDFEXPORT(WdfIoTargetGetState), \ + VFWDFEXPORT(WdfIoTargetGetDevice), \ + VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle), \ + VFWDFEXPORT(WdfIoTargetSendReadSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForRead), \ + VFWDFEXPORT(WdfIoTargetSendWriteSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForWrite), \ + VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously), \ + VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl), \ + VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue), \ + VFWDFEXPORT(WdfMemoryCreate), \ + VFWDFEXPORT(WdfMemoryCreatePreallocated), \ + VFWDFEXPORT(WdfMemoryGetBuffer), \ + VFWDFEXPORT(WdfMemoryAssignBuffer), \ + VFWDFEXPORT(WdfMemoryCopyToBuffer), \ + VFWDFEXPORT(WdfMemoryCopyFromBuffer), \ + VFWDFEXPORT(WdfObjectGetTypedContextWorker), \ + VFWDFEXPORT(WdfObjectAllocateContext), \ + VFWDFEXPORT(WdfObjectContextGetObject), \ + VFWDFEXPORT(WdfObjectReferenceActual), \ + VFWDFEXPORT(WdfObjectDereferenceActual), \ + VFWDFEXPORT(WdfObjectCreate), \ + VFWDFEXPORT(WdfObjectDelete), \ + VFWDFEXPORT(WdfObjectQuery), \ + VFWDFEXPORT(WdfRegistryOpenKey), \ + VFWDFEXPORT(WdfRegistryCreateKey), \ + VFWDFEXPORT(WdfRegistryClose), \ + VFWDFEXPORT(WdfRegistryWdmGetHandle), \ + VFWDFEXPORT(WdfRegistryRemoveKey), \ + VFWDFEXPORT(WdfRegistryRemoveValue), \ + VFWDFEXPORT(WdfRegistryQueryValue), \ + VFWDFEXPORT(WdfRegistryQueryMemory), \ + VFWDFEXPORT(WdfRegistryQueryMultiString), \ + VFWDFEXPORT(WdfRegistryQueryUnicodeString), \ + VFWDFEXPORT(WdfRegistryQueryString), \ + VFWDFEXPORT(WdfRegistryQueryULong), \ + VFWDFEXPORT(WdfRegistryAssignValue), \ + VFWDFEXPORT(WdfRegistryAssignMemory), \ + VFWDFEXPORT(WdfRegistryAssignMultiString), \ + VFWDFEXPORT(WdfRegistryAssignUnicodeString), \ + VFWDFEXPORT(WdfRegistryAssignString), \ + VFWDFEXPORT(WdfRegistryAssignULong), \ + VFWDFEXPORT(WdfRequestCreate), \ + VFWDFEXPORT(WdfRequestReuse), \ + VFWDFEXPORT(WdfRequestChangeTarget), \ + VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType), \ + VFWDFEXPORT(WdfRequestSend), \ + VFWDFEXPORT(WdfRequestGetStatus), \ + VFWDFEXPORT(WdfRequestMarkCancelable), \ + VFWDFEXPORT(WdfRequestMarkCancelableEx), \ + VFWDFEXPORT(WdfRequestUnmarkCancelable), \ + VFWDFEXPORT(WdfRequestIsCanceled), \ + VFWDFEXPORT(WdfRequestCancelSentRequest), \ + VFWDFEXPORT(WdfRequestIsFrom32BitProcess), \ + VFWDFEXPORT(WdfRequestSetCompletionRoutine), \ + VFWDFEXPORT(WdfRequestGetCompletionParams), \ + VFWDFEXPORT(WdfRequestAllocateTimer), \ + VFWDFEXPORT(WdfRequestComplete), \ + VFWDFEXPORT(WdfRequestCompleteWithInformation), \ + VFWDFEXPORT(WdfRequestGetParameters), \ + VFWDFEXPORT(WdfRequestRetrieveInputMemory), \ + VFWDFEXPORT(WdfRequestRetrieveOutputMemory), \ + VFWDFEXPORT(WdfRequestRetrieveInputBuffer), \ + VFWDFEXPORT(WdfRequestRetrieveOutputBuffer), \ + VFWDFEXPORT(WdfRequestSetInformation), \ + VFWDFEXPORT(WdfRequestGetInformation), \ + VFWDFEXPORT(WdfRequestGetFileObject), \ + VFWDFEXPORT(WdfRequestGetRequestorMode), \ + VFWDFEXPORT(WdfRequestForwardToIoQueue), \ + VFWDFEXPORT(WdfRequestGetIoQueue), \ + VFWDFEXPORT(WdfRequestRequeue), \ + VFWDFEXPORT(WdfRequestStopAcknowledge), \ + VFWDFEXPORT(WdfRequestImpersonate), \ + VFWDFEXPORT(WdfRequestGetRequestorProcessId), \ + VFWDFEXPORT(WdfRequestIsFromUserModeDriver), \ + VFWDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo), \ + VFWDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo), \ + VFWDFEXPORT(WdfRequestSetActivityId), \ + VFWDFEXPORT(WdfRequestRetrieveActivityId), \ + VFWDFEXPORT(WdfRequestGetEffectiveIoType), \ + VFWDFEXPORT(WdfCmResourceListGetCount), \ + VFWDFEXPORT(WdfCmResourceListGetDescriptor), \ + VFWDFEXPORT(WdfStringCreate), \ + VFWDFEXPORT(WdfStringGetUnicodeString), \ + VFWDFEXPORT(WdfObjectAcquireLock), \ + VFWDFEXPORT(WdfObjectReleaseLock), \ + VFWDFEXPORT(WdfWaitLockCreate), \ + VFWDFEXPORT(WdfWaitLockAcquire), \ + VFWDFEXPORT(WdfWaitLockRelease), \ + VFWDFEXPORT(WdfSpinLockCreate), \ + VFWDFEXPORT(WdfSpinLockAcquire), \ + VFWDFEXPORT(WdfSpinLockRelease), \ + VFWDFEXPORT(WdfTimerCreate), \ + VFWDFEXPORT(WdfTimerStart), \ + VFWDFEXPORT(WdfTimerStop), \ + VFWDFEXPORT(WdfTimerGetParentObject), \ + VFWDFEXPORT(WdfUsbTargetDeviceCreate), \ + VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters), \ + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation), \ + VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor), \ + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor), \ + VFWDFEXPORT(WdfUsbTargetDeviceQueryString), \ + VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString), \ + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString), \ + VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces), \ + VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig), \ + VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously), \ + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer), \ + VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously), \ + VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability), \ + VFWDFEXPORT(WdfUsbTargetPipeGetInformation), \ + VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint), \ + VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint), \ + VFWDFEXPORT(WdfUsbTargetPipeGetType), \ + VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck), \ + VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite), \ + VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead), \ + VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader), \ + VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort), \ + VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously), \ + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset), \ + VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber), \ + VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints), \ + VFWDFEXPORT(WdfUsbInterfaceGetDescriptor), \ + VFWDFEXPORT(WdfUsbInterfaceGetNumSettings), \ + VFWDFEXPORT(WdfUsbInterfaceSelectSetting), \ + VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation), \ + VFWDFEXPORT(WdfUsbTargetDeviceGetInterface), \ + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex), \ + VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes), \ + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe), \ + VFWDFEXPORT(WdfVerifierDbgBreakPoint), \ + VFWDFEXPORT(WdfVerifierKeBugCheck), \ + VFWDFEXPORT(WdfGetTriageInfo), \ + VFWDFEXPORT(WdfWorkItemCreate), \ + VFWDFEXPORT(WdfWorkItemEnqueue), \ + VFWDFEXPORT(WdfWorkItemGetParentObject), \ + VFWDFEXPORT(WdfWorkItemFlush), \ + ) +#endif // #pragma alloc_text + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + _Out_ + WDFCOLLECTION* Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONCREATE) WdfVersion.Functions.pfnWdfCollectionCreate)(DriverGlobals, CollectionAttributes, Collection); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCollectionGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETCOUNT) WdfVersion.Functions.pfnWdfCollectionGetCount)(DriverGlobals, Collection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionAdd)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONADD) WdfVersion.Functions.pfnWdfCollectionAdd)(DriverGlobals, Collection, Object); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Item + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCOLLECTIONREMOVE) WdfVersion.Functions.pfnWdfCollectionRemove)(DriverGlobals, Collection, Item); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemoveItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCOLLECTIONREMOVEITEM) WdfVersion.Functions.pfnWdfCollectionRemoveItem)(DriverGlobals, Collection, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETITEM) WdfVersion.Functions.pfnWdfCollectionGetItem)(DriverGlobals, Collection, Index); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetFirstItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETFIRSTITEM) WdfVersion.Functions.pfnWdfCollectionGetFirstItem)(DriverGlobals, Collection); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetLastItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCOLLECTIONGETLASTITEM) WdfVersion.Functions.pfnWdfCollectionGetLastItem)(DriverGlobals, Collection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFCXDEVICE_INIT +VFWDFEXPORT(WdfCxDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCXDEVICEINITALLOCATE) WdfVersion.Functions.pfnWdfCxDeviceInitAllocate)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXDEVICEINITSETREQUESTATTRIBUTES) WdfVersion.Functions.pfnWdfCxDeviceInitSetRequestAttributes)(DriverGlobals, CxDeviceInit, RequestAttributes); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXDEVICEINITSETFILEOBJECTCONFIG) WdfVersion.Functions.pfnWdfCxDeviceInitSetFileObjectConfig)(DriverGlobals, CxDeviceInit, CxFileObjectConfig, FileObjectAttributes); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfCxVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFOBJECT Object, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFCXVERIFIERKEBUGCHECK) WdfVersion.Functions.pfnWdfCxVerifierKeBugCheck)(DriverGlobals, Object, BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceGetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + PWDF_DEVICE_STATE DeviceState + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEGETDEVICESTATE) WdfVersion.Functions.pfnWdfDeviceGetDeviceState)(DriverGlobals, Device, DeviceState); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_STATE DeviceState + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETDEVICESTATE) WdfVersion.Functions.pfnWdfDeviceSetDeviceState)(DriverGlobals, Device, DeviceState); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFCONTEXT DispatchContext + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMDISPATCHIRP) WdfVersion.Functions.pfnWdfDeviceWdmDispatchIrp)(DriverGlobals, Device, Irp, DispatchContext); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFQUEUE Queue, + _In_ + ULONG Flags + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEWDMDISPATCHIRPTOIOQUEUE) WdfVersion.Functions.pfnWdfDeviceWdmDispatchIrpToIoQueue)(DriverGlobals, Device, Irp, Queue, Flags); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +VFWDFEXPORT(WdfDeviceGetDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDRIVER) WdfVersion.Functions.pfnWdfDeviceGetDriver)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETIOTARGET) WdfVersion.Functions.pfnWdfDeviceGetIoTarget)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignS0IdleSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNS0IDLESETTINGS) WdfVersion.Functions.pfnWdfDeviceAssignS0IdleSettings)(DriverGlobals, Device, Settings); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignSxWakeSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNSXWAKESETTINGS) WdfVersion.Functions.pfnWdfDeviceAssignSxWakeSettings)(DriverGlobals, Device, Settings); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEOPENREGISTRYKEY) WdfVersion.Functions.pfnWdfDeviceOpenRegistryKey)(DriverGlobals, Device, DeviceInstanceKeyType, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenDevicemapKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEOPENDEVICEMAPKEY) WdfVersion.Functions.pfnWdfDeviceOpenDevicemapKey)(DriverGlobals, Device, KeyName, DesiredAccess, KeyAttributes, Key); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPNPPOWEREVENTCALLBACKS) WdfVersion.Functions.pfnWdfDeviceInitSetPnpPowerEventCallbacks)(DriverGlobals, DeviceInit, PnpPowerEventCallbacks); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERPOLICYEVENTCALLBACKS) WdfVersion.Functions.pfnWdfDeviceInitSetPowerPolicyEventCallbacks)(DriverGlobals, DeviceInit, PowerPolicyEventCallbacks); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsPowerPolicyOwner + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETPOWERPOLICYOWNERSHIP) WdfVersion.Functions.pfnWdfDeviceInitSetPowerPolicyOwnership)(DriverGlobals, DeviceInit, IsPowerPolicyOwner); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_IO_TYPE IoType + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETIOTYPE) WdfVersion.Functions.pfnWdfDeviceInitSetIoType)(DriverGlobals, DeviceInit, IoType); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETFILEOBJECTCONFIG) WdfVersion.Functions.pfnWdfDeviceInitSetFileObjectConfig)(DriverGlobals, DeviceInit, FileObjectConfig, FileObjectAttributes); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETREQUESTATTRIBUTES) WdfVersion.Functions.pfnWdfDeviceInitSetRequestAttributes)(DriverGlobals, DeviceInit, RequestAttributes); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT* DeviceInit, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + _Out_ + WDFDEVICE* Device + ) +{ + VF_HOOK_PROCESS_INFO hookInfo; + NTSTATUS status; + + PAGED_CODE_LOCKED(); + RtlZeroMemory(&hookInfo, sizeof(VF_HOOK_PROCESS_INFO)); + + status = AddEventHooksWdfDeviceCreate( + &hookInfo, + DriverGlobals, + DeviceInit, + DeviceAttributes, + Device); + + UNREFERENCED_PARAMETER(status); + + if (hookInfo.DonotCallKmdfLib) { + return hookInfo.DdiCallStatus; + } + + return ((PFN_WDFDEVICECREATE) WdfVersion.Functions.pfnWdfDeviceCreate)(DriverGlobals, DeviceInit, DeviceAttributes, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetStaticStopRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN Stoppable + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETSTATICSTOPREMOVE) WdfVersion.Functions.pfnWdfDeviceSetStaticStopRemove)(DriverGlobals, Device, Stoppable); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateDeviceInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECREATEDEVICEINTERFACE) WdfVersion.Functions.pfnWdfDeviceCreateDeviceInterface)(DriverGlobals, Device, InterfaceClassGUID, ReferenceString); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + BOOLEAN IsInterfaceEnabled + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETDEVICEINTERFACESTATE) WdfVersion.Functions.pfnWdfDeviceSetDeviceInterfaceState)(DriverGlobals, Device, InterfaceClassGUID, ReferenceString, IsInterfaceEnabled); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICERETRIEVEDEVICEINTERFACESTRING) WdfVersion.Functions.pfnWdfDeviceRetrieveDeviceInterfaceString)(DriverGlobals, Device, InterfaceClassGUID, ReferenceString, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateSymbolicLink)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING SymbolicLinkName + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECREATESYMBOLICLINK) WdfVersion.Functions.pfnWdfDeviceCreateSymbolicLink)(DriverGlobals, Device, SymbolicLinkName); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEQUERYPROPERTY) WdfVersion.Functions.pfnWdfDeviceQueryProperty)(DriverGlobals, Device, DeviceProperty, BufferLength, PropertyBuffer, ResultLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEALLOCANDQUERYPROPERTY) WdfVersion.Functions.pfnWdfDeviceAllocAndQueryProperty)(DriverGlobals, Device, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPnpCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETPNPCAPABILITIES) WdfVersion.Functions.pfnWdfDeviceSetPnpCapabilities)(DriverGlobals, Device, PnpCapabilities); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPowerCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETPOWERCAPABILITIES) WdfVersion.Functions.pfnWdfDeviceSetPowerCapabilities)(DriverGlobals, Device, PowerCapabilities); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetFailed)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_FAILED_ACTION FailedAction + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICESETFAILED) WdfVersion.Functions.pfnWdfDeviceSetFailed)(DriverGlobals, Device, FailedAction); +} + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0 + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICESTOPIDLENOTRACK) WdfVersion.Functions.pfnWdfDeviceStopIdleNoTrack)(DriverGlobals, Device, WaitForD0); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICERESUMEIDLENOTRACK) WdfVersion.Functions.pfnWdfDeviceResumeIdleNoTrack)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICESTOPIDLEACTUAL) WdfVersion.Functions.pfnWdfDeviceStopIdleActual)(DriverGlobals, Device, WaitForD0, Tag, Line, File); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICERESUMEIDLEACTUAL) WdfVersion.Functions.pfnWdfDeviceResumeIdleActual)(DriverGlobals, Device, Tag, Line, File); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfDeviceGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PFILE_OBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETFILEOBJECT) WdfVersion.Functions.pfnWdfDeviceGetFileObject)(DriverGlobals, Device, FileObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfDeviceGetDefaultQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETDEFAULTQUEUE) WdfVersion.Functions.pfnWdfDeviceGetDefaultQueue)(DriverGlobals, Device); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureRequestDispatching)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFQUEUE Queue, + _In_ + _Strict_type_match_ + WDF_REQUEST_TYPE RequestType + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECONFIGUREREQUESTDISPATCHING) WdfVersion.Functions.pfnWdfDeviceConfigureRequestDispatching)(DriverGlobals, Device, Queue, RequestType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDisptach, + _In_opt_ + WDFCONTEXT DriverContext + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICECONFIGUREWDMIRPDISPATCHCALLBACK) WdfVersion.Functions.pfnWdfDeviceConfigureWdmIrpDispatchCallback)(DriverGlobals, Device, Driver, MajorFunction, EvtDeviceWdmIrpDisptach, DriverContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +POWER_ACTION +VFWDFEXPORT(WdfDeviceGetSystemPowerAction)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETSYSTEMPOWERACTION) WdfVersion.Functions.pfnWdfDeviceGetSystemPowerAction)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETRELEASEHARDWAREORDERONFAILURE) WdfVersion.Functions.pfnWdfDeviceInitSetReleaseHardwareOrderOnFailure)(DriverGlobals, DeviceInit, ReleaseHardwareOrderOnFailure); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITSETIOTYPEEX) WdfVersion.Functions.pfnWdfDeviceInitSetIoTypeEx)(DriverGlobals, DeviceInit, IoTypeConfig); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDevicePostEvent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + REFGUID EventGuid, + _In_ + WDF_EVENT_TYPE WdfEventType, + _In_reads_bytes_(DataSizeCb) + BYTE* Data, + _In_ + ULONG DataSizeCb + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEPOSTEVENT) WdfVersion.Functions.pfnWdfDevicePostEvent)(DriverGlobals, Device, EventGuid, WdfEventType, Data, DataSizeCb); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceMapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PHYSICAL_ADDRESS PhysicalAddress, + _In_ + SIZE_T NumberOfBytes, + _In_ + MEMORY_CACHING_TYPE CacheType, + _Out_ + PVOID* PseudoBaseAddress + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEMAPIOSPACE) WdfVersion.Functions.pfnWdfDeviceMapIoSpace)(DriverGlobals, Device, PhysicalAddress, NumberOfBytes, CacheType, PseudoBaseAddress); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceUnmapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress, + _In_ + SIZE_T NumberOfBytes + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEUNMAPIOSPACE) WdfVersion.Functions.pfnWdfDeviceUnmapIoSpace)(DriverGlobals, Device, PseudoBaseAddress, NumberOfBytes); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETHARDWAREREGISTERMAPPEDADDRESS) WdfVersion.Functions.pfnWdfDeviceGetHardwareRegisterMappedAddress)(DriverGlobals, Device, PseudoBaseAddress); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +SIZE_T +VFWDFEXPORT(WdfDeviceReadFromHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _Out_writes_all_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEREADFROMHARDWARE) WdfVersion.Functions.pfnWdfDeviceReadFromHardware)(DriverGlobals, Device, Type, Size, TargetAddress, Buffer, Count); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceWriteToHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _In_ + SIZE_T Value, + _In_reads_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEWRITETOHARDWARE) WdfVersion.Functions.pfnWdfDeviceWriteToHardware)(DriverGlobals, Device, Type, Size, TargetAddress, Value, Buffer, Count); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG BufferLength, + _In_reads_bytes_opt_(BufferLength) + PVOID PropertyBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNINTERFACEPROPERTY) WdfVersion.Functions.pfnWdfDeviceAssignInterfaceProperty)(DriverGlobals, Device, PropertyData, Type, BufferLength, PropertyBuffer); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEALLOCANDQUERYINTERFACEPROPERTY) WdfVersion.Functions.pfnWdfDeviceAllocAndQueryInterfaceProperty)(DriverGlobals, Device, PropertyData, PoolType, PropertyMemoryAttributes, PropertyMemory, Type); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + ULONG BufferLength, + _Out_writes_bytes_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEQUERYINTERFACEPROPERTY) WdfVersion.Functions.pfnWdfDeviceQueryInterfaceProperty)(DriverGlobals, Device, PropertyData, BufferLength, PropertyBuffer, ResultLength, Type); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceGetDeviceStackIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + WDF_DEVICE_IO_TYPE* ReadWriteIoType, + _Out_ + WDF_DEVICE_IO_TYPE* IoControlIoType + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEGETDEVICESTACKIOTYPE) WdfVersion.Functions.pfnWdfDeviceGetDeviceStackIoType)(DriverGlobals, Device, ReadWriteIoType, IoControlIoType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfDeviceQueryPropertyEx)(DriverGlobals, Device, DeviceProperty, BufferLength, PropertyBuffer, RequiredSize, Type); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEALLOCANDQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfDeviceAllocAndQueryPropertyEx)(DriverGlobals, Device, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory, Type); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG Size, + _In_opt_ + PVOID Data + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEASSIGNPROPERTY) WdfVersion.Functions.pfnWdfDeviceAssignProperty)(DriverGlobals, Device, DeviceProperty, Type, Size, Data); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEGETSELFIOTARGET) WdfVersion.Functions.pfnWdfDeviceGetSelfIoTarget)(DriverGlobals, Device); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITALLOWSELFIOTARGET) WdfVersion.Functions.pfnWdfDeviceInitAllowSelfIoTarget)(DriverGlobals, DeviceInit); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PCUNICODE_STRING RegistryPath, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + _In_ + PWDF_DRIVER_CONFIG DriverConfig, + _Out_opt_ + WDFDRIVER* Driver + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERCREATE) WdfVersion.Functions.pfnWdfDriverCreate)(DriverGlobals, DriverObject, RegistryPath, DriverAttributes, DriverConfig, Driver); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWSTR +VFWDFEXPORT(WdfDriverGetRegistryPath)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERGETREGISTRYPATH) WdfVersion.Functions.pfnWdfDriverGetRegistryPath)(DriverGlobals, Driver); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverOpenParametersRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVEROPENPARAMETERSREGISTRYKEY) WdfVersion.Functions.pfnWdfDriverOpenParametersRegistryKey)(DriverGlobals, Driver, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverRetrieveVersionString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERRETRIEVEVERSIONSTRING) WdfVersion.Functions.pfnWdfDriverRetrieveVersionString)(DriverGlobals, Driver, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDriverIsVersionAvailable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDRIVERISVERSIONAVAILABLE) WdfVersion.Functions.pfnWdfDriverIsVersionAvailable)(DriverGlobals, Driver, VersionAvailableParams); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITOPENREGISTRYKEY) WdfVersion.Functions.pfnWdfFdoInitOpenRegistryKey)(DriverGlobals, DeviceInit, DeviceInstanceKeyType, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITQUERYPROPERTY) WdfVersion.Functions.pfnWdfFdoInitQueryProperty)(DriverGlobals, DeviceInit, DeviceProperty, BufferLength, PropertyBuffer, ResultLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITALLOCANDQUERYPROPERTY) WdfVersion.Functions.pfnWdfFdoInitAllocAndQueryProperty)(DriverGlobals, DeviceInit, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfFdoInitQueryPropertyEx)(DriverGlobals, DeviceInit, DeviceProperty, BufferLength, PropertyBuffer, ResultLength, Type); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFDOINITALLOCANDQUERYPROPERTYEX) WdfVersion.Functions.pfnWdfFdoInitAllocAndQueryPropertyEx)(DriverGlobals, DeviceInit, DeviceProperty, PoolType, PropertyMemoryAttributes, PropertyMemory, Type); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetFilter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFFDOINITSETFILTER) WdfVersion.Functions.pfnWdfFdoInitSetFilter)(DriverGlobals, DeviceInit); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PUNICODE_STRING +VFWDFEXPORT(WdfFileObjectGetFileName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETFILENAME) WdfVersion.Functions.pfnWdfFileObjectGetFileName)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfFileObjectGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETDEVICE) WdfVersion.Functions.pfnWdfFileObjectGetDevice)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfFileObjectGetInitiatorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETINITIATORPROCESSID) WdfVersion.Functions.pfnWdfFileObjectGetInitiatorProcessId)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfFileObjectGetRelatedFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFFILEOBJECTGETRELATEDFILEOBJECT) WdfVersion.Functions.pfnWdfFileObjectGetRelatedFileObject)(DriverGlobals, FileObject); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitEnableHidInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFDEVICEINITENABLEHIDINTERFACE) WdfVersion.Functions.pfnWdfDeviceInitEnableHidInterface)(DriverGlobals, DeviceInit); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceHidNotifyPresence)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN IsPresent + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFDEVICEHIDNOTIFYPRESENCE) WdfVersion.Functions.pfnWdfDeviceHidNotifyPresence)(DriverGlobals, Device, IsPresent); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfInterruptCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_INTERRUPT_CONFIG Configuration, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFINTERRUPT* Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTCREATE) WdfVersion.Functions.pfnWdfInterruptCreate)(DriverGlobals, Device, Configuration, Attributes, Interrupt); +} + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueDpcForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTQUEUEDPCFORISR) WdfVersion.Functions.pfnWdfInterruptQueueDpcForIsr)(DriverGlobals, Interrupt); +} + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTQUEUEWORKITEMFORISR) WdfVersion.Functions.pfnWdfInterruptQueueWorkItemForIsr)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptSynchronize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + _In_ + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTSYNCHRONIZE) WdfVersion.Functions.pfnWdfInterruptSynchronize)(DriverGlobals, Interrupt, Callback, Context); +} + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTACQUIRELOCK) WdfVersion.Functions.pfnWdfInterruptAcquireLock)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTRELEASELOCK) WdfVersion.Functions.pfnWdfInterruptReleaseLock)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptEnable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTENABLE) WdfVersion.Functions.pfnWdfInterruptEnable)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptDisable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTDISABLE) WdfVersion.Functions.pfnWdfInterruptDisable)(DriverGlobals, Interrupt); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptGetInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _Out_ + PWDF_INTERRUPT_INFO Info + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTGETINFO) WdfVersion.Functions.pfnWdfInterruptGetInfo)(DriverGlobals, Interrupt, Info); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + WDF_INTERRUPT_POLICY Policy, + _In_ + WDF_INTERRUPT_PRIORITY Priority, + _In_ + KAFFINITY TargetProcessorSet + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTSETPOLICY) WdfVersion.Functions.pfnWdfInterruptSetPolicy)(DriverGlobals, Interrupt, Policy, Priority, TargetProcessorSet); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetExtendedPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFINTERRUPTSETEXTENDEDPOLICY) WdfVersion.Functions.pfnWdfInterruptSetExtendedPolicy)(DriverGlobals, Interrupt, PolicyAndGroup); +} + +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfInterruptGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTGETDEVICE) WdfVersion.Functions.pfnWdfInterruptGetDevice)(DriverGlobals, Interrupt); +} + +_Must_inspect_result_ +_Post_satisfies_(return == 1 || return == 0) +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptTryToAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFINTERRUPTTRYTOACQUIRELOCK) WdfVersion.Functions.pfnWdfInterruptTryToAcquireLock)(DriverGlobals, Interrupt); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_IO_QUEUE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + _Out_opt_ + WDFQUEUE* Queue + ) +{ + VF_HOOK_PROCESS_INFO hookInfo; + NTSTATUS status; + + PAGED_CODE_LOCKED(); + RtlZeroMemory(&hookInfo, sizeof(VF_HOOK_PROCESS_INFO)); + + status = AddEventHooksWdfIoQueueCreate( + &hookInfo, + DriverGlobals, + Device, + Config, + QueueAttributes, + Queue); + + UNREFERENCED_PARAMETER(status); + + if (hookInfo.DonotCallKmdfLib) { + return hookInfo.DdiCallStatus; + } + + return ((PFN_WDFIOQUEUECREATE) WdfVersion.Functions.pfnWdfIoQueueCreate)(DriverGlobals, Device, Config, QueueAttributes, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_QUEUE_STATE +VFWDFEXPORT(WdfIoQueueGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_opt_ + PULONG QueueRequests, + _Out_opt_ + PULONG DriverRequests + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEGETSTATE) WdfVersion.Functions.pfnWdfIoQueueGetState)(DriverGlobals, Queue, QueueRequests, DriverRequests); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTART) WdfVersion.Functions.pfnWdfIoQueueStart)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopComplete, + _When_(StopComplete != 0, _In_) + _When_(StopComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOP) WdfVersion.Functions.pfnWdfIoQueueStop)(DriverGlobals, Queue, StopComplete, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOPSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueueStopSynchronously)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoQueueGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEGETDEVICE) WdfVersion.Functions.pfnWdfIoQueueGetDevice)(DriverGlobals, Queue); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveNextRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + NTSTATUS rtn = ((PFN_WDFIOQUEUERETRIEVENEXTREQUEST) WdfVersion.Functions.pfnWdfIoQueueRetrieveNextRequest)(DriverGlobals, Queue, OutRequest); + if (rtn == STATUS_SUCCESS) { + PerfIoStart(*OutRequest); + } + return rtn; +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFFILEOBJECT FileObject, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + NTSTATUS rtn = ((PFN_WDFIOQUEUERETRIEVEREQUESTBYFILEOBJECT) WdfVersion.Functions.pfnWdfIoQueueRetrieveRequestByFileObject)(DriverGlobals, Queue, FileObject, OutRequest); + if (rtn == STATUS_SUCCESS) { + PerfIoStart(*OutRequest); + } + return rtn; +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueFindRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + WDFREQUEST FoundRequest, + _In_opt_ + WDFFILEOBJECT FileObject, + _Inout_opt_ + PWDF_REQUEST_PARAMETERS Parameters, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEFINDREQUEST) WdfVersion.Functions.pfnWdfIoQueueFindRequest)(DriverGlobals, Queue, FoundRequest, FileObject, Parameters, OutRequest); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFREQUEST FoundRequest, + _Out_ + WDFREQUEST* OutRequest + ) +{ + PAGED_CODE_LOCKED(); + NTSTATUS rtn = ((PFN_WDFIOQUEUERETRIEVEFOUNDREQUEST) WdfVersion.Functions.pfnWdfIoQueueRetrieveFoundRequest)(DriverGlobals, Queue, FoundRequest, OutRequest); + if (rtn == STATUS_SUCCESS) { + PerfIoStart(*OutRequest); + } + return rtn; +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrainSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEDRAINSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueueDrainSynchronously)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrain)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + _When_(DrainComplete != 0, _In_) + _When_(DrainComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEDRAIN) WdfVersion.Functions.pfnWdfIoQueueDrain)(DriverGlobals, Queue, DrainComplete, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEPURGESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueuePurgeSynchronously)(DriverGlobals, Queue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + _When_(PurgeComplete != 0, _In_) + _When_(PurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUEPURGE) WdfVersion.Functions.pfnWdfIoQueuePurge)(DriverGlobals, Queue, PurgeComplete, Context); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueReadyNotify)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + PFN_WDF_IO_QUEUE_STATE QueueReady, + _In_opt_ + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOQUEUEREADYNOTIFY) WdfVersion.Functions.pfnWdfIoQueueReadyNotify)(DriverGlobals, Queue, QueueReady, Context); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + _When_(StopAndPurgeComplete != 0, _In_) + _When_(StopAndPurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOPANDPURGE) WdfVersion.Functions.pfnWdfIoQueueStopAndPurge)(DriverGlobals, Queue, StopAndPurgeComplete, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOQUEUESTOPANDPURGESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoQueueStopAndPurgeSynchronously)(DriverGlobals, Queue); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + _Out_ + WDFIOTARGET* IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETCREATE) WdfVersion.Functions.pfnWdfIoTargetCreate)(DriverGlobals, Device, IoTargetAttributes, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetOpen)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETOPEN) WdfVersion.Functions.pfnWdfIoTargetOpen)(DriverGlobals, IoTarget, OpenParams); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetCloseForQueryRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETCLOSEFORQUERYREMOVE) WdfVersion.Functions.pfnWdfIoTargetCloseForQueryRemove)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETCLOSE) WdfVersion.Functions.pfnWdfIoTargetClose)(DriverGlobals, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSTART) WdfVersion.Functions.pfnWdfIoTargetStart)(DriverGlobals, IoTarget); +} + +_When_(Action == 3, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1 || Action == 2, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_SENT_IO_ACTION Action + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETSTOP) WdfVersion.Functions.pfnWdfIoTargetStop)(DriverGlobals, IoTarget, Action); +} + +_When_(Action == 2, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_PURGE_IO_ACTION Action + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFIOTARGETPURGE) WdfVersion.Functions.pfnWdfIoTargetPurge)(DriverGlobals, IoTarget, Action); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_TARGET_STATE +VFWDFEXPORT(WdfIoTargetGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETGETSTATE) WdfVersion.Functions.pfnWdfIoTargetGetState)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoTargetGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETGETDEVICE) WdfVersion.Functions.pfnWdfIoTargetGetDevice)(DriverGlobals, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETWDMGETTARGETFILEHANDLE) WdfVersion.Functions.pfnWdfIoTargetWdmGetTargetFileHandle)(DriverGlobals, IoTarget); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesRead + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDREADSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendReadSynchronously)(DriverGlobals, IoTarget, Request, OutputBuffer, DeviceOffset, RequestOptions, BytesRead); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORREAD) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForRead)(DriverGlobals, IoTarget, Request, OutputBuffer, OutputBufferOffset, DeviceOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesWritten + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDWRITESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendWriteSynchronously)(DriverGlobals, IoTarget, Request, InputBuffer, DeviceOffset, RequestOptions, BytesWritten); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORWRITE) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForWrite)(DriverGlobals, IoTarget, Request, InputBuffer, InputBufferOffset, DeviceOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSENDIOCTLSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfIoTargetSendIoctlSynchronously)(DriverGlobals, IoTarget, Request, IoctlCode, InputBuffer, OutputBuffer, RequestOptions, BytesReturned); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETFORMATREQUESTFORIOCTL) WdfVersion.Functions.pfnWdfIoTargetFormatRequestForIoctl)(DriverGlobals, IoTarget, Request, IoctlCode, InputBuffer, InputBufferOffset, OutputBuffer, OutputBufferOffset); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFIOTARGETSELFASSIGNDEFAULTIOQUEUE) WdfVersion.Functions.pfnWdfIoTargetSelfAssignDefaultIoQueue)(DriverGlobals, IoTarget, Queue); +} + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + ULONG PoolTag, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory, + _Outptr_opt_result_bytebuffer_(BufferSize) + PVOID* Buffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCREATE) WdfVersion.Functions.pfnWdfMemoryCreate)(DriverGlobals, Attributes, PoolType, PoolTag, BufferSize, Memory, Buffer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreatePreallocated)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ __drv_aliasesMem + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCREATEPREALLOCATED) WdfVersion.Functions.pfnWdfMemoryCreatePreallocated)(DriverGlobals, Attributes, Buffer, BufferSize, Memory); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfMemoryGetBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Out_opt_ + size_t* BufferSize + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYGETBUFFER) WdfVersion.Functions.pfnWdfMemoryGetBuffer)(DriverGlobals, Memory, BufferSize); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYASSIGNBUFFER) WdfVersion.Functions.pfnWdfMemoryAssignBuffer)(DriverGlobals, Memory, Buffer, BufferSize); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyToBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY SourceMemory, + _In_ + size_t SourceOffset, + _Out_writes_bytes_( NumBytesToCopyTo ) + PVOID Buffer, + _In_ + _When_(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCOPYTOBUFFER) WdfVersion.Functions.pfnWdfMemoryCopyToBuffer)(DriverGlobals, SourceMemory, SourceOffset, Buffer, NumBytesToCopyTo); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyFromBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY DestinationMemory, + _In_ + size_t DestinationOffset, + _In_ + PVOID Buffer, + _In_ + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFMEMORYCOPYFROMBUFFER) WdfVersion.Functions.pfnWdfMemoryCopyFromBuffer)(DriverGlobals, DestinationMemory, DestinationOffset, Buffer, NumBytesToCopyFrom); +} + +WDFAPI +PVOID +FASTCALL +VFWDFEXPORT(WdfObjectGetTypedContextWorker)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTGETTYPEDCONTEXTWORKER) WdfVersion.Functions.pfnWdfObjectGetTypedContextWorker)(DriverGlobals, Handle, TypeInfo); +} + +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectAllocateContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PWDF_OBJECT_ATTRIBUTES ContextAttributes, + _Outptr_opt_ + PVOID* Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTALLOCATECONTEXT) WdfVersion.Functions.pfnWdfObjectAllocateContext)(DriverGlobals, Handle, ContextAttributes, Context); +} + +WDFAPI +WDFOBJECT +FASTCALL +VFWDFEXPORT(WdfObjectContextGetObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PVOID ContextPointer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTCONTEXTGETOBJECT) WdfVersion.Functions.pfnWdfObjectContextGetObject)(DriverGlobals, ContextPointer); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTREFERENCEACTUAL) WdfVersion.Functions.pfnWdfObjectReferenceActual)(DriverGlobals, Handle, Tag, Line, File); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDereferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTDEREFERENCEACTUAL) WdfVersion.Functions.pfnWdfObjectDereferenceActual)(DriverGlobals, Handle, Tag, Line, File); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFOBJECT* Object + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTCREATE) WdfVersion.Functions.pfnWdfObjectCreate)(DriverGlobals, Attributes, Object); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDelete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTDELETE) WdfVersion.Functions.pfnWdfObjectDelete)(DriverGlobals, Object); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectQuery)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object, + _In_ + CONST GUID* Guid, + _In_ + ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFOBJECTQUERY) WdfVersion.Functions.pfnWdfObjectQuery)(DriverGlobals, Object, Guid, QueryBufferLength, QueryBuffer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryOpenKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYOPENKEY) WdfVersion.Functions.pfnWdfRegistryOpenKey)(DriverGlobals, ParentKey, KeyName, DesiredAccess, KeyAttributes, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryCreateKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_ + ULONG CreateOptions, + _Out_opt_ + PULONG CreateDisposition, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYCREATEKEY) WdfVersion.Functions.pfnWdfRegistryCreateKey)(DriverGlobals, ParentKey, KeyName, DesiredAccess, CreateOptions, CreateDisposition, KeyAttributes, Key); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRegistryClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREGISTRYCLOSE) WdfVersion.Functions.pfnWdfRegistryClose)(DriverGlobals, Key); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfRegistryWdmGetHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYWDMGETHANDLE) WdfVersion.Functions.pfnWdfRegistryWdmGetHandle)(DriverGlobals, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYREMOVEKEY) WdfVersion.Functions.pfnWdfRegistryRemoveKey)(DriverGlobals, Key); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYREMOVEVALUE) WdfVersion.Functions.pfnWdfRegistryRemoveValue)(DriverGlobals, Key, ValueName); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueLength, + _Out_writes_bytes_opt_( ValueLength) + PVOID Value, + _Out_opt_ + PULONG ValueLengthQueried, + _Out_opt_ + PULONG ValueType + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYVALUE) WdfVersion.Functions.pfnWdfRegistryQueryValue)(DriverGlobals, Key, ValueName, ValueLength, Value, ValueLengthQueried, ValueType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _Out_ + WDFMEMORY* Memory, + _Out_opt_ + PULONG ValueType + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYMEMORY) WdfVersion.Functions.pfnWdfRegistryQueryMemory)(DriverGlobals, Key, ValueName, PoolType, MemoryAttributes, Memory, ValueType); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + _In_ + WDFCOLLECTION Collection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYMULTISTRING) WdfVersion.Functions.pfnWdfRegistryQueryMultiString)(DriverGlobals, Key, ValueName, StringsAttributes, Collection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_opt_ + PUSHORT ValueByteLength, + _Inout_opt_ + PUNICODE_STRING Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYUNICODESTRING) WdfVersion.Functions.pfnWdfRegistryQueryUnicodeString)(DriverGlobals, Key, ValueName, ValueByteLength, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYSTRING) WdfVersion.Functions.pfnWdfRegistryQueryString)(DriverGlobals, Key, ValueName, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_ + PULONG Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYQUERYULONG) WdfVersion.Functions.pfnWdfRegistryQueryULong)(DriverGlobals, Key, ValueName, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + ULONG ValueLength, + _In_reads_( ValueLength) + PVOID Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNVALUE) WdfVersion.Functions.pfnWdfRegistryAssignValue)(DriverGlobals, Key, ValueName, ValueType, ValueLength, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET MemoryOffsets + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNMEMORY) WdfVersion.Functions.pfnWdfRegistryAssignMemory)(DriverGlobals, Key, ValueName, ValueType, Memory, MemoryOffsets); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFCOLLECTION StringsCollection + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNMULTISTRING) WdfVersion.Functions.pfnWdfRegistryAssignMultiString)(DriverGlobals, Key, ValueName, StringsCollection); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + PCUNICODE_STRING Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNUNICODESTRING) WdfVersion.Functions.pfnWdfRegistryAssignUnicodeString)(DriverGlobals, Key, ValueName, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNSTRING) WdfVersion.Functions.pfnWdfRegistryAssignString)(DriverGlobals, Key, ValueName, String); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG Value + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREGISTRYASSIGNULONG) WdfVersion.Functions.pfnWdfRegistryAssignULong)(DriverGlobals, Key, ValueName, Value); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_opt_ + WDFIOTARGET IoTarget, + _Out_ + WDFREQUEST* Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCREATE) WdfVersion.Functions.pfnWdfRequestCreate)(DriverGlobals, RequestAttributes, IoTarget, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestReuse)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTREUSE) WdfVersion.Functions.pfnWdfRequestReuse)(DriverGlobals, Request, ReuseParams); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestChangeTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET IoTarget + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCHANGETARGET) WdfVersion.Functions.pfnWdfRequestChangeTarget)(DriverGlobals, Request, IoTarget); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTFORMATREQUESTUSINGCURRENTTYPE) WdfVersion.Functions.pfnWdfRequestFormatRequestUsingCurrentType)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS == 0, _Must_inspect_result_) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestSend)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET Target, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS Options + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTSEND) WdfVersion.Functions.pfnWdfRequestSend)(DriverGlobals, Request, Target, Options); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestGetStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETSTATUS) WdfVersion.Functions.pfnWdfRequestGetStatus)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestMarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTMARKCANCELABLE) WdfVersion.Functions.pfnWdfRequestMarkCancelable)(DriverGlobals, Request, EvtRequestCancel); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestMarkCancelableEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTMARKCANCELABLEEX) WdfVersion.Functions.pfnWdfRequestMarkCancelableEx)(DriverGlobals, Request, EvtRequestCancel); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestUnmarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTUNMARKCANCELABLE) WdfVersion.Functions.pfnWdfRequestUnmarkCancelable)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsCanceled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTISCANCELED) WdfVersion.Functions.pfnWdfRequestIsCanceled)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestCancelSentRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTCANCELSENTREQUEST) WdfVersion.Functions.pfnWdfRequestCancelSentRequest)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsFrom32BitProcess)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTISFROM32BITPROCESS) WdfVersion.Functions.pfnWdfRequestIsFrom32BitProcess)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetCompletionRoutine)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_opt_ + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ __drv_aliasesMem + WDFCONTEXT CompletionContext + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSETCOMPLETIONROUTINE) WdfVersion.Functions.pfnWdfRequestSetCompletionRoutine)(DriverGlobals, Request, CompletionRoutine, CompletionContext); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetCompletionParams)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_COMPLETION_PARAMS Params + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTGETCOMPLETIONPARAMS) WdfVersion.Functions.pfnWdfRequestGetCompletionParams)(DriverGlobals, Request, Params); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestAllocateTimer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTALLOCATETIMER) WdfVersion.Functions.pfnWdfRequestAllocateTimer)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestComplete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status + ) +{ + PAGED_CODE_LOCKED(); + PerfIoComplete(Request); + ((PFN_WDFREQUESTCOMPLETE) WdfVersion.Functions.pfnWdfRequestComplete)(DriverGlobals, Request, Status); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestCompleteWithInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + ULONG_PTR Information + ) +{ + PAGED_CODE_LOCKED(); + PerfIoComplete(Request); + ((PFN_WDFREQUESTCOMPLETEWITHINFORMATION) WdfVersion.Functions.pfnWdfRequestCompleteWithInformation)(DriverGlobals, Request, Status, Information); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_PARAMETERS Parameters + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTGETPARAMETERS) WdfVersion.Functions.pfnWdfRequestGetParameters)(DriverGlobals, Request, Parameters); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEINPUTMEMORY) WdfVersion.Functions.pfnWdfRequestRetrieveInputMemory)(DriverGlobals, Request, Memory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEOUTPUTMEMORY) WdfVersion.Functions.pfnWdfRequestRetrieveOutputMemory)(DriverGlobals, Request, Memory); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEINPUTBUFFER) WdfVersion.Functions.pfnWdfRequestRetrieveInputBuffer)(DriverGlobals, Request, MinimumRequiredLength, Buffer, Length); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredSize, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEOUTPUTBUFFER) WdfVersion.Functions.pfnWdfRequestRetrieveOutputBuffer)(DriverGlobals, Request, MinimumRequiredSize, Buffer, Length); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + ULONG_PTR Information + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSETINFORMATION) WdfVersion.Functions.pfnWdfRequestSetInformation)(DriverGlobals, Request, Information); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG_PTR +VFWDFEXPORT(WdfRequestGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETINFORMATION) WdfVersion.Functions.pfnWdfRequestGetInformation)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfRequestGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETFILEOBJECT) WdfVersion.Functions.pfnWdfRequestGetFileObject)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +KPROCESSOR_MODE +VFWDFEXPORT(WdfRequestGetRequestorMode)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETREQUESTORMODE) WdfVersion.Functions.pfnWdfRequestGetRequestorMode)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestForwardToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE DestinationQueue + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTFORWARDTOIOQUEUE) WdfVersion.Functions.pfnWdfRequestForwardToIoQueue)(DriverGlobals, Request, DestinationQueue); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfRequestGetIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETIOQUEUE) WdfVersion.Functions.pfnWdfRequestGetIoQueue)(DriverGlobals, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRequeue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTREQUEUE) WdfVersion.Functions.pfnWdfRequestRequeue)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestStopAcknowledge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN Requeue + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSTOPACKNOWLEDGE) WdfVersion.Functions.pfnWdfRequestStopAcknowledge)(DriverGlobals, Request, Requeue); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestImpersonate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_ + PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate, + _In_opt_ + PVOID Context + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTIMPERSONATE) WdfVersion.Functions.pfnWdfRequestImpersonate)(DriverGlobals, Request, ImpersonationLevel, EvtRequestImpersonate, Context); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfRequestGetRequestorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETREQUESTORPROCESSID) WdfVersion.Functions.pfnWdfRequestGetRequestorProcessId)(DriverGlobals, Request); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsFromUserModeDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTISFROMUSERMODEDRIVER) WdfVersion.Functions.pfnWdfRequestIsFromUserModeDriver)(DriverGlobals, Request); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN IsUserModeDriverInitiated + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSETUSERMODEDRIVERINITIATEDIO) WdfVersion.Functions.pfnWdfRequestSetUserModeDriverInitiatedIo)(DriverGlobals, Request, IsUserModeDriverInitiated); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETUSERMODEDRIVERINITIATEDIO) WdfVersion.Functions.pfnWdfRequestGetUserModeDriverInitiatedIo)(DriverGlobals, Request); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + LPGUID ActivityId + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFREQUESTSETACTIVITYID) WdfVersion.Functions.pfnWdfRequestSetActivityId)(DriverGlobals, Request, ActivityId); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + LPGUID ActivityId + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTRETRIEVEACTIVITYID) WdfVersion.Functions.pfnWdfRequestRetrieveActivityId)(DriverGlobals, Request, ActivityId); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDF_DEVICE_IO_TYPE +VFWDFEXPORT(WdfRequestGetEffectiveIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFREQUESTGETEFFECTIVEIOTYPE) WdfVersion.Functions.pfnWdfRequestGetEffectiveIoType)(DriverGlobals, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCmResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCMRESOURCELISTGETCOUNT) WdfVersion.Functions.pfnWdfCmResourceListGetCount)(DriverGlobals, List); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PCM_PARTIAL_RESOURCE_DESCRIPTOR +VFWDFEXPORT(WdfCmResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFCMRESOURCELISTGETDESCRIPTOR) WdfVersion.Functions.pfnWdfCmResourceListGetDescriptor)(DriverGlobals, List, Index); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfStringCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PCUNICODE_STRING UnicodeString, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringAttributes, + _Out_ + WDFSTRING* String + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFSTRINGCREATE) WdfVersion.Functions.pfnWdfStringCreate)(DriverGlobals, UnicodeString, StringAttributes, String); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfStringGetUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFSTRING String, + _Out_ + PUNICODE_STRING UnicodeString + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFSTRINGGETUNICODESTRING) WdfVersion.Functions.pfnWdfStringGetUnicodeString)(DriverGlobals, String, UnicodeString); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTACQUIRELOCK) WdfVersion.Functions.pfnWdfObjectAcquireLock)(DriverGlobals, Object); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFOBJECTRELEASELOCK) WdfVersion.Functions.pfnWdfObjectReleaseLock)(DriverGlobals, Object); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LockAttributes, + _Out_ + WDFWAITLOCK* Lock + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWAITLOCKCREATE) WdfVersion.Functions.pfnWdfWaitLockCreate)(DriverGlobals, LockAttributes, Lock); +} + +_When_(Timeout == NULL, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Timeout != NULL && *Timeout == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Timeout != NULL && *Timeout != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +_Always_(_When_(Timeout == NULL, _Acquires_lock_(Lock))) +_When_(Timeout != NULL && return == STATUS_SUCCESS, _Acquires_lock_(Lock)) +_When_(Timeout != NULL, _Must_inspect_result_) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + WDFWAITLOCK Lock, + _In_opt_ + PLONGLONG Timeout + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWAITLOCKACQUIRE) WdfVersion.Functions.pfnWdfWaitLockAcquire)(DriverGlobals, Lock, Timeout); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWaitLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFWAITLOCK Lock + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWAITLOCKRELEASE) WdfVersion.Functions.pfnWdfWaitLockRelease)(DriverGlobals, Lock); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfSpinLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + _Out_ + WDFSPINLOCK* SpinLock + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFSPINLOCKCREATE) WdfVersion.Functions.pfnWdfSpinLockCreate)(DriverGlobals, SpinLockAttributes, SpinLock); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + _IRQL_saves_ + WDFSPINLOCK SpinLock + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFSPINLOCKACQUIRE) WdfVersion.Functions.pfnWdfSpinLockAcquire)(DriverGlobals, SpinLock); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_min_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + _IRQL_restores_ + WDFSPINLOCK SpinLock + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFSPINLOCKRELEASE) WdfVersion.Functions.pfnWdfSpinLockRelease)(DriverGlobals, SpinLock); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfTimerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_TIMER_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFTIMER* Timer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERCREATE) WdfVersion.Functions.pfnWdfTimerCreate)(DriverGlobals, Config, Attributes, Timer); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + LONGLONG DueTime + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERSTART) WdfVersion.Functions.pfnWdfTimerStart)(DriverGlobals, Timer, DueTime); +} + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + BOOLEAN Wait + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERSTOP) WdfVersion.Functions.pfnWdfTimerStop)(DriverGlobals, Timer, Wait); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfTimerGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFTIMERGETPARENTOBJECT) WdfVersion.Functions.pfnWdfTimerGetParentObject)(DriverGlobals, Timer); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECREATE) WdfVersion.Functions.pfnWdfUsbTargetDeviceCreate)(DriverGlobals, Device, Attributes, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_USB_DEVICE_CREATE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICECREATEWITHPARAMETERS) WdfVersion.Functions.pfnWdfUsbTargetDeviceCreateWithParameters)(DriverGlobals, Device, Config, Attributes, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PWDF_USB_DEVICE_INFORMATION Information + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICERETRIEVEINFORMATION) WdfVersion.Functions.pfnWdfUsbTargetDeviceRetrieveInformation)(DriverGlobals, UsbDevice, Information); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBTARGETDEVICEGETDEVICEDESCRIPTOR) WdfVersion.Functions.pfnWdfUsbTargetDeviceGetDeviceDescriptor)(DriverGlobals, UsbDevice, UsbDeviceDescriptor); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_writes_bytes_to_opt_(*ConfigDescriptorLength,*ConfigDescriptorLength) + PVOID ConfigDescriptor, + _Inout_ + PUSHORT ConfigDescriptorLength + ) +{ + PAGED_CODE_LOCKED(); +#pragma prefast(suppress: __WARNING_HIGH_PRIORITY_OVERFLOW_POSTCONDITION, "This is a verifier DDI hook routine and all it does is call original routine.") + return ((PFN_WDFUSBTARGETDEVICERETRIEVECONFIGDESCRIPTOR) WdfVersion.Functions.pfnWdfUsbTargetDeviceRetrieveConfigDescriptor)(DriverGlobals, UsbDevice, ConfigDescriptor, ConfigDescriptorLength); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_writes_opt_(*NumCharacters) + PUSHORT String, + _Inout_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEQUERYSTRING) WdfVersion.Functions.pfnWdfUsbTargetDeviceQueryString)(DriverGlobals, UsbDevice, Request, RequestOptions, String, NumCharacters, StringIndex, LangID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + _Out_ + WDFMEMORY* StringMemory, + _Out_opt_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEALLOCANDQUERYSTRING) WdfVersion.Functions.pfnWdfUsbTargetDeviceAllocAndQueryString)(DriverGlobals, UsbDevice, StringMemoryAttributes, StringMemory, NumCharacters, StringIndex, LangID); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET Offset, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORSTRING) WdfVersion.Functions.pfnWdfUsbTargetDeviceFormatRequestForString)(DriverGlobals, UsbDevice, Request, Memory, Offset, StringIndex, LangID); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +UCHAR +VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEGETNUMINTERFACES) WdfVersion.Functions.pfnWdfUsbTargetDeviceGetNumInterfaces)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipeAttributes, + _Inout_ + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICESELECTCONFIG) WdfVersion.Functions.pfnWdfUsbTargetDeviceSelectConfig)(DriverGlobals, UsbDevice, PipeAttributes, Params); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesTransferred + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICESENDCONTROLTRANSFERSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetDeviceSendControlTransferSynchronously)(DriverGlobals, UsbDevice, Request, RequestOptions, SetupPacket, MemoryDescriptor, BytesTransferred); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + WDFMEMORY TransferMemory, + _In_opt_ + PWDFMEMORY_OFFSET TransferOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORCONTROLTRANSFER) WdfVersion.Functions.pfnWdfUsbTargetDeviceFormatRequestForControlTransfer)(DriverGlobals, UsbDevice, Request, SetupPacket, TransferMemory, TransferOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICERESETPORTSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetDeviceResetPortSynchronously)(DriverGlobals, UsbDevice); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + CONST GUID* CapabilityType, + _In_ + ULONG CapabilityBufferLength, + _When_(CapabilityBufferLength == 0, _Out_opt_) + _When_(CapabilityBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(CapabilityBufferLength)) + _When_(CapabilityBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + _Out_opt_ + _When_(ResultLength != NULL,_Deref_out_range_(<=,CapabilityBufferLength)) + PULONG ResultLength + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEQUERYUSBCAPABILITY) WdfVersion.Functions.pfnWdfUsbTargetDeviceQueryUsbCapability)(DriverGlobals, UsbDevice, CapabilityType, CapabilityBufferLength, CapabilityBuffer, ResultLength); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _Out_ + PWDF_USB_PIPE_INFORMATION PipeInformation + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBTARGETPIPEGETINFORMATION) WdfVersion.Functions.pfnWdfUsbTargetPipeGetInformation)(DriverGlobals, Pipe, PipeInformation); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEISINENDPOINT) WdfVersion.Functions.pfnWdfUsbTargetPipeIsInEndpoint)(DriverGlobals, Pipe); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEISOUTENDPOINT) WdfVersion.Functions.pfnWdfUsbTargetPipeIsOutEndpoint)(DriverGlobals, Pipe); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_USB_PIPE_TYPE +VFWDFEXPORT(WdfUsbTargetPipeGetType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEGETTYPE) WdfVersion.Functions.pfnWdfUsbTargetPipeGetType)(DriverGlobals, Pipe); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBTARGETPIPESETNOMAXIMUMPACKETSIZECHECK) WdfVersion.Functions.pfnWdfUsbTargetPipeSetNoMaximumPacketSizeCheck)(DriverGlobals, Pipe); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesWritten + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEWRITESYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeWriteSynchronously)(DriverGlobals, Pipe, Request, RequestOptions, MemoryDescriptor, BytesWritten); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY WriteMemory, + _In_opt_ + PWDFMEMORY_OFFSET WriteOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORWRITE) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForWrite)(DriverGlobals, Pipe, Request, WriteMemory, WriteOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesRead + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEREADSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeReadSynchronously)(DriverGlobals, Pipe, Request, RequestOptions, MemoryDescriptor, BytesRead); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY ReadMemory, + _In_opt_ + PWDFMEMORY_OFFSET ReadOffset + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORREAD) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForRead)(DriverGlobals, Pipe, Request, ReadMemory, ReadOffset); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPECONFIGCONTINUOUSREADER) WdfVersion.Functions.pfnWdfUsbTargetPipeConfigContinuousReader)(DriverGlobals, Pipe, Config); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEABORTSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeAbortSynchronously)(DriverGlobals, Pipe, Request, RequestOptions); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORABORT) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForAbort)(DriverGlobals, Pipe, Request); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPERESETSYNCHRONOUSLY) WdfVersion.Functions.pfnWdfUsbTargetPipeResetSynchronously)(DriverGlobals, Pipe, Request, RequestOptions); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETPIPEFORMATREQUESTFORRESET) WdfVersion.Functions.pfnWdfUsbTargetPipeFormatRequestForReset)(DriverGlobals, Pipe, Request); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETINTERFACENUMBER) WdfVersion.Functions.pfnWdfUsbInterfaceGetInterfaceNumber)(DriverGlobals, UsbInterface); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETNUMENDPOINTS) WdfVersion.Functions.pfnWdfUsbInterfaceGetNumEndpoints)(DriverGlobals, UsbInterface, SettingIndex); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _Out_ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBINTERFACEGETDESCRIPTOR) WdfVersion.Functions.pfnWdfUsbInterfaceGetDescriptor)(DriverGlobals, UsbInterface, SettingIndex, InterfaceDescriptor); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETNUMSETTINGS) WdfVersion.Functions.pfnWdfUsbInterfaceGetNumSettings)(DriverGlobals, UsbInterface); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbInterfaceSelectSetting)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + _In_ + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACESELECTSETTING) WdfVersion.Functions.pfnWdfUsbInterfaceSelectSetting)(DriverGlobals, UsbInterface, PipesAttributes, Params); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _In_ + UCHAR EndpointIndex, + _Out_ + PWDF_USB_PIPE_INFORMATION EndpointInfo + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFUSBINTERFACEGETENDPOINTINFORMATION) WdfVersion.Functions.pfnWdfUsbInterfaceGetEndpointInformation)(DriverGlobals, UsbInterface, SettingIndex, EndpointIndex, EndpointInfo); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBINTERFACE +VFWDFEXPORT(WdfUsbTargetDeviceGetInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + UCHAR InterfaceIndex + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBTARGETDEVICEGETINTERFACE) WdfVersion.Functions.pfnWdfUsbTargetDeviceGetInterface)(DriverGlobals, UsbDevice, InterfaceIndex); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE Interface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETCONFIGUREDSETTINGINDEX) WdfVersion.Functions.pfnWdfUsbInterfaceGetConfiguredSettingIndex)(DriverGlobals, Interface); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETNUMCONFIGUREDPIPES) WdfVersion.Functions.pfnWdfUsbInterfaceGetNumConfiguredPipes)(DriverGlobals, UsbInterface); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBPIPE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR PipeIndex, + _Out_opt_ + PWDF_USB_PIPE_INFORMATION PipeInfo + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFUSBINTERFACEGETCONFIGUREDPIPE) WdfVersion.Functions.pfnWdfUsbInterfaceGetConfiguredPipe)(DriverGlobals, UsbInterface, PipeIndex, PipeInfo); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierDbgBreakPoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFVERIFIERDBGBREAKPOINT) WdfVersion.Functions.pfnWdfVerifierDbgBreakPoint)(DriverGlobals); +} + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFVERIFIERKEBUGCHECK) WdfVersion.Functions.pfnWdfVerifierKeBugCheck)(DriverGlobals, BugCheckCode, BugCheckParameter1, BugCheckParameter2, BugCheckParameter3, BugCheckParameter4); +} + +WDFAPI +PVOID +VFWDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFGETTRIAGEINFO) WdfVersion.Functions.pfnWdfGetTriageInfo)(DriverGlobals); +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWorkItemCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_WORKITEM_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFWORKITEM* WorkItem + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWORKITEMCREATE) WdfVersion.Functions.pfnWdfWorkItemCreate)(DriverGlobals, Config, Attributes, WorkItem); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWORKITEMENQUEUE) WdfVersion.Functions.pfnWdfWorkItemEnqueue)(DriverGlobals, WorkItem); +} + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfWorkItemGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ) +{ + PAGED_CODE_LOCKED(); + return ((PFN_WDFWORKITEMGETPARENTOBJECT) WdfVersion.Functions.pfnWdfWorkItemGetParentObject)(DriverGlobals, WorkItem); +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemFlush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ) +{ + PAGED_CODE_LOCKED(); + ((PFN_WDFWORKITEMFLUSH) WdfVersion.Functions.pfnWdfWorkItemFlush)(DriverGlobals, WorkItem); +} + + diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/verifier.cpp b/sdk/lib/drivers/wdf/shared/enhancedverif/verifier.cpp new file mode 100644 index 00000000000..89aebcc7999 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/verifier.cpp @@ -0,0 +1,650 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Verifier.cpp + +Abstract: + + This file has implementation of verifier support routines + +Author: + + + +Environment: + + Shared (Kernel and user) + +Revision History: + + + +--*/ + + +#include "vfpriv.hpp" + +extern "C" +{ + +extern WDFVERSION WdfVersion; + +// Tracing support +#if defined(EVENT_TRACING) +#include "verifier.tmh" +#endif + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(FX_ENHANCED_VERIFIER_SECTION_NAME, \ + AddEventHooksWdfDeviceCreate, \ + AddEventHooksWdfIoQueueCreate, \ + VfAddContextToHandle, \ + VfAllocateContext, \ + VfWdfObjectGetTypedContext \ + ) +#endif + +_Must_inspect_result_ +NTSTATUS +AddEventHooksWdfDeviceCreate( + __inout PVF_HOOK_PROCESS_INFO HookProcessInfo, + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in PWDFDEVICE_INIT* DeviceInit, + __in PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + __out WDFDEVICE* Device + ) +/*++ + +Routine Description: + + This routine is called by main hook for WdfDeviceCreate. + The routine swaps the event callbacks provided by client. + +Arguments: + +Return value: + +--*/ +{ + NTSTATUS status; + PWDFDEVICE_INIT deviceInit = *DeviceInit; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerEvtsOriginal; + WDF_PNPPOWER_EVENT_CALLBACKS *pnpPowerEvts; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PVOID contextHeader = NULL; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE_LOCKED(); + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, DeviceInit); + FxPointerNotNull(pFxDriverGlobals, *DeviceInit); + FxPointerNotNull(pFxDriverGlobals, Device); + + // + // Check if there are any callbacks set by the client driver. If not, we + // don't need any callback hooking. + // + if (deviceInit->PnpPower.PnpPowerEventCallbacks.Size != + sizeof(WDF_PNPPOWER_EVENT_CALLBACKS)) { + // + // no hooking required. + // + status = STATUS_SUCCESS; + HookProcessInfo->DonotCallKmdfLib = FALSE; + return status; + } + + // + // Hooking can be done only if we are able to allocate context memory. + // Try to allocate a context + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE( + &attributes, + VF_WDFDEVICECREATE_CONTEXT + ); + + status = VfAllocateContext(DriverGlobals, &attributes, &contextHeader); + + if (!NT_SUCCESS(status)) { + // + // couldn't allocate context. hooking not possible + // + HookProcessInfo->DonotCallKmdfLib = FALSE; + return status; + } + + // + // store original driver callbacks to local variable + // + RtlCopyMemory(&pnpPowerEvtsOriginal, + &deviceInit->PnpPower.PnpPowerEventCallbacks, + sizeof(WDF_PNPPOWER_EVENT_CALLBACKS) + ); + + // + // Set callback hooks + // + // Normally override the hooks on local copy of stucture (not the original + // structure itself) and then pass the local struture to DDI call and + // copy back the original poniter when returning back to caller. In this case + // device_init is null'ed out by fx when returning to caller so we can + // directly override the original + // + pnpPowerEvts = &deviceInit->PnpPower.PnpPowerEventCallbacks; + + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0Entry); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0EntryPostInterruptsEnabled); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0Exit); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceD0ExitPreInterruptsDisabled); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDevicePrepareHardware); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceReleaseHardware); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoCleanup); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoFlush); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoInit); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoSuspend); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSelfManagedIoRestart); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceSurpriseRemoval); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceQueryRemove); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceQueryStop); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceUsageNotification); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceUsageNotificationEx); + SET_HOOK_IF_CALLBACK_PRESENT(pnpPowerEvts, pnpPowerEvts, EvtDeviceRelationsQuery); + + // + // Call the DDI on behalf of driver. + // + status = ((PFN_WDFDEVICECREATE)WdfVersion.Functions.pfnWdfDeviceCreate)( + DriverGlobals, + DeviceInit, + DeviceAttributes, + Device + ); + // + // Tell main hook routine not to call the DDI in kmdf lib since we + // already called it + // + HookProcessInfo->DonotCallKmdfLib = TRUE; + HookProcessInfo->DdiCallStatus = status; + + // + // if DDI Succeeds, add context + // + if (NT_SUCCESS(status)) { + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + // + // add the already allocated context to the object. + // + status = VfAddContextToHandle(contextHeader, + &attributes, + *Device, + (PVOID *)&context); + + if (NT_SUCCESS(status)) { + // + // store the DriverGlobals pointer used to associate the driver + // with its client driver callback later in the callback hooks + // + context->CommonHeader.DriverGlobals = DriverGlobals; + + // + // store original client driver callbacks in context + // + RtlCopyMemory( + &context->PnpPowerEventCallbacksOriginal, + &pnpPowerEvtsOriginal, + sizeof(WDF_PNPPOWER_EVENT_CALLBACKS) + ); + } + else { + // + // For some reason adding context to handle failed. This should be + // rare failure, because context allocation was already successful, + // only adding to handle failed. + // + // Hooking failed if adding context is unsuccessful. This means + // kmdf has callbacks hooks but verifier cannot assiociate client + // driver callbacks with callback hooks. This would be a fatal error. + // + ASSERTMSG("KMDF Enhanced Verifier failed to add context to object " + "handle\n", FALSE); + + if (contextHeader != NULL) { + FxPoolFree(contextHeader); + } + } + } + else { + // + // KMDF DDI call failed. In case of failure, DeviceInit is not NULL'ed + // so the driver could potentially call WdfDeviceCreate again with this + // DeviceInit that contains callback hooks, and result in infinite + // callback loop. So put original callbacks back + // + if ((*DeviceInit) != NULL) { + // + // we overwrote only the pnppower callbacks. Put the original back. + // + deviceInit = *DeviceInit; + RtlCopyMemory(&deviceInit->PnpPower.PnpPowerEventCallbacks, + &pnpPowerEvtsOriginal, + sizeof(WDF_PNPPOWER_EVENT_CALLBACKS) + ); + } + + if (contextHeader != NULL) { + FxPoolFree(contextHeader); + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +AddEventHooksWdfIoQueueCreate( + __inout PVF_HOOK_PROCESS_INFO HookProcessInfo, + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in WDFDEVICE Device, + __in PWDF_IO_QUEUE_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, + __out WDFQUEUE* Queue + ) +/*++ + +Routine Description: + +Arguments: + +Return value: + +--*/ +{ + NTSTATUS status; + WDF_IO_QUEUE_CONFIG configNew; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFQUEUE *pQueue; + WDFQUEUE queue; + PVOID contextHeader = NULL; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE_LOCKED(); + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Config); + + // + // Check if there are any callbacks set by the client driver. If not, we + // don't need any callback hooking. + // + if (Config->Size != sizeof(WDF_IO_QUEUE_CONFIG)) { + // + // no hooking required. + // + status = STATUS_SUCCESS; + HookProcessInfo->DonotCallKmdfLib = FALSE; + return status; + } + + // + // Hooking can be done only if we are able to allocate context memory. + // Try to allocate a context + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, + VF_WDFIOQUEUECREATE_CONTEXT); + + status = VfAllocateContext(DriverGlobals, &attributes, &contextHeader); + + if (!NT_SUCCESS(status)) { + // + // couldn't allocate context. hooking not possible + // + HookProcessInfo->DonotCallKmdfLib = FALSE; + return status; + } + + // + // create a local copy of config + // + RtlCopyMemory(&configNew, + Config, + sizeof(configNew) + ); + + // + // Override local copy with event callback hooks. + // + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoDefault); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoRead); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoWrite); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoDeviceControl); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoInternalDeviceControl); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoStop); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoResume); + SET_HOOK_IF_CALLBACK_PRESENT(Config, &configNew, EvtIoCanceledOnQueue); + + // + // Queue handle is an optional parameter + // + if (Queue == NULL) { + pQueue = &queue; + } + else { + pQueue = Queue; + } + + // + // call the DDI + // + status = WdfVersion.Functions.pfnWdfIoQueueCreate( + DriverGlobals, + Device, + &configNew, + QueueAttributes, + pQueue + ); + + // + // Tell main hook routine not to call the DDI in kmdf lib since we + // already called it + // + HookProcessInfo->DonotCallKmdfLib = TRUE; + HookProcessInfo->DdiCallStatus = status; + + // + // if DDI Succeeds, add context + // + if (NT_SUCCESS(status)) { + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + // + // add the already allocated context to the object. + // + status = VfAddContextToHandle(contextHeader, + &attributes, + *pQueue, + (PVOID *)&context); + + if (NT_SUCCESS(status)) { + // + // store the DriverGlobals pointer used to associate the driver + // with its client driver callback later in the callback hooks + // + context->CommonHeader.DriverGlobals = DriverGlobals; + + // + // add stored original callbacks to context + // + RtlCopyMemory( + &context->IoQueueConfigOriginal, + Config, + sizeof(WDF_IO_QUEUE_CONFIG) + ); + } + else { + // + // For some reason adding context to handle failed. This should be + // rare failure, because context allocation was already successful, + // only adding to handle failed. + // + // Hooking failed if adding context is unsuccessful. This means + // kmdf has callbacks hooks but verifier cannot assiociate client + // driver callbacks with callback hooks. This would be a fatal error. + // + ASSERTMSG("KMDF Enhanced Verifier failed to add context to object " + "handle\n", FALSE); + + if (contextHeader != NULL) { + FxPoolFree(contextHeader); + } + } + } + else { + // + // DDI call to KMDF failed. Nothing to do by verifier. Just return + // kmdf's status after freeing context header memory. + // + if (contextHeader != NULL) { + FxPoolFree(contextHeader); + } + } + + return status; +} + +_Must_inspect_result_ +PVOID +FASTCALL +VfWdfObjectGetTypedContext( + __in + WDFOBJECT Handle, + __in + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ) +/*++ + +Routine Description: + Retrieves the requested type from a handle + +Arguments: + Handle - the handle to retrieve the context from + TypeInfo - global constant pointer which describes the type. Since the pointer + value is unique in all of kernel space, we will perform a pointer compare + instead of a deep structure compare + +Return Value: + A valid context pointere or NULL. NULL is not a failure, querying for a type + not associated with the handle is a legitimate operation. + + --*/ +{ + FxContextHeader* pHeader; + FxObject* pObject; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFOBJECT_OFFSET offset; + + PAGED_CODE_LOCKED(); + + // + // Do not call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because this is a + // hot spot / workhorse function that should be as efficient as possible. + // + // A call to FxObjectHandleGetPtr would : + // 1) invoke a virtual call to QueryInterface + // + // 2) ASSERT that the ref count of the object is > zero. Since this is one + // of the few functions that can be called in EvtObjectDestroy where the + // ref count is zero, that is not a good side affect. + // + offset = 0; + pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + + // + // Use the object's globals, not the caller's + // + pFxDriverGlobals = pObject->GetDriverGlobals(); + + FxPointerNotNull(pFxDriverGlobals, Handle); + FxPointerNotNull(pFxDriverGlobals, TypeInfo); + + pHeader = pObject->GetContextHeader(); + + for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) { + if (pHeader->ContextTypeInfo == TypeInfo) { + return &pHeader->Context[0]; + } + } + + PCHAR pGivenName; + + if (TypeInfo->ContextName != NULL) { + pGivenName = TypeInfo->ContextName; + } + else { + pGivenName = ""; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE, + "Attempting to get context type %s from WDFOBJECT 0x%p", + pGivenName, Handle); + + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +VfAllocateContext( + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __out PVOID* ContextHeader + ) +/*++ + +Routine Description: + Allocates an additional context on the handle if the object is in the + correct state + +Arguments: + Handle - handle on which to add a context + Attributes - attributes which describe the type and size of the new context + Context - optional pointer which will recieve the new context + +Return Value: + STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type + is already attached to the handle, and !NT_SUCCESS on failure + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxContextHeader *pHeader; + size_t size; + + PAGED_CODE_LOCKED(); + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + status = FxValidateObjectAttributes( + pFxDriverGlobals, Attributes, FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Must have a context type! + // + if (Attributes->ContextTypeInfo == NULL) { + status = STATUS_OBJECT_NAME_INVALID; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE, + "Attributes %p ContextTypeInfo is NULL, %!STATUS!", + Attributes, status); + return status; + } + + // + // By passing 0's for raw object size and extra size, we can compute the + // size of only the header and its contents. + // + status = FxCalculateObjectTotalSize(pFxDriverGlobals, 0, 0, Attributes, &size); + if (!NT_SUCCESS(status)) { + return status; + } + + pHeader = (FxContextHeader*) + FxPoolAllocate(pFxDriverGlobals, NonPagedPool, size); + + if (pHeader != NULL) { + *ContextHeader = pHeader; + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +VfAddContextToHandle( + __in PVOID ContextHeader, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in WDFOBJECT Handle, + __out_opt PVOID* Context + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status = STATUS_SUCCESS; + FxObject* pObject; + FxContextHeader *pHeader; + WDFOBJECT_OFFSET offset; + + PAGED_CODE_LOCKED(); + + pHeader = (FxContextHeader *)ContextHeader; + + if (pHeader == NULL) { + return STATUS_INVALID_PARAMETER; + } + + // + // No need to call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because + // we assume that the object handle will point back to an FxObject. (The + // call to FxObjectHandleGetPtr will just make needless virtual call into + // FxObject anyways). + // + offset = 0; + pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + + pFxDriverGlobals = pObject->GetDriverGlobals(); + + if (offset != 0) { + // + // for lack of a better error code + // + status = STATUS_OBJECT_PATH_INVALID; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE, + "WDFHANDLE %p cannot have contexts added to it, %!STATUS!", + Handle, status); + + goto cleanup; + } + + pObject->ADDREF(&status); + + FxContextHeaderInit(pHeader, pObject, Attributes); + + status = pObject->AddContext(pHeader, Context, Attributes); + + // + // STATUS_OBJECT_NAME_EXISTS will not fail NT_SUCCESS, so check + // explicitly for STATUS_SUCCESS. + // + if (status != STATUS_SUCCESS) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE, + "WDFHANDLE %p failed to add context, %!STATUS!", + Handle, status); + } + + pObject->RELEASE(&status); + +cleanup: + + if (status != STATUS_SUCCESS && pHeader != NULL) { + FxPoolFree(pHeader); + } + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/vfeventhooks.cpp b/sdk/lib/drivers/wdf/shared/enhancedverif/vfeventhooks.cpp new file mode 100644 index 00000000000..e1320c8997c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/vfeventhooks.cpp @@ -0,0 +1,1020 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + VfEventHooks.cpp + +Abstract: + Generated implementation of verifier event callback hooks + +Environment: + User and Kernel + + ** Warning ** : manual changes to this file will be lost. + +--*/ + +#include "vfpriv.hpp" + + +extern "C" { +extern WDFVERSION WdfVersion; +} + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(FX_ENHANCED_VERIFIER_SECTION_NAME, \ + VfEvtDeviceD0Entry, \ + VfEvtDeviceD0EntryPostInterruptsEnabled, \ + VfEvtDeviceD0Exit, \ + VfEvtDeviceD0ExitPreInterruptsDisabled, \ + VfEvtDevicePrepareHardware, \ + VfEvtDeviceReleaseHardware, \ + VfEvtDeviceSelfManagedIoCleanup, \ + VfEvtDeviceSelfManagedIoFlush, \ + VfEvtDeviceSelfManagedIoInit, \ + VfEvtDeviceSelfManagedIoSuspend, \ + VfEvtDeviceSelfManagedIoRestart, \ + VfEvtDeviceQueryStop, \ + VfEvtDeviceQueryRemove, \ + VfEvtDeviceSurpriseRemoval, \ + VfEvtDeviceUsageNotification, \ + VfEvtDeviceUsageNotificationEx, \ + VfEvtDeviceRelationsQuery, \ + VfEvtIoDefault, \ + VfEvtIoStop, \ + VfEvtIoResume, \ + VfEvtIoRead, \ + VfEvtIoWrite, \ + VfEvtIoDeviceControl, \ + VfEvtIoInternalDeviceControl, \ + VfEvtIoCanceledOnQueue \ +) +#endif + +NTSTATUS +VfEvtDeviceD0Entry( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE PreviousState +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_D0_ENTRY pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceD0Entry; + if (pfn != NULL) { + GUID activityId = { 0 }; + if (PerfEvtDeviceD0EntryStart(Device, &activityId)) { + returnVal = (pfn)( + Device, + PreviousState + ); + + PerfEvtDeviceD0EntryStop(Device, &activityId); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + PreviousState + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceD0EntryPostInterruptsEnabled( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE PreviousState +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceD0EntryPostInterruptsEnabled; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + PreviousState + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceD0Exit( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE TargetState +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_D0_EXIT pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceD0Exit; + if (pfn != NULL) { + GUID activityId = { 0 }; + if (PerfEvtDeviceD0ExitStart(Device, &activityId)) { + returnVal = (pfn)( + Device, + TargetState + ); + + PerfEvtDeviceD0ExitStop(Device, &activityId); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + TargetState + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceD0ExitPreInterruptsDisabled( + WDFDEVICE Device, + WDF_POWER_DEVICE_STATE TargetState +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceD0ExitPreInterruptsDisabled; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + TargetState + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +NTSTATUS +VfEvtDevicePrepareHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourcesRaw, + WDFCMRESLIST ResourcesTranslated +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_PREPARE_HARDWARE pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDevicePrepareHardware; + if (pfn != NULL) { + GUID activityId = { 0 }; + if (PerfEvtDevicePrepareHardwareStart(Device, &activityId)) { + returnVal = (pfn)( + Device, + ResourcesRaw, + ResourcesTranslated + ); + + PerfEvtDevicePrepareHardwareStop(Device, &activityId); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + ResourcesRaw, + ResourcesTranslated + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceReleaseHardware( + WDFDEVICE Device, + WDFCMRESLIST ResourcesTranslated +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_RELEASE_HARDWARE pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceReleaseHardware; + if (pfn != NULL) { + GUID activityId = { 0 }; + if (PerfEvtDeviceReleaseHardwareStart(Device, &activityId)) { + returnVal = (pfn)( + Device, + ResourcesTranslated + ); + + PerfEvtDeviceReleaseHardwareStop(Device, &activityId); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + ResourcesTranslated + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return returnVal; +} + +VOID +VfEvtDeviceSelfManagedIoCleanup( + WDFDEVICE Device +) +{ + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceSelfManagedIoCleanup; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + +VOID +VfEvtDeviceSelfManagedIoFlush( + WDFDEVICE Device +) +{ + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceSelfManagedIoFlush; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + +NTSTATUS +VfEvtDeviceSelfManagedIoInit( + WDFDEVICE Device +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceSelfManagedIoInit; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceSelfManagedIoSuspend( + WDFDEVICE Device +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceSelfManagedIoSuspend; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceSelfManagedIoRestart( + WDFDEVICE Device +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceSelfManagedIoRestart; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceQueryStop( + WDFDEVICE Device +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_QUERY_STOP pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceQueryStop; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +NTSTATUS +VfEvtDeviceQueryRemove( + WDFDEVICE Device +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_QUERY_REMOVE pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceQueryRemove; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +VOID +VfEvtDeviceSurpriseRemoval( + WDFDEVICE Device +) +{ + PFN_WDF_DEVICE_SURPRISE_REMOVAL pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceSurpriseRemoval; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Device + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + +VOID +VfEvtDeviceUsageNotification( + WDFDEVICE Device, + WDF_SPECIAL_FILE_TYPE NotificationType, + BOOLEAN IsInNotificationPath +) +{ + PFN_WDF_DEVICE_USAGE_NOTIFICATION pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceUsageNotification; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Device, + NotificationType, + IsInNotificationPath + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + +NTSTATUS +VfEvtDeviceUsageNotificationEx( + WDFDEVICE Device, + WDF_SPECIAL_FILE_TYPE NotificationType, + BOOLEAN IsInNotificationPath +) +{ + NTSTATUS returnVal = STATUS_SUCCESS; + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceUsageNotificationEx; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + returnVal = (pfn)( + Device, + NotificationType, + IsInNotificationPath + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return returnVal; +} + +VOID +VfEvtDeviceRelationsQuery( + WDFDEVICE Device, + DEVICE_RELATION_TYPE RelationType +) +{ + PFN_WDF_DEVICE_RELATIONS_QUERY pfn = NULL; + PVF_WDFDEVICECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Device, VF_WDFDEVICECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->PnpPowerEventCallbacksOriginal.EvtDeviceRelationsQuery; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Device, + RelationType + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + +VOID +VfEvtIoDefault( + WDFQUEUE Queue, + WDFREQUEST Request +) +{ + PFN_WDF_IO_QUEUE_IO_DEFAULT pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoDefault; + if (pfn != NULL) { + if (PerfIoStart(Request)) { + (pfn)( + Queue, + Request + ); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return; +} + +VOID +VfEvtIoStop( + WDFQUEUE Queue, + WDFREQUEST Request, + ULONG ActionFlags +) +{ + PFN_WDF_IO_QUEUE_IO_STOP pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoStop; + if (pfn != NULL) { + GUID activityId = { 0 }; + if (PerfEvtIoStopStart(Queue, &activityId)) { + (pfn)( + Queue, + Request, + ActionFlags + ); + + PerfEvtIoStopStop(Queue, &activityId); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request, + ActionFlags + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return; +} + +VOID +VfEvtIoResume( + WDFQUEUE Queue, + WDFREQUEST Request +) +{ + PFN_WDF_IO_QUEUE_IO_RESUME pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoResume; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + +VOID +VfEvtIoRead( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t Length +) +{ + PFN_WDF_IO_QUEUE_IO_READ pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoRead; + if (pfn != NULL) { + if (PerfIoStart(Request)) { + (pfn)( + Queue, + Request, + Length + ); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request, + Length + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return; +} + +VOID +VfEvtIoWrite( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t Length +) +{ + PFN_WDF_IO_QUEUE_IO_WRITE pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoWrite; + if (pfn != NULL) { + if (PerfIoStart(Request)) { + (pfn)( + Queue, + Request, + Length + ); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request, + Length + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return; +} + +VOID +VfEvtIoDeviceControl( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t OutputBufferLength, + size_t InputBufferLength, + ULONG IoControlCode +) +{ + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoDeviceControl; + if (pfn != NULL) { + if (PerfIoStart(Request)) { + (pfn)( + Queue, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode + ); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return; +} + +VOID +VfEvtIoInternalDeviceControl( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t OutputBufferLength, + size_t InputBufferLength, + ULONG IoControlCode +) +{ + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoInternalDeviceControl; + if (pfn != NULL) { + if (PerfIoStart(Request)) { + (pfn)( + Queue, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode + ); + } else { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + } + + return; +} + +VOID +VfEvtIoCanceledOnQueue( + WDFQUEUE Queue, + WDFREQUEST Request +) +{ + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE pfn = NULL; + PVF_WDFIOQUEUECREATE_CONTEXT context = NULL; + + PAGED_CODE_LOCKED(); + + context = GET_CONTEXT(Queue, VF_WDFIOQUEUECREATE_CONTEXT); + ASSERT(context != NULL); + + pfn = context->IoQueueConfigOriginal.EvtIoCanceledOnQueue; + if (pfn != NULL) { + KIRQL irql = PASSIVE_LEVEL; + BOOLEAN critRegion = FALSE; + + VerifyIrqlEntry(&irql); + VerifyCriticalRegionEntry(&critRegion); + + (pfn)( + Queue, + Request + ); + + VerifyIrqlExit(context->CommonHeader.DriverGlobals, irql); + VerifyCriticalRegionExit(context->CommonHeader.DriverGlobals, critRegion, (PVOID)pfn); + } + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/vfeventhooks.hpp b/sdk/lib/drivers/wdf/shared/enhancedverif/vfeventhooks.hpp new file mode 100644 index 00000000000..4ffc0446970 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/vfeventhooks.hpp @@ -0,0 +1,50 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + VfEventHooks.hpp + +Abstract: + Generated header of verifier event callback hooks + +Environment: + kernel mode only + + ** Warning ** : manual changes to this file will be lost. + +--*/ + +#pragma once + +extern "C" +{ + +EVT_WDF_DEVICE_D0_ENTRY VfEvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED VfEvtDeviceD0EntryPostInterruptsEnabled; +EVT_WDF_DEVICE_D0_EXIT VfEvtDeviceD0Exit; +EVT_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED VfEvtDeviceD0ExitPreInterruptsDisabled; +EVT_WDF_DEVICE_PREPARE_HARDWARE VfEvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE VfEvtDeviceReleaseHardware; +EVT_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP VfEvtDeviceSelfManagedIoCleanup; +EVT_WDF_DEVICE_SELF_MANAGED_IO_FLUSH VfEvtDeviceSelfManagedIoFlush; +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT VfEvtDeviceSelfManagedIoInit; +EVT_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND VfEvtDeviceSelfManagedIoSuspend; +EVT_WDF_DEVICE_SELF_MANAGED_IO_RESTART VfEvtDeviceSelfManagedIoRestart; +EVT_WDF_DEVICE_QUERY_STOP VfEvtDeviceQueryStop; +EVT_WDF_DEVICE_QUERY_REMOVE VfEvtDeviceQueryRemove; +EVT_WDF_DEVICE_SURPRISE_REMOVAL VfEvtDeviceSurpriseRemoval; +EVT_WDF_DEVICE_USAGE_NOTIFICATION VfEvtDeviceUsageNotification; +EVT_WDF_DEVICE_USAGE_NOTIFICATION_EX VfEvtDeviceUsageNotificationEx; +EVT_WDF_DEVICE_RELATIONS_QUERY VfEvtDeviceRelationsQuery; +EVT_WDF_IO_QUEUE_IO_DEFAULT VfEvtIoDefault; +EVT_WDF_IO_QUEUE_IO_STOP VfEvtIoStop; +EVT_WDF_IO_QUEUE_IO_RESUME VfEvtIoResume; +EVT_WDF_IO_QUEUE_IO_READ VfEvtIoRead; +EVT_WDF_IO_QUEUE_IO_WRITE VfEvtIoWrite; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL VfEvtIoDeviceControl; +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL VfEvtIoInternalDeviceControl; +EVT_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE VfEvtIoCanceledOnQueue; + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/enhancedverif/vfpriv.hpp b/sdk/lib/drivers/wdf/shared/enhancedverif/vfpriv.hpp new file mode 100644 index 00000000000..61f9a717aec --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/enhancedverif/vfpriv.hpp @@ -0,0 +1,138 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + vfpriv.hpp + +Abstract: + + common header file for verifier + +Author: + + + +Environment: + + user/kernel mode + +Revision History: + +--*/ + +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE +#include "VfPrivKm.hpp" +#else if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#include "VfPrivUm.hpp" +#endif + +extern "C" { +#include "FxDynamics.h" +} +#include "vfeventhooks.hpp" + + +#define FX_ENHANCED_VERIFIER_SECTION_NAME WDF_FX_VF_SECTION_NAME + +#define GET_CONTEXT(_objectHandle, _type) \ + (_type *)VfWdfObjectGetTypedContext(_objectHandle, WDF_GET_CONTEXT_TYPE_INFO(_type)); + +#define SET_HOOK_IF_CALLBACK_PRESENT(Source, Target, Name) \ + if ((Source)-> ## Name != NULL) { \ + (Target)-> ## Name = Vf ## Name; \ + } + +typedef struct _VF_HOOK_PROCESS_INFO { + // + // Return status of the DDI of called by hook routine. + // this will be returned by stub if it does not call the DDI (since + // hook already called. + // + ULONG DdiCallStatus; + + // + // Whether kmdf lib needs to be called after hook functin returns + // + BOOLEAN DonotCallKmdfLib; + +} VF_HOOK_PROCESS_INFO, *PVF_HOOK_PROCESS_INFO; + +typedef struct _VF_COMMON_CONTEXT_HEADER { + + PWDF_DRIVER_GLOBALS DriverGlobals; + +} VF_COMMON_CONTEXT_HEADER, *PVF_COMMON_CONTEXT_HEADER; + +typedef struct _VF_WDFDEVICECREATE_CONTEXT { + + VF_COMMON_CONTEXT_HEADER CommonHeader; + + WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacksOriginal; + +} VF_WDFDEVICECREATE_CONTEXT, *PVF_WDFDEVICECREATE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE(VF_WDFDEVICECREATE_CONTEXT); + +typedef struct _VF_WDFIOQUEUECREATE_CONTEXT { + + VF_COMMON_CONTEXT_HEADER CommonHeader; + + WDF_IO_QUEUE_CONFIG IoQueueConfigOriginal; + +} VF_WDFIOQUEUECREATE_CONTEXT, *PVF_WDFIOQUEUECREATE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE(VF_WDFIOQUEUECREATE_CONTEXT); + +extern "C" { + +_Must_inspect_result_ +PVOID +FASTCALL +VfWdfObjectGetTypedContext( + __in + WDFOBJECT Handle, + __in + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ); + +_Must_inspect_result_ +NTSTATUS +VfAllocateContext( + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __out PVOID* ContextHeader + ); + +_Must_inspect_result_ +NTSTATUS +VfAddContextToHandle( + __in PVOID ContextHeader, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in WDFOBJECT Handle, + __out_opt PVOID* Context + ); + +_Must_inspect_result_ +NTSTATUS +AddEventHooksWdfDeviceCreate( + __inout PVF_HOOK_PROCESS_INFO HookProcessInfo, + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in PWDFDEVICE_INIT* DeviceInit, + __in PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + __out WDFDEVICE* Device + ); + +_Must_inspect_result_ +NTSTATUS +AddEventHooksWdfIoQueueCreate( + __inout PVF_HOOK_PROCESS_INFO HookProcessInfo, + __in PWDF_DRIVER_GLOBALS DriverGlobals, + __in WDFDEVICE Device, + __in PWDF_IO_QUEUE_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, + __out WDFQUEUE* Queue + ); + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/dbgmacros.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/dbgmacros.h new file mode 100644 index 00000000000..e298ef20247 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/dbgmacros.h @@ -0,0 +1,63 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + DbgMacros.h + +Abstract: + + This file contains debug macros + to make sure that an object is intialized + + This is useful in mode agnostic primitives + where initialization is important in user mode + but not in kernel mode (e.g. for a lock) + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#if DBG_WDF +#define DECLARE_DBGFLAG_INITIALIZED \ + protected: \ + BOOLEAN m_DbgFlagIsInitialized; + +#define ASSERT_DBGFLAG_INITIALIZED \ +{ \ + ASSERT(m_DbgFlagIsInitialized == TRUE); \ +} + +#define SET_DBGFLAG_INITIALIZED \ +{ \ + m_DbgFlagIsInitialized = TRUE; \ +} + +#define CLEAR_DBGFLAG_INITIALIZED \ +{ \ + m_DbgFlagIsInitialized = FALSE; \ +} + +#define ASSERT_DBGFLAG_NOT_INITIALIZED \ +{ \ + ASSERT(m_DbgFlagIsInitialized == FALSE); \ +} + +#else + +#define DECLARE_DBGFLAG_INITIALIZED +#define ASSERT_DBGFLAG_INITIALIZED +#define SET_DBGFLAG_INITIALIZED +#define CLEAR_DBGFLAG_INITIALIZED +#define ASSERT_DBGFLAG_NOT_INITIALIZED + +#endif diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mx.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mx.h new file mode 100644 index 00000000000..6e5da3ad4a9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mx.h @@ -0,0 +1,42 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + Mx.h + +Abstract: + + This file includes MxUm.h/MxKm.h based on the mode + + Shared code can use this header to have appropriate + mode headers pulled in + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#include "MxMacros.h" + +// +// Greater than 64 logical processors support: direct DDK to include the new +// routines to handle groups and exclude any potentially dangerous, old +// interfaces. +// +#define NT_PROCESSOR_GROUPS 1 + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "MxUm.h" +#elif (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#include "MxKm.h" +#endif + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxdeviceobject.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxdeviceobject.h new file mode 100644 index 00000000000..91a9057de74 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxdeviceobject.h @@ -0,0 +1,152 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDeviceObject.h + +Abstract: + + Mode agnostic definition of Device Object + + See MxDeviceObjectKm.h and MxDeviceObjectUm.h/cpp for mode + specific implementations + +--*/ + +#pragma once + +class MxDeviceObject +{ +private: + // + // MdDeviceObject is typedef'ed to appropriate type for the mode + // in the mode specific file + // + MdDeviceObject m_DeviceObject; + +public: + __inline + MxDeviceObject( + __in MdDeviceObject DeviceObject + ) : + m_DeviceObject(DeviceObject) + { + } + + __inline + MxDeviceObject( + VOID + ) : + m_DeviceObject(NULL) + { + } + + __inline + MdDeviceObject + GetObject( + VOID + ) + { + return m_DeviceObject; + } + + __inline + VOID + SetObject( + __in_opt MdDeviceObject DeviceObject + ) + { + m_DeviceObject = DeviceObject; + } + + CCHAR + GetStackSize( + VOID + ); + + VOID + SetStackSize( + _In_ CCHAR Size + ); + + VOID + ReferenceObject( + ); + + MdDeviceObject + GetAttachedDeviceReference( + VOID + ); + + VOID + DereferenceObject( + ); + + ULONG + GetFlags( + VOID + ); + + VOID + SetFlags( + ULONG Flags + ); + + POWER_STATE + SetPowerState( + __in POWER_STATE_TYPE Type, + __in POWER_STATE State + ); + + VOID + InvalidateDeviceRelations( + __in DEVICE_RELATION_TYPE Type + ); + + VOID + InvalidateDeviceState( + __in MdDeviceObject Fdo //used in UMDF + ); + + PVOID + GetDeviceExtension( + VOID + ); + + VOID + SetDeviceExtension( + PVOID Value + ); + + DEVICE_TYPE + GetDeviceType( + VOID + ); + + ULONG + GetCharacteristics( + VOID + ); + + VOID + SetDeviceType( + DEVICE_TYPE Value + ); + + VOID + SetCharacteristics( + ULONG Characteristics + ); + + VOID + SetAlignmentRequirement( + _In_ ULONG Value + ); + + ULONG + GetAlignmentRequirement( + VOID + ); +}; diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxdriverobject.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxdriverobject.h new file mode 100644 index 00000000000..3a92469b8f6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxdriverobject.h @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDrierObjet.h + +Abstract: + + Mode agnostic definition of Driver Object + + See MxDriverObjectKm.h and MxDriverObjectUm.h/cpp for mode + specific implementations + +--*/ + +#pragma once + +// +// Forward declare enum +// +enum FxDriverObjectUmFlags : USHORT; + +class MxDriverObject +{ +private: + // + // MdDeviceObject is typedef'ed to appropriate type for the mode + // in the mode specific file + // + MdDriverObject m_DriverObject; + +public: + __inline + MxDriverObject( + __in MdDriverObject DriverObject + ) : + m_DriverObject(DriverObject) + { + } + + __inline + MxDriverObject( + VOID + ) : + m_DriverObject(NULL) + { + } + + __inline + MdDriverObject + GetObject( + VOID + ) + { + return m_DriverObject; + } + + __inline + VOID + SetObject( + __in_opt MdDriverObject DriverObject + ) + { + m_DriverObject = DriverObject; + } + + PVOID + GetDriverExtensionAddDevice( + VOID + ); + + VOID + SetDriverExtensionAddDevice( + _In_ MdDriverAddDevice Value + ); + + MdDriverUnload + GetDriverUnload( + VOID + ); + + VOID + SetDriverUnload( + _In_ MdDriverUnload Value + ); + + VOID + SetMajorFunction( + _In_ UCHAR i, + _In_ MdDriverDispatch Value + ); + + VOID + SetDriverObjectFlag( + _In_ FxDriverObjectUmFlags Flag + ); + + BOOLEAN + IsDriverObjectFlagSet( + _In_ FxDriverObjectUmFlags Flag + ); + + +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxevent.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxevent.h new file mode 100644 index 00000000000..46ee5673b37 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxevent.h @@ -0,0 +1,143 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxEvent.h + +Abstract: + + Mode agnostic definition of event + + See MxEventKm.h and MxEventUm.h for mode + specific implementations + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +class MxEvent +{ + +private: + // + // MdEvent is typedef'ed to appropriate type for the mode + // in the mode specific file + // + MdEvent m_Event; + + DECLARE_DBGFLAG_INITIALIZED; + +public: + __inline + MxEvent( + ); + + __inline + ~MxEvent( + ); + + CHECK_RETURN_IF_USER_MODE + __inline + NTSTATUS + Initialize( + __in EVENT_TYPE Type, + __in BOOLEAN InitialState + ); + + // + // GetEvent will return the underlying primitive event + // PKEVENT in case of kernel mode and event HANDLE in case of user-mode + // + __inline + PVOID + GetEvent( + ); + + __inline + VOID + Set( + ); + + __inline + VOID + SetWithIncrement( + __in KPRIORITY Priority + ); + + __inline + VOID + Clear( + ); + + __drv_when(Timeout == NULL && Alertable == FALSE, __drv_valueIs(==0)) + __drv_when(Timeout != NULL && Alertable == FALSE, __drv_valueIs(==0;==258)) + __drv_when(Timeout != NULL || Alertable == TRUE, _Must_inspect_result_) + __inline + NTSTATUS + WaitFor( + __in KWAIT_REASON WaitReason, + __in KPROCESSOR_MODE WaitMode, + __in BOOLEAN Alertable, + __in_opt PLARGE_INTEGER Timeout + ); + + // + // NOTE: In user mode this function can only be called + // for a notification event (and not for a + // synchronization event) + // + __inline + LONG + ReadState( + ); + + __inline + VOID + Uninitialize( + ); + + MxEvent* + GetSelfPointer( + VOID + ) + { + // + // Since operator& is hidden, we still need to be able to get a pointer + // to this object, so we must make it an explicit method. + // + return this; + } + +private: + MxEvent* operator&( + VOID + ) + { + // + // By making the address of operator private, we make it harder + // to accidentally use this object in an improper fashion, ie + // something like this is prevented: + // + // MxEvent event; + // KeWaitForSingleObject(&event, ...); + // + // However please note that in some cases event pointer is needed when + // event is passed around, in which case, GetSelfPointer() is used and + // this protection is circumvented. Calling code should be careful + // not to pass the pointer to KeWaitForSingleObject in such cases. + // + ASSERT(FALSE); + return NULL; + } + +}; diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxfileobject.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxfileobject.h new file mode 100644 index 00000000000..f91af7da710 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxfileobject.h @@ -0,0 +1,97 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxFileObject.h + +Abstract: + + Mode agnostic definition of File Object + + See MxFileObjectKm.h and MxFileObjectUm.h/cpp for mode + specific implementations + +--*/ + +#pragma once + +class MxFileObject +{ +private: + MdFileObject m_FileObject; + +public: + __inline + MxFileObject( + _In_ MdFileObject FileObject + ) : + m_FileObject(FileObject) + { + } + + __inline + VOID + SetFileObject( + _In_ MdFileObject FileObject + ) + { + m_FileObject = FileObject; + } + + __inline + MdFileObject + GetFileObject( + VOID + ) + { + return m_FileObject; + } + + __inline + MxFileObject( + VOID + ) : + m_FileObject(NULL) + { + } + + PUNICODE_STRING + GetFileName( + _Inout_opt_ PUNICODE_STRING Filename + ); + + PLARGE_INTEGER + GetCurrentByteOffset( + VOID + ); + + ULONG + GetFlags( + VOID + ); + + VOID + SetFsContext( + _In_ PVOID Value + ); + + VOID + SetFsContext2( + _In_ PVOID Value + ); + + PVOID + GetFsContext( + VOID + ); + + PVOID + GetFsContext2( + VOID + ); + +}; + + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxgeneral.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxgeneral.h new file mode 100644 index 00000000000..8301e8ce3b1 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxgeneral.h @@ -0,0 +1,606 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxGeneral.h + +Abstract: + + Mode agnostic definitions for general OS + functions used in framework code + + See MxGeneralKm.h and MxGeneralUm.h for mode + specific implementations + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +// +// Placeholder macro for a no-op +// +#define DO_NOTHING() (0) + +// +// We need to make these static functions of the class +// to force common definition to apply to um and km versions +// +// If we don't do this, um and km definitions can diverge +// +class Mx +{ +public: + + // + // IsUM/IsKM don't change at runtime + // but defining them as functions makes it more convenient to check + // for UM/KM as compared to using ifdef's in certain places + // + // Since they are forceinlined and return a constant value, + // optimized code is no different than using an ifdef + // + // See FxPoolAllocator in WdfPool.cpp for example of such usage + // + __inline + static + BOOLEAN + IsUM( + ); + + __inline + static + BOOLEAN + IsKM( + ); + + __inline + static + MxThread + MxGetCurrentThread( + ); + + __inline + static + MdEThread + GetCurrentEThread( + ); + + NTSTATUS + static + MxTerminateCurrentThread( + __in NTSTATUS Status + ); + + __inline + static + KIRQL + MxGetCurrentIrql( + ); + + __drv_maxIRQL(HIGH_LEVEL) + __drv_raisesIRQL(NewIrql) + __inline + static + VOID + MxRaiseIrql( + __in KIRQL NewIrql, + __out __deref __drv_savesIRQL PKIRQL OldIrql + ); + + __drv_maxIRQL(HIGH_LEVEL) + __inline + static + VOID + MxLowerIrql( + __in __drv_restoresIRQL __drv_nonConstant KIRQL NewIrql + ); + + __inline + static + VOID + MxQueryTickCount( + __out PLARGE_INTEGER TickCount + ); + + __inline + static + ULONG + MxQueryTimeIncrement( + ); + + + + + + + + + static + VOID + MxBugCheckEx( + __in ULONG BugCheckCode, + __in ULONG_PTR BugCheckParameter1, + __in ULONG_PTR BugCheckParameter2, + __in ULONG_PTR BugCheckParameter3, + __in ULONG_PTR BugCheckParameter4 + ); + + __inline + static + VOID + MxDbgBreakPoint( + ); + + static + VOID + MxDbgPrint( + __drv_formatString(printf) + __in PCSTR DebugMessage, + ... + ); + + __inline + static + VOID + MxAssert( + __in BOOLEAN Condition + ); + + __inline + static + VOID + MxAssertMsg( + __in LPSTR Message, + __in BOOLEAN Condition + ); + + _Acquires_lock_(_Global_critical_region_) + __inline + static + VOID + MxEnterCriticalRegion( + ); + + _Releases_lock_(_Global_critical_region_) //implies _Requires_lock_held_(_Global_critical_region_) + __inline + static + VOID + MxLeaveCriticalRegion( + ); + + __inline + static + VOID + MxDelayExecutionThread( + __in KPROCESSOR_MODE WaitMode, + __in BOOLEAN Alertable, + __in PLARGE_INTEGER Interval + ); + + // + // Mode agnostic function to get address of a system function + // Should be used only for Rtl* functions applicable both to + // kernel mode and user mode + // + // User mode version is assumed to reside in ntdll.dll + // + // The argument type is MxFuncName so that it can be defined + // as LPCWSTR in kernel mode and LPCSTR in user mode + // which is what MmGetSystemRoutineAddress and GetProcAddress + // expect respectively + // + __inline + static + PVOID + MxGetSystemRoutineAddress( + __in MxFuncName FuncName + ); + + __inline + static + VOID + MxReferenceObject( + __in PVOID Object + ); + + __inline + static + VOID + MxDereferenceObject( + __in PVOID Object + ); + + __inline + static + VOID + MxInitializeRemoveLock( + __in MdRemoveLock Lock, + __in ULONG AllocateTag, + __in ULONG MaxLockedMinutes, + __in ULONG HighWatermark + ); + + __inline + static + NTSTATUS + MxAcquireRemoveLock( + __in MdRemoveLock RemoveLock, + __in_opt PVOID Tag + ); + + __inline + static + VOID + MxReleaseRemoveLock( + __in MdRemoveLock RemoveLock, + __in PVOID Tag + ); + + __inline + static + VOID + MxReleaseRemoveLockAndWait( + __in MdRemoveLock RemoveLock, + __in PVOID Tag + ); + + __inline + static + BOOLEAN + MxHasEnoughRemainingThreadStack( + VOID + ); + + + _Releases_lock_(_Global_cancel_spin_lock_) //implies _Requires_lock_held_(_Global_cancel_spin_lock_) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + static + VOID + ReleaseCancelSpinLock( + __in __drv_restoresIRQL __drv_useCancelIRQL KIRQL Irql + ); + + __inline + static + NTSTATUS + CreateCallback( + __out PCALLBACK_OBJECT *CallbackObject, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in BOOLEAN Create, + __in BOOLEAN AllowMultipleCallbacks + ); + + __inline + static + PVOID + RegisterCallback( + __in PCALLBACK_OBJECT CallbackObject, + __in MdCallbackFunction CallbackFunction, + __in PVOID CallbackContext + ); + + __inline + static + VOID + UnregisterCallback( + __in PVOID CbRegistration + ); + + static + VOID + MxGlobalInit( + VOID + ); + + __inline + static + VOID + MxUnlockPages( + __in PMDL Mdl + ); + + __inline + static + PVOID + MxGetSystemAddressForMdlSafe( + __inout PMDL Mdl, + __in ULONG Priority + ); + + __inline + static + VOID + MxBuildMdlForNonPagedPool( + __inout PMDL Mdl + ); + + __inline + static + PVOID + MxGetDriverObjectExtension( + __in MdDriverObject DriverObject, + __in PVOID ClientIdentificationAddress + ); + + __inline + static + NTSTATUS + MxAllocateDriverObjectExtension( + _In_ MdDriverObject DriverObject, + _In_ PVOID ClientIdentificationAddress, + _In_ ULONG DriverObjectExtensionSize, + // When successful, this always allocates already-aliased memory. + _Post_ _At_(*DriverObjectExtension, _When_(return==0, + __drv_aliasesMem __drv_allocatesMem(Mem) _Post_notnull_)) + _When_(return == 0, _Outptr_result_bytebuffer_(DriverObjectExtensionSize)) + PVOID *DriverObjectExtension + ); + + __inline + static + MdDeviceObject + MxGetAttachedDeviceReference( + __in MdDeviceObject DriverObject + ); + + __inline + static + VOID + MxDeleteSymbolicLink( + __in PUNICODE_STRING Link + ); + + __inline + static + VOID + MxDeleteNPagedLookasideList( + _In_ PNPAGED_LOOKASIDE_LIST LookasideList + ); + + __inline + static + VOID + MxDeletePagedLookasideList( + _In_ PPAGED_LOOKASIDE_LIST LookasideList + ); + + __inline + static + VOID + MxInitializeNPagedLookasideList( + _Out_ PNPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ PALLOCATE_FUNCTION Allocate, + _In_opt_ PFREE_FUNCTION Free, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Tag, + _In_ USHORT Depth + ); + + __inline + static + VOID + MxInitializePagedLookasideList( + _Out_ PPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ PALLOCATE_FUNCTION Allocate, + _In_opt_ PFREE_FUNCTION Free, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Tag, + _In_ USHORT Depth + ); + + __inline + static + VOID + MxDeleteDevice( + _In_ MdDeviceObject Device + ); + + static + VOID + MxDetachDevice( + _Inout_ MdDeviceObject Device + ); + + __inline + static + MdDeviceObject + MxAttachDeviceToDeviceStack( + _In_ MdDeviceObject SourceDevice, + _In_ MdDeviceObject TargetDevice + ); + + __inline + static + NTSTATUS + MxCreateDeviceSecure( + _In_ MdDriverObject DriverObject, + _In_ ULONG DeviceExtensionSize, + _In_opt_ PUNICODE_STRING DeviceName, + _In_ DEVICE_TYPE DeviceType, + _In_ ULONG DeviceCharacteristics, + _In_ BOOLEAN Exclusive, + _In_ PCUNICODE_STRING DefaultSDDLString, + _In_opt_ LPCGUID DeviceClassGuid, + _Out_ MdDeviceObject *DeviceObject + ); + + __inline + static + NTSTATUS + MxCreateDevice( + _In_ MdDriverObject DriverObject, + _In_ ULONG DeviceExtensionSize, + _In_opt_ PUNICODE_STRING DeviceName, + _In_ DEVICE_TYPE DeviceType, + _In_ ULONG DeviceCharacteristics, + _In_ BOOLEAN Exclusive, + _Out_ MdDeviceObject *DeviceObject + ); + + __inline + static + NTSTATUS + MxCreateSymbolicLink( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ PUNICODE_STRING DeviceName + ); + + __inline + static + VOID + MxFlushQueuedDpcs( + ); + + __inline + static + NTSTATUS + MxOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ); + + __inline + static + NTSTATUS + MxSetDeviceInterfaceState( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ BOOLEAN Enable + ); + + __inline + static + NTSTATUS + MxRegisterDeviceInterface( + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _In_ const GUID *InterfaceClassGuid, + _In_opt_ PUNICODE_STRING ReferenceString, + _Out_ PUNICODE_STRING SymbolicLinkName + ); + + __inline + static + NTSTATUS + MxDeleteKey( + _In_ HANDLE KeyHandle + ); + + __inline + static + VOID + MxInitializeMdl( + _In_ PMDL MemoryDescriptorList, + _In_ PVOID BaseVa, + _In_ SIZE_T Length + ); + + __inline + static + PVOID + MxGetMdlVirtualAddress( + _In_ PMDL Mdl + ); + + __inline + static + VOID + MxBuildPartialMdl( + _In_ PMDL SourceMdl, + _Inout_ PMDL TargetMdl, + _In_ PVOID VirtualAddress, + _In_ ULONG Length + ); + + __inline + static + VOID + MxQuerySystemTime( + _Out_ PLARGE_INTEGER CurrentTime + ); + + __inline + static + NTSTATUS + MxSetValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_opt_ ULONG TitleIndex, + _In_ ULONG Type, + _In_opt_ PVOID Data, + _In_ ULONG DataSize + ); + + __inline + static + NTSTATUS + MxQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_opt_ PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength + ); + __inline + static + NTSTATUS + MxReferenceObjectByHandle( + __in HANDLE Handle, + __in ACCESS_MASK DesiredAccess, + __in_opt POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE AccessMode, + __out PVOID *Object, + __out_opt POBJECT_HANDLE_INFORMATION HandleInformation + ); + + __inline + static + NTSTATUS + MxUnRegisterPlugPlayNotification( + __in __drv_freesMem(Pool) PVOID NotificationEntry + ); + + __inline + static + NTSTATUS + MxClose ( + __in HANDLE Handle + ); + + __inline + static + KIRQL + MxAcquireInterruptSpinLock( + _Inout_ PKINTERRUPT Interrupt + ); + + __inline + static + VOID + MxReleaseInterruptSpinLock( + _Inout_ PKINTERRUPT Interrupt, + _In_ KIRQL OldIrql + ); + + __inline + static + BOOLEAN + MxInsertQueueDpc( + __inout PRKDPC Dpc, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ); +}; diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxlock.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxlock.h new file mode 100644 index 00000000000..7c672914fa8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxlock.h @@ -0,0 +1,109 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxLock.h + +Abstract: + + Mode agnostic definition of lock + + See MxLockKm.h and MxLockUm.h for mode + specific implementations + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +// +// MxLockNoDynam has no c'tor/d'tor +// so as to be usable in global structs in km +// +// MxLock dervies from it and adds c'tor/d'tor +// +class MxLockNoDynam +{ + +DECLARE_DBGFLAG_INITIALIZED; + +protected: + MdLock m_Lock; +public: + MdLock & + Get( + ) + { + return m_Lock; + } + + __inline + VOID + Initialize( + ); + + _Acquires_lock_(this->m_Lock) + __drv_maxIRQL(DISPATCH_LEVEL) + __drv_setsIRQL(DISPATCH_LEVEL) + __inline + VOID + Acquire( + __out __drv_deref(__drv_savesIRQL) KIRQL * OldIrql + ); + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) + + CHECK_RETURN_IF_USER_MODE + __inline + BOOLEAN + TryToAcquire( + VOID + ); +#endif + + _Acquires_lock_(this->m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + VOID + AcquireAtDpcLevel( + ); + + _Releases_lock_(this->m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + VOID + Release( + __drv_restoresIRQL KIRQL NewIrql + ); + + _Releases_lock_(this->m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + VOID + ReleaseFromDpcLevel( + ); + + __inline + VOID + Uninitialize( + ); +}; + +class MxLock : public MxLockNoDynam +{ +public: + __inline + MxLock(); + + __inline + ~MxLock(); +}; diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxmacros.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxmacros.h new file mode 100644 index 00000000000..a92c7644c5b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxmacros.h @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxMacros.h + +Abstract: + + This file contains macros used by Mx files + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) +#define CHECK_RETURN_IF_USER_MODE _Must_inspect_result_ +#else +#define CHECK_RETURN_IF_USER_MODE +#endif diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxmemory.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxmemory.h new file mode 100644 index 00000000000..f1441ef86a4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxmemory.h @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxMemory.h + +Abstract: + + Mode agnostic definition of memory + allocation/deallocation functions + + See MxMemoryKm.h and MxMemoryUm.h for mode + specific implementations + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +class MxMemory +{ +public: + + __inline + static + PVOID + MxAllocatePoolWithTag( + __in POOL_TYPE PoolType, + __in SIZE_T NumberOfBytes, + __in ULONG Tag + ); + + __inline + static + VOID + MxFreePool( + __in PVOID Ptr + ); +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxpagedlock.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxpagedlock.h new file mode 100644 index 00000000000..8c7da180f2f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxpagedlock.h @@ -0,0 +1,103 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxPagedLock.h + +Abstract: + + Mode agnostic definition of paged lock + + See MxPagedLockKm.h and MxPagedLockUm.h for mode + specific implementations + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +// +// MxPagedLockNoDynam has no c'tor/d'tor +// so as to be usable in global structs in km +// +// MxPagedLock dervies from it and adds c'tor/d'tor +// +class MxPagedLockNoDynam +{ + +DECLARE_DBGFLAG_INITIALIZED; + +protected: + MdPagedLock m_Lock; +public: + _Must_inspect_result_ + __inline + NTSTATUS + Initialize( + ); + + __drv_maxIRQL(APC_LEVEL) + __drv_setsIRQL(APC_LEVEL) + __drv_savesIRQLGlobal(FastMutexObject, this->m_Lock) + _Acquires_lock_(this->m_Lock) + __inline + VOID + Acquire( + ); + + + __inline + VOID + AcquireUnsafe( + ); + + _Must_inspect_result_ + __drv_maxIRQL(APC_LEVEL) + __drv_savesIRQLGlobal(FastMutexObject, this->m_Lock) + __drv_valueIs(==1;==0) + __drv_when(return==1, __drv_setsIRQL(APC_LEVEL)) + _When_(return==1, _Acquires_lock_(this->m_Lock)) + __inline + BOOLEAN + TryToAcquire( + ); + + __drv_requiresIRQL(APC_LEVEL) + __drv_restoresIRQLGlobal(FastMutexObject,this->m_Lock) + _Releases_lock_(this->m_Lock) + __inline + VOID + Release( + ); + + + __inline + VOID + ReleaseUnsafe( + ); + + __inline + VOID + Uninitialize( + ); +}; + +class MxPagedLock : public MxPagedLockNoDynam +{ +public: + __inline + MxPagedLock(); + + __inline + ~MxPagedLock(); +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxtimer.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxtimer.h new file mode 100644 index 00000000000..a31ff815cc5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxtimer.h @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxTimer.h + +Abstract: + + Mode agnostic definiton of timer + + See MxTimerKm.h and MxTimerUm.h for + mode specific implementations + +Author: + + +Revision History: + + + +--*/ + +#pragma once + +class MxTimer +{ +private: + // + // Handle to the timer object + // + MdTimer m_Timer; + +public: + + __inline + MxTimer( + VOID + ); + + __inline + ~MxTimer( + VOID + ); + + CHECK_RETURN_IF_USER_MODE + __inline + NTSTATUS + Initialize( + __in_opt PVOID TimerContext, + __in MdDeferredRoutine TimerCallback, + __in LONG Period + ); + + CHECK_RETURN_IF_USER_MODE + __inline + NTSTATUS + InitializeEx( + __in_opt PVOID TimerContext, + __in MdExtCallbackType TimerCallback, + __in LONG Period, + __in ULONG TolerableDelay, + __in BOOLEAN UseHighResolutionTimer + ); + + __inline + VOID + Start( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay = 0 + ); + + __inline + BOOLEAN + StartWithReturn( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay = 0 + ); + + _Must_inspect_result_ + __inline + BOOLEAN + Stop( + VOID + ); + + __inline + VOID + FlushQueuedDpcs( + VOID + ); +}; + + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxworkitem.h b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxworkitem.h new file mode 100644 index 00000000000..126c05e4123 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/common/mxworkitem.h @@ -0,0 +1,118 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxWorkItem.h + +Abstract: + + Mode agnostic definition of WorkItem functions + + See MxWorkItemKm.h and MxWorkItemUm.h for mode + specific implementations + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +class MxWorkItem +{ + +protected: + MdWorkItem m_WorkItem; + +public: + + __inline + MxWorkItem( + ); + + // + // This is used only by the UM implementation + // + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) + static + VOID + CALLBACK + _WorkerThunk ( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Parameter, + _Inout_ PTP_WAIT Wait, + _In_ TP_WAIT_RESULT WaitResult + ); + + VOID + WaitForCallbacksToComplete( + VOID + ); + +#endif + + _Must_inspect_result_ + __inline + NTSTATUS + Allocate( + __in MdDeviceObject DeviceObject, + __in_opt PVOID ThreadPoolEnv = NULL + ); + + __inline + VOID + Enqueue( + __in PMX_WORKITEM_ROUTINE Callback, + __in PVOID Context + ); + + __inline + MdWorkItem + GetWorkItem( + ); + + static + __inline + VOID + _Free( + __in MdWorkItem Item + ); + + __inline + VOID + Free( + ); + + __inline + ~MxWorkItem( + ) + { + } + +}; + +// +// MxAutoWorkItem adds value to MxWorkItem by automatically freeing the +// associated MdWorkItem when it goes out of scope +// +struct MxAutoWorkItem : public MxWorkItem { +public: + + MxAutoWorkItem( + ) + { + } + + __inline + ~MxAutoWorkItem( + ); +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxdeviceobjectkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxdeviceobjectkm.h new file mode 100644 index 00000000000..5bb6126e279 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxdeviceobjectkm.h @@ -0,0 +1,189 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDeviceObjectKm.h + +Abstract: + + Kernel Mode implementation of Device Object defined in MxDeviceObject.h + +--*/ + +#pragma once + +#include "MxDeviceObject.h" + +__inline +CCHAR +MxDeviceObject::GetStackSize( + VOID + ) +{ + return m_DeviceObject->StackSize; +} + +__inline +VOID +MxDeviceObject::SetStackSize( + _In_ CCHAR Size + ) +{ + m_DeviceObject->StackSize = Size; +} + +__inline +VOID +MxDeviceObject::ReferenceObject( + ) +{ + ObReferenceObject(m_DeviceObject); +} + +__inline +MdDeviceObject +MxDeviceObject::GetAttachedDeviceReference( + VOID + ) +{ + return IoGetAttachedDeviceReference(m_DeviceObject); +} + +__inline +VOID +MxDeviceObject::DereferenceObject( + ) +{ + ObDereferenceObject(m_DeviceObject); +} + +__inline +ULONG +MxDeviceObject::GetFlags( + VOID + ) +{ +#pragma warning(disable:28129) + return m_DeviceObject->Flags; +} + +__inline +VOID +MxDeviceObject::SetFlags( + ULONG Flags + ) +{ +#pragma warning(disable:28129) + m_DeviceObject->Flags = Flags; +} + +__inline +POWER_STATE +MxDeviceObject::SetPowerState( + __in POWER_STATE_TYPE Type, + __in POWER_STATE State + ) +{ + return PoSetPowerState(m_DeviceObject, Type, State); +} + +__inline +VOID +MxDeviceObject::InvalidateDeviceRelations( + __in DEVICE_RELATION_TYPE Type + ) +{ + IoInvalidateDeviceRelations(m_DeviceObject, Type); +} + +__inline +VOID +MxDeviceObject::InvalidateDeviceState( + __in MdDeviceObject Fdo + ) +{ + // + // UMDF currently needs Fdo for InvalidateDeviceState + // FDO is not used in km. + // + // m_DeviceObject holds PDO that is what is used below. + // + + UNREFERENCED_PARAMETER(Fdo); + + IoInvalidateDeviceState(m_DeviceObject); +} + +__inline +PVOID +MxDeviceObject::GetDeviceExtension( + VOID + ) +{ + return m_DeviceObject->DeviceExtension; +} + +__inline +VOID +MxDeviceObject::SetDeviceExtension( + PVOID Value + ) +{ + m_DeviceObject->DeviceExtension = Value; +} + +__inline +DEVICE_TYPE +MxDeviceObject::GetDeviceType( + VOID + ) +{ + return m_DeviceObject->DeviceType; +} + +__inline +ULONG +MxDeviceObject::GetCharacteristics( + VOID + ) +{ + return m_DeviceObject->Characteristics; +} + +__inline +VOID +MxDeviceObject::SetDeviceType( + DEVICE_TYPE Value + ) +{ + m_DeviceObject->DeviceType = Value; +} + +__inline +VOID +MxDeviceObject::SetCharacteristics( + ULONG Characteristics + ) +{ + m_DeviceObject->Characteristics = Characteristics; +} + +__inline +VOID +MxDeviceObject::SetAlignmentRequirement( + _In_ ULONG Value + ) +{ + m_DeviceObject->AlignmentRequirement = Value; +} + +__inline +ULONG +MxDeviceObject::GetAlignmentRequirement( + VOID + ) +{ + return m_DeviceObject->AlignmentRequirement; +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxdriverobjectkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxdriverobjectkm.h new file mode 100644 index 00000000000..796a4a5bc6d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxdriverobjectkm.h @@ -0,0 +1,72 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDriverObjectKm.h + +Abstract: + + Kernel Mode implementation of Driver Object defined in MxDriverObject.h + +--*/ + +#pragma once + +typedef DRIVER_ADD_DEVICE MdDriverAddDeviceType, *MdDriverAddDevice; +typedef DRIVER_UNLOAD MdDriverUnloadType, *MdDriverUnload; +typedef DRIVER_DISPATCH MdDriverDispatchType, *MdDriverDispatch; + +#include "MxDriverObject.h" + +__inline +PVOID +MxDriverObject::GetDriverExtensionAddDevice( + VOID + ) +{ + return m_DriverObject->DriverExtension->AddDevice; +} + +__inline +VOID +MxDriverObject::SetDriverExtensionAddDevice( + _In_ MdDriverAddDevice Value + ) +{ + m_DriverObject->DriverExtension->AddDevice = Value; +} + +__inline +MdDriverUnload +MxDriverObject::GetDriverUnload( + VOID + ) +{ + return m_DriverObject->DriverUnload; +} + +__inline +VOID +MxDriverObject::SetDriverUnload( + _In_ MdDriverUnload Value + ) +{ + m_DriverObject->DriverUnload = Value; +} + + +__inline +VOID +MxDriverObject::SetMajorFunction( + _In_ UCHAR i, + _In_ MdDriverDispatch Value + ) +{ + m_DriverObject->MajorFunction[i] = Value; +} + + + + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxeventkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxeventkm.h new file mode 100644 index 00000000000..16e27bbc0c0 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxeventkm.h @@ -0,0 +1,148 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxEvent.h + +Abstract: + + Kernel mode implementation of event + class defined in MxEvent.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +typedef KEVENT MdEvent; + +#include "MxEvent.h" + +__inline +MxEvent::MxEvent() +{ + // + // Make sure that m_Event is the first member. That way if someone passes + // address of MxEvent to Ke*Event functions, it would still work. + // + // If this statement causes compilation failure, check if you added a field + // before m_Event. + // + C_ASSERT(FIELD_OFFSET(MxEvent, m_Event) == 0); + + CLEAR_DBGFLAG_INITIALIZED; +} + +__inline +MxEvent::~MxEvent() +{ +} + +__inline +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "_Must_inspect_result_ not needed in kernel mode as the function always succeeds"); +MxEvent::Initialize( + __in EVENT_TYPE Type, + __in BOOLEAN InitialState + ) +{ + KeInitializeEvent(&m_Event, Type, InitialState); + + SET_DBGFLAG_INITIALIZED; + + return STATUS_SUCCESS; +} + +__inline +PVOID +MxEvent::GetEvent( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + return &m_Event; +} + + +__inline +VOID +MxEvent::SetWithIncrement( + __in KPRIORITY Priority + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeSetEvent(&m_Event, Priority, FALSE); +} + +__inline +VOID +MxEvent::Set( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeSetEvent(&m_Event, IO_NO_INCREMENT, FALSE); +} + + +__inline +VOID +MxEvent::Clear( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeClearEvent(&m_Event); +} + +__drv_when(Timeout == NULL && Alertable == FALSE, __drv_valueIs(==0)) +__drv_when(Timeout != NULL && Alertable == FALSE, __drv_valueIs(==0;==258)) +__drv_when(Timeout != NULL || Alertable == TRUE, _Must_inspect_result_) +__inline +NTSTATUS +MxEvent::WaitFor( + __in KWAIT_REASON WaitReason, + __in KPROCESSOR_MODE WaitMode, + __in BOOLEAN Alertable, + __in_opt PLARGE_INTEGER Timeout + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + return KeWaitForSingleObject( + &m_Event, + WaitReason, + WaitMode, + Alertable, + Timeout + ); +} + +LONG +__inline +MxEvent::ReadState( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + return KeReadStateEvent(&m_Event); +} + + +__inline +VOID +MxEvent::Uninitialize( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxfileobjectkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxfileobjectkm.h new file mode 100644 index 00000000000..b90c992f551 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxfileobjectkm.h @@ -0,0 +1,82 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxFileObjectKm.h + +Abstract: + + Kernel Mode implementation of File Object defined in MxFileObject.h + +--*/ + +#pragma once + +#include "MxFileObject.h" + +__inline +PUNICODE_STRING +MxFileObject::GetFileName( + _Inout_opt_ PUNICODE_STRING Filename + ) +{ + UNREFERENCED_PARAMETER(Filename); + + return &m_FileObject->FileName; +} + +__inline +PLARGE_INTEGER +MxFileObject::GetCurrentByteOffset( + VOID + ) +{ + return &m_FileObject->CurrentByteOffset; +} + +__inline +ULONG +MxFileObject::GetFlags( + VOID + ) +{ + return m_FileObject->Flags; +} + +__inline +VOID +MxFileObject::SetFsContext( + _In_ PVOID Value + ) +{ + m_FileObject->FsContext = Value; +} + +__inline +VOID +MxFileObject::SetFsContext2( + _In_ PVOID Value + ) +{ + m_FileObject->FsContext2 = Value; +} + +__inline +PVOID +MxFileObject::GetFsContext( + VOID + ) +{ + return m_FileObject->FsContext; +} + +__inline +PVOID +MxFileObject::GetFsContext2( + VOID + ) +{ + return m_FileObject->FsContext2; +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxgeneralkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxgeneralkm.h new file mode 100644 index 00000000000..58582c89294 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxgeneralkm.h @@ -0,0 +1,778 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxGeneralKm.h + +Abstract: + + Kernel mode implementation for general OS + functions defined in MxGeneral.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#define MAKE_MX_FUNC_NAME(x) L##x +typedef LPCWSTR MxFuncName; +typedef PKTHREAD MxThread; +typedef PETHREAD MdEThread; +typedef PDEVICE_OBJECT MdDeviceObject; +typedef PDRIVER_OBJECT MdDriverObject; +typedef PFILE_OBJECT MdFileObject; +typedef PIO_REMOVE_LOCK MdRemoveLock; +typedef PCALLBACK_OBJECT MdCallbackObject; +typedef CALLBACK_FUNCTION MdCallbackFunctionType, *MdCallbackFunction; +typedef PKINTERRUPT MdInterrupt; +typedef KSERVICE_ROUTINE MdInterruptServiceRoutineType, *MdInterruptServiceRoutine; +typedef KSYNCHRONIZE_ROUTINE MdInterruptSynchronizeRoutineType, *MdInterruptSynchronizeRoutine; + +#include "MxGeneral.h" +#include + +__inline +BOOLEAN +Mx::IsUM( + ) +{ + return FALSE; +} + +__inline +BOOLEAN +Mx::IsKM( + ) +{ + return TRUE; +} + +__inline +MxThread +Mx::MxGetCurrentThread( + ) +{ + return KeGetCurrentThread(); +} + +__inline +MdEThread +Mx::GetCurrentEThread( + ) +{ + return PsGetCurrentThread(); +} + +__inline +NTSTATUS +Mx::MxTerminateCurrentThread( + __in NTSTATUS Status + ) +{ + return PsTerminateSystemThread(Status); +} + +__inline +KIRQL +Mx::MxGetCurrentIrql( + ) +{ + return KeGetCurrentIrql(); +} + +__drv_maxIRQL(HIGH_LEVEL) +__drv_raisesIRQL(NewIrql) +__inline +VOID +Mx::MxRaiseIrql( + __in KIRQL NewIrql, + __out __deref __drv_savesIRQL PKIRQL OldIrql + ) +{ + KeRaiseIrql(NewIrql, OldIrql); +} + +__drv_maxIRQL(HIGH_LEVEL) +__inline +VOID +Mx::MxLowerIrql( + __in __drv_restoresIRQL __drv_nonConstant KIRQL NewIrql + ) +{ + KeLowerIrql(NewIrql); +} + +__inline +VOID +Mx::MxQueryTickCount( + __out PLARGE_INTEGER TickCount + ) +{ + KeQueryTickCount(TickCount); +} + +__inline +ULONG +Mx::MxQueryTimeIncrement( + ) +{ + return KeQueryTimeIncrement(); +} + +__inline +VOID +Mx::MxBugCheckEx( + __in ULONG BugCheckCode, + __in ULONG_PTR BugCheckParameter1, + __in ULONG_PTR BugCheckParameter2, + __in ULONG_PTR BugCheckParameter3, + __in ULONG_PTR BugCheckParameter4 +) +{ + #pragma prefast(suppress:__WARNING_USE_OTHER_FUNCTION, "KeBugCheckEx is the intent."); + KeBugCheckEx( + BugCheckCode, + BugCheckParameter1, + BugCheckParameter2, + BugCheckParameter3, + BugCheckParameter4 + ); +} + +__inline +VOID +Mx::MxDbgBreakPoint( + ) +{ + DbgBreakPoint(); +} + +__inline +VOID +Mx::MxAssert( + __in BOOLEAN Condition + ) +{ + UNREFERENCED_PARAMETER(Condition); + + ASSERT(Condition); //this get defined as RtlAssert +} + +__inline +VOID +Mx::MxAssertMsg( + __in LPSTR Message, + __in BOOLEAN Condition + ) +{ + UNREFERENCED_PARAMETER(Message); + UNREFERENCED_PARAMETER(Condition); + + ASSERTMSG(Message, Condition); +} + +_Acquires_lock_(_Global_critical_region_) +__inline +VOID +Mx::MxEnterCriticalRegion( + ) +{ + KeEnterCriticalRegion(); +} + +_Releases_lock_(_Global_critical_region_) +__inline +VOID +Mx::MxLeaveCriticalRegion( + ) +{ + KeLeaveCriticalRegion(); +} + +__inline +VOID +Mx::MxDelayExecutionThread( + __in KPROCESSOR_MODE WaitMode, + __in BOOLEAN Alertable, + __in PLARGE_INTEGER Interval + ) +{ + ASSERTMSG("Interval must be relative\n", Interval->QuadPart <= 0); + + KeDelayExecutionThread( + WaitMode, + Alertable, + Interval + ); +} + +__inline +PVOID +Mx::MxGetSystemRoutineAddress( + __in MxFuncName FuncName + ) +{ + UNICODE_STRING funcName; + + RtlInitUnicodeString(&funcName, FuncName); + return MmGetSystemRoutineAddress(&funcName); +} + +__inline +VOID +Mx::MxReferenceObject( + __in PVOID Object + ) +{ + ObReferenceObject(Object); +} + +__inline +VOID +Mx::MxDereferenceObject( + __in PVOID Object + ) +{ + ObDereferenceObject(Object); +} + +__inline +VOID +Mx::MxInitializeRemoveLock( + __in MdRemoveLock Lock, + __in ULONG AllocateTag, + __in ULONG MaxLockedMinutes, + __in ULONG HighWatermark + ) +{ + IoInitializeRemoveLock(Lock, AllocateTag, MaxLockedMinutes, HighWatermark); +} + +__inline +NTSTATUS +Mx::MxAcquireRemoveLock( + __in MdRemoveLock RemoveLock, + __in_opt PVOID Tag + ) +{ + return IoAcquireRemoveLock(RemoveLock, Tag); +} + +__inline +VOID +Mx::MxReleaseRemoveLock( + __in MdRemoveLock RemoveLock, + __in PVOID Tag + ) +{ + IoReleaseRemoveLock(RemoveLock, Tag); +} + +__inline +VOID +Mx::MxReleaseRemoveLockAndWait( + __in MdRemoveLock RemoveLock, + __in PVOID Tag + ) +{ + IoReleaseRemoveLockAndWait(RemoveLock, Tag); +} + +__inline +BOOLEAN +Mx::MxHasEnoughRemainingThreadStack( + VOID + ) +{ + return (IoGetRemainingStackSize() < KERNEL_STACK_SIZE/2) ? FALSE : TRUE; +} + +_Releases_lock_(_Global_cancel_spin_lock_) +__drv_requiresIRQL(DISPATCH_LEVEL) +__inline +VOID +Mx::ReleaseCancelSpinLock( + __in __drv_restoresIRQL __drv_useCancelIRQL KIRQL Irql + ) +{ + IoReleaseCancelSpinLock(Irql); +} + +__inline +NTSTATUS +Mx::CreateCallback( + __out PCALLBACK_OBJECT *CallbackObject, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in BOOLEAN Create, + __in BOOLEAN AllowMultipleCallbacks + ) +{ + return ExCreateCallback( + CallbackObject, + ObjectAttributes, + Create, + AllowMultipleCallbacks); +} + +__inline +PVOID +Mx::RegisterCallback( + __in PCALLBACK_OBJECT CallbackObject, + __in MdCallbackFunction CallbackFunction, + __in PVOID CallbackContext + ) +{ + return ExRegisterCallback( + CallbackObject, + CallbackFunction, + CallbackContext); +} + +__inline +VOID +Mx::UnregisterCallback( + __in PVOID CbRegistration + ) +{ + ExUnregisterCallback(CbRegistration); +} + +__inline +VOID +Mx::MxUnlockPages( + __in PMDL Mdl + ) +{ + MmUnlockPages(Mdl); +} + +__inline +PVOID +Mx::MxGetSystemAddressForMdlSafe( + __inout PMDL Mdl, + __in ULONG Priority + ) +{ + return MmGetSystemAddressForMdlSafe(Mdl, Priority); +} + +__inline +VOID +Mx::MxBuildMdlForNonPagedPool( + __inout PMDL Mdl + ) +{ + MmBuildMdlForNonPagedPool(Mdl); +} + +__inline +PVOID +Mx::MxGetDriverObjectExtension( + __in PDRIVER_OBJECT DriverObject, + __in PVOID ClientIdentificationAddress + ) +{ + return IoGetDriverObjectExtension(DriverObject, + ClientIdentificationAddress); +} + +__inline +NTSTATUS +Mx::MxAllocateDriverObjectExtension( + _In_ MdDriverObject DriverObject, + _In_ PVOID ClientIdentificationAddress, + _In_ ULONG DriverObjectExtensionSize, + // When successful, this always allocates already-aliased memory. + _Post_ _At_(*DriverObjectExtension, _When_(return==0, + __drv_aliasesMem __drv_allocatesMem(Mem) _Post_notnull_)) + _When_(return == 0, _Outptr_result_bytebuffer_(DriverObjectExtensionSize)) + PVOID *DriverObjectExtension + ) +{ + return IoAllocateDriverObjectExtension(DriverObject, + ClientIdentificationAddress, + DriverObjectExtensionSize, + DriverObjectExtension); +} + +__inline +MdDeviceObject +Mx::MxGetAttachedDeviceReference( + __in PDEVICE_OBJECT DriverObject + ) +{ + return IoGetAttachedDeviceReference(DriverObject); +} + +__inline +VOID +Mx::MxDeleteSymbolicLink( + __in PUNICODE_STRING Value + ) +{ + IoDeleteSymbolicLink(Value); +} + +__inline +VOID +Mx::MxDeleteNPagedLookasideList( + _In_ PNPAGED_LOOKASIDE_LIST LookasideList + ) +{ + ExDeleteNPagedLookasideList(LookasideList); +} + +__inline +VOID +Mx::MxDeletePagedLookasideList( + _In_ PPAGED_LOOKASIDE_LIST LookasideList + ) +{ + ExDeletePagedLookasideList(LookasideList); +} + +__inline +VOID +Mx::MxInitializeNPagedLookasideList( + _Out_ PNPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ PALLOCATE_FUNCTION Allocate, + _In_opt_ PFREE_FUNCTION Free, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Tag, + _In_ USHORT Depth + ) +{ + ExInitializeNPagedLookasideList(Lookaside, + Allocate, + Free, + Flags, + Size, + Tag, + Depth); +} + +__inline +VOID +Mx::MxInitializePagedLookasideList( + _Out_ PPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ PALLOCATE_FUNCTION Allocate, + _In_opt_ PFREE_FUNCTION Free, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Tag, + _In_ USHORT Depth + ) +{ + ExInitializePagedLookasideList(Lookaside, + Allocate, + Free, + Flags, + Size, + Tag, + Depth); +} + +__inline +VOID +Mx::MxDeleteDevice( + _In_ MdDeviceObject Device + ) +{ + IoDeleteDevice(Device); +} + +__inline +VOID +Mx::MxDetachDevice( + _Inout_ MdDeviceObject Device + ) +{ + IoDetachDevice(Device); +} + +__inline +MdDeviceObject +Mx::MxAttachDeviceToDeviceStack( + _In_ MdDeviceObject SourceDevice, + _In_ MdDeviceObject TargetDevice + ) +{ + return IoAttachDeviceToDeviceStack(SourceDevice, TargetDevice); +} + +__inline +NTSTATUS +Mx::MxCreateDeviceSecure( + _In_ PDRIVER_OBJECT DriverObject, + _In_ ULONG DeviceExtensionSize, + _In_opt_ PUNICODE_STRING DeviceName, + _In_ DEVICE_TYPE DeviceType, + _In_ ULONG DeviceCharacteristics, + _In_ BOOLEAN Exclusive, + _In_ PCUNICODE_STRING DefaultSDDLString, + _In_opt_ LPCGUID DeviceClassGuid, + _Out_ MdDeviceObject *DeviceObject + ) +{ + return IoCreateDeviceSecure(DriverObject, + DeviceExtensionSize, + DeviceName, + DeviceType, + DeviceCharacteristics, + Exclusive, + DefaultSDDLString, + DeviceClassGuid, + DeviceObject); +} + +__inline +NTSTATUS +Mx::MxCreateDevice( + _In_ PDRIVER_OBJECT DriverObject, + _In_ ULONG DeviceExtensionSize, + _In_opt_ PUNICODE_STRING DeviceName, + _In_ DEVICE_TYPE DeviceType, + _In_ ULONG DeviceCharacteristics, + _In_ BOOLEAN Exclusive, + _Out_ MdDeviceObject *DeviceObject +) +{ + return IoCreateDevice(DriverObject, + DeviceExtensionSize, + DeviceName, + DeviceType, + DeviceCharacteristics, + Exclusive, + DeviceObject); + +} + +__inline +NTSTATUS +Mx::MxCreateSymbolicLink( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ PUNICODE_STRING DeviceName + ) +{ + return IoCreateSymbolicLink(SymbolicLinkName, DeviceName); +} + +__inline +VOID +Mx::MxFlushQueuedDpcs( + ) +{ + KeFlushQueuedDpcs(); +} + +__inline +NTSTATUS +Mx::MxOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ) +{ + return ZwOpenKey(KeyHandle, DesiredAccess, ObjectAttributes); +} + +__inline +NTSTATUS +Mx::MxSetDeviceInterfaceState( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ BOOLEAN Enable + ) +{ + return IoSetDeviceInterfaceState(SymbolicLinkName, Enable); +} + + +__inline +NTSTATUS +Mx::MxRegisterDeviceInterface( + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _In_ const GUID *InterfaceClassGuid, + _In_opt_ PUNICODE_STRING ReferenceString, + _Out_ PUNICODE_STRING SymbolicLinkName + ) +{ + return IoRegisterDeviceInterface(PhysicalDeviceObject, + InterfaceClassGuid, + ReferenceString, + SymbolicLinkName); +} + +__inline +NTSTATUS +Mx::MxDeleteKey( + _In_ HANDLE KeyHandle + ) +{ + return ZwDeleteKey(KeyHandle); +} + +__inline +VOID +Mx::MxInitializeMdl( + _In_ PMDL MemoryDescriptorList, + _In_ PVOID BaseVa, + _In_ SIZE_T Length + ) +{ + MmInitializeMdl(MemoryDescriptorList, BaseVa, Length); +} + +__inline +PVOID +Mx::MxGetMdlVirtualAddress( + _In_ PMDL Mdl + ) +{ + return MmGetMdlVirtualAddress(Mdl); +} + +__inline +VOID +Mx::MxBuildPartialMdl( + _In_ PMDL SourceMdl, + _Inout_ PMDL TargetMdl, + _In_ PVOID VirtualAddress, + _In_ ULONG Length + ) +{ + IoBuildPartialMdl(SourceMdl, + TargetMdl, + VirtualAddress, + Length + ); +} + +__inline +VOID +Mx::MxQuerySystemTime( + _Out_ PLARGE_INTEGER CurrentTime + ) +{ + KeQuerySystemTime(CurrentTime); +} + +__inline +NTSTATUS +Mx::MxSetValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_opt_ ULONG TitleIndex, + _In_ ULONG Type, + _In_opt_ PVOID Data, + _In_ ULONG DataSize + ) +{ + return ZwSetValueKey(KeyHandle, + ValueName, + TitleIndex, + Type, + Data, + DataSize + ); +} + +__inline +NTSTATUS +Mx::MxQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_opt_ PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength +) +{ + return ZwQueryValueKey(KeyHandle, + ValueName, + KeyValueInformationClass, + KeyValueInformation, + Length, + ResultLength + ); +} + +__inline +NTSTATUS +Mx::MxReferenceObjectByHandle( + __in HANDLE Handle, + __in ACCESS_MASK DesiredAccess, + __in_opt POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE AccessMode, + __out PVOID *Object, + __out_opt POBJECT_HANDLE_INFORMATION HandleInformation + ) +{ + return ObReferenceObjectByHandle( + Handle, + DesiredAccess, + ObjectType, + AccessMode, + Object, + HandleInformation); +} + +__inline +NTSTATUS +Mx::MxUnRegisterPlugPlayNotification( + __in __drv_freesMem(Pool) PVOID NotificationEntry + ) +{ + return IoUnregisterPlugPlayNotification(NotificationEntry); +} + + +__inline +NTSTATUS +Mx::MxClose( + __in HANDLE Handle + ) +{ + return ZwClose(Handle); +} + +__inline +KIRQL +Mx::MxAcquireInterruptSpinLock( + _Inout_ PKINTERRUPT Interrupt + ) +{ + return KeAcquireInterruptSpinLock(Interrupt); +} + +__inline +VOID +Mx::MxReleaseInterruptSpinLock( + _Inout_ PKINTERRUPT Interrupt, + _In_ KIRQL OldIrql + ) +{ + KeReleaseInterruptSpinLock(Interrupt, OldIrql); +} + +__inline +BOOLEAN +Mx::MxInsertQueueDpc( + __inout PRKDPC Dpc, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 +) +{ + return KeInsertQueueDpc(Dpc, SystemArgument1, SystemArgument2); +} + + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxkm.h new file mode 100644 index 00000000000..3933be326a3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxkm.h @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxKm.h + +Abstract: + + This file includes ntddk.h and + kernel mode versions of mode agnostic headers + + It also contains definitions pulled out from wdm.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#include +#include +#include + +#include +#include + +typedef KDEFERRED_ROUTINE MdDeferredRoutineType, *MdDeferredRoutine; +typedef EXT_CALLBACK MdExtCallbackType, *MdExtCallback; +#define FX_DEVICEMAP_PATH L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP\\" + +#include "MxGeneralKm.h" +#include "MxLockKm.h" +#include "MxPagedLockKm.h" +#include "MxEventKm.h" +#include "MxMemoryKm.h" +#include "MxTimerKm.h" +#include "MxWorkItemKm.h" +#include "MxDriverObjectKm.h" +#include "MxDeviceObjectKm.h" +#include "MxFileObjectKm.h" + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxlockkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxlockkm.h new file mode 100644 index 00000000000..eb019725974 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxlockkm.h @@ -0,0 +1,115 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxLockKm.h + +Abstract: + + Kernel mode implementation of lock + class defined in MxLock.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#include "DbgMacros.h" + +typedef KSPIN_LOCK MdLock; + +#include "MxLock.h" + +__inline +MxLock::MxLock( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; + + MxLock::Initialize(); +} + +__inline +VOID +MxLockNoDynam::Initialize( + ) +{ + KeInitializeSpinLock(&m_Lock); + + SET_DBGFLAG_INITIALIZED; +} + +_Acquires_lock_(this->m_Lock) +__drv_maxIRQL(DISPATCH_LEVEL) +__drv_setsIRQL(DISPATCH_LEVEL) +__inline +VOID +MxLockNoDynam::Acquire( + __out __drv_deref(__drv_savesIRQL) KIRQL * OldIrql + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeAcquireSpinLock(&m_Lock, OldIrql); +} + +_Acquires_lock_(this->m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +__inline +VOID +MxLockNoDynam::AcquireAtDpcLevel( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeAcquireSpinLockAtDpcLevel(&m_Lock); +} + +_Releases_lock_(this->m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +__inline +VOID +MxLockNoDynam::Release( + __drv_restoresIRQL KIRQL NewIrql + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeReleaseSpinLock(&m_Lock, NewIrql); +} + +_Releases_lock_(this->m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +__inline +VOID +MxLockNoDynam::ReleaseFromDpcLevel( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KeReleaseSpinLockFromDpcLevel(&m_Lock); +} + +__inline +VOID +MxLockNoDynam::Uninitialize( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; +} + +__inline +MxLock::~MxLock( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxmemorykm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxmemorykm.h new file mode 100644 index 00000000000..958953c7d9d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxmemorykm.h @@ -0,0 +1,47 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxMemoryKm.h + +Abstract: + + Kernel mode implementation of memory + class defined in MxMemory.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#include "MxMemory.h" + +__inline +PVOID +MxMemory::MxAllocatePoolWithTag( + __in POOL_TYPE PoolType, + __in SIZE_T NumberOfBytes, + __in ULONG Tag + ) +{ + return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag); +} + +__inline +VOID +MxMemory::MxFreePool( + __in PVOID Ptr + ) +{ + ExFreePool(Ptr); +} + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxpagedlockkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxpagedlockkm.h new file mode 100644 index 00000000000..deace98e4db --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxpagedlockkm.h @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxPagedLockKm.h + +Abstract: + + Kernel mode implementation of paged lock defined in + MxPagedLock.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#include "DbgMacros.h" + +typedef FAST_MUTEX MdPagedLock; + +#include "MxPagedLock.h" + +__inline +MxPagedLock::MxPagedLock( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; + + // + // Temporarily call initialize from c'tor + // so that we don't have to churn all of the KMDF code + // +#ifndef MERGE_COMPLETE + (VOID) MxPagedLock::Initialize(); +#endif +} + +__inline +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "_Must_inspect_result_ not needed in kernel mode as the function always succeeds"); +MxPagedLockNoDynam::Initialize( + ) +{ + ExInitializeFastMutex(&m_Lock); + + SET_DBGFLAG_INITIALIZED; + + return STATUS_SUCCESS; +} + +__drv_maxIRQL(APC_LEVEL) +__drv_setsIRQL(APC_LEVEL) +__drv_savesIRQLGlobal(FastMutexObject, this->m_Lock) +_Acquires_lock_(this->m_Lock) +__inline +VOID +MxPagedLockNoDynam::Acquire( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + ExAcquireFastMutex(&m_Lock); +} + +__inline +VOID +MxPagedLockNoDynam::AcquireUnsafe( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + ExAcquireFastMutexUnsafe(&m_Lock); +} + +_Must_inspect_result_ +__drv_maxIRQL(APC_LEVEL) +__drv_savesIRQLGlobal(FastMutexObject, this->m_Lock) +__drv_valueIs(==1;==0) +__drv_when(return==1, __drv_setsIRQL(APC_LEVEL)) +_When_(return==1, _Acquires_lock_(this->m_Lock)) +__inline +BOOLEAN +MxPagedLockNoDynam::TryToAcquire( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + return ExTryToAcquireFastMutex(&m_Lock); +} + +__drv_requiresIRQL(APC_LEVEL) +__drv_restoresIRQLGlobal(FastMutexObject, this->m_Lock) +_Releases_lock_(this->m_Lock) +__inline +VOID +MxPagedLockNoDynam::Release( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + ExReleaseFastMutex(&m_Lock); +} + +__inline +VOID +MxPagedLockNoDynam::ReleaseUnsafe( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + ExReleaseFastMutexUnsafe(&m_Lock); +} + + +__inline +VOID +MxPagedLockNoDynam::Uninitialize( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; +} + +__inline +MxPagedLock::~MxPagedLock( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxtimerkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxtimerkm.h new file mode 100644 index 00000000000..3284b451cb8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxtimerkm.h @@ -0,0 +1,291 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxTimerKm.h + +Abstract: + + Kernel mode implementation of timer defined in + MxTimer.h + +Author: + + +Revision History: + + + +--*/ + +#pragma once + +#define TolerableDelayUnlimited ((ULONG)-1) + +typedef +BOOLEAN +(*PFN_KE_SET_COALESCABLE_TIMER) ( + __inout PKTIMER Timer, + __in LARGE_INTEGER DueTime, + __in ULONG Period, + __in ULONG TolerableDelay, + __in_opt PKDPC Dpc + ); + +typedef struct _MdTimer { + + + // + // The timer period + // + LONG m_Period; + + // + // Tracks whether the ex timer is being used + // + BOOLEAN m_IsExtTimer; + +#pragma warning(push) +#pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union + + union { + struct { + // + // Callback function to be invoked upon timer expiration + // + MdDeferredRoutine m_TimerCallback; + KTIMER KernelTimer; + KDPC TimerDpc; + }; + + struct { + // + // Callback function to be invoked upon timer expiration + // + MdExtCallback m_ExTimerCallback; + PEX_TIMER m_KernelExTimer; + }; + }; + +#pragma warning(pop) + + // + // Context to be passed in to the callback function + // + PVOID m_TimerContext; + +} MdTimer; + +#include "MxTimer.h" + +MxTimer::MxTimer( + VOID + ) +{ + m_Timer.m_TimerContext = NULL; + m_Timer.m_TimerCallback = NULL; + m_Timer.m_Period = 0; + m_Timer.m_KernelExTimer = NULL; +} + +MxTimer::~MxTimer( + VOID + ) +{ + BOOLEAN wasCancelled; + + if (m_Timer.m_IsExtTimer && + m_Timer.m_KernelExTimer) { + wasCancelled = ExDeleteTimer(m_Timer.m_KernelExTimer, + TRUE, // Cancel if pending. We don't expect + // it to be pending though + FALSE,// Wait + NULL); + // + // Timer should not have been pending + // + ASSERT(wasCancelled == FALSE); + m_Timer.m_KernelExTimer = NULL; + } +} + +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "_Must_inspect_result_ not needed in kernel mode as the function always succeeds"); +MxTimer::Initialize( + __in_opt PVOID TimerContext, + __in MdDeferredRoutine TimerCallback, + __in LONG Period + ) +{ + m_Timer.m_TimerContext = TimerContext; + m_Timer.m_TimerCallback = TimerCallback; + m_Timer.m_Period = Period; + + KeInitializeTimerEx(&(m_Timer.KernelTimer), NotificationTimer); + KeInitializeDpc(&(m_Timer.TimerDpc), // Timer DPC + m_Timer.m_TimerCallback, // DeferredRoutine + m_Timer.m_TimerContext); // DeferredContext + + m_Timer.m_IsExtTimer = FALSE; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +MxTimer::InitializeEx( + __in_opt PVOID TimerContext, + __in MdExtCallback TimerCallback, + __in LONG Period, + __in ULONG TolerableDelay, + __in BOOLEAN UseHighResolutionTimer + ) +/*++ + +Routine Description: + + Initializes an Ex timer. By invoking this routine instead of + Initialize, the client is implicitly declaring that it wants + to use the new timers + +Arguments: + + TimerContext - Context to be passed back with the cllback + TimerCallback - Callback to be invoked when the timer fires + Period - Period in ms + TolerableDelay - Tolerable delay in ms + UseHighResolutionTimer- Indicates whether to use the high + resolution timers + +Returns: + + Status + +--*/ + +{ + NTSTATUS status; + ULONG attributes = 0; + + m_Timer.m_TimerContext = TimerContext; + m_Timer.m_ExTimerCallback = TimerCallback; + m_Timer.m_Period = Period; + + if (TolerableDelay != 0) { + + attributes |= EX_TIMER_NO_WAKE; + + } else if (UseHighResolutionTimer) { + + attributes |= EX_TIMER_HIGH_RESOLUTION; + } + + m_Timer.m_KernelExTimer = ExAllocateTimer(m_Timer.m_ExTimerCallback, + TimerContext, + attributes); + if (m_Timer.m_KernelExTimer) { + + status = STATUS_SUCCESS; + + } else { + + status = STATUS_INSUFFICIENT_RESOURCES; + } + + m_Timer.m_IsExtTimer = TRUE; + + return status; +} + + +__inline +BOOLEAN +MxTimer::StartWithReturn( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay + ) +{ + if (m_Timer.m_IsExtTimer) { + + EXT_SET_PARAMETERS parameters; + + ExInitializeSetTimerParameters(¶meters); + + // + // We get the delay in ms but the underlying API needs it in 100 ns + // units. Convert tolerable delay from ms to 100 ns. However, + // MAXULONG (TolerableDelayUnlimited) has a special meaning that the + // system should never be woken up, so we assign the corresponding + // special value for Ex timers + // + if (TolerableDelay == TolerableDelayUnlimited) { + parameters.NoWakeTolerance = EX_TIMER_UNLIMITED_TOLERANCE; + } else { + parameters.NoWakeTolerance = ((LONGLONG) TolerableDelay) * 10 * 1000; + } + + return ExSetTimer(m_Timer.m_KernelExTimer, + DueTime.QuadPart, + (((LONGLONG) m_Timer.m_Period) * 10 * 1000), + ¶meters); + + } else { + + return KeSetCoalescableTimer(&(m_Timer.KernelTimer), + DueTime, + m_Timer.m_Period, + TolerableDelay, + &(m_Timer.TimerDpc)); + } + +} + + +VOID +MxTimer::Start( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay + ) +{ + if (m_Timer.m_IsExtTimer) { + + StartWithReturn(DueTime,TolerableDelay); + + } else { + KeSetCoalescableTimer(&(m_Timer.KernelTimer), + DueTime, + m_Timer.m_Period, + TolerableDelay, + &(m_Timer.TimerDpc)); + } + + return; +} + +_Must_inspect_result_ +BOOLEAN +MxTimer::Stop( + VOID + ) +{ + BOOLEAN bRetVal; + + if (m_Timer.m_IsExtTimer) { + bRetVal = ExCancelTimer(m_Timer.m_KernelExTimer, NULL); + + } else { + bRetVal = KeCancelTimer(&(m_Timer.KernelTimer)); + } + + return bRetVal; +} + +VOID +MxTimer::FlushQueuedDpcs( + VOID + ) +{ + Mx::MxFlushQueuedDpcs(); +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxworkitemkm.h b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxworkitemkm.h new file mode 100644 index 00000000000..930476b7f6e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/km/mxworkitemkm.h @@ -0,0 +1,109 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxWorkItemKm.h + +Abstract: + + Kernel mode implementation of work item + class defined in MxWorkItem.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +typedef IO_WORKITEM_ROUTINE MX_WORKITEM_ROUTINE, *PMX_WORKITEM_ROUTINE; +typedef PIO_WORKITEM MdWorkItem; + +#include "MxWorkItem.h" + +__inline +MxWorkItem::MxWorkItem( + ) +{ + m_WorkItem = NULL; +} + +_Must_inspect_result_ +__inline +NTSTATUS +MxWorkItem::Allocate( + __in MdDeviceObject DeviceObject, + __in_opt PVOID ThreadPoolEnv + ) +{ + UNREFERENCED_PARAMETER(ThreadPoolEnv); + + m_WorkItem = IoAllocateWorkItem(DeviceObject); + if (NULL == m_WorkItem) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + return STATUS_SUCCESS; +} + +__inline +VOID +MxWorkItem::Enqueue( + __in PMX_WORKITEM_ROUTINE Callback, + __in PVOID Context + ) +{ + IoQueueWorkItem( + m_WorkItem, + Callback, + DelayedWorkQueue, + Context + ); +} + +__inline +MdWorkItem +MxWorkItem::GetWorkItem( + ) +{ + return m_WorkItem; +} + +__inline +VOID +MxWorkItem::_Free( + __in MdWorkItem Item + ) +{ + IoFreeWorkItem(Item); +} + +__inline +VOID +MxWorkItem::Free( + ) +{ + if (NULL != m_WorkItem) { + MxWorkItem::_Free(m_WorkItem); + m_WorkItem = NULL; + } +} + +// +// FxAutoWorkitem +// +__inline +MxAutoWorkItem::~MxAutoWorkItem( + ) +{ + this->Free(); +} + + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/errtostatus.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/errtostatus.h new file mode 100644 index 00000000000..721066110b6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/errtostatus.h @@ -0,0 +1,2036 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +// +// This is a generated file. Please do not modify it directly. +// + +#pragma once + +typedef struct _ERROR_BUCKET { + ULONG BaseErrorCode; //Starting error code in the bucket + USHORT RunLength; //Number of contiguous error codes starting with BaseErrorCode +} ERROR_BUCKET, *PERROR_BUCKET; + +const NTSTATUS INVALID_STATUS = (ULONG)(-1); + +CONST NTSTATUS ErrorTable[] = { + 0x0, + 0xc0000010, + 0xc000000f, + 0xc000003a, + 0xc000011f, + 0xc0000022, + 0xc0000008, + 0xc0000017, + 0xc0000087, + 0xc00000d4, + 0x80000006, + 0xc00000a2, + 0xc00000a3, + 0xc0000184, + 0xc000003f, + 0xc0000004, + 0xc0000015, + 0x8000000e, + 0xc0000001, + 0xc0000043, + 0xc0000054, + 0xc0000012, + 0xc0000011, + 0xc00000bb, + 0xc00000bc, + 0xc00000bd, + 0xc00000be, + 0xc00000bf, + 0xc00000c0, + 0xc00000c1, + 0xc00000c2, + 0xc00000c3, + 0xc000013e, + 0xc00000c5, + 0xc00000c6, + 0xc00000c7, + 0xc00000c8, + 0xc00000c9, + 0xc00000ca, + 0xc00000cb, + 0xc00000cc, + 0xc00000cd, + 0xc00000ce, + 0xc00000cf, + 0xc00000d0, + 0xc00000d1, + 0xc00002ea, + 0xc000006a, + 0xc000000d, + 0xc00000d2, + 0xc000014b, + 0xc000007f, + 0xc00000b5, + 0xc0000023, + 0xc0000033, + 0xc0000148, + 0xc0000135, + 0xc000007a, + 0x80, + 0xc0000101, + 0xc0000086, + 0xc000004a, + 0xc000002a, + 0xc0000039, + 0x80000011, + 0xc0000138, + 0xc0000035, + 0xc000007b, + 0xc0000100, + 0xc0000106, + 0xc0000901, + 0xc0000902, + 0xc0000903, + 0xc0000904, + 0xc0000905, + 0xc0000906, + 0xc0000907, + 0xc00000ad, + 0xc00000ae, + 0xc00000d9, + 0xc00000b0, + 0xc0000016, + 0xc00000d6, + 0x80000013, + 0x80000014, + 0x8000001a, + 0xc0000103, + 0xc000004f, + 0xc0000264, + 0xc0000047, + 0x8000000d, + 0xc00000e2, + 0xc00000e3, + 0xc0000304, + 0xc000019e, + 0xc000019f, + 0xc00001a0, + 0xc00001a1, + 0xc00001a3, + 0xc00001a4, + 0xc0000109, + 0xc0000018, + 0xc0000095, + 0xc00000b2, + 0xc00000b3, + 0xc0000421, + 0xc0000113, + 0x4000001d, + 0xc000026f, + 0xc000000c, + 0xc0000027, + 0xc0000028, + 0xc0000029, + 0xc000002e, + 0xc000002f, + 0xc0000031, + 0xc0000038, + 0xc00000aa, + 0xc00000b7, + 0xc00000b8, + 0xc00000b9, + 0xc00000d3, + 0xc00000d8, + 0xc00000db, + 0xc00000ea, + 0xc00000eb, + 0xc00000ec, + 0xc00000ff, + 0xc000010c, + 0xc0000118, + 0xc0000119, + 0xc000011a, + 0xc0000129, + 0xc000012a, + 0xc000012c, + 0xc0000132, + 0xc0000134, + 0xc0000136, + 0xc0000137, + 0xc000013a, + 0xc0000143, + 0xc0000144, + 0xc0000145, + 0xc0000146, + 0xc0000428, + 0xc0000147, + 0xc000014a, + 0xc000014e, + 0xc000015e, + 0xc0000161, + 0xc0000163, + 0xc0000164, + 0xc000016e, + 0xc0000187, + 0xc0000191, + 0xc000019c, + 0xc0000218, + 0xc0000219, + 0xc000021a, + 0xc000021b, + 0xc000021d, + 0xc000021e, + 0xc000021f, + 0xc0000222, + 0xc0000223, + 0xc0000226, + 0xc0000228, + 0xc000022c, + 0xc000022e, + 0xc000022f, + 0xc0000231, + 0xc0000232, + 0xc0000242, + 0xc0000244, + 0xc0000245, + 0xc0000250, + 0xc0000251, + 0xc0000252, + 0xc0000254, + 0xc0000255, + 0xc0000256, + 0xc0000258, + 0xc000025a, + 0xc000025b, + 0xc000025c, + 0xc000025f, + 0xc0000260, + 0xc0000261, + 0xc0000266, + 0xc0000268, + 0xc0000269, + 0xc000026b, + 0xc0000271, + 0xc0000273, + 0xc0000282, + 0xc00002a0, + 0xc00002b3, + 0xc00002b4, + 0xc00002b5, + 0xc00002b9, + 0xc00002c2, + 0xc00002c4, + 0xc00002c8, + 0xc00002ce, + 0xc00002d1, + 0xc00002d2, + 0xc00002de, + 0xc00002e8, + 0xc00002eb, + 0xc0000353, + 0xc0000355, + 0xc000028c, + 0xc000035f, + 0xc0000365, + 0xc0000366, + 0xc0000368, + 0xc0000369, + 0xc000036a, + 0xc000036d, + 0xc000036e, + 0xc000038e, + 0xc0000407, + 0xc0000411, + 0xc0000427, + 0xc0000420, + 0xc0140001, + 0xc0009898, + 0xc0040035, + 0xc0040036, + 0xc0040037, + 0xc0040038, + 0x80000007, + 0x8000000a, + 0x80000017, + 0x80000018, + 0x80000020, + 0x8000000c, + 0x8000002d, + 0x80000026, + 0x80000028, + 0x80000029, + 0x8000002a, + 0x8000002b, + 0x8000002c, + 0x80010001, + 0x40010001, + 0x40010002, + 0x40010003, + 0x40010004, + 0x40010005, + 0x40010006, + 0x40010007, + 0x40010008, + 0x40010009, + 0x40000000, + 0x40000001, + 0x40000003, + 0x40000004, + 0x40000005, + 0x40000007, + 0x4000000a, + 0x4000000b, + 0x4000000e, + 0x4000000f, + 0x40000010, + 0x40000011, + 0x40000012, + 0x40000013, + 0x40000014, + 0x40000015, + 0x40000016, + 0x40000017, + 0x40000018, + 0x40000019, + 0x4000001a, + 0x4000001b, + 0x40000023, + 0x40000024, + 0x40000025, + 0x40000026, + 0x40000027, + 0x40000029, + 0x4000002a, + 0x4000002b, + 0x4000002c, + 0x4000002d, + 0x40000294, + 0x1, + 0x2, + 0x3, + 0x3f, + 0xbf, + 0xc0, + 0x100, + 0x101, + 0xc000042c, + 0x104, + 0x108, + 0x109, + 0x10a, + 0x10b, + 0x10e, + 0x110, + 0x111, + 0x112, + 0x113, + 0x114, + 0x115, + 0x116, + 0x117, + 0x118, + 0x119, + 0x120, + 0x122, + 0x123, + 0x124, + 0x125, + 0x126, + 0x127, + 0x128, + 0x367, + 0x10001, + 0x10002, + 0xc0000423, + 0xc0000426, + 0xc0000429, + 0xc000042a, + 0xc0000709, + 0xc0000800, + 0x4000002f, + 0x40000031, + 0xc0000713, + 0x40000032, + 0xc0000372, + 0x40000033, + 0xc000a080, + 0xc000a081, + 0xc000a082, + 0xc0000908, + 0x215, + 0x8000002e, + 0xc0000909, + 0x216, + 0x8000002f, + 0xc00001a2, + 0xc0000120, + 0x103, + 0xc0000005, + 0xc0000006, + 0xc00000fd, + 0xc000014f, + 0xc0000098, + 0xc0000159, + 0xc000007c, + 0xc000014c, + 0x40000009, + 0xc000014d, + 0xc000015c, + 0xc000017c, + 0xc000017d, + 0xc0000180, + 0xc0000181, + 0x10c, + 0xc000010e, + 0xc000025e, + 0x8000001e, + 0x8000001b, + 0x8000001f, + 0x80000021, + 0x80000022, + 0xc0000172, + 0xc0000173, + 0xc0000174, + 0xc0000175, + 0xc0000176, + 0x8000001c, + 0x8000001d, + 0xc0000178, + 0xc0000717, + 0xc0000142, + 0xc00002fe, + 0xc00000e9, + 0xc0000150, + 0xc000016c, + 0x40000008, + 0x4000000c, + 0xc0000165, + 0xc0000166, + 0xc0000167, + 0xc0000168, + 0xc0000169, + 0xc000016a, + 0xc000016b, + 0xc0000177, + 0xc0000205, + 0xc0000194, + 0xc0000220, + 0xc0000265, + 0xc0000283, + 0xc0000284, + 0xc0000285, + 0xc0000286, + 0xc0000287, + 0x80000288, + 0x80000289, + 0xc000009d, + 0xc0000225, + 0xc0000272, + 0xc0000230, + 0xc000029f, + 0xc00002b7, + 0xc00002b8, + 0xc00002cf, + 0xc000026d, + 0xc0000122, + 0xc0000207, + 0xc0000195, + 0xc0000196, + 0xc0000243, + 0xc0000236, + 0xc0000237, + 0xc0000238, + 0xc0000239, + 0xc000023a, + 0xc000023b, + 0xc000023c, + 0xc000023d, + 0xc000023e, + 0xc000023f, + 0xc0000240, + 0xc0000241, + 0xc000022d, + 0xc0000246, + 0xc0000247, + 0xc0000248, + 0xc0000160, + 0xc00002cc, + 0xc0000300, + 0xc00002ff, + 0xc0000350, + 0xc000035d, + 0xc0000361, + 0xc00002c9, + 0xc0000320, + 0xc0000321, + 0xc0000388, + 0xc000036c, + 0xc000036f, + 0xc0000227, + 0xc0000409, + 0xc0000410, + 0xc0000354, + 0xc0000412, + 0xc0000414, + 0xc0000417, + 0xc0000432, + 0xc0000450, + 0xc000042b, + 0xc0000712, + 0xc0000802, + 0xc0000804, + 0xc0000446, + 0x106, + 0x107, + 0x10d, + 0x40000006, + 0x4000000d, + 0xc0000058, + 0xc0000059, + 0xc000005a, + 0xc000005b, + 0xc000005c, + 0xc000005d, + 0xc000005e, + 0xc000005f, + 0xc0000060, + 0xc0000061, + 0xc0000062, + 0xc0000063, + 0xc0000064, + 0xc0000065, + 0xc0000066, + 0xc0000067, + 0xc0000068, + 0xc0000069, + 0xc000006b, + 0xc000006c, + 0xc000006d, + 0xc000006e, + 0xc000006f, + 0xc0000070, + 0xc0000071, + 0xc0000072, + 0xc0000073, + 0xc0000074, + 0xc0000075, + 0xc0000076, + 0xc0000077, + 0xc0000078, + 0xc0000079, + 0xc000007d, + 0xc0000080, + 0xc0000081, + 0xc0000084, + 0xc0000099, + 0xc00000a4, + 0xc00000a5, + 0xc00000a6, + 0xc00000a7, + 0xc00000a8, + 0xc00000d7, + 0xc00000da, + 0xc00000dc, + 0xc00000dd, + 0xc00000de, + 0xc00000df, + 0xc00000e0, + 0xc00000e1, + 0xc00000e4, + 0xc00000e5, + 0xc00000e6, + 0xc00000e7, + 0xc00000ed, + 0xc00000ee, + 0xc00000fe, + 0xc0000104, + 0xc0000105, + 0xc000010b, + 0xc000010d, + 0xc000011c, + 0xc000011d, + 0xc0000124, + 0xc0000125, + 0xc0000126, + 0xc0000127, + 0xc000012b, + 0xc0000151, + 0xc0000152, + 0xc0000153, + 0xc0000154, + 0xc0000155, + 0xc0000156, + 0xc0000157, + 0xc0000158, + 0xc000015a, + 0xc000015b, + 0xc000015d, + 0xc000017a, + 0xc000017b, + 0xc000017e, + 0xc000017f, + 0x8000000b, + 0xc0000102, + 0xc0000032, + 0xc0000202, + 0xc0000259, + 0x80090322, + 0xc00002c3, + 0xc0000133, + 0xc00002e9, + 0xc0000117, + 0xc000009a, + 0xc00000a1, + 0xc0000007, + 0xc000012d, + 0x102, + 0xc0000715, + 0xc000a083, + 0xc000a084, + 0xc0000453, + 0xc000a085, + 0xc000a086, + 0xc0000454, + 0xc000018e, + 0xc000018f, + 0xc0000188, + 0xc0000197, + 0xc0000500, + 0xc0000501, + 0xc0000502, + 0xc00002b6, + 0xc0000602, + 0xc0020001, + 0xc0020002, + 0xc0020004, + 0xc0020005, + 0xc0020006, + 0xc0020007, + 0xc0020008, + 0xc0020009, + 0xc002000a, + 0xc002000b, + 0xc002000c, + 0xc002000d, + 0xc002000e, + 0xc002000f, + 0xc0020010, + 0xc0020011, + 0xc0020012, + 0xc0020013, + 0xc0020014, + 0xc0020015, + 0xc0020016, + 0xc0020017, + 0xc0020018, + 0xc0020019, + 0xc002001a, + 0xc002001b, + 0xc002001c, + 0xc002001d, + 0xc0020064, + 0xc002001f, + 0xc0020021, + 0xc0020022, + 0xc0020023, + 0xc0020024, + 0xc0020025, + 0xc0020026, + 0xc0020028, + 0xc0020029, + 0xc002002a, + 0xc002002b, + 0xc002002c, + 0xc002002d, + 0xc002002e, + 0xc002002f, + 0xc0020030, + 0xc0020031, + 0xc0020032, + 0xc0020033, + 0xc0020034, + 0xc0020035, + 0xc0020036, + 0xc0020037, + 0xc0020038, + 0xc0020039, + 0xc002003a, + 0xc002003b, + 0xc002003c, + 0xc002003d, + 0xc002003e, + 0xc002003f, + 0xc0020040, + 0xc0020041, + 0xc0020042, + 0xc0020043, + 0xc0020044, + 0xc0020045, + 0xc0020046, + 0xc0020047, + 0xc0020048, + 0xc0030001, + 0xc0030002, + 0xc0030003, + 0xc0030006, + 0xc0030007, + 0xc0030008, + 0xc0030009, + 0xc003000a, + 0xc003000b, + 0xc003000c, + 0xc00000e8, + 0xc0000014, + 0xc000018a, + 0xc000018b, + 0xc000018c, + 0xc000018d, + 0xc0000190, + 0xc0020049, + 0xc0000192, + 0xc0000193, + 0x80000023, + 0xc002004a, + 0xc0000198, + 0xc0000199, + 0xc000019a, + 0xc000019b, + 0x80000024, + 0xc0000089, + 0xc000008a, + 0xc000008b, + 0xc0000204, + 0xc0000044, + 0xc002004f, + 0xc0020050, + 0xc0020051, + 0xc0020052, + 0xc0020053, + 0xc0020054, + 0xc0020055, + 0x40020056, + 0xc0020057, + 0xc0020058, + 0xc0030059, + 0xc003005a, + 0xc003005b, + 0xc003005c, + 0xc003005d, + 0xc003005e, + 0xc0020065, + 0xc002004b, + 0xc002004c, + 0xc002004d, + 0xc0000224, + 0xc0000233, + 0xc0000234, + 0x400200af, + 0xc0020062, + 0xc0020063, + 0xc003005f, + 0xc0030060, + 0xc0030061, + 0xc0000279, + 0xc0000280, + 0x80090317, + 0xc0000401, + 0xc0000402, + 0xc0000403, + 0xc0000413, + 0xc0000418, + 0xc000026c, + 0xc0000107, + 0x80000025, + 0xc0000108, + 0xc0040039, + 0xc0000295, + 0xc0000296, + 0xc0000297, + 0xc0000298, + 0xc0000303, + 0xc0000301, + 0xc0000302, + 0xc00002c6, + 0xc00002c7, + 0xc0220103, + 0xc00002ca, + 0x80000027, + 0xc0000267, + 0xc000029d, + 0xc000029e, + 0xc0000275, + 0xc00002b2, + 0xc0000278, + 0xc0000276, + 0xc0000277, + 0xc000022b, + 0xc0130001, + 0xc0130002, + 0xc0130003, + 0xc0130004, + 0xc0130005, + 0xc0130006, + 0xc0130007, + 0xc0130008, + 0xc0130009, + 0xc013000a, + 0xc013000b, + 0xc013000c, + 0xc013000d, + 0xc013000e, + 0xc013000f, + 0xc0130010, + 0xc0130012, + 0xc0130014, + 0xc0130015, + 0xc0130016, + 0x80130001, + 0x80130002, + 0x80130003, + 0x80130004, + 0x80130005, + 0xc0130013, + 0xc0130011, + 0xc0130017, + 0x80090329, + 0x80090330, + 0xc0000293, + 0xc0000291, + 0xc0000292, + 0xc0000352, + 0xc0000441, + 0xc0000442, + 0xc0000443, + 0xc0000444, + 0xc0000445, + 0xc000021c, + 0xc01a0001, + 0xc01a0002, + 0xc01a0003, + 0xc01a0004, + 0xc01a0005, + 0xc01a0006, + 0xc01a0007, + 0xc01a0008, + 0xc01a0009, + 0xc01a000a, + 0xc01a000b, + 0x401a000c, + 0xc01a000d, + 0xc01a000e, + 0xc01a000f, + 0xc01a0010, + 0xc01a0011, + 0xc01a0012, + 0xc01a0013, + 0xc01a0014, + 0xc01a0015, + 0xc01a0016, + 0xc01a0017, + 0xc01a0018, + 0xc01a0019, + 0xc01a001a, + 0xc01a001b, + 0xc01a001c, + 0xc01a001d, + 0x80190009, + 0xc01a001e, + 0xc01a001f, + 0xc01a0020, + 0xc01a0021, + 0xc01a0022, + 0xc01a0023, + 0xc01a0024, + 0xc01a0025, + 0xc01a0026, + 0xc01a0027, + 0xc01a0028, + 0xc01a0029, + 0xc01a002a, + 0xc01a002b, + 0xc01a002c, + 0xc01a002d, + 0xc01a002e, + 0xc01a002f, + 0xc01a0030, + 0xc0190002, + 0xc0190003, + 0xc0190013, + 0xc0190014, + 0xc0190015, + 0xc0190016, + 0xc0190004, + 0x202, + 0xc0190007, + 0xc0190012, + 0xc019000f, + 0xc0190010, + 0xc0190011, + 0xc0190017, + 0xc0190018, + 0xc019004e, + 0xc019004f, + 0xc0190050, + 0xc0190051, + 0xc0190052, + 0xc0190053, + 0xc0190054, + 0xc0190055, + 0xc0190057, + 0xc0190058, + 0xc019005b, + 0xc019005c, + 0xc019005d, + 0xc019005e, + 0xc019005f, + 0xc0190001, + 0xc0190005, + 0xc0190006, + 0xc0190008, + 0xc019000a, + 0xc019000b, + 0xc0190021, + 0xc0190022, + 0xc0190023, + 0xc0190024, + 0xc0190025, + 0xc0190026, + 0xc019000c, + 0xc0190028, + 0x80190029, + 0xc0190030, + 0x80190031, + 0xc0190032, + 0xc0190033, + 0x40190034, + 0x40190035, + 0xc0190036, + 0xc0190037, + 0xc0190038, + 0xc0190039, + 0xc019003a, + 0xc019003b, + 0xc019003c, + 0xc019003d, + 0xc019003e, + 0xc019003f, + 0xc0190019, + 0xc0190040, + 0x80190041, + 0x80190042, + 0xc0190043, + 0xc0190044, + 0xc0190045, + 0xc0190046, + 0xc0190047, + 0xc0190048, + 0x80000803, + 0xc0190049, + 0xc019004a, + 0xc019004b, + 0xc019004c, + 0xc019004d, + 0xc0000805, + 0xc0190056, + 0xc0000806, + 0xc0190059, + 0xc019005a, + 0xc0190060, + 0xc0190061, + 0xc00a0001, + 0xc00a0002, + 0xc00a0003, + 0xc00a002f, + 0xc00a0006, + 0xc00a0007, + 0xc00a0008, + 0xc00a0009, + 0xc00a000a, + 0xc00a000b, + 0xc00a000c, + 0xc00a000d, + 0xc00a000e, + 0xc00a000f, + 0xc00a0010, + 0xc00a0015, + 0xc00a0016, + 0xc00a0017, + 0xc00a0018, + 0xc00a0022, + 0xc00a0037, + 0xc00a0024, + 0xc00a0026, + 0xc00a0027, + 0xc00a0028, + 0xc00a002a, + 0xc00a002b, + 0xc00a002e, + 0xc00a0030, + 0xc00a0031, + 0xc00a0034, + 0xc00a0033, + 0xc00a0013, + 0xc00a0012, + 0xc00a0014, + 0xc00a0036, + 0xc00a0035, + 0xc00a0032, + 0x400a0004, + 0x400a0005, + 0xc00a0038, + 0xc00a0039, + 0x121, + 0xc00002a1, + 0xc00002a2, + 0xc00002a3, + 0xc00002a4, + 0xc00002a5, + 0xc00002a6, + 0xc00002a7, + 0xc00002a8, + 0xc00002a9, + 0xc00002aa, + 0xc00002ab, + 0xc00002ac, + 0xc00002ad, + 0xc00002ae, + 0xc00002af, + 0xc00002b0, + 0xc0000299, + 0xc000029a, + 0xc000029b, + 0xc00002c1, + 0x40000370, + 0xc00002b1, + 0xc00002cb, + 0xc00002cd, + 0xc00002d0, + 0xc00002d4, + 0xc00002d5, + 0xc00002d6, + 0xc00002d7, + 0xc00002d8, + 0xc00002d9, + 0xc00002da, + 0xc00002db, + 0xc00002dc, + 0xc00002df, + 0xc00002e0, + 0xc00002e1, + 0xc00002e2, + 0xc0000419, + 0xc00002e3, + 0xc00002e4, + 0xc00002e5, + 0xc00002e6, + 0xc00002e7, + 0xc00002ec, + 0xc00002ed, + 0xc0000404, + 0xc0000357, + 0xc0000358, + 0xc0000405, + 0xc0000406, + 0xc0000801, + 0xc0000371, + 0xc000041a, + 0xc000041b, + 0xc000041c, + 0xc000a087, + 0xc000a088, + 0xc0360001, + 0xc0360002, + 0xc0360003, + 0xc0360004, + 0xc0360005, + 0xc0360006, + 0xc0360007, + 0xc0360008, + 0xc0360009, + 0xc0368000, + 0xc0368001, + 0xc0368002, + 0xc0368003, + 0xc0368004, + 0xc0368005, + 0xc0368006, + 0xc0150001, + 0xc0150002, + 0xc0150003, + 0xc0150004, + 0xc0150005, + 0xc0150006, + 0xc0150007, + 0xc0150008, + 0xc0150009, + 0xc015000a, + 0xc015000b, + 0xc015000e, + 0xc015001b, + 0xc015000c, + 0xc0150014, + 0xc0150015, + 0xc015000f, + 0xc0150010, + 0xc0150011, + 0xc0150013, + 0x4015000d, + 0xc0150012, + 0xc0150016, + 0xc0150017, + 0xc0150018, + 0xc0150019, + 0xc015001a, + 0xc0150020, + 0xc0150021, + 0xc015001c, + 0xc015001d, + 0xc015001e, + 0xc015001f, + 0xc0150022, + 0xc0150023, + 0xc0150024, + 0xc0150025, + 0xc0150026, + 0xc0150027, + 0xc00b0001, + 0xc00b0002, + 0xc00b0003, + 0xc00b0004, + 0xc00b0005, + 0xc00b0006, + 0xc00b0007, + 0xc0000451, + 0xc0000452, + 0xc000a100, + 0xc000a101, + 0x1c0001, + 0xc01d0001, + 0xc01d0002, + 0x401e0307, + 0x401e031e, + 0x401e034b, + 0x401e034c, + 0x401e0351, + 0x40230001, + 0x401e000a, + 0x401e042f, + 0x401e0437, + 0x401e0439, + 0x401e043a, + 0x80000001, + 0x80000003, + 0x80000004, + 0xc0000305, + 0xc0000306, + 0xc0000307, + 0xc0000308, + 0xc0000309, + 0xc000030a, + 0xc000030b, + 0xc000a000, + 0xc0000384, + 0xc0000386, + 0xc000038f, + 0xc000a001, + 0xc00002ee, + 0xc00002ef, + 0xc00002f1, + 0xc00002f2, + 0xc00002f3, + 0xc00002f4, + 0xc00002f5, + 0xc00002f6, + 0xc00002f7, + 0xc00002f8, + 0xc00002f9, + 0xc00002fa, + 0xc00002fb, + 0xc00002fc, + 0xc00002fd, + 0xc0000351, + 0xc000035b, + 0xc0000322, + 0xc0000389, + 0xc000038a, + 0xc000038b, + 0xc000038c, + 0xc000038d, + 0xc000040a, + 0xc000040b, + 0xc000040c, + 0xc000040d, + 0xc000040e, + 0xc000040f, + 0xc000042d, + 0xc000042e, + 0xc0000440, + 0xc0000603, + 0xc0000383, + 0xc0000385, + 0xc0000387, + 0xc0000380, + 0xc0000381, + 0xc0000382, + 0xc01c0001, + 0xc01c0002, + 0xc01c0003, + 0xc01c0004, + 0xc01c0005, + 0xc01c0006, + 0xc01c0007, + 0xc01c0008, + 0xc01c0009, + 0xc01c000a, + 0xc01c000b, + 0xc01c000c, + 0xc01c000d, + 0xc01c000e, + 0xc01c000f, + 0xc01c0010, + 0xc01c0011, + 0xc01c0012, + 0xc01c0013, + 0xc01c0014, + 0xc01c0015, + 0xc01c0016, + 0xc01c0017, + 0xc01c0018, + 0xc01c0019, + 0xc01c001a, + 0xc01c001b, + 0xc01c001c, + 0xc01c0020, + 0xc0000415, + 0xc0210000, + 0xc0210001, + 0xc0210009, + 0xc0210002, + 0xc0210003, + 0xc0210004, + 0xc0210005, + 0xc021000a, + 0xc021000b, + 0xc021000c, + 0xc021000d, + 0xc021000e, + 0xc021000f, + 0xc0210017, + 0xc0210010, + 0xc0210011, + 0xc0210012, + 0xc0210013, + 0xc0210014, + 0xc0210015, + 0xc0210016, + 0xc0210018, + 0xc0210019, + 0xc021001a, + 0xc021001b, + 0xc021001c, + 0xc0210006, + 0xc0210008, + 0xc0210007, + 0xc021001e, + 0xc0210021, + 0xc021001d, + 0xc0210022, + 0xc0210023, + 0xc0210024, + 0xc0210025, + 0x80210002, + 0xc0210026, + 0xc0210030, + 0xc0210027, + 0xc0210028, + 0xc0210029, + 0xc0220001, + 0xc0220002, + 0xc0220003, + 0xc0220004, + 0xc0220005, + 0xc0220006, + 0xc0220007, + 0xc0220008, + 0xc0220009, + 0xc022000a, + 0xc022000b, + 0xc022000c, + 0xc022000d, + 0xc022000e, + 0xc022000f, + 0xc0220010, + 0xc0220011, + 0xc0220012, + 0xc0220013, + 0xc0220014, + 0xc0220015, + 0xc0220016, + 0xc0220017, + 0xc0220018, + 0xc0220019, + 0xc022001a, + 0xc022001b, + 0xc022001c, + 0xc022001d, + 0xc022001e, + 0xc022001f, + 0xc0220020, + 0xc0220021, + 0xc0220022, + 0xc0220023, + 0xc0220024, + 0xc0220025, + 0xc0220026, + 0xc0220027, + 0xc0220028, + 0xc0220029, + 0xc022002a, + 0xc022002b, + 0xc022002c, + 0xc022002d, + 0xc022002e, + 0xc022002f, + 0xc0220030, + 0xc0220031, + 0xc0220032, + 0xc0220033, + 0xc0220034, + 0xc0220035, + 0xc0220036, + 0xc0220037, + 0xc0220038, + 0xc0220039, + 0xc022003a, + 0xc022003b, + 0xc022003c, + 0xc0220104, + 0xc0230002, + 0xc0230004, + 0xc0230005, + 0xc0230006, + 0xc0230007, + 0xc0230008, + 0xc0230009, + 0xc023000a, + 0xc023000b, + 0xc023000c, + 0xc023000d, + 0xc023000f, + 0xc0230010, + 0xc0230011, + 0xc0230014, + 0xc0230015, + 0xc0230016, + 0xc0230017, + 0xc0230018, + 0xc0230019, + 0xc023001a, + 0xc023001b, + 0xc023001c, + 0xc023001d, + 0xc023001e, + 0xc023001f, + 0xc0230022, + 0xc023002a, + 0xc023002b, + 0xc023002c, + 0xc023002d, + 0xc023002e, + 0xc023002f, + 0xc02300bb, + 0xc0232000, + 0xc0232001, + 0xc0232002, + 0xc0232003, + 0xc0232004, + 0x80370001, + 0x80380001, + 0x80380002, + 0x80390001, + 0x80390003, + 0x803a0001, + 0xc000001d, + 0xc0000025, + 0xc0000026, + 0xc000002b, + 0xc000008c, + 0xc000008d, + 0xc000008e, + 0xc000008f, + 0xc0000090, + 0xc0000091, + 0xc0000092, + 0xc0000093, + 0xc0000094, + 0xc0000096, + 0xc0000356, + 0xc000035e, + 0x40000034, + 0xc01e05e8, + 0xc01d0003, + 0xc01d0004, + 0xc01d0005, + 0xc01d0006, + 0xc01d0007, + 0xc01d0008, + 0xc01d0009, + 0xc01d000a, + 0xc01e0000, + 0xc01e0001, + 0xc01e0002, + 0xc01e0003, + 0xc01e0004, + 0xc01e0005, + 0xc01e0006, + 0xc01e0007, + 0xc01e0008, + 0xc01e0009, + 0xc01e000b, + 0xc01e000c, + 0xc01e0100, + 0xc01e0101, + 0xc01e0102, + 0xc01e0103, + 0xc01e0104, + 0xc01e0105, + 0xc01e0106, + 0xc01e0107, + 0xc01e0108, + 0xc01e0109, + 0xc01e0110, + 0xc01e0111, + 0xc01e0112, + 0xc01e0113, + 0xc01e0114, + 0xc01e0115, + 0xc01e0116, + 0xc01e0200, + 0xc01e0300, + 0xc01e0301, + 0xc01e0302, + 0xc01e0303, + 0xc01e0304, + 0xc01e0305, + 0xc01e0306, + 0xc01e0308, + 0xc01e0309, + 0xc01e030a, + 0xc01e030b, + 0xc01e030c, + 0xc01e0310, + 0xc01e0311, + 0xc01e0312, + 0xc01e0313, + 0xc01e0314, + 0xc01e0315, + 0xc01e0316, + 0xc01e0317, + 0xc01e0318, + 0xc01e0319, + 0xc01e031a, + 0xc01e031b, + 0xc01e031c, + 0xc01e031d, + 0xc01e031f, + 0xc01e0320, + 0xc01e0321, + 0xc01e0322, + 0xc01e0323, + 0xc01e0324, + 0xc01e0325, + 0xc01e0326, + 0xc01e0327, + 0xc01e0328, + 0xc01e0329, + 0xc01e032a, + 0xc01e032b, + 0xc01e032c, + 0xc01e032d, + 0xc01e032e, + 0xc01e032f, + 0xc01e0330, + 0xc01e0331, + 0xc01e0332, + 0xc01e0333, + 0xc01e0334, + 0xc01e0335, + 0xc01e0336, + 0xc01e0337, + 0xc01e0338, + 0xc01e0339, + 0xc01e033a, + 0xc01e033b, + 0xc01e033c, + 0xc01e033d, + 0xc01e033e, + 0xc01e033f, + 0xc01e0340, + 0xc01e0341, + 0xc01e0342, + 0xc01e0343, + 0xc01e0344, + 0xc01e0345, + 0xc01e0346, + 0xc01e0347, + 0xc01e0348, + 0xc01e0349, + 0xc01e034a, + 0xc01e034d, + 0xc01e034e, + 0xc01e034f, + 0xc01e0350, + 0xc01e0352, + 0xc01e0353, + 0xc01e0354, + 0xc01e0355, + 0xc01e0356, + 0xc01e0357, + 0xc01e0358, + 0xc01e0359, + 0xc01e035a, + 0xc01e035b, + 0xc01e035c, + 0xc01e0400, + 0xc01e0401, + 0xc01e0430, + 0xc01e0431, + 0xc01e0432, + 0xc01e0433, + 0xc01e0434, + 0xc01e0435, + 0xc01e0436, + 0xc01e0438, + 0xc01e043b, + 0xc01e0500, + 0xc01e0501, + 0xc01e0502, + 0xc01e0503, + 0xc01e0505, + 0xc01e050b, + 0xc01e050c, + 0xc01e050e, + 0xc01e050f, + 0xc01e0510, + 0xc01e0511, + 0xc01e0512, + 0xc01e0513, + 0xc01e0514, + 0xc01e0515, + 0xc01e0516, + 0xc01e0517, + 0xc01e0518, + 0xc01e051a, + 0xc01e051c, + 0xc01e051d, + 0xc01e051e, + 0xc01e051f, + 0xc01e0520, + 0xc01e0521, + 0xc01e0580, + 0xc01e0581, + 0xc01e0582, + 0xc01e0583, + 0xc01e0584, + 0xc01e0585, + 0xc01e0586, + 0xc01e0587, + 0xc01e0588, + 0xc01e0589, + 0xc01e058a, + 0xc01e058b, + 0xc01e058c, + 0xc01e058d, + 0xc01e05e0, + 0xc01e05e1, + 0xc01e05e2, + 0xc01e05e3, + 0xc01e05e4, + 0xc01e05e5, + 0xc01e05e6, + 0xc01e05e7, + 0xc023100f, + 0xc0231012, + 0xc0231013, + 0xc0350002, + 0xc0350003, + 0xc0350004, + 0xc0350005, + 0xc0350006, + 0xc0350007, + 0xc0350008, + 0xc0350009, + 0xc035000a, + 0xc035000b, + 0xc035000c, + 0xc035000d, + 0xc035000e, + 0xc0350011, + 0xc0350012, + 0xc0350013, + 0xc0350014, + 0xc0350016, + 0xc0350017, + 0xc0350018, + 0xc0350019, + 0xc035001a, + 0xc035001b, + 0xc035001c, + 0xc035001d, + 0xc035001e, + 0xc0351000, + 0xc0370001, + 0xc0370002, + 0xc0370003, + 0xc0370004, + 0xc0370005, + 0xc0370006, + 0xc0370007, + 0xc0370008, + 0xc0370009, + 0xc037000a, + 0xc037000b, + 0xc037000c, + 0xc037000d, + 0xc037000e, + 0xc037000f, + 0xc0370010, + 0xc0370011, + 0xc0370012, + 0xc0370013, + 0xc0370014, + 0xc0370015, + 0xc0370016, + 0xc0370017, + 0xc0370018, + 0xc0370019, + 0xc037001a, + 0xc037001b, + 0xc037001c, + 0xc037001d, + 0xc037001e, + 0xc037001f, + 0xc0370020, + 0xc0370021, + 0xc0370022, + 0xc0370023, + 0xc0370024, + 0xc0370025, + 0xc0370026, + 0xc0370027, + 0xc0370028, + 0xc0370029, + 0xc0380001, + 0xc0380002, + 0xc0380003, + 0xc0380004, + 0xc0380005, + 0xc0380006, + 0xc0380007, + 0xc0380008, + 0xc0380009, + 0xc038000a, + 0xc038000b, + 0xc038000c, + 0xc038000d, + 0xc038000e, + 0xc038000f, + 0xc0380010, + 0xc0380011, + 0xc0380012, + 0xc0380013, + 0xc0380014, + 0xc0380015, + 0xc0380016, + 0xc0380017, + 0xc0380018, + 0xc0380019, + 0xc038001a, + 0xc038001b, + 0xc038001c, + 0xc038001d, + 0xc038001e, + 0xc038001f, + 0xc0380020, + 0xc0380021, + 0xc0380022, + 0xc0380023, + 0xc0380024, + 0xc0380025, + 0xc0380026, + 0xc0380027, + 0xc0380028, + 0xc0380029, + 0xc038002a, + 0xc038002b, + 0xc038002c, + 0xc038002d, + 0xc038002e, + 0xc038002f, + 0xc0380030, + 0xc0380031, + 0xc0380032, + 0xc0380033, + 0xc0380034, + 0xc0380035, + 0xc0380036, + 0xc0380037, + 0xc0380038, + 0xc0380039, + 0xc038003a, + 0xc038003b, + 0xc038003c, + 0xc038003d, + 0xc038003e, + 0xc038003f, + 0xc0380040, + 0xc0380041, + 0xc0380042, + 0xc0380043, + 0xc0380044, + 0xc0380045, + 0xc0380046, + 0xc0380047, + 0xc0380048, + 0xc0380049, + 0xc038004a, + 0xc038004b, + 0xc038004c, + 0xc038004d, + 0xc038004e, + 0xc038004f, + 0xc0380050, + 0xc0380051, + 0xc0380052, + 0xc0380053, + 0xc0380054, + 0xc0380055, + 0xc0380056, + 0xc0380057, + 0xc0380058, + 0xc0380059, + 0xc038005a, + 0xc038005b, + 0xc038005c, + 0xc0390002, + 0xc03a0001, + 0xc03a0002, + 0xc03a0003, + 0xc03a0004, + 0xc03a0005, + 0xc03a0006, + 0xc03a0007, + 0xc03a0008, + 0xc03a0009, + 0xc03a000a, + 0xc03a000b, + 0xc03a000c, + 0xc03a000d, + 0xc03a000e, + 0xc03a000f, + 0xc03a0010, + 0xc03a0011, + 0xc03a0012, + 0xc03a0013, + 0xc03a0014, + 0xc03a0015, + 0xc03a0016, + 0xc03a0017, + 0xc03a0018, + 0xc03a0019, +}; + +CONST ERROR_BUCKET ErrorBucketTable[] = { + {0x0, 7}, + {0x8, 1}, + {0xe, 1}, + {0x11, 3}, + {0x15, 4}, + {0x1b, 2}, + {0x1f, 4}, + {0x26, 1}, + {0x32, 23}, + {0x52, 1}, + {0x56, 3}, + {0x6d, 1}, + {0x70, 1}, + {0x79, 4}, + {0x7e, 3}, + {0x91, 1}, + {0x9a, 1}, + {0x9c, 1}, + {0x9e, 1}, + {0xa1, 1}, + {0xaa, 1}, + {0xb6, 2}, + {0xc1, 1}, + {0xcb, 1}, + {0xce, 1}, + {0xdc, 7}, + {0xe6, 5}, + {0xf0, 1}, + {0xfe, 2}, + {0x103, 1}, + {0x10b, 1}, + {0x11a, 1}, + {0x120, 1}, + {0x12a, 5}, + {0x130, 6}, + {0x13d, 1}, + {0x1e7, 1}, + {0x216, 28}, + {0x233, 82}, + {0x286, 11}, + {0x299, 1}, + {0x29c, 67}, + {0x2e0, 34}, + {0x307, 2}, + {0x30b, 2}, + {0x30e, 10}, + {0x320, 6}, + {0x3e3, 1}, + {0x3e5, 3}, + {0x3e9, 1}, + {0x3ed, 5}, + {0x3f6, 1}, + {0x3f8, 7}, + {0x420, 1}, + {0x422, 1}, + {0x44c, 16}, + {0x45d, 16}, + {0x476, 1}, + {0x488, 11}, + {0x494, 1}, + {0x49a, 2}, + {0x49d, 1}, + {0x4b1, 1}, + {0x4ba, 1}, + {0x4be, 1}, + {0x4c3, 2}, + {0x4c8, 17}, + {0x4db, 1}, + {0x4e3, 1}, + {0x4e6, 3}, + {0x4eb, 3}, + {0x4ef, 3}, + {0x4fb, 2}, + {0x4ff, 1}, + {0x502, 5}, + {0x508, 2}, + {0x50b, 3}, + {0x50f, 2}, + {0x513, 24}, + {0x52c, 15}, + {0x53c, 60}, + {0x5a4, 1}, + {0x5aa, 1}, + {0x5ad, 3}, + {0x5b4, 1}, + {0x5b7, 1}, + {0x5b9, 6}, + {0x5dc, 4}, + {0x60e, 3}, + {0x651, 1}, + {0x675, 1}, + {0x6a4, 2}, + {0x6a7, 28}, + {0x6c4, 6}, + {0x6cb, 36}, + {0x6f1, 18}, + {0x70e, 28}, + {0x76a, 3}, + {0x773, 3}, + {0x779, 6}, + {0x780, 2}, + {0x78b, 5}, + {0x791, 1}, + {0x7d1, 1}, + {0x961, 2}, + {0x964, 1}, + {0xf6e, 1}, + {0x1068, 4}, + {0x106e, 2}, + {0x1074, 3}, + {0x10dd, 1}, + {0x10e8, 1}, + {0x10f4, 1}, + {0x10fe, 3}, + {0x1126, 5}, + {0x1392, 1}, + {0x13af, 16}, + {0x13c0, 1}, + {0x13c2, 8}, + {0x13ce, 1}, + {0x1712, 2}, + {0x1770, 3}, + {0x1777, 2}, + {0x177d, 1}, + {0x1781, 5}, + {0x17e6, 1}, + {0x19c8, 49}, + {0x1a2c, 25}, + {0x1a46, 5}, + {0x1a90, 4}, + {0x1a95, 8}, + {0x1a9e, 42}, + {0x1b59, 4}, + {0x1b5f, 11}, + {0x1b6e, 4}, + {0x1b7b, 1}, + {0x1b7d, 2}, + {0x1b80, 3}, + {0x1b84, 2}, + {0x1b89, 10}, + {0x1b99, 5}, + {0x2009, 20}, + {0x2024, 1}, + {0x20ac, 1}, + {0x211e, 1}, + {0x2138, 3}, + {0x2141, 9}, + {0x2151, 4}, + {0x215b, 1}, + {0x215d, 1}, + {0x2163, 3}, + {0x216d, 1}, + {0x2171, 2}, + {0x217b, 2}, + {0x2182, 1}, + {0x219d, 1}, + {0x219f, 1}, + {0x21a4, 1}, + {0x21ac, 1}, + {0x21ba, 5}, + {0x3656, 9}, + {0x3665, 6}, + {0x366c, 1}, + {0x36b0, 12}, + {0x36cc, 1}, + {0x3701, 13}, + {0x3712, 13}, + {0x3afc, 7}, + {0x3b92, 1}, + {0x3bc3, 3}, + {0x1f0001, 1}, + {0x261001, 2}, + {0x262307, 1}, + {0x26231e, 1}, + {0x26234b, 2}, + {0x262351, 1}, + {0x340001, 1}, + {0x4026200a, 1}, + {0x4026242f, 1}, + {0x40262437, 1}, + {0x40262439, 2}, + {0x80000001, 1}, + {0x80000003, 2}, + {0x80030305, 7}, + {0x80090006, 1}, + {0x8009000d, 1}, + {0x80090016, 1}, + {0x80090022, 1}, + {0x8009002f, 1}, + {0x80090333, 12}, + {0x80090340, 4}, + {0x80090346, 1}, + {0x80090348, 1}, + {0x80090351, 11}, + {0x80090361, 2}, + {0x80097019, 1}, + {0x800b010c, 1}, + {0x8010000c, 1}, + {0x8010002c, 1}, + {0x8010002f, 1}, + {0x8010006b, 2}, + {0x8010006f, 1}, + {0x801f0001, 28}, + {0x801f0020, 1}, + {0x80260001, 1}, + {0x80310000, 2}, + {0x80310009, 1}, + {0x80310010, 2}, + {0x80310013, 2}, + {0x80310016, 2}, + {0x80310019, 1}, + {0x8031001b, 2}, + {0x80310024, 5}, + {0x8031003c, 4}, + {0x80310041, 5}, + {0x80310047, 1}, + {0x80310049, 1}, + {0x8031004b, 1}, + {0x8031004d, 5}, + {0x80310054, 2}, + {0x80310057, 1}, + {0x8031005a, 1}, + {0x8031006f, 1}, + {0x80310079, 1}, + {0x80310088, 2}, + {0x80320001, 60}, + {0x80320104, 1}, + {0x80340002, 1}, + {0x80340004, 10}, + {0x8034000f, 3}, + {0x80340014, 12}, + {0x80340022, 1}, + {0x8034002a, 6}, + {0x803400bb, 1}, + {0x80342000, 5}, + {0x80370001, 1}, + {0x80380001, 2}, + {0x80390001, 1}, + {0x80390003, 1}, + {0x803a0001, 1}, + {0xc000001d, 1}, + {0xc0000025, 2}, + {0xc000002b, 1}, + {0xc000008c, 9}, + {0xc0000096, 1}, + {0xc0090001, 3}, + {0xc02605e8, 1}, + {0xc0261003, 8}, + {0xc0262000, 10}, + {0xc026200b, 2}, + {0xc0262100, 10}, + {0xc0262110, 7}, + {0xc0262200, 1}, + {0xc0262300, 7}, + {0xc0262308, 5}, + {0xc0262310, 14}, + {0xc026231f, 44}, + {0xc026234d, 4}, + {0xc0262352, 11}, + {0xc0262400, 2}, + {0xc0262430, 7}, + {0xc0262438, 1}, + {0xc026243b, 1}, + {0xc0262500, 4}, + {0xc0262505, 1}, + {0xc026250b, 2}, + {0xc026250e, 11}, + {0xc026251a, 1}, + {0xc026251c, 6}, + {0xc0262580, 14}, + {0xc02625e0, 8}, + {0xc034100f, 1}, + {0xc0341012, 2}, + {0xc0350002, 13}, + {0xc0350011, 4}, + {0xc0350016, 9}, + {0xc0351000, 1}, + {0xc0370001, 41}, + {0xc0380001, 92}, + {0xc0390002, 1}, + {0xc03a0001, 25}, + {0x0, 0} +}; + +extern "C" +BOOL +ConvertWinErrorToNtstatus( + __in ULONG WinError, + __out NTSTATUS * Status + ); + +extern "C" +NTSTATUS +WinErrorToNtStatus( + __in ULONG WinError + ); diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxdeviceobjectum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxdeviceobjectum.h new file mode 100644 index 00000000000..7a308dd21d8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxdeviceobjectum.h @@ -0,0 +1,18 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDeviceObjectUm.h + +Abstract: + + User Mode implementation of Device Object defined in MxDeviceObject.h + +--*/ + +#pragma once + + +#include "MxDeviceObject.h" diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxdriverobjectum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxdriverobjectum.h new file mode 100644 index 00000000000..154809c829f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxdriverobjectum.h @@ -0,0 +1,24 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDriverObjectUm.h + +Abstract: + + User Mode implementation of Driver Object defined in MxDriverObject.h + +--*/ + +#pragma once + +typedef PDRIVER_OBJECT_UM MdDriverObject; +typedef DRIVER_ADD_DEVICE_UM MdDriverAddDeviceType, *MdDriverAddDevice; +typedef DRIVER_UNLOAD_UM MdDriverUnloadType, *MdDriverUnload; +typedef DRIVER_DISPATCH_UM MdDriverDispatchType, *MdDriverDispatch; + +#include "MxDriverObject.h" + + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxeventum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxeventum.h new file mode 100644 index 00000000000..252542499cf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxeventum.h @@ -0,0 +1,289 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxEventUm.h + +Abstract: + + User mode implementation of event + class defined in MxEvent.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +typedef struct { + HANDLE Event; +#if DBG + EVENT_TYPE Type; //tracked to allow ReadState only for notification events +#endif +} MdEvent; + +#include "DbgMacros.h" +#include "MxEvent.h" + +__inline +MxEvent::MxEvent() +{ + CLEAR_DBGFLAG_INITIALIZED; + + m_Event.Event = NULL; +} + +__inline +MxEvent::~MxEvent() +{ + // + // PLEASE NOTE: shared code must not rely of d'tor uninitializing the + // event. d'tor may not be invoked if the event is used in a structure + // which is allocated/deallocated using MxPoolAllocate/Free instead of + // new/delete + // + Uninitialize(); +} + +_Must_inspect_result_ +__inline +NTSTATUS +MxEvent::Initialize( + __in EVENT_TYPE Type, + __in BOOLEAN InitialState + ) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE event; + BOOL bManualReset; + + if (NotificationEvent == Type) + { + bManualReset = TRUE; + } + else + { + bManualReset = FALSE; + } + + event = CreateEvent( + NULL, + bManualReset, + InitialState ? TRUE : FALSE, + NULL + ); + + if (NULL == event) { + DWORD err = GetLastError(); + status = WinErrorToNtStatus(err); + goto exit; + } + + m_Event.Event = event; + +#if DBG + m_Event.Type = Type; +#endif + + SET_DBGFLAG_INITIALIZED; + +exit: + return status; +} + +__inline +PVOID +MxEvent::GetEvent( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + return m_Event.Event; +} + +__inline +VOID +MxEvent::Set( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + SetEvent(m_Event.Event); +} + +__inline +VOID +MxEvent::SetWithIncrement( + __in KPRIORITY Priority + ) +{ + UNREFERENCED_PARAMETER(Priority); + + ASSERT_DBGFLAG_INITIALIZED; + + Set(); +} + +__inline +VOID +MxEvent::Clear( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + ResetEvent(m_Event.Event); +} + +__drv_when(Timeout != NULL, _Must_inspect_result_) +__inline +NTSTATUS +MxEvent::WaitFor( + __in KWAIT_REASON WaitReason, + __in KPROCESSOR_MODE WaitMode, + __in BOOLEAN Alertable, + __in_opt PLARGE_INTEGER Timeout + ) +/*++ + +Routine Description: + Waits for the event + +Arguments: + WaitReason - Unused (only there to match km definition) + + WaitMode - Unuses (only there to match km definition) + + Altertable - Whether the wait is alertable + + Timout - Timeout in 100 ns units, MUST BE NEGATIVE + (negative implies relative timeout) + +Return Value: + Status corresponding to return value of WaitForSingleObjectEx + + --*/ +{ + ASSERT_DBGFLAG_INITIALIZED; + + DWORD retVal; + + UNREFERENCED_PARAMETER(WaitReason); + UNREFERENCED_PARAMETER(WaitMode); + + LONGLONG relativeTimeOut = 0; + LONGLONG timeoutInMs = 0; + DWORD dwTimeout = 0; + + if (NULL != Timeout) + { + // + // Make sure that timeout is 0 or -ve (which implies relative timeout) + // + if (Timeout->QuadPart > 0) + { + Mx::MxAssertMsg( + "Absolute wait not supported in user mode", + FALSE + ); + + return STATUS_INVALID_PARAMETER; + } + + // + // Remove the -ve sign + // + if (Timeout->QuadPart < 0) + { + relativeTimeOut = -1 * Timeout->QuadPart; + } + + // + // Convert from 100ns units to milliseconds + // + timeoutInMs = (relativeTimeOut / (10 * 1000)); + + if (timeoutInMs > ULONG_MAX) + { + Mx::MxAssertMsg("Timeout too large", FALSE); + + return STATUS_INVALID_PARAMETER; + } + else + { + dwTimeout = (DWORD) timeoutInMs; + } + } + + retVal = WaitForSingleObjectEx( + m_Event.Event, + (NULL == Timeout) ? INFINITE : dwTimeout, + Alertable + ); + + switch(retVal) + { + case WAIT_ABANDONED: + return STATUS_ABANDONED; + case WAIT_OBJECT_0: + return STATUS_SUCCESS; + case WAIT_TIMEOUT: + return STATUS_TIMEOUT; + case WAIT_FAILED: + { + DWORD err = GetLastError(); + return WinErrorToNtStatus(err); + } + default: + { + // + // We shoudn't get here + // + Mx::MxAssert(FALSE); + return STATUS_UNSUCCESSFUL; + } + } +} + +LONG +__inline +MxEvent::ReadState( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + +#if DBG + Mx::MxAssert(m_Event.Type == NotificationEvent); +#endif + + if (WAIT_OBJECT_0 == WaitForSingleObject( + m_Event.Event, + 0 + )) { + return 1; + } + else { + return 0; + } +} + + +__inline +VOID +MxEvent::Uninitialize( + ) +{ + if (NULL != m_Event.Event) { + CloseHandle(m_Event.Event); + m_Event.Event = NULL; + } + + CLEAR_DBGFLAG_INITIALIZED; +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxfileobjectum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxfileobjectum.h new file mode 100644 index 00000000000..c6932d50760 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxfileobjectum.h @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxFileObjectUm.h + +Abstract: + + User Mode implementation of File Object defined in MxFileObject.h + +--*/ + +#pragma once + +struct IWudfFile; + +typedef IWudfFile * MdFileObject; + +#include "MxFileObject.h" + +__inline +PLARGE_INTEGER +MxFileObject::GetCurrentByteOffset( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return NULL; +} + +__inline +ULONG +MxFileObject::GetFlags( + VOID + ) +{ + + + + + + + + + return 0; +} + +__inline +VOID +MxFileObject::SetFsContext( + _In_ PVOID Value + ) +{ + UNREFERENCED_PARAMETER(Value); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +VOID +MxFileObject::SetFsContext2( + _In_ PVOID Value + ) +{ + UNREFERENCED_PARAMETER(Value); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +PVOID +MxFileObject::GetFsContext( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return NULL; +} + +__inline +PVOID +MxFileObject::GetFsContext2( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return NULL; +} + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxgeneralum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxgeneralum.h new file mode 100644 index 00000000000..44076a9c8f9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxgeneralum.h @@ -0,0 +1,1078 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxGeneralUm.h + +Abstract: + + User mode implementation for general OS + functions defined in MxGeneral.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#define MAKE_MX_FUNC_NAME(x) x + + + + + + + + +#define REMOVE_LOCK_RELEASE_TIMEOUT_IN_SECONDS 45 + +typedef VOID THREADPOOL_WAIT_CALLBACK ( + __inout PTP_CALLBACK_INSTANCE Instance, + __inout_opt PVOID Context, + __inout PTP_WAIT Wait, + __in TP_WAIT_RESULT WaitResult + ); + +typedef THREADPOOL_WAIT_CALLBACK MdInterruptServiceRoutineType, *MdInterruptServiceRoutine; + +typedef +BOOLEAN +InterruptSynchronizeRoutine ( + __in PVOID SynchronizeContext + ); + +typedef InterruptSynchronizeRoutine MdInterruptSynchronizeRoutineType, *MdInterruptSynchronizeRoutine; + +typedef struct _CALLBACK_OBJECT *PCALLBACK_OBJECT; + +typedef +VOID +CALLBACK_FUNCTION( + __in PVOID CallbackContext, + __in_opt PVOID Argument1, + __in_opt PVOID Argument2 + ); + +typedef CALLBACK_FUNCTION MdCallbackFunctionType, *MdCallbackFunction; + +// +// Define PnP notification event categories +// + +typedef enum _IO_NOTIFICATION_EVENT_CATEGORY { + EventCategoryReserved, + EventCategoryHardwareProfileChange, + EventCategoryDeviceInterfaceChange, + EventCategoryTargetDeviceChange +} IO_NOTIFICATION_EVENT_CATEGORY; + +#include "MxGeneral.h" + +__inline +BOOLEAN +Mx::IsUM( + ) +{ + return TRUE; +} + +__inline +BOOLEAN +Mx::IsKM( + ) +{ + return FALSE; +} + +__inline +MxThread +Mx::MxGetCurrentThread( + ) +{ + // + // We can't use GetCurrentThread as it returns a pseudo handle + // which would have same numeric value for different threads + // We could use DuplicateHandle to get real handle but that has the + // following problems: + // 1) It returns different handle values for the same thread + // if called again without closing handle. + // 2) Makes the caller call CloseHandle making it inconvenient to + // call this function just to get an identifier for the thread + // 3) More expensive than GetCurrentThreadId + // + // Since framework uses the thread only for comparison, logging + // purposes GetCurrentThreadId works well. + // It is cast to PVOID to match the pointer type PKTHREAD otherwise + // trace functions complain of data type mismatch + // + + return (PVOID) ::GetCurrentThreadId(); +} + +__inline +MdEThread +Mx::GetCurrentEThread( + ) +{ + // + // See comments in MxGetCurrentThread. + // + return (PVOID) MxGetCurrentThread(); +} + +__inline +NTSTATUS +Mx::MxTerminateCurrentThread( + __in NTSTATUS Status + ) +{ + #pragma prefast(suppress:__WARNING_USINGTERMINATETHREAD, "TerminateThread is the intent."); + if (!TerminateThread(::GetCurrentThread(), HRESULT_FROM_NT(Status))) { + DWORD err = GetLastError(); + return WinErrorToNtStatus(err); + } + return STATUS_SUCCESS; +} + +__inline +KIRQL +Mx::MxGetCurrentIrql( + ) +{ + return PASSIVE_LEVEL; +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +Mx::MxRaiseIrql( + __in KIRQL NewIrql, + __out PKIRQL OldIrql + ) +{ + UNREFERENCED_PARAMETER(NewIrql); + UNREFERENCED_PARAMETER(OldIrql); + + DO_NOTHING(); +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +Mx::MxLowerIrql( + __in KIRQL NewIrql + ) +{ + UNREFERENCED_PARAMETER(NewIrql); + + DO_NOTHING(); +} + +__inline +VOID +Mx::MxQueryTickCount( + __out PLARGE_INTEGER TickCount + ) +{ + TickCount->QuadPart = GetTickCount(); +} + +__inline +ULONG +Mx::MxQueryTimeIncrement( + ) +{ + // + // The way to get absolute time is TickCount * TimeIncrement. + // In UM, TickCount is expressed in miliseconds, so this + // conversion ensures that absolute time is expressed + // in 100ns units as it is in KM. + // + return 1000 * 10; +} + +__inline +VOID +Mx::MxDbgBreakPoint( + ) +{ + DebugBreak(); +} + +__inline +VOID +Mx::MxAssert( + __in BOOLEAN Condition + ) +{ + if (!Condition) + { + + + + DebugBreak(); + } +} + +__inline +VOID +Mx::MxAssertMsg( + __in LPSTR Message, + __in BOOLEAN Condition + ) +{ + UNREFERENCED_PARAMETER(Message); + + if (!Condition) + { + + + + DebugBreak(); + } +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +Mx::MxEnterCriticalRegion( + ) +{ + + + + + + // DO_NOTHING(); +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +Mx::MxLeaveCriticalRegion( + ) +{ + + + + + + // DO_NOTHING(); +} + +__inline +VOID +Mx::MxDelayExecutionThread( + __in KPROCESSOR_MODE WaitMode, + __in BOOLEAN Alertable, + __in PLARGE_INTEGER Interval + ) +{ + UNREFERENCED_PARAMETER(WaitMode); + ASSERTMSG("Interval must be relative\n", Interval->QuadPart <= 0); + + LARGE_INTEGER intervalMillisecond; + + // + // This function uses KeDelayExecutionThread's contract, where relative + // intervals are negative numbers expressed in 100ns units. We must + // flip the sign and convert to ms units before calling SleepEx. + // + intervalMillisecond.QuadPart = -1 * Interval->QuadPart; + intervalMillisecond.QuadPart /= 10 * 1000; + + SleepEx((DWORD)intervalMillisecond.QuadPart, Alertable); +} + +__inline +PVOID +Mx::MxGetSystemRoutineAddress( + __in MxFuncName FuncName + ) +/*++ +Description: + + This function is meant to be called only by mode agnostic code + System routine is assumed to be in ntdll.dll. + + This is because system routines (Rtl*) that can be used both + in kernel mode as well as user mode reside in ntdll.dll. + Kernel32.dll contains the user mode only Win32 API. + +Arguments: + + MxFuncName FuncName - + +Return Value: + + NTSTATUS Status code. +--*/ +{ + HMODULE hMod; + + hMod = GetModuleHandleW(L"ntdll.dll"); + + return GetProcAddress(hMod, FuncName); +} + +__inline +VOID +Mx::MxReferenceObject( + __in PVOID Object + ) +{ + UNREFERENCED_PARAMETER(Object); + + + + + + + // DO_NOTHING(); +} + +__inline +VOID +Mx::MxDereferenceObject( + __in PVOID Object + ) +{ + UNREFERENCED_PARAMETER(Object); + + + + + + + // DO_NOTHING(); +} + +__inline +VOID +Mx::MxInitializeRemoveLock( + __in MdRemoveLock Lock, + __in ULONG AllocateTag, + __in ULONG MaxLockedMinutes, + __in ULONG HighWatermark + ) +{ + UNREFERENCED_PARAMETER(AllocateTag); + UNREFERENCED_PARAMETER(MaxLockedMinutes); + UNREFERENCED_PARAMETER(HighWatermark); + + ZeroMemory(Lock, sizeof(*Lock)); + Lock->IoCount = 1; + Lock->Removed = FALSE; + Lock->RemoveEvent = NULL; + Lock->ReleaseRemLockAndWaitStatus = (DWORD)-1; +} + +__inline +NTSTATUS +Mx::MxAcquireRemoveLock( + __in MdRemoveLock RemoveLock, + __in_opt PVOID Tag + ) +{ + UNREFERENCED_PARAMETER(Tag); + LONG lockValue; + NTSTATUS status; + + lockValue = InterlockedIncrement(&RemoveLock->IoCount); + + ASSERT(lockValue > 0); + + if (! RemoveLock->Removed) { + return STATUS_SUCCESS; + } + else { + if (0 == InterlockedDecrement(&RemoveLock->IoCount)) { + if (! SetEvent(RemoveLock->RemoveEvent)) { + Mx::MxBugCheckEx(WDF_VIOLATION, + 0, 0, 0, 0); + } + } + status = STATUS_DELETE_PENDING; + } + + return status; +} + +__inline +VOID +Mx::MxReleaseRemoveLock( + __in MdRemoveLock RemoveLock, + __in PVOID Tag + ) +{ + UNREFERENCED_PARAMETER(Tag); + LONG lockValue; + + lockValue = InterlockedDecrement(&RemoveLock->IoCount); + + ASSERT(0 <= lockValue); + + if (0 == lockValue) { + ASSERT (RemoveLock->Removed); + + // + // The device needs to be removed. Signal the remove event + // that it's safe to go ahead. + // + if (! SetEvent(RemoveLock->RemoveEvent)) { + Mx::MxBugCheckEx(WDF_VIOLATION, + 0, 0, 0, 0); + } + } +} + +__inline +VOID +Mx::MxReleaseRemoveLockAndWait( + __in MdRemoveLock RemoveLock, + __in PVOID Tag + ) +{ + UNREFERENCED_PARAMETER(Tag); + LONG ioCount; + DWORD retVal = ERROR_SUCCESS; + + RemoveLock->Removed = TRUE; + + ioCount = InterlockedDecrement (&RemoveLock->IoCount); + ASSERT(0 < ioCount); + + if (0 < InterlockedDecrement (&RemoveLock->IoCount)) { + retVal = WaitForSingleObject(RemoveLock->RemoveEvent, + REMOVE_LOCK_RELEASE_TIMEOUT_IN_SECONDS*1000); + ASSERT(retVal == WAIT_OBJECT_0); + } + + // This only serves as a debugging aid. + RemoveLock->ReleaseRemLockAndWaitStatus = retVal; +} + +__inline +BOOLEAN +Mx::MxHasEnoughRemainingThreadStack( + VOID + ) +{ + + + + + // + // Thread stack is not so scarce in UM so return TRUE always + // + return TRUE; +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +Mx::ReleaseCancelSpinLock( + __in KIRQL Irql + ) +{ + UNREFERENCED_PARAMETER(Irql); + + // + // UMDF Host doesn't have cancel spinlock equivalent concept so do nothing. + // + DO_NOTHING(); +} + +__inline +NTSTATUS +Mx::CreateCallback( + __out PCALLBACK_OBJECT *CallbackObject, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in BOOLEAN Create, + __in BOOLEAN AllowMultipleCallbacks + ) +{ + UNREFERENCED_PARAMETER(CallbackObject); + UNREFERENCED_PARAMETER(ObjectAttributes); + UNREFERENCED_PARAMETER(Create); + UNREFERENCED_PARAMETER(AllowMultipleCallbacks); + + return STATUS_UNSUCCESSFUL; +} + +__inline +PVOID +Mx::RegisterCallback( + __in PCALLBACK_OBJECT CallbackObject, + __in MdCallbackFunction CallbackFunction, + __in PVOID CallbackContext + ) +{ + UNREFERENCED_PARAMETER(CallbackObject); + UNREFERENCED_PARAMETER(CallbackFunction); + UNREFERENCED_PARAMETER(CallbackContext); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__inline +VOID +Mx::UnregisterCallback( + __in PVOID CbRegistration + ) +{ + UNREFERENCED_PARAMETER(CbRegistration); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +VOID +Mx::MxUnlockPages( + __in PMDL Mdl + ) +{ + UNREFERENCED_PARAMETER(Mdl); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +PVOID +Mx::MxGetSystemAddressForMdlSafe( + __inout PMDL Mdl, + __in ULONG Priority + ) +{ + UNREFERENCED_PARAMETER(Mdl); + UNREFERENCED_PARAMETER(Priority); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__inline +VOID +Mx::MxBuildMdlForNonPagedPool( + __inout PMDL Mdl + ) +{ + UNREFERENCED_PARAMETER(Mdl); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +PVOID +Mx::MxGetDriverObjectExtension( + __in MdDriverObject DriverObject, + __in PVOID ClientIdentificationAddress + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(ClientIdentificationAddress); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__inline +NTSTATUS +Mx::MxAllocateDriverObjectExtension( + _In_ MdDriverObject DriverObject, + _In_ PVOID ClientIdentificationAddress, + _In_ ULONG DriverObjectExtensionSize, + // When successful, this always allocates already-aliased memory. + _Post_ _At_(*DriverObjectExtension, _When_(return==0, + __drv_aliasesMem __drv_allocatesMem(Mem) _Post_notnull_)) + _When_(return == 0, _Outptr_result_bytebuffer_(DriverObjectExtensionSize)) + PVOID *DriverObjectExtension + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(ClientIdentificationAddress); + UNREFERENCED_PARAMETER(DriverObjectExtensionSize); + UNREFERENCED_PARAMETER(DriverObjectExtension); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_UNSUCCESSFUL; +} + +__inline +MdDeviceObject +Mx::MxGetAttachedDeviceReference( + __in MdDeviceObject DriverObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__inline +VOID +Mx::MxDeleteSymbolicLink( + __in PUNICODE_STRING Value + ) +{ + UNREFERENCED_PARAMETER(Value); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +VOID +Mx::MxDeleteNPagedLookasideList( + _In_ PNPAGED_LOOKASIDE_LIST LookasideList + ) +{ + UNREFERENCED_PARAMETER(LookasideList); +} + +__inline +VOID +Mx::MxDeletePagedLookasideList( + _In_ PPAGED_LOOKASIDE_LIST LookasideList + ) +{ + UNREFERENCED_PARAMETER(LookasideList); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +VOID +Mx::MxInitializeNPagedLookasideList( + _Out_ PNPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ PALLOCATE_FUNCTION Allocate, + _In_opt_ PFREE_FUNCTION Free, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Tag, + _In_ USHORT Depth + ) +{ + + UNREFERENCED_PARAMETER(Lookaside); + UNREFERENCED_PARAMETER(Allocate); + UNREFERENCED_PARAMETER(Free); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Size); + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Depth); + + //ASSERTMSG("Not implemented for UMDF\n", FALSE); + +} + +__inline +VOID +Mx::MxInitializePagedLookasideList( + _Out_ PPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ PALLOCATE_FUNCTION Allocate, + _In_opt_ PFREE_FUNCTION Free, + _In_ ULONG Flags, + _In_ SIZE_T Size, + _In_ ULONG Tag, + _In_ USHORT Depth + ) +{ + + UNREFERENCED_PARAMETER(Lookaside); + UNREFERENCED_PARAMETER(Allocate); + UNREFERENCED_PARAMETER(Free); + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(Size); + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Depth); + + //ASSERTMSG("Not implemented for UMDF\n", FALSE); + +} + +__inline +VOID +Mx::MxDeleteDevice( + _In_ MdDeviceObject Device + ) +{ + UNREFERENCED_PARAMETER(Device); + + + + + // + // Host's device stack object holds the only reference to the host devices. + // The infrastructure controls the device object's lifetime. + // + DO_NOTHING(); +} + +__inline +NTSTATUS +Mx::MxCreateDeviceSecure( + _In_ MdDriverObject DriverObject, + _In_ ULONG DeviceExtensionSize, + _In_opt_ PUNICODE_STRING DeviceName, + _In_ DEVICE_TYPE DeviceType, + _In_ ULONG DeviceCharacteristics, + _In_ BOOLEAN Exclusive, + _In_ PCUNICODE_STRING DefaultSDDLString, + _In_opt_ LPCGUID DeviceClassGuid, + _Out_opt_ MdDeviceObject *DeviceObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(DeviceExtensionSize); + UNREFERENCED_PARAMETER(DeviceName); + UNREFERENCED_PARAMETER(DeviceType); + UNREFERENCED_PARAMETER(Exclusive); + UNREFERENCED_PARAMETER(DeviceCharacteristics); + UNREFERENCED_PARAMETER(DefaultSDDLString); + UNREFERENCED_PARAMETER(DeviceClassGuid); + UNREFERENCED_PARAMETER(DeviceObject); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_SUCCESS; +} + +__inline +MdDeviceObject +Mx::MxAttachDeviceToDeviceStack( + _In_ MdDeviceObject SourceDevice, + _In_ MdDeviceObject TargetDevice + ) +{ + + UNREFERENCED_PARAMETER(SourceDevice); + UNREFERENCED_PARAMETER(TargetDevice); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__inline +NTSTATUS +Mx::MxCreateDevice( + _In_ MdDriverObject DriverObject, + _In_ ULONG DeviceExtensionSize, + _In_opt_ PUNICODE_STRING DeviceName, + _In_ DEVICE_TYPE DeviceType, + _In_ ULONG DeviceCharacteristics, + _In_ BOOLEAN Exclusive, + _Out_opt_ MdDeviceObject *DeviceObject + ) +{ + UNREFERENCED_PARAMETER(DriverObject); + UNREFERENCED_PARAMETER(DeviceExtensionSize); + UNREFERENCED_PARAMETER(DeviceName); + UNREFERENCED_PARAMETER(DeviceType); + UNREFERENCED_PARAMETER(DeviceCharacteristics); + UNREFERENCED_PARAMETER(Exclusive); + UNREFERENCED_PARAMETER(DeviceObject); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_SUCCESS; + +} + +__inline +NTSTATUS +Mx::MxCreateSymbolicLink( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ PUNICODE_STRING DeviceName + ) +{ + UNREFERENCED_PARAMETER(SymbolicLinkName); + UNREFERENCED_PARAMETER(DeviceName); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +VOID +Mx::MxFlushQueuedDpcs( + ) +{ + // + // Not supported for UMDF + // +} + +__inline +NTSTATUS +Mx::MxOpenKey( + _In_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes + ) +{ + UNREFERENCED_PARAMETER(KeyHandle); + UNREFERENCED_PARAMETER(DesiredAccess); + UNREFERENCED_PARAMETER(ObjectAttributes); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +NTSTATUS +Mx::MxSetDeviceInterfaceState( + _In_ PUNICODE_STRING SymbolicLinkName, + _In_ BOOLEAN Enable + ) +{ + UNREFERENCED_PARAMETER(SymbolicLinkName); + UNREFERENCED_PARAMETER(Enable); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + + +__inline +NTSTATUS +Mx::MxRegisterDeviceInterface( + _In_ PDEVICE_OBJECT PhysicalDeviceObject, + _In_ const GUID *InterfaceClassGuid, + _In_opt_ PUNICODE_STRING ReferenceString, + _Out_ PUNICODE_STRING SymbolicLinkName + ) +{ + UNREFERENCED_PARAMETER(PhysicalDeviceObject); + UNREFERENCED_PARAMETER(InterfaceClassGuid); + UNREFERENCED_PARAMETER(ReferenceString); + UNREFERENCED_PARAMETER(SymbolicLinkName); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +NTSTATUS +Mx::MxDeleteKey( + _In_ HANDLE KeyHandle + ) + +{ + UNREFERENCED_PARAMETER(KeyHandle); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +VOID +Mx::MxInitializeMdl( + _In_ PMDL MemoryDescriptorList, + _In_ PVOID BaseVa, + _In_ SIZE_T Length + ) +{ + UNREFERENCED_PARAMETER(MemoryDescriptorList); + UNREFERENCED_PARAMETER(BaseVa); + UNREFERENCED_PARAMETER(Length); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + +} + +__inline +PVOID +Mx::MxGetMdlVirtualAddress( + _In_ PMDL Mdl + ) +{ + UNREFERENCED_PARAMETER(Mdl); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return NULL; +} + +__inline +VOID +Mx::MxBuildPartialMdl( + _In_ PMDL SourceMdl, + _Inout_ PMDL TargetMdl, + _In_ PVOID VirtualAddress, + _In_ ULONG Length + ) +{ + UNREFERENCED_PARAMETER(SourceMdl); + UNREFERENCED_PARAMETER(TargetMdl); + UNREFERENCED_PARAMETER(VirtualAddress); + UNREFERENCED_PARAMETER(Length); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +VOID +Mx::MxQuerySystemTime( + _Out_ PLARGE_INTEGER CurrentTime + ) +{ + UNREFERENCED_PARAMETER(CurrentTime); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +NTSTATUS +Mx::MxSetValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_opt_ ULONG TitleIndex, + _In_ ULONG Type, + _In_opt_ PVOID Data, + _In_ ULONG DataSize + ) +{ + UNREFERENCED_PARAMETER(KeyHandle); + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(TitleIndex); + UNREFERENCED_PARAMETER(Type); + UNREFERENCED_PARAMETER(Data); + UNREFERENCED_PARAMETER(DataSize); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +NTSTATUS +Mx::MxQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_opt_ PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength +) +{ + UNREFERENCED_PARAMETER(KeyHandle); + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(KeyValueInformationClass); + UNREFERENCED_PARAMETER(KeyValueInformation); + UNREFERENCED_PARAMETER(Length); + UNREFERENCED_PARAMETER(ResultLength); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +NTSTATUS +Mx::MxUnRegisterPlugPlayNotification( + __in __drv_freesMem(Pool) PVOID NotificationEntry + ) +{ + UNREFERENCED_PARAMETER(NotificationEntry); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +NTSTATUS +Mx::MxReferenceObjectByHandle( + __in HANDLE Handle, + __in ACCESS_MASK DesiredAccess, + __in_opt POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE AccessMode, + __out PVOID *Object, + __out_opt POBJECT_HANDLE_INFORMATION HandleInformation + ) +{ + UNREFERENCED_PARAMETER(Handle); + UNREFERENCED_PARAMETER(DesiredAccess); + UNREFERENCED_PARAMETER(ObjectType); + UNREFERENCED_PARAMETER(AccessMode); + UNREFERENCED_PARAMETER(Object); + UNREFERENCED_PARAMETER(HandleInformation); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +__inline +NTSTATUS +Mx::MxClose( + __in HANDLE Handle + ) +{ + CloseHandle(Handle); + + return STATUS_SUCCESS; +} + +__inline +KIRQL +Mx::MxAcquireInterruptSpinLock( + _Inout_ PKINTERRUPT Interrupt + ) +{ + UNREFERENCED_PARAMETER(Interrupt); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return PASSIVE_LEVEL; +} + +__inline +VOID +Mx::MxReleaseInterruptSpinLock( + _Inout_ PKINTERRUPT Interrupt, + _In_ KIRQL OldIrql + ) +{ + UNREFERENCED_PARAMETER(Interrupt); + UNREFERENCED_PARAMETER(OldIrql); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +BOOLEAN +Mx::MxInsertQueueDpc( + __inout PRKDPC Dpc, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 +) +{ + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return FALSE; +} + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxlockum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxlockum.h new file mode 100644 index 00000000000..bac5838fffc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxlockum.h @@ -0,0 +1,185 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxLockUm.h + +Abstract: + + User mode implementation of lock + class defined in MxLock.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +typedef struct { + CRITICAL_SECTION Lock; + bool Initialized; + DWORD OwnerThreadId; +} MdLock; + +#include "DbgMacros.h" +#include "MxLock.h" + +__inline +MxLock::MxLock( + ) +{ + CLEAR_DBGFLAG_INITIALIZED; + + m_Lock.Initialized = false; + m_Lock.OwnerThreadId = 0; + + MxLock::Initialize(); +} + +__inline +VOID +MxLockNoDynam::Initialize( + ) +{ + BOOL ret; + + ASSERT_DBGFLAG_NOT_INITIALIZED; + + ret = InitializeCriticalSectionAndSpinCount(&m_Lock.Lock, 0); + + // + // InitializeCriticalSectionAndSpinCount always returns TRUE on Vista+ + // Assert this contract on checked builds using DBGFLAG macro. + // + if (ret) { + m_Lock.Initialized = true; + SET_DBGFLAG_INITIALIZED; + } + + ASSERT_DBGFLAG_INITIALIZED; +} + + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +MxLockNoDynam::Acquire( + __out KIRQL * OldIrql + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + EnterCriticalSection(&m_Lock.Lock); + + DWORD threadId = GetCurrentThreadId(); + + if (threadId == m_Lock.OwnerThreadId) { + Mx::MxAssertMsg("Recursive acquision of the lock is not allowed", FALSE); + } + + m_Lock.OwnerThreadId = threadId; + + *OldIrql = PASSIVE_LEVEL; +} + +__inline +BOOLEAN +MxLockNoDynam::TryToAcquire( + VOID + ) +{ + BOOLEAN acquired; + + ASSERT_DBGFLAG_INITIALIZED; + + acquired = (BOOLEAN) TryEnterCriticalSection(&m_Lock.Lock); + + if (acquired) { + DWORD threadId = GetCurrentThreadId(); + + if (threadId == m_Lock.OwnerThreadId) { + Mx::MxAssertMsg("Recursive acquision of the lock is not allowed", FALSE); + } + + m_Lock.OwnerThreadId = threadId; + } + + return acquired; +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +MxLockNoDynam::AcquireAtDpcLevel( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + KIRQL dontCare; + + Acquire(&dontCare); +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +MxLockNoDynam::Release( + KIRQL NewIrql + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + Mx::MxAssert(NewIrql == PASSIVE_LEVEL); + + m_Lock.OwnerThreadId = 0; + + LeaveCriticalSection(&m_Lock.Lock); +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +MxLockNoDynam::ReleaseFromDpcLevel( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + Release(PASSIVE_LEVEL); +} + +__inline +VOID +MxLockNoDynam::Uninitialize( + ) +{ + ASSERT_DBGFLAG_INITIALIZED; + + DeleteCriticalSection(&m_Lock.Lock); + m_Lock.Initialized = false; + + CLEAR_DBGFLAG_INITIALIZED; +} + +__inline +MxLock::~MxLock( + ) +{ + // + // PLEASE NOTE: shared code must not rely of d'tor uninitializing the + // lock. d'tor may not be invoked if the event is used in a structure + // which is allocated/deallocated using MxPoolAllocate/Free instead of + // new/delete + // + + if (m_Lock.Initialized) { + this->Uninitialize(); + } +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxmemoryum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxmemoryum.h new file mode 100644 index 00000000000..ed1d77f2bad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxmemoryum.h @@ -0,0 +1,58 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxMemoryUm.h + +Abstract: + + User mode implementation of memory + class defined in MxMemory.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#include "MxMemory.h" + +__inline +PVOID +MxMemory::MxAllocatePoolWithTag( + __in POOL_TYPE PoolType, + __in SIZE_T NumberOfBytes, + __in ULONG Tag + ) +{ + UNREFERENCED_PARAMETER(PoolType); + UNREFERENCED_PARAMETER(Tag); + + return ::HeapAlloc( + GetProcessHeap(), + 0, + NumberOfBytes + ); +} + +__inline +VOID +MxMemory::MxFreePool( + __in PVOID Ptr + ) +{ + ::HeapFree( + GetProcessHeap(), + 0, + Ptr + ); +} + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxpagedlockum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxpagedlockum.h new file mode 100644 index 00000000000..ba6b7efdf56 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxpagedlockum.h @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxPagedLockUm.h + +Abstract: + + User mode implementation of paged lock defined in + MxPagedLock.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +typedef struct { + CRITICAL_SECTION Lock; + bool Initialized; + DWORD OwnerThreadId; +} MdPagedLock; + +#include "MxPagedLock.h" + +__inline +MxPagedLock::MxPagedLock( + ) +{ + m_Lock.Initialized = false; + m_Lock.OwnerThreadId = 0; +} + +_Must_inspect_result_ +__inline +NTSTATUS +MxPagedLockNoDynam::Initialize( + ) +{ + if (InitializeCriticalSectionAndSpinCount(&m_Lock.Lock, 0)) { + m_Lock.Initialized = true; + + return S_OK; + } + else { + DWORD err = GetLastError(); + return WinErrorToNtStatus(err); + } +} + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +MxPagedLockNoDynam::Acquire( + ) +{ + EnterCriticalSection(&m_Lock.Lock); + + DWORD threadId = GetCurrentThreadId(); + + if (threadId == m_Lock.OwnerThreadId) { + Mx::MxAssertMsg("Recursive acquision of the lock is not allowed", FALSE); + } + + m_Lock.OwnerThreadId = GetCurrentThreadId(); +} + +__inline +VOID +MxPagedLockNoDynam::AcquireUnsafe( + ) +{ + MxPagedLockNoDynam::Acquire(); +} + +__inline +BOOLEAN +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +MxPagedLockNoDynam::TryToAcquire( + ) +{ + return TryEnterCriticalSection(&m_Lock.Lock) == TRUE ? TRUE : FALSE; +} + + +__inline +VOID +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "Can't apply kernel mode annotations."); +MxPagedLockNoDynam::Release( + ) +{ + m_Lock.OwnerThreadId = 0; + + LeaveCriticalSection(&m_Lock.Lock); +} + +__inline +VOID +MxPagedLockNoDynam::ReleaseUnsafe( + ) +{ + MxPagedLockNoDynam::Release(); +} + +__inline +VOID +MxPagedLockNoDynam::Uninitialize( + ) +{ + DeleteCriticalSection(&m_Lock.Lock); + m_Lock.Initialized = false; +} + +__inline +MxPagedLock::~MxPagedLock( + ) +{ + if (m_Lock.Initialized) { + this->Uninitialize(); + } +} diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxtimerum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxtimerum.h new file mode 100644 index 00000000000..d1dbee7751b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxtimerum.h @@ -0,0 +1,479 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxTimerUm.h + +Abstract: + + User mode implementation of timer defined in + MxTimer.h + +Author: + + +Revision History: + + + +--*/ + +#pragma once + +typedef struct _MdTimer { + // + // Callback function to be invoked upon timer expiration and the context to + // be passed in to the callback function + // + MdDeferredRoutine m_TimerCallback; + PVOID m_TimerContext; + + // + // The timer period + // + LONG m_Period; + + // + // Handle to the timer object + // + PTP_TIMER m_TimerHandle; + + // + // Work object to be executed by threadpool upon timer expiration + // + PTP_WORK m_WorkObject; + + // + // Flag to indicate that the timer callback has started running + // + BOOL m_CallbackStartedRunning; + + // + // Flag to indicate that the timer was started + // since it was created or since it was last stopped. + // + BOOL m_TimerWasStarted; + + _MdTimer( + VOID + ) + { + m_TimerHandle = NULL; + m_WorkObject = NULL; + m_TimerCallback = NULL; + m_TimerContext = NULL; + m_Period = 0; + m_CallbackStartedRunning = FALSE; + m_TimerWasStarted = FALSE; + } + + ~_MdTimer( + VOID + ) + { + // + // Release the timer object + // + if (m_TimerHandle) + { + CloseThreadpoolTimer(m_TimerHandle); + m_TimerHandle = NULL; + } + + // + // Release the work object + // + if (m_WorkObject) + { + CloseThreadpoolWork(m_WorkObject); + m_WorkObject = NULL; + } + } + + BOOLEAN + IsInSystemQueue( + VOID + ) + { + // + // Timer was not started since it was created or since + // it was last stopped, so it can't be in the system timer queue. + // + if (!m_TimerWasStarted) { + return FALSE; + } + + // + // Periodic timers are always in the system timer queue. + // + if (m_Period != 0) { + return TRUE; + } + + // + // Non-periodic timer: + // + // At this point, the timer callback function has either been canceled or + // has finished running. Examine the m_CallbackStartedRunning value to see + // which one of these happened. + // + if (m_CallbackStartedRunning) + { + // + // Timer cancellation was too late. Timer callback already started + // running and the timer was removed from the system timer queue. + // + return FALSE; + } + else + { + // + // Timer cancellation happened on time and prevented the timer callback + // from running. + // + return TRUE; + } + } + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in_opt PVOID TimerContext, + __in MdDeferredRoutine TimerCallback, + __in LONG Period + ) + { + NTSTATUS ntStatus = STATUS_SUCCESS; + + m_TimerCallback = TimerCallback; + m_TimerContext = TimerContext; + m_Period = Period; + + // + // Create the timer object + // + m_TimerHandle = CreateThreadpoolTimer(_MdTimer::s_MdTimerCallback, + this, + NULL); + if (NULL == m_TimerHandle) + { + ntStatus = WinErrorToNtStatus(GetLastError()); + } + + // + // Create the work object + // + if (NT_SUCCESS(ntStatus)) + { + m_WorkObject = CreateThreadpoolWork(_MdTimer::s_MdWorkCallback, + this, + NULL); + if (NULL == m_WorkObject) + { + ntStatus = WinErrorToNtStatus(GetLastError()); + } + } + + return ntStatus; + } + + BOOLEAN + Start( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay + ) + { + BOOLEAN bRetVal; + FILETIME dueFileTime; + + if (m_TimerWasStarted) { + // + // Cancel the previously pended timer callback, + // we want it to execute after a full period elapsed. + // + WaitForThreadpoolTimerCallbacks(m_TimerHandle, TRUE); + } + + // + // Return TRUE if the timer is in the system timer queue. + // + bRetVal = IsInSystemQueue(); + + // + // This is a fresh start for the timer, so clear the flag that the + // timer callback function may have previously set. + // + m_CallbackStartedRunning = FALSE; + + // + // Set the timer started flag. + // + m_TimerWasStarted = TRUE; + + // + // Copy the due time into a FILETIME structure + // + dueFileTime.dwLowDateTime = DueTime.LowPart; + dueFileTime.dwHighDateTime = (DWORD) DueTime.HighPart; + + // + // Start the timer + // + SetThreadpoolTimer(m_TimerHandle, + &dueFileTime, + (DWORD) m_Period, + TolerableDelay); + + return bRetVal; + } + + _Must_inspect_result_ + BOOLEAN + Stop( + VOID + ) + { + BOOLEAN bRetVal; + + bRetVal = IsInSystemQueue(); + + // + // Stop the timer + // + SetThreadpoolTimer(m_TimerHandle, + NULL, // pftDueTime + 0, // msPeriod + 0 // msWindowLength + ); + + // + // Cancel pending callbacks that have not yet started to execute and wait + // for outstanding callbacks to complete. + // + WaitForThreadpoolTimerCallbacks(m_TimerHandle, + TRUE // cancel pending callbacks + ); + + // + // Reset the timer started flag. + // + m_TimerWasStarted = FALSE; + + return bRetVal; + } + + VOID + TimerCallback( + VOID + ) + { + // + // Invoke the user's callback function + // + m_TimerCallback(NULL, /* Reserved1 */ + m_TimerContext, + NULL, /* Reserved2 */ + NULL /* Reserved3 */ + ); + + return; + } + + static + VOID CALLBACK + s_MdWorkCallback( + __inout PTP_CALLBACK_INSTANCE Instance, + __inout_opt PVOID Context, + __inout PTP_WORK Work + ) + { + struct _MdTimer *pThis = NULL; + + UNREFERENCED_PARAMETER(Instance); + UNREFERENCED_PARAMETER(Work); + + pThis = (struct _MdTimer*) Context; + pThis->TimerCallback(); + + return; + } + + static + VOID CALLBACK + s_MdTimerCallback( + __inout PTP_CALLBACK_INSTANCE Instance, + __inout_opt PVOID Context, + __inout PTP_TIMER Timer + ) + { + struct _MdTimer *pThis = NULL; + + UNREFERENCED_PARAMETER(Instance); + UNREFERENCED_PARAMETER(Timer); + + pThis = (struct _MdTimer*) Context; + + // + // First, indicate that the callback has started running + // + pThis->m_CallbackStartedRunning = TRUE; + + // + // Post a work object to execute the callback function supplied by the + // user of MxTimer. + // + // We do not execute the user-supplied callback here because we could + // run into a deadlock if the user is trying to cancel the timer by + // calling MxTimer::Stop. MxTimer::Stop actually blocks waiting for + // MdTimer::s_MdTimerCallback to finish executing, so that it can know + // where its attempt to cancel the timer was successful. If we were to + // execute the user's callback in MdTimer::s_MdTimerCallback, the user + // would have to be careful not to call MxTimer::Stop while holding a + // lock that the user's callback tries to acquire. In order to avoid + // imposing such a restriction on the user, we allow + // MdTimer::s_MdTimerCallback to return immediately after posting a + // work object to run the user's callback. + // + SubmitThreadpoolWork(pThis->m_WorkObject); + + return; + } + + BOOLEAN + StartWithReturn( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay + ) + { + return Start(DueTime, TolerableDelay); + } +} MdTimer; + +#include "MxTimer.h" + +// +// Implementation of MxTimer functions +// +MxTimer::MxTimer( + VOID + ) +{ +} + +MxTimer::~MxTimer( + VOID + ) +{ +} + +_Must_inspect_result_ +NTSTATUS +MxTimer::Initialize( + __in_opt PVOID TimerContext, + __in MdDeferredRoutine TimerCallback, + __in LONG Period + ) +/*++ +Routine description: + Initializes the MxTimer object. + +Arguments: + TimerContext - Context information that will be passed in to the timer + callback function. + + TimerCallback - The timer callback function. + + *** IMPORTANT NOTE *** + MxTimer object must not be freed inside the timer callback function + because in the pre-Vista, user mode implementation of MxTimer, the + destructor blocks waiting for all callback functions to finish + executing. Hence freeing the MxTimer object inside the callback + function will result in a deadlock. + + Period - The period of the timer in milliseconds. + +Return value: + An NTSTATUS value that indicates whether or not we succeeded in + initializing the MxTimer +--*/ +{ + NTSTATUS ntStatus; + + ntStatus = m_Timer.Initialize(TimerContext, + TimerCallback, + Period); + + return ntStatus; +} + +_Must_inspect_result_ +NTSTATUS +MxTimer::InitializeEx( + __in_opt PVOID TimerContext, + __in MdExtCallback TimerCallback, + __in LONG Period, + __in ULONG TolerableDelay, + __in BOOLEAN UseHighResolutionTimer + ) +{ + + UNREFERENCED_PARAMETER(TolerableDelay); + UNREFERENCED_PARAMETER(UseHighResolutionTimer); + UNREFERENCED_PARAMETER(TimerCallback); + UNREFERENCED_PARAMETER(TimerContext); + UNREFERENCED_PARAMETER(Period); + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return STATUS_NOT_IMPLEMENTED; + +} + +VOID +MxTimer::Start( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay + ) +{ + m_Timer.Start(DueTime, TolerableDelay); + + return; +} + +_Must_inspect_result_ +BOOLEAN +MxTimer::Stop( + VOID + ) +{ + BOOLEAN bRetVal; + + bRetVal = m_Timer.Stop(); + + return bRetVal; +} + +_Must_inspect_result_ +BOOLEAN +MxTimer::StartWithReturn( + __in LARGE_INTEGER DueTime, + __in ULONG TolerableDelay + ) +{ + BOOLEAN bRetVal = TRUE; + + bRetVal = m_Timer.StartWithReturn(DueTime, TolerableDelay); + + return bRetVal; +} + +VOID +MxTimer::FlushQueuedDpcs( + VOID + ) +{ + WaitForThreadpoolWorkCallbacks(m_Timer.m_WorkObject, + TRUE // cancel pending callbacks + ); +} + diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxum.h new file mode 100644 index 00000000000..f2153977ea6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxum.h @@ -0,0 +1,248 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxUm.h + +Abstract: + + This file includes standard NT headers and + user mode versions of mode agnostic headers + + It also contains definitions pulled out from wdm.h + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +#ifndef UMDF_USING_NTSTATUS +#define UMDF_USING_NTSTATUS +#endif + +#include +#include +#include + + + + +#ifdef UMDF_INFRASTRUCTURE +#ifndef WUDF_KERNEL +typedef PVOID PIRP; +typedef PVOID PIO_REMOVE_LOCK; +#endif +#endif + +#include "wdmdefs.h" + +#define WDF_VIOLATION ((ULONG)0x0000010DL) + +#define FX_PLUGPLAY_REGKEY_DEVICEMAP 0x8 + +// +// Define the callback function to be supplied by a user-mode user of MxTimer +// It has the extra parameters Reserved1, Reserved2 and Reserved3 to make it +// look like the KDEFERRED_ROUTINE that used as the callback function for the +// kernel mode version of MxTimer. The user-mode user of MxTimer should not +// use these ReservedX parameters. +// + +typedef +VOID +TIMER_CALLBACK_ROUTINE( + __in PKDPC Reserved1, + __in_opt PVOID Context, + __in_opt PVOID Reserved2, + __in_opt PVOID Reserved3 + ); + +typedef PVOID PEX_TIMER; + +typedef +VOID +TIMER_CALLBACK_ROUTINE_EX( + __in PEX_TIMER Reserved1, + __in_opt PVOID Context + ); + +typedef TIMER_CALLBACK_ROUTINE MdDeferredRoutineType, *MdDeferredRoutine; +typedef TIMER_CALLBACK_ROUTINE_EX MdExtCallbackType, *MdExtCallback; + +// +// Forward defines +// +struct IFxMessageDispatch; +struct IUnknown; +struct IWudfIrp; +struct IWudfIoIrp; +struct IWudfFile; +struct IWDFObject; +struct IObjectCleanup; +struct IWudfDeviceStack; +struct IWudfDeviceStack2; +struct IWudfTargetCallbackDeviceChange; +struct IWudfIoDispatcher; +struct IWudfRemoteDispatcher; +struct IWudfDevice; +struct IWudfDevice2; +struct IWudfHost; +struct IWudfHost2; + +// +// typedefs +// +typedef IWudfDevice * MdDeviceObject; +typedef IWudfIrp* MdIrp; +typedef LPCSTR MxFuncName; +typedef PVOID MxThread; +typedef PVOID MdEThread; +typedef PWUDF_IO_REMOVE_LOCK MdRemoveLock; +typedef PVOID MdInterrupt; + +typedef struct _STACK_DEVICE_CAPABILITIES *PSTACK_DEVICE_CAPABILITIES; +typedef UINT64 WUDF_INTERFACE_CONTEXT; +typedef enum _WDF_REQUEST_TYPE WDF_REQUEST_TYPE; +typedef struct _WDF_INTERRUPT_INFO *PWDF_INTERRUPT_INFO; +typedef enum _WDF_INTERRUPT_POLICY WDF_INTERRUPT_POLICY; +typedef enum _WDF_INTERRUPT_PRIORITY WDF_INTERRUPT_PRIORITY; +typedef struct _WDF_OBJECT_ATTRIBUTES *PWDF_OBJECT_ATTRIBUTES; +typedef enum _WDF_DEVICE_IO_BUFFER_RETRIEVAL WDF_DEVICE_IO_BUFFER_RETRIEVAL; +typedef enum RdWmiPowerAction; +typedef struct _WDF_REQUEST_PARAMETERS *PWDF_REQUEST_PARAMETERS; +typedef enum _WDF_EVENT_TYPE WDF_EVENT_TYPE; +typedef enum _WDF_FILE_INFORMATION_CLASS WDF_FILE_INFORMATION_CLASS; +typedef WDF_FILE_INFORMATION_CLASS *PWDF_FILE_INFORMATION_CLASS; + +typedef +NTSTATUS +WUDF_IO_COMPLETION_ROUTINE ( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp, + __in PVOID Context + ); + +typedef WUDF_IO_COMPLETION_ROUTINE *PWUDF_IO_COMPLETION_ROUTINE; + +typedef +VOID +WUDF_DRIVER_CANCEL ( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp + ); + +typedef WUDF_DRIVER_CANCEL *PWUDF_DRIVER_CANCEL; +typedef WUDF_IO_COMPLETION_ROUTINE MdCompletionRoutineType, *MdCompletionRoutine; +typedef WUDF_DRIVER_CANCEL MdCancelRoutineType, *MdCancelRoutine; + +// +// From wdm.h +// + +typedef +__drv_functionClass(REQUEST_POWER_COMPLETE) +__drv_sameIRQL +VOID +REQUEST_POWER_COMPLETE ( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in_opt PVOID Context, + __in PIO_STATUS_BLOCK IoStatus + ); + +typedef REQUEST_POWER_COMPLETE *PREQUEST_POWER_COMPLETE; +typedef REQUEST_POWER_COMPLETE MdRequestPowerCompleteType, *MdRequestPowerComplete; + +typedef enum _WDF_DEVICE_IO_TYPE WDF_DEVICE_IO_TYPE; +typedef struct _DRIVER_OBJECT_UM *PDRIVER_OBJECT_UM; + +// +// Driver object's basic interface. +// +typedef +NTSTATUS +DRIVER_ADD_DEVICE_UM ( + _In_ PDRIVER_OBJECT_UM DriverObject, + _In_ PVOID Context, + _In_ IWudfDeviceStack * DevStack, + _In_ LPCWSTR KernelDeviceName, + _In_opt_ HKEY hPdoKey, + _In_ LPCWSTR pwszServiceName, + _In_ LPCWSTR pwszDevInstanceID, + _In_ ULONG ulDriverID + ); + +typedef DRIVER_ADD_DEVICE_UM *PFN_DRIVER_ADD_DEVICE_UM; + +typedef +VOID +DRIVER_DISPATCH_UM ( + _In_ IWudfDevice * DeviceObject, + _In_ IWudfIrp * Irp, + _In_opt_ IUnknown * Context + ); + +typedef DRIVER_DISPATCH_UM *PFN_DRIVER_DISPATCH_UM; + +typedef +VOID +DRIVER_UNLOAD_UM ( + _In_ PDRIVER_OBJECT_UM DriverObject + ); + +typedef DRIVER_UNLOAD_UM *PFN_DRIVER_UNLOAD_UM; + + + + +#ifdef UMDF_INFRASTRUCTURE +#ifndef WUDF_KERNEL +typedef CCHAR KPROCESSOR_MODE; +typedef PVOID PMDL; +typedef +_IRQL_requires_same_ +_Function_class_(ALLOCATE_FUNCTION) +PVOID +ALLOCATE_FUNCTION ( + _In_ POOL_TYPE PoolType, + _In_ SIZE_T NumberOfBytes, + _In_ ULONG Tag + ); +typedef ALLOCATE_FUNCTION *PALLOCATE_FUNCTION; +typedef +_IRQL_requires_same_ +_Function_class_(FREE_FUNCTION) +VOID +FREE_FUNCTION ( + _In_ __drv_freesMem(Mem) PVOID Buffer + ); +typedef FREE_FUNCTION *PFREE_FUNCTION; +#endif +#endif + +//=============================================================================== +#include +#include + +#include "ErrToStatus.h" + +#include "MxDriverObjectUm.h" +#include "MxDeviceObjectUm.h" +#include "MxFileObjectUm.h" +#include "MxGeneralUm.h" +#include "MxLockUm.h" +#include "MxPagedLockUm.h" +#include "MxEventUm.h" +#include "MxMemoryUm.h" +#include "MxTimerUm.h" +#include "MxWorkItemUm.h" diff --git a/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxworkitemum.h b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxworkitemum.h new file mode 100644 index 00000000000..ab55efabd7e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/primitives/um/mxworkitemum.h @@ -0,0 +1,294 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxWorkItemUm.h + +Abstract: + + User mode implementation of work item + class defined in MxWorkItem.h + + ***********PLEASE NOTE***************************** + A significant difference from kernel mode implementation of work item + is that user mode version of MxWorkItem::_Free synchronously waits for + callback to return. + + This implies that _Free cannot be invoked from within the callback otherwise + it would lead to a deadlock. + + PLEASE NOTE that _Free cannot be made to return without waiting without + significant changes. + + If Free is not made to wait synchronously there is a potential for binary + unload while workitem is running - even with waiting for an event/reference + count etc., the tail instructions may be running. + The only way to resolve that is to move work-item code out of framework + binary and into the host so that host can take a reference on framework + binary around the work item callback invocation (similar to the way I/O + manager keeps a reference on the device object around the invocation of + + workitem callback). + **************************************************** + +Author: + + + +Revision History: + + + + + + +--*/ + +#pragma once + +typedef +VOID +MX_WORKITEM_ROUTINE ( + __in MdDeviceObject DeviceObject, + __in_opt PVOID Context + ); + +typedef MX_WORKITEM_ROUTINE *PMX_WORKITEM_ROUTINE; + +typedef struct { + MdDeviceObject DeviceObject; + + // + // threadpool wait block + // + PTP_WAIT WaitBlock; + + HANDLE WorkItemEvent; + + PMX_WORKITEM_ROUTINE Callback; + + PVOID Context; + + // + // True if callbacks run in the default thread pool environment, + // rather than in an environment explicitly owned by the driver. + // This has implications in MxWorkItem::_Free. + // + BOOLEAN DefaultThreadpoolEnv; +} UmWorkItem; + +typedef UmWorkItem* MdWorkItem; + +#include "MxWorkItem.h" + +__inline +MxWorkItem::MxWorkItem( + ) +{ + m_WorkItem = NULL; +} + +_Must_inspect_result_ +__inline +NTSTATUS +MxWorkItem::Allocate( + __in MdDeviceObject DeviceObject, + __in_opt PVOID ThreadPoolEnv + ) +{ + DWORD err = 0; + + m_WorkItem = (MdWorkItem)::HeapAlloc( + GetProcessHeap(), + 0, + sizeof(UmWorkItem) + ); + + if (NULL == m_WorkItem) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + ZeroMemory(m_WorkItem, sizeof(UmWorkItem)); + + m_WorkItem->WorkItemEvent = CreateEvent( + NULL, + FALSE, + FALSE, + NULL); + + if (NULL == m_WorkItem->WorkItemEvent) { + err = GetLastError(); + goto exit; + } + + m_WorkItem->WaitBlock = CreateThreadpoolWait( + _WorkerThunk, + this->GetWorkItem(), // Context to callback function + (PTP_CALLBACK_ENVIRON)ThreadPoolEnv + ); + + if (m_WorkItem->WaitBlock == NULL) { + err = GetLastError(); + goto exit; + } + + m_WorkItem->DefaultThreadpoolEnv = (NULL == ThreadPoolEnv); + + m_WorkItem->DeviceObject = DeviceObject; + +exit: + // + // Cleanup in case of failure + // + if (0 != err) { + if (NULL != m_WorkItem->WorkItemEvent) { + CloseHandle(m_WorkItem->WorkItemEvent); + m_WorkItem->WorkItemEvent = NULL; + } + + ::HeapFree(GetProcessHeap(), 0, m_WorkItem); + m_WorkItem = NULL; + } + + return NTSTATUS_FROM_WIN32(err); +} + +__inline +VOID +MxWorkItem::Enqueue( + __in PMX_WORKITEM_ROUTINE Callback, + __in PVOID Context + ) +{ + // + // ASSUMPTION: This function assumes that another call to Enqueue + // is made only after the callback has been invoked, altough it is OK + // to make another call from within the callback. + // + // It is up to a higher layer/caller to ensure this. + // For example: FxSystemWorkItem layered on top of MxWorkItem ensures this. + // + + // + // Since multiple calls to Enqueue cannot be made at the same time + // as explained above, it is OK to store callback and context in + // the workitem itself. + // + // This behavior is similar to that of IoQueueWorkItem which accepts + // a callback and a context which are stored within the work-item. + // + + m_WorkItem->Callback = Callback; + m_WorkItem->Context = Context; + + // + // We must register the event with the wait object before signaling it + // to trigger the wait callback. + // + SetThreadpoolWait(m_WorkItem->WaitBlock, + m_WorkItem->WorkItemEvent, + NULL // timeout + ); + + SetEvent(m_WorkItem->WorkItemEvent); +} + +__inline +MdWorkItem +MxWorkItem::GetWorkItem( + ) +{ + return m_WorkItem; +} + +__inline +VOID +MxWorkItem::_Free( + __in MdWorkItem Item + ) +{ + // + // PLEASE NOTE that _Free waits for callback to return synchronously. + // + // DO NOT call _Free from work item callback otherwise it would cause a + // deadlock. + // + // Please see comments on the top of the file. + // + + if (NULL != Item) { + // + // Wait indefinitely for work item to complete + // + if (NULL != Item->WaitBlock) { + // + // this will prevent any new waits to be queued but callbacks + // already queued will still occur. + // + SetThreadpoolWait(Item->WaitBlock, NULL, NULL); + + // + // If the callbacks ran in the default thread pool environment, + // wait for callbacks to finish. + // If they ran in an environment explicitly owned by the driver, + // then this wait will happen before the driver DLL is unloaded, + // the host takes care of this. + // + if (Item->DefaultThreadpoolEnv) { + WaitForThreadpoolWaitCallbacks(Item->WaitBlock, + FALSE // donot cancel pending waits + ); + } + + // + // Release the wait object. + // + CloseThreadpoolWait(Item->WaitBlock); + } + + if (NULL != Item->WorkItemEvent) { + CloseHandle(Item->WorkItemEvent); + Item->WorkItemEvent = NULL; + } + + ::HeapFree( + GetProcessHeap(), + 0, + Item + ); + } +} + +__inline +VOID +MxWorkItem::Free( + ) +{ + // + // PLEASE NOTE that _Free waits for callback to return synchronously. + // + // DO NOT call Free from work item callback otherwise it would cause a + // deadlock. + // + // Please see comments on the top of the file. + // + + if (NULL != m_WorkItem) { + MxWorkItem::_Free(m_WorkItem); + m_WorkItem = NULL; + } +} + +// +// FxAutoWorkitem +// +__inline +MxAutoWorkItem::~MxAutoWorkItem( + ) +{ + this->Free(); +} + + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/dbgtrace.h b/sdk/lib/drivers/wdf/shared/inc/private/common/dbgtrace.h new file mode 100644 index 00000000000..ed55b2ae486 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/dbgtrace.h @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + DbgTrace.h + +Abstract: + + This file can be used to redirect WPP traces to + debugger. + + + + + + + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#if !defined(EVENT_TRACING) + + + + + + + +#if !defined(TRACE_LEVEL_NONE) + #define TRACE_LEVEL_NONE 0 + #define TRACE_LEVEL_CRITICAL 1 + #define TRACE_LEVEL_FATAL 1 + #define TRACE_LEVEL_ERROR 2 + #define TRACE_LEVEL_WARNING 3 + #define TRACE_LEVEL_INFORMATION 4 + #define TRACE_LEVEL_VERBOSE 5 + #define TRACE_LEVEL_RESERVED6 6 + #define TRACE_LEVEL_RESERVED7 7 + #define TRACE_LEVEL_RESERVED8 8 + #define TRACE_LEVEL_RESERVED9 9 +#endif + + +// +// Define Debug Flags +// +#define TRACINGDEVICE 0x00000001 +#define TRACINGOBJECT 0x00000002 +#define TRACINGAPIERROR 0x00000004 +#define TRACINGHANDLE 0x00000008 +#define TRACINGPOOL 0x00000010 +#define TRACINGERROR 0x00000020 +#define TRACINGUSEROBJECT 0x00000040 +#define TRACINGREQUEST 0x00000080 +#define TRACINGIO 0x00000100 +#define TRACINGPNP 0x00000200 +#define TRACINGDRIVER 0x00001000 +#define TRACINGPNPPOWERSTATES 0x00002000 + +extern "C" { +void +__cdecl +DoTraceLevelMessage ( + __in PVOID FxDriverGlobals, + __in ULONG DebugPrintLevel, + __in ULONG DebugPrintFlag, + __drv_formatString(FormatMessage) + __in PCSTR DebugMessage, + ... + ); +} + +// +// When linking the lib with UMDF framework we don't want these macros +// to be defined since UMDF WPP tracing uses these macros + + + +// +#ifndef UMDF +#define WPP_INIT_TRACING(DriverObject, RegistryPath) +#define WPP_CLEANUP(DriverObject) +#endif + +extern ULONG DebugLevel; +extern ULONG DebugFlag; + +#endif diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxautoregistry.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxautoregistry.hpp new file mode 100644 index 00000000000..4ffc1ae5339 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxautoregistry.hpp @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxAutoRegistry.hpp + +Abstract: + + This is the C++ header for registry related objects which follows the RAII + (resource acquisition is initialization) pattern where + it frees the allocated item when the struct goes out of scope. + +Author: + + + +Revision History: + + + + +--*/ +#ifndef _FXAUTOREGISTRY_H_ +#define _FXAUTOREGISTRY_H_ + +struct FxAutoRegKey { +public: + FxAutoRegKey() + { + m_Key = NULL; + } + + ~FxAutoRegKey() + { + if (m_Key != NULL) { + FxRegKey::_Close(m_Key); + } + } + +public: + HANDLE m_Key; +}; + +#endif // _FXAUTOREGISTRY_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxautostring.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxautostring.hpp new file mode 100644 index 00000000000..6c93927cf9c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxautostring.hpp @@ -0,0 +1,53 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxAutoString.hpp + +Abstract: + + This is the C++ header for FxAutoString which represents a UNICODE_STRING + and follows the RAII (resource acquisiion is initialization) pattern where + it frees the buffer when the struct goes out of scope. + +Author: + + + +Revision History: + + + +--*/ + +#ifndef _FXAUTOSTRING_H_ +#define _FXAUTOSTRING_H_ + +struct FxAutoString { + FxAutoString( + VOID + ) + { + RtlZeroMemory(&m_UnicodeString, sizeof(m_UnicodeString)); + } + + ~FxAutoString( + VOID + ) + { + if (m_UnicodeString.Buffer != NULL) { +#if _WDFLDR_ + ExFreePool(m_UnicodeString.Buffer); +#else + FxPoolFree(m_UnicodeString.Buffer); +#endif + RtlZeroMemory(&m_UnicodeString, sizeof(m_UnicodeString)); + } + } + + UNICODE_STRING m_UnicodeString; +}; + +#endif // _FXAUTOSTRING_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallback.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallback.hpp new file mode 100644 index 00000000000..2c109b29d69 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallback.hpp @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCallback.hpp + +Abstract: + + This represents a delegate object base class for + calling back into the driver. + +Author: + + + + +Revision History: + +--*/ + +#ifndef _FXCALLBACK_H_ +#define _FXCALLBACK_H_ + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxCallback.hpp.tmh" +#endif +} + +class FxCallback { + +public: + + FxCallback( + __in_opt PFX_DRIVER_GLOBALS FxDriverGlobals = NULL + ) + { + UNREFERENCED_PARAMETER(FxDriverGlobals); + } + + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in POOL_TYPE PoolType = NonPagedPool + ) + { + return FxPoolAllocate(FxDriverGlobals, PoolType, Size); + } + + VOID + operator delete( + __in PVOID pointer + ) + { + FxPoolFree(pointer); + } + +protected: + void + __inline + CallbackStart( + VOID + ) + { + // intentionally does nothing, visual place marker only for now + DO_NOTHING(); + } + + void + __inline + CallbackEnd( + VOID + ) + { + // intentionally does nothing, visual place marker only for now + DO_NOTHING(); + } +}; + +class FxLockedCallback { + +private: + FxCallbackLock* m_CallbackLock; + +public: + FxLockedCallback( + VOID + ) + { + m_CallbackLock = NULL; + } + + FxCallbackLock* + GetCallbackLockPtr( + VOID + ) + { + return m_CallbackLock; + } + + void + SetCallbackLockPtr( + FxCallbackLock* Lock + ) + { + m_CallbackLock = Lock; + } + +protected: + __inline + void + CallbackStart( + __out PKIRQL PreviousIrql + ) + { + if (m_CallbackLock != NULL) { + m_CallbackLock->Lock(PreviousIrql); + } + } + + __inline + void + CallbackEnd( + __in KIRQL PreviousIrql + ) + { + if (m_CallbackLock != NULL) { + m_CallbackLock->Unlock(PreviousIrql); + } + } +}; + +#endif // _FXCALLBACK_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbacklock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbacklock.hpp new file mode 100644 index 00000000000..9002ffb1a49 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbacklock.hpp @@ -0,0 +1,648 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCallbackLock.hpp + +Abstract: + + This is the C++ header for the FxCallbackLock + + This represents an abstract class for implementing + the locks used when we callback into the device driver. + +Author: + + + + +Revision History: + + + Made it mode agnostic + +--*/ + +#ifndef _FXCALLBACKLOCK_H_ +#define _FXCALLBACKLOCK_H_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxCallbackLock.hpp.tmh" +#endif + +} + +// +// Callback locks track current owner. This is used to determine if a callback +// event into the driver needs to be deferred to prevent recursive +// locking. +// +// A Callback lock supports recursive locking, but this is not exposed in +// the current Driver Frameworks <-> Device Driver interactions, and results +// in a verifier assert. +// + +class FxCallbackLock : public FxGlobalsStump { + +protected: + MxThread m_OwnerThread; + ULONG m_RecursionCount; + + // For Verifier + FxVerifierLock* m_Verifier; + +public: + + + + + + + + KIRQL m_PreviousIrql; + +public: + + FxCallbackLock( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxGlobalsStump(FxDriverGlobals) + { + m_OwnerThread = NULL; + m_RecursionCount = 0; + m_Verifier = NULL; + } + + virtual ~FxCallbackLock() + { + } + + virtual + void + Initialize( + FxObject* ParentObject + ) = 0; + + virtual + void + Lock( + __out PKIRQL PreviousIrql + ) = 0; + + virtual + void + Unlock( + __in KIRQL PreviousIrql + ) = 0; + + // TRUE if the current thread is the owner + _Must_inspect_result_ + virtual + BOOLEAN + IsOwner( + VOID + ) = 0; + + VOID + CheckOwnership( + VOID + ) + { + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + // + // If verify locks is on, catch drivers + // returning with the lock released. + // + if (pFxDriverGlobals->FxVerifierLock) { + if (IsOwner() == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Callback: Driver released the callback lock 0x%p", + this); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif // _FXCALLBACKLOCK_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbackmutexlock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbackmutexlock.hpp new file mode 100644 index 00000000000..0cfa17bfb3d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbackmutexlock.hpp @@ -0,0 +1,173 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCallbackMutexLock.hpp + +Abstract: + + This is the C++ header for the FxCallbackMutexLock + + This represents a container for handling locking + when we callback into the device driver at thread + level. + +Author: + + + + +Revision History: + + +--*/ + +#ifndef _FXCALLBACKMUTEXLOCK_H_ +#define _FXCALLBACKMUTEXLOCK_H_ + +extern "C" { +#include "FxCallbackMutexLock.hpp.tmh" +} + +class FxCallbackMutexLock : public FxCallbackLock { + +private: + + + + + + + + MxPagedLock m_Lock; + +public: + + FxCallbackMutexLock( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallbackLock(FxDriverGlobals) + { + m_Lock.Initialize(); + } + + virtual + ~FxCallbackMutexLock() + { + if (m_Verifier) { + delete m_Verifier; + } + } + + virtual + void + Initialize( + FxObject* ParentObject + ) + { + PFX_DRIVER_GLOBALS fxDriverGlobals; + + m_Verifier = NULL; + fxDriverGlobals = GetDriverGlobals(); + + if (fxDriverGlobals->FxVerifierLock) { + + // + // VerifierLock CreateAndInitialize failure is not fatal, + // we just won't track anything + // + (void) FxVerifierLock::CreateAndInitialize(&m_Verifier, + fxDriverGlobals, + ParentObject, + TRUE); + } + } + + virtual + void + Lock( + __out PKIRQL PreviousIrql + ) + { + MxThread cur = Mx::MxGetCurrentThread(); + + if (m_OwnerThread == cur) { + PFX_DRIVER_GLOBALS fxDriverGlobals; + + fxDriverGlobals = GetDriverGlobals(); + m_RecursionCount++; + + // + // For now we have decided not to allow this. + // + + + + + + + + // + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGDEVICE, + "Recursive acquire of callback lock 0x%p", this); + + FxVerifierBugCheck(fxDriverGlobals, + WDF_RECURSIVE_LOCK, + (ULONG_PTR)this); + } + else { + if (m_Verifier != NULL) { + m_Verifier->Lock(PreviousIrql, FALSE); + } + else { + Mx::MxEnterCriticalRegion(); + m_Lock.AcquireUnsafe(); + } + m_OwnerThread = cur; + } + } + + virtual + void + Unlock( + __in KIRQL PreviousIrql + ) + { + CheckOwnership(); + + if (m_RecursionCount > 0) { + m_RecursionCount--; + } + else { + m_OwnerThread = NULL; + if (m_Verifier) { + m_Verifier->Unlock(PreviousIrql, FALSE); + } + else { + m_Lock.ReleaseUnsafe(); + Mx::MxLeaveCriticalRegion(); + } + } + } + + _Must_inspect_result_ + virtual + BOOLEAN + IsOwner( + VOID + ) + { + MxThread cur = Mx::MxGetCurrentThread(); + + if (m_OwnerThread == cur) { + return TRUE; + } + else { + return FALSE; + } + } +}; + +#endif // _FXCALLBACKMUTEXLOCK_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbackspinlock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbackspinlock.hpp new file mode 100644 index 00000000000..b87407efd32 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcallbackspinlock.hpp @@ -0,0 +1,171 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCallbackSpinLock.hpp + +Abstract: + + This is the C++ header for the FxCallbackSpinLock + + This is the spinlock based driver callback lock + + +Author: + + + + +Revision History: + + +--*/ + +#ifndef _FXCALLBACKSPINLOCK_H_ +#define _FXCALLBACKSPINLOCK_H_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxCallbackSpinLock.hpp.tmh" +#endif + +} + +class FxCallbackSpinLock : public FxCallbackLock { + +private: + MxLock m_Lock; + +public: + + FxCallbackSpinLock( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallbackLock(FxDriverGlobals) + { + } + + virtual + ~FxCallbackSpinLock( + VOID + ) + { + if (m_Verifier) { + delete m_Verifier; + } + } + + virtual + void + Initialize( + FxObject* ParentObject + ) + { + PFX_DRIVER_GLOBALS fxDriverGlobals; + + m_Verifier = NULL; + fxDriverGlobals = GetDriverGlobals(); + + if (fxDriverGlobals->FxVerifierLock) { + + // + // VerifierLock CreateAndInitialize failure is not fatal, + // we just won't track anything + // + (void) FxVerifierLock::CreateAndInitialize(&m_Verifier, + fxDriverGlobals, + ParentObject, + FALSE); + + } + } + + virtual + void + Lock( + __out PKIRQL PreviousIrql + ) + { + MxThread cur = Mx::MxGetCurrentThread(); + + if (m_OwnerThread == cur) { + PFX_DRIVER_GLOBALS fxDriverGlobals; + + fxDriverGlobals = GetDriverGlobals(); + m_RecursionCount++; + + // + // For now we have decided not to allow this. + // + + + + + + // + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGDEVICE, + "Recursive acquire of callback lock! 0x%p", this); + + FxVerifierBugCheck(fxDriverGlobals, + WDF_RECURSIVE_LOCK, + (ULONG_PTR) this); + return; + } + else { + if (m_Verifier != NULL) { + m_Verifier->Lock(PreviousIrql, FALSE); + } + else { + m_Lock.Acquire(PreviousIrql); + } + + m_OwnerThread = cur; + return; + } + } + + virtual + void + Unlock( + __in KIRQL PreviousIrql + ) + { + CheckOwnership(); + + if (m_RecursionCount > 0) { + m_RecursionCount--; + } + else { + m_OwnerThread = NULL; + if (m_Verifier != NULL) { + m_Verifier->Unlock(PreviousIrql, FALSE); + } + else { + m_Lock.Release(PreviousIrql); + } + } + } + + _Must_inspect_result_ + inline + virtual + BOOLEAN + IsOwner( + VOID + ) + { + MxThread cur = Mx::MxGetCurrentThread(); + + if (m_OwnerThread == cur) { + return TRUE; + } + else { + return FALSE; + } + } +}; + +#endif // _FXCALLBACKSPINLOCK_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxchildlist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxchildlist.hpp new file mode 100644 index 00000000000..331e3bdb512 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxchildlist.hpp @@ -0,0 +1,816 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxChildList.hpp + +Abstract: + + Defines the interface for asynchronously creating and destroying child + devices + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDEVICELIST_H_ +#define _FXDEVICELIST_H_ + +enum FxChildListIteratorIndexValues { + DescriptionIndex = 0, + ModificationIndex, +}; + +struct FxChildListCreateDeviceCallback : public FxCallback { + + FxChildListCreateDeviceCallback( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFCHILDLIST DeviceList, + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __in PWDFDEVICE_INIT ChildInit + ) + { + NTSTATUS status; + + CallbackStart(); + status = m_Method(DeviceList, IdentificationDescription, ChildInit); + CallbackEnd(); + + return status; + } + + PFN_WDF_CHILD_LIST_CREATE_DEVICE m_Method; +}; + +struct FxChildListScanForChildrenCallback : public FxCallback { + + FxChildListScanForChildrenCallback( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFCHILDLIST DeviceList + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(DeviceList); + CallbackEnd(); + } + } + + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN m_Method; +}; + +enum FxChildListState { + ListUnlocked = 1, + ListLockedForEnum, + ListLockedForParentRemove, +}; + +enum FxChildListScanTagStates { + ScanTagUndefined = 0, + ScanTagActive, + ScanTagCancelled, + ScanTagFinished, +}; + +class FxChildList : public FxNonPagedObject { + friend struct FxDeviceDescriptionEntry; + +public: + + static + _Must_inspect_result_ + NTSTATUS + _CreateAndInit( + __out FxChildList** ChildList, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES ListAttributes, + __in size_t TotalDescriptionSize, + __in CfxDevice* Device, + __in PWDF_CHILD_LIST_CONFIG ListConfig, + __in BOOLEAN Static = FALSE + ); + + WDFCHILDLIST + GetHandle( + VOID + ) + { + return (WDFCHILDLIST) GetObjectHandle(); + } + + MxEvent* + GetScanEvent( + VOID + ) + { + return m_ScanEvent.GetSelfPointer(); + } + + WDFDEVICE + GetDevice( + VOID + ); + + CfxDevice* + GetDeviceFromId( + __inout PWDF_CHILD_RETRIEVE_INFO Info + ); + + _Must_inspect_result_ + NTSTATUS + GetAddressDescription( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + + VOID + GetAddressDescriptionFromEntry( + __in FxDeviceDescriptionEntry* Entry, + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + + VOID + BeginScan( + __out_opt PULONG ScanTag = NULL + ); + + VOID + EndScan( + __inout_opt PULONG ScanTag = NULL + ); + + VOID + CancelScan( + __in BOOLEAN EndTheScan, + __inout_opt PULONG ScanTag + ); + + VOID + BeginIteration( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ); + + VOID + EndIteration( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ); + + VOID + InitIterator( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ); + + _Must_inspect_result_ + NTSTATUS + GetNextDevice( + __out WDFDEVICE* Device, + __inout PWDF_CHILD_LIST_ITERATOR Iterator, + __inout_opt PWDF_CHILD_RETRIEVE_INFO Info + ); + + WDFDEVICE + GetNextStaticDevice( + __in WDFDEVICE PreviousDevice, + __in ULONG Flags + ); + + BOOLEAN + IsScanCancelled( + __in PULONG ScanTag + ) + { + return *ScanTag == ScanTagCancelled ? TRUE : FALSE; + } + + _Must_inspect_result_ + NTSTATUS + UpdateAsMissing( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Description + ); + + _Must_inspect_result_ + NTSTATUS + UpdateDeviceAsMissing( + __in CfxDevice* Device + ); + + VOID + ReenumerateEntry( + __inout FxDeviceDescriptionEntry* Entry + ); + + VOID + UpdateAllAsPresent( + __in_opt PULONG ScanTag = NULL + ); + + _Must_inspect_result_ + NTSTATUS + Add( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription, + __in_opt PULONG ScanTag = NULL + ); + + VOID + UpdateAddressDescriptionFromEntry( + __inout FxDeviceDescriptionEntry* Entry, + __in PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ); + + BOOLEAN + HasAddressDescriptions( + VOID + ) + { + return m_AddressDescriptionSize > 0 ? TRUE : FALSE; + } + + ULONG + GetAddressDescriptionSize( + VOID + ) + { + return m_AddressDescriptionSize; + } + + ULONG + GetIdentificationDescriptionSize( + VOID + ) + { + return m_IdentificationDescriptionSize; + } + + VOID + CopyId( + __out PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Dest, + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Source + ) + { + if (m_EvtIdentificationDescriptionCopy != NULL) { + m_EvtIdentificationDescriptionCopy(GetHandle(), Source, Dest); + } + else { + RtlCopyMemory(Dest, Source, m_IdentificationDescriptionSize); + } + } + + _Must_inspect_result_ + NTSTATUS + ProcessBusRelations( + __inout PDEVICE_RELATIONS *DeviceRelations + ); + + VOID + InvokeReportedMissingCallback( + VOID + ); + + VOID + PostParentToD0( + VOID + ); + + VOID + IndicateWakeStatus( + __in NTSTATUS WakeWakeStatus + ); + + VOID + ScanForChildren( + VOID + ) + { + m_EvtScanForChildren.Invoke(GetHandle()); + } + + // + // This notification is for the parent device. + // Child pnp remove notifications occur on the FxDeviceDescriptionEntry + // + VOID + NotifyDeviceSurpriseRemove( + VOID + ); + + // + // This notification is for the parent device. + // Child pnp remove notifications occur on the FxDeviceDescriptionEntry + // + VOID + NotifyDeviceRemove( + __inout PLONG ChildCount + ); + + BOOLEAN + IsStaticList( + VOID + ) + { + return m_StaticList; + } + + static + _Must_inspect_result_ + NTSTATUS + _ValidateConfig( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_CHILD_LIST_CONFIG Config, + __in size_t* TotalDescriptionSize + ); + + static + _Must_inspect_result_ + NTSTATUS + _ComputeTotalDescriptionSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_CHILD_LIST_CONFIG Config, + __in size_t* TotalDescriptionSize + ); + + static + size_t + _ComputeRelationsSize( + __in ULONG Count + ) + { + if (Count == 0) { + return sizeof(((PDEVICE_RELATIONS) NULL)->Count); + } + else { + return sizeof(DEVICE_RELATIONS) + (Count-1)*sizeof(PDEVICE_OBJECT); + } + } + + static + FxChildList* + _FromEntry( + __in FxTransactionedEntry* Entry + ) + { + return CONTAINING_RECORD(Entry, FxChildList, m_TransactionLink); + } + + ULONG + GetScanCount( + VOID + ) + { + return m_ScanCount; + } + +protected: + + FxChildList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t TotalDescriptionSize, + __in CfxDevice* Device, + __in BOOLEAN Static + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + VOID + Initialize( + __in PWDF_CHILD_LIST_CONFIG Config + ); + + BOOLEAN + ReenumerateEntryLocked( + __inout FxDeviceDescriptionEntry* Entry, + __in BOOLEAN FromQDR + ); + + BOOLEAN + CloneEntryLocked( + __inout PLIST_ENTRY FreeListHead, + __inout FxDeviceDescriptionEntry* Entry, + __in BOOLEAN FromQDR + ); + + VOID + ProcessModificationsLocked( + __inout PLIST_ENTRY FreeListHead + ); + + VOID + MarkDescriptionNotPresentWorker( + __inout FxDeviceDescriptionEntry* DescriptionEntry, + __in BOOLEAN ModificationCanBeQueued + ); + + VOID + MarkModificationNotPresentWorker( + __inout PLIST_ENTRY FreeListHead, + __inout FxDeviceDescriptionEntry* ModificationEntry + ); + + VOID + DrainFreeListHead( + __inout PLIST_ENTRY FreeListHead + ); + + FxDeviceDescriptionEntry* + SearchBackwardsForMatchingModificationLocked( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id + ); + + FxDeviceDescriptionEntry* + SearchBackwardsForMatchingDescriptionLocked( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id + ); + + _Must_inspect_result_ + NTSTATUS + VerifyDescriptionEntry( + __in PLIST_ENTRY Entry + ); + + _Must_inspect_result_ + NTSTATUS + VerifyModificationEntry( + __in PLIST_ENTRY Entry + ); + + BOOLEAN + CreateDevice( + __inout FxDeviceDescriptionEntry* Entry, + __inout PBOOLEAN InvalidateRelations + ); + + _Must_inspect_result_ + NTSTATUS + DuplicateId( + __out PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Dest, + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Source + ) + { + if (m_EvtIdentificationDescriptionDuplicate != NULL) { + return m_EvtIdentificationDescriptionDuplicate(GetHandle(), + Source, + Dest); + } + else { + RtlCopyMemory(Dest, Source, m_IdentificationDescriptionSize); + return STATUS_SUCCESS; + } + } + + BOOLEAN + CompareId( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Lhs, + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Rhs + ) + { + if (m_EvtIdentificationDescriptionCompare != NULL) { + return m_EvtIdentificationDescriptionCompare(GetHandle(), + Lhs, + Rhs); + } + else { + return (m_IdentificationDescriptionSize == + RtlCompareMemory(Lhs, + Rhs, + m_IdentificationDescriptionSize)) ? TRUE + : FALSE; + } + } + + _Must_inspect_result_ + NTSTATUS + DuplicateAddress( + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Dest, + __in PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Source + ) + { + if (m_EvtAddressDescriptionDuplicate != NULL) { + return m_EvtAddressDescriptionDuplicate(GetHandle(), Source, Dest); + } + else { + RtlCopyMemory(Dest, Source, m_AddressDescriptionSize); + return STATUS_SUCCESS; + } + } + + VOID + CopyAddress( + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Dest, + __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER Source + ) + { + if (Source != NULL) { + if (m_EvtAddressDescriptionCopy != NULL) { + m_EvtAddressDescriptionCopy(GetHandle(), Source, Dest); + } + else { + RtlCopyMemory(Dest, Source, m_AddressDescriptionSize); + } + } + } + + VOID + CleanupDescriptions( + __in_opt PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdDescription, + __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddrDescription + ) + { + if (m_EvtAddressDescriptionCleanup != NULL && AddrDescription != NULL) { + m_EvtAddressDescriptionCleanup(GetHandle(), AddrDescription); + } + + if (m_EvtIdentificationDescriptionCleanup != NULL && IdDescription != NULL) { + m_EvtIdentificationDescriptionCleanup(GetHandle(), IdDescription); + } + } + +public: + // + // Link into list of FxChildList pointers maintained by the package. This + // differs from IFxStateChangeNotification's link because that one links + // into the list of pnp state change notifications for the device we are + // associated with. + // + FxTransactionedEntry m_TransactionLink; + +protected: + size_t m_TotalDescriptionSize; + + ULONG m_IdentificationDescriptionSize; + + ULONG m_AddressDescriptionSize; + + FxChildListCreateDeviceCallback m_EvtCreateDevice; + + FxChildListScanForChildrenCallback m_EvtScanForChildren; + + // + // These callbacks are not wrapped in FxCallback derived structures becase + // they are called under the framework locking and not in a locking model + // in which the driver writer can configure. + // + // copy one ID description to another + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY m_EvtIdentificationDescriptionCopy; + + // duplicate one ID description to another + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE m_EvtIdentificationDescriptionDuplicate; + + // cleanup an ID description + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP m_EvtIdentificationDescriptionCleanup; + + // compare to ID descriptions + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE m_EvtIdentificationDescriptionCompare; + + // copy one address description to another + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY m_EvtAddressDescriptionCopy; + + // duplicate one address description to another + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE m_EvtAddressDescriptionDuplicate; + + // cleanup an address description + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP m_EvtAddressDescriptionCleanup; + + // clone notification + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED m_EvtChildListDeviceReenumerated; + + KSPIN_LOCK m_ListLock; + + LIST_ENTRY m_DescriptionListHead; + + LIST_ENTRY m_ModificationListHead; + + FxChildListState m_State; + + BOOLEAN m_InvalidationNeeded; + + BOOLEAN m_StaticList; + + // + // Whether the child list is added to the enumerated children list. + // + BOOLEAN m_IsAdded; + + UCHAR m_EnumRetries; + + PULONG m_ScanTag; + + ULONG m_ScanCount; + + MxEvent m_ScanEvent; +}; + +// begin_wpp enum +enum FxChildListModificationState { + ModificationUnspecified = 0, + ModificationInsert, + ModificationRemove, + ModificationRemoveNotify, + ModificationClone, + ModificationNeedsPnpRemoval, +}; +// end_wpp + +// begin_wpp enum +enum FxChildListDescriptionState { + DescriptionUnspecified = 0, + DescriptionPresentNeedsInstantiation, + DescriptionInstantiatedHasObject, + DescriptionReportedMissing, + DescriptionNotPresent, +}; +// end_wpp + +// begin_wpp enum +enum FxChildListReportedMissingCallbackState : UCHAR { + CallbackStateUnspecified = 0, + CallbackNeedsToBeInvoked, + CallbackInvoked, +}; +// end_wpp + +enum FxChildListValues { + FX_CHILD_LIST_MAX_RETRIES = 3 +}; + +struct FxDeviceDescriptionEntry : public FxStump { + friend class FxDevice; + friend class FxChildList; + +public: + FxDeviceDescriptionEntry( + __inout FxChildList* DeviceList, + __in ULONG AddressDescriptionSize, + __in ULONG IdentificationDescriptionSize + ); + + ~FxDeviceDescriptionEntry(); + + _Must_inspect_result_ + PVOID + operator new( + __in size_t AllocatorBlock, + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in size_t TotalDescriptionSize + ); + + FxChildList* + GetParentList( + VOID + ) + { + return m_DeviceList; + } + + + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER + GetId( + VOID + ) + { + return m_IdentificationDescription; + } + + BOOLEAN + IsDeviceReportedMissing( + VOID + ); + + BOOLEAN + IsDeviceRemoved( + VOID + ); + + VOID + ProcessDeviceRemoved( + VOID + ); + + VOID + DeviceSurpriseRemoved( + VOID + ); + + _Must_inspect_result_ + FxDeviceDescriptionEntry* + Clone( + __inout PLIST_ENTRY FreeListHead + ); + + BOOLEAN + MatchStateToFlags( + __in ULONG Flags + ) + { + if (((Flags & WdfRetrievePresentChildren) && + m_DescriptionState == DescriptionInstantiatedHasObject) + || + ((Flags & WdfRetrieveMissingChildren) && + (m_DescriptionState == DescriptionReportedMissing || + m_DescriptionState == DescriptionNotPresent)) + || + ((Flags & WdfRetrievePendingChildren) && + m_DescriptionState == DescriptionPresentNeedsInstantiation) + ) { + + return TRUE; + } + + return FALSE; + } + +protected: + BOOLEAN + __inline + IsPresent( + VOID + ) + { + if (m_DescriptionState == DescriptionPresentNeedsInstantiation || + m_DescriptionState == DescriptionInstantiatedHasObject) { + return TRUE; + } + else { + return FALSE; + } + } + + static + FxDeviceDescriptionEntry* + _FromDescriptionLink( + __in PLIST_ENTRY Link + ) + { + return CONTAINING_RECORD(Link, + FxDeviceDescriptionEntry, + m_DescriptionLink); + } + + static + FxDeviceDescriptionEntry* + _FromModificationLink( + __in PLIST_ENTRY Link + ) + { + return CONTAINING_RECORD(Link, + FxDeviceDescriptionEntry, + m_ModificationLink); + } + +protected: + LIST_ENTRY m_DescriptionLink; + + FxChildListDescriptionState m_DescriptionState; + + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER m_IdentificationDescription; + + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER m_AddressDescription; + + LIST_ENTRY m_ModificationLink; + + FxChildListModificationState m_ModificationState; + + CfxDevice* m_Pdo; + + FxChildList* m_DeviceList; + + BOOLEAN m_FoundInLastScan; + + BOOLEAN m_ProcessingSurpriseRemove; + + BOOLEAN m_PendingDeleteOnScanEnd; + + FxChildListReportedMissingCallbackState m_ReportedMissingCallbackState; +}; + +#endif // _FXDEVICELIST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcollection.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcollection.hpp new file mode 100644 index 00000000000..f0659ae535f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcollection.hpp @@ -0,0 +1,227 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCollection.hpp + +Abstract: + + This module implements a simple collection class to operate on + objects derived from FxObject. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXCOLLECTION_HPP_ +#define _FXCOLLECTION_HPP_ + +class FxCollectionEntry : public FxStump { + + friend FxCollection; + friend FxCollectionInternal; + +protected: + FxCollectionEntry( + VOID + ) + { + } + +public: + FxObject *m_Object; + + LIST_ENTRY m_ListEntry; + +public: + FxCollectionEntry* + Next( + VOID + ) + { + return CONTAINING_RECORD(m_ListEntry.Flink, FxCollectionEntry, m_ListEntry); + } +}; + +struct FxCollectionInternal { +protected: + ULONG m_Count; + + LIST_ENTRY m_ListHead; + +public: + FxCollectionInternal( + VOID + ); + + ~FxCollectionInternal( + VOID + ); + + _Must_inspect_result_ + FxCollectionEntry* + FindEntry( + __in ULONG Index + ); + + _Must_inspect_result_ + FxCollectionEntry* + FindEntryByObject( + __in FxObject* Object + ); + + ULONG + Count( + VOID + ); + + BOOLEAN + Add( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject *Item + ); + + _Must_inspect_result_ + FxObject * + GetItem( + __in ULONG Index + ); + + _Must_inspect_result_ + FxObject* + GetFirstItem( + VOID + ); + + _Must_inspect_result_ + FxObject* + GetLastItem( + VOID + ); + + NTSTATUS + Remove( + __in ULONG Index + ); + + VOID + CleanupEntry( + __in FxCollectionEntry* Entry + ); + + VOID + CleanupEntryObject( + __in FxObject* Object + ) + { + Object->RELEASE(this); + } + + NTSTATUS + RemoveEntry( + __in FxCollectionEntry* Entry + ); + + _Must_inspect_result_ + NTSTATUS + RemoveItem( + __in FxObject* Item + ); + + _Must_inspect_result_ + FxCollectionEntry* + Start( + VOID + ) + { + return CONTAINING_RECORD(m_ListHead.Flink, FxCollectionEntry, m_ListEntry); + } + + _Must_inspect_result_ + FxCollectionEntry* + End( + VOID + ) + { + return CONTAINING_RECORD(&m_ListHead, FxCollectionEntry, m_ListEntry); + } + + VOID + Clear( + VOID + ); + +protected: + _Must_inspect_result_ + FxCollectionEntry* + AllocateEntry( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + return new(FxDriverGlobals) FxCollectionEntry(); + } + + VOID + AddEntry( + __in FxCollectionEntry *Node, + __in FxObject* Item + ) + { + Node->m_Object = Item; + + // + // Refcount the item we are adding to the list. + // + Item->ADDREF(this); + + // + // Increment the number of items in the collection. + // + m_Count++; + } +}; + +class FxCollection : public FxNonPagedObject, public FxCollectionInternal { + +public: + FxCollection( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxCollection( + VOID + ); + + BOOLEAN + Add( + __in FxObject *Item + ) + { + return FxCollectionInternal::Add(GetDriverGlobals(), Item); + } + + VOID + StealCollection( + __in FxCollection* Collection + ); + +protected: + FxCollection( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFTYPE Type, + __in USHORT Size + ); + +}; + +#endif // _FXCOLLECTION_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcxdeviceinfo.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcxdeviceinfo.hpp new file mode 100644 index 00000000000..9c8c7ab82c4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcxdeviceinfo.hpp @@ -0,0 +1,31 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXCXDEVICEINFO_H_ +#define _FXCXDEVICEINFO_H_ + +#include "FxDeviceCallbacks.hpp" + +struct FxCxDeviceInfo : public FxStump { + FxCxDeviceInfo(PFX_DRIVER_GLOBALS FxDriverGlobals) : + Driver(NULL), + IoInCallerContextCallback(FxDriverGlobals), + Index(0) + { + InitializeListHead(&ListEntry); + RtlZeroMemory(&RequestAttributes, sizeof(RequestAttributes)); + } + + ~FxCxDeviceInfo() + { + ASSERT(IsListEmpty(&ListEntry)); + } + + LIST_ENTRY ListEntry; + FxDriver* Driver; + FxIoInCallerContext IoInCallerContextCallback; + WDF_OBJECT_ATTRIBUTES RequestAttributes; + CCHAR Index; +}; + +#endif // _FXCXDEVICEINFO_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxcxdeviceinit.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcxdeviceinit.hpp new file mode 100644 index 00000000000..45499e369d2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxcxdeviceinit.hpp @@ -0,0 +1,95 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCxDeviceInit.hpp + +Abstract: + + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef __FXCXDEVICEINIT_HPP__ +#define __FXCXDEVICEINIT_HPP__ + +// +// Holds class extension file object configuration. +// +struct CxFileObjectInit { + WDF_FILEOBJECT_CLASS Class; + + WDF_OBJECT_ATTRIBUTES Attributes; + + WDFCX_FILEOBJECT_CONFIG Callbacks; + + WDF_TRI_STATE AutoForwardCleanupClose; + + BOOLEAN Set; +}; + +// +// The typedef for a pointer to this structure is exposed in wdfdevice.h +// +struct WDFCXDEVICE_INIT : public FxStump { +public: + WDFCXDEVICE_INIT(); + ~WDFCXDEVICE_INIT(); + + static + _Must_inspect_result_ + PWDFCXDEVICE_INIT + _AllocateCxDeviceInit( + __in PWDFDEVICE_INIT DeviceInit + ); + +public: + // + // Class extension init list entry. + // + LIST_ENTRY ListEntry; + + // + // Client and Cx's globals. + // + PFX_DRIVER_GLOBALS ClientDriverGlobals; + PFX_DRIVER_GLOBALS CxDriverGlobals; + + // + // Pre-proc info. + // + FxIrpPreprocessInfo* PreprocessInfo; + + // + // In caller context info. + // + PFN_WDF_IO_IN_CALLER_CONTEXT IoInCallerContextCallback; + + // + // Request attributes info. + // + WDF_OBJECT_ATTRIBUTES RequestAttributes; + + // + // File object info. + // + CxFileObjectInit FileObject; + + // + // Set during the device create. + // + FxCxDeviceInfo* CxDeviceInfo; +}; + +#endif __FXCXDEVICEINIT_HPP__ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdefaultirphandler.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdefaultirphandler.hpp new file mode 100644 index 00000000000..69f9f7d2052 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdefaultirphandler.hpp @@ -0,0 +1,22 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXDEFAULTIRPHANDLER_HPP_ +#define _FXDEFAULTIRPHANDLER_HPP_ + +class FxDefaultIrpHandler : public FxPackage { +public: + FxDefaultIrpHandler( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice* Device + ); + + _Must_inspect_result_ + virtual + NTSTATUS + Dispatch( + __in MdIrp Irp + ); +}; + +#endif // _FXDEFAULTIRPHANDLER_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevice.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevice.hpp new file mode 100644 index 00000000000..8a83180b230 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevice.hpp @@ -0,0 +1,2297 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDevice.hpp + +Abstract: + + This is the definition of the FxDevice object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDEVICE_H_ +#define _FXDEVICE_H_ + +#include "FxCxDeviceInit.hpp" +#include "FxDeviceInit.hpp" +#include "FxTelemetry.hpp" + +struct FxWdmDeviceExtension { +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + WUDF_IO_REMOVE_LOCK IoRemoveLock; +#else + IO_REMOVE_LOCK IoRemoveLock; +#endif + ULONG RemoveLockOptionFlags; +}; + +// +// The following enum is used in serializing packet based DMA transactions. +// According to the DDK docs: +// Only one DMA request can be queued for a device object at any +// one time. Therefore, the driver should not call AllocateAdapterChannel +// again for another DMA operation on the same device object until the +// AdapterControl routine has completed execution. In addition, +// a driver must not call AllocateAdapterChannel from within its +// AdapterControl routine. +// +// This is because when AllocateAdapterChannel blocks waiting for +// map registers, it obtains its wait context block from the device object. +// If AllocateAdapterChannel is then called through a different adapter +// object attached to the same device the wait block will be reused and the +// map register wait list will be corrupted. +// +// For this reason, we need to make sure that for a device used in creating +// DMA enablers, there can be only one packet base DMA transaction +// queued at any one time. +// +// In WDM, one can workaround this limitation by creating dummy deviceobject. +// We can also workaround this limitation by creating a control-device on the +// side for additional enabler objects. Since packet based multi-channel +// devices are rarity these days, IMO, we will defer this feature until there +// is a big demand for it. +// +enum FxDmaPacketTransactionStatus { + FxDmaPacketTransactionCompleted =0, + FxDmaPacketTransactionPending, +}; + +// +// The following enum is used in determining whether the RemLock for a device +// object needs to be held while processing an IRP. For processing certain +// IRPs, it might not be necessary to hold the RemLock, but it might be +// necessary to just test whether the RemLock can be acquired and released. +// +enum FxDeviceRemLockAction { + FxDeviceRemLockNotRequired = 0, + FxDeviceRemLockRequired, + FxDeviceRemLockTestValid, + FxDeviceRemLockOptIn +}; + +enum FxPropertyType { + FxDeviceProperty = 0, + FxInterfaceProperty, +}; + +// +// This mask is used to validate the WdfDeviceWdmDispatchIrp's Flags. +// +#define FX_DISPATCH_IRP_TO_IO_QUEUE_FLAGS_MASK \ + (WDF_DISPATCH_IRP_TO_IO_QUEUE_INVOKE_INCALLERCTX_CALLBACK |\ + WDF_DISPATCH_IRP_TO_IO_QUEUE_PREPROCESSED_IRP) + +// +// The following inline functions are used for extracting the normalized file +// object class value and checking the file object class's flags. +// +WDF_FILEOBJECT_CLASS +__inline +FxFileObjectClassNormalize( + __in WDF_FILEOBJECT_CLASS FileObjectClass + ) +{ + return (WDF_FILEOBJECT_CLASS)(FileObjectClass & ~WdfFileObjectCanBeOptional); +} + +BOOLEAN +__inline +FxIsFileObjectOptional( + __in WDF_FILEOBJECT_CLASS FileObjectClass + ) +{ + return (FileObjectClass & WdfFileObjectCanBeOptional) ? TRUE : FALSE; +} + +// +// Base class for all devices. +// +class FxDeviceBase : public FxNonPagedObject, public IFxHasCallbacks { + +protected: + FxDeviceBase( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxDriver* Driver, + __in WDFTYPE Type, + __in USHORT Size + ); + + ~FxDeviceBase( + VOID + ); + + VOID + Init( + __in MdDeviceObject DeviceObject, + __in MdDeviceObject AttachedDevice, + __in MdDeviceObject PhysicalDevice + ); + +public: + NTSTATUS + ConfigureConstraints( + __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes + ); + + // begin IFxHasCallbacks overrides + VOID + GetConstraints( + __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, + __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) ; + + FxCallbackLock* + GetCallbackLockPtr( + __out_opt FxObject** LockObject + ); + // end IFxHasCallbacks overrides + + __inline + FxDriver* + GetDriver( + VOID + ) + { + return m_Driver; + } + + + MdDeviceObject + __inline + GetDeviceObject( + VOID + ) + { + return m_DeviceObject.GetObject(); + } + + __inline + MxDeviceObject* + GetMxDeviceObject( + VOID + ) + { + return &m_DeviceObject; + } + + ULONG + __inline + GetDeviceObjectFlags( + VOID + ) + { + return m_DeviceObject.GetFlags(); + } + + VOID + __inline + SetDeviceObjectFlags( + _In_ ULONG Flags + ) + { + m_DeviceObject.SetFlags(Flags); + } + + MdDeviceObject + __inline + GetAttachedDevice( + VOID + ) + { + return m_AttachedDevice.GetObject(); + } + + ULONG + __inline + GetAttachedDeviceObjectFlags( + VOID + ) + { + return m_AttachedDevice.GetFlags(); + } + + MdDeviceObject + __inline + GetPhysicalDevice( + VOID + ) + { + return m_PhysicalDevice.GetObject(); + } + + WDFDEVICE + __inline + GetHandle( + VOID + ) + { + return (WDFDEVICE) GetObjectHandle(); + } + + virtual + _Must_inspect_result_ + NTSTATUS + AddIoTarget( + __inout FxIoTarget* IoTarget + ) + { + UNREFERENCED_PARAMETER(IoTarget); + + // + // Intentionally does nothing + // + return STATUS_SUCCESS; + } + + virtual + VOID + RemoveIoTarget( + __inout FxIoTarget* IoTarget + ) + { + // + // Intentionally does nothing + // + UNREFERENCED_PARAMETER(IoTarget); + } + + virtual + _Must_inspect_result_ + NTSTATUS + AllocateEnumInfo( + VOID + ) + { + return STATUS_SUCCESS; + } + + virtual + VOID + AddChildList( + __inout FxChildList* List + ) + { + // + // Intentionally does nothing + // + UNREFERENCED_PARAMETER(List); + } + + virtual + VOID + RemoveChildList( + __inout FxChildList* List + ) + { + // + // Intentionally does nothing + // + UNREFERENCED_PARAMETER(List); + } + + virtual + _Must_inspect_result_ + NTSTATUS + AllocateDmaEnablerList( + VOID + ) + { + return STATUS_SUCCESS; + } + + virtual + VOID + AddDmaEnabler( + __inout FxDmaEnabler* Enabler + ) + { + // + // Intentionally does nothing + // + UNREFERENCED_PARAMETER(Enabler); + } + + virtual + VOID + RemoveDmaEnabler( + __inout FxDmaEnabler* Enabler + ) + { + // + // Intentionally does nothing + // + UNREFERENCED_PARAMETER(Enabler); + } + + virtual + VOID + SetDeviceTelemetryInfoFlags( + _In_ FxDeviceInfoFlags Flag + ) + { + // + // Intentionally does nothing + // + UNREFERENCED_PARAMETER(Flag); + } + + __inline + _Must_inspect_result_ + NTSTATUS + AcquireDmaPacketTransaction( + VOID + ) + { + // + // Set the status to Pending only if the previous transaction is Completed. + // + if (InterlockedCompareExchange( + &m_DmaPacketTransactionStatus, + FxDmaPacketTransactionPending, + FxDmaPacketTransactionCompleted) == FxDmaPacketTransactionCompleted) { + return STATUS_SUCCESS; + } else { + return STATUS_WDF_BUSY; + } + } + + __inline + VOID + ReleaseDmaPacketTransaction( + VOID + ) + { + LONG val; + + val = InterlockedExchange(&m_DmaPacketTransactionStatus, + FxDmaPacketTransactionCompleted); + + ASSERT(val == FxDmaPacketTransactionPending); // To catch double release + UNREFERENCED_PARAMETER(val); + } + + VOID + AddToDisposeList( + __inout FxObject* Object + ) + { + m_DisposeList->Add(Object); + } + + // begin FxObject overrides + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __inout FxQueryInterfaceParams* Params + ); + // end FxObject overrides + + static + FxDeviceBase* + _SearchForDevice( + __in FxObject* Object, + __out_opt IFxHasCallbacks** Callbacks + ); + + static + FxDeviceBase* + _SearchForDevice( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ); + + _Must_inspect_result_ + NTSTATUS + QueryForInterface( + __in const GUID* InterfaceType, + __out PINTERFACE Interface, + __in USHORT Size, + __in USHORT Version, + __in PVOID InterfaceSpecificData, + __in_opt MdDeviceObject TargetDevice = NULL + ); + + __inline + MdDeviceObject + GetAttachedDeviceReference( + VOID + ) + { + return Mx::MxGetAttachedDeviceReference(m_DeviceObject.GetObject()); + } + + virtual + FxIoTarget* + GetDefaultIoTarget( + VOID + ) + { + return NULL; + } + + _Must_inspect_result_ + NTSTATUS + AllocateTarget( + _Out_ FxIoTarget** Target, + _In_ BOOLEAN SelfTarget + ); + + // + // Note: these fields are carefully aligned to minimize space. If you add + // additional fields make sure to insert them correctly. Always + // double check your assumptions by loading the amd64 image and + // comparing the size of this type before and after. For example the + // m_RequestLookasideList is aligned on SYSTEM_CACHE_ALIGNMENT_SIZE (64/128), + // a simple change can increase the size by 64/128 bytes. + // + +public: + // + // This is used to defer items that must be cleaned up at passive + // level, and FxDevice waits on this list to empty in DeviceRemove. + // + FxDisposeList* m_DisposeList; + +protected: + FxDriver* m_Driver; + + MxDeviceObject m_DeviceObject; + MxDeviceObject m_AttachedDevice; + MxDeviceObject m_PhysicalDevice; + + FxCallbackLock* m_CallbackLockPtr; + FxObject* m_CallbackLockObjectPtr; + + WDF_EXECUTION_LEVEL m_ExecutionLevel; + WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope; + + // + // Used to serialize packet dma transactions on this device. + // + LONG m_DmaPacketTransactionStatus; +}; + +class FxDevice : public FxDeviceBase { + friend VOID GetTriageInfo(VOID); + friend class FxDriver; + friend class FxIrp; + friend class FxFileObject; + friend class FxPkgPnp; + + // + // Note: these fields are carefully aligned to minimize space. If you add + // additional fileds make sure to insert them correctly. Always + // double check your assumptions by loading the amd64 image and + // comparing the size of this type before and after. For example the + // m_RequestLookasideList is aligned on SYSTEM_CACHE_ALIGNMENT_SIZE (64/128), + // a simple change can increase the size by 64/128 bytes. + // + +private: + // + // Maintain the current device states. + // + WDF_DEVICE_PNP_STATE m_CurrentPnpState; + WDF_DEVICE_POWER_STATE m_CurrentPowerState; + WDF_DEVICE_POWER_POLICY_STATE m_CurrentPowerPolicyState; + + // + // Store the IO type for read/write + // + WDF_DEVICE_IO_TYPE m_ReadWriteIoType; + + // + // Bit-flags, see FxDeviceCallbackFlags for definitions. + // + BYTE m_CallbackFlags; + + // TRUE if a Filter + BOOLEAN m_Filter; + + // + // If TRUE, DO_POWER_PAGABLE can be set on m_DeviceObject->Flags if we are + // not in a special usage path. + // + // ***Ignored for filters*** + // + BOOLEAN m_PowerPageableCapable; + + // + // TRUE if the parent is removed while the child is still around + // + BOOLEAN m_ParentWaitingOnChild; + + // + // TRUE if the device only allows one create to succeed at any given time + // + BOOLEAN m_Exclusive; + + // + // More deterministic the m_PkgPnp == NULL since m_PkgPnp can be == NULL + // if there is an allocation failure and during deletion due to insufficient + // resources we need to know if the device is legacy or not. + // + BOOLEAN m_Legacy; + + // + // If TRUE, m_DeviceObject was deleted in FxDevice::DeleteObject and should + // not be deleted again later in the destroy path. + // + BOOLEAN m_DeviceObjectDeleted; + + // + // This boost will be used in IoCompleteRequest + // for read, write and ioctl requests if the client driver + // completes the request without specifying the boost. + // + // + CHAR m_DefaultPriorityBoost; + + static const CHAR m_PriorityBoosts[]; + +public: + // + // Track the parent if applicable + // + CfxDevice *m_ParentDevice; + + // + // Properties used during Device Creation + // + + // + // Store the device name that is used during device creation. + // + UNICODE_STRING m_DeviceName; + + UNICODE_STRING m_SymbolicLinkName; + + // + // Store the name of the resource that is used to store the MOF data + // + UNICODE_STRING m_MofResourceName; + + // + // When reporting a PDO via query device relations, there is a period of + // time where it is an "official" PDO as recognized by the pnp subsystem. + // In that period of time, we cannot use the soon to be PDO in any export + // which expects a PDO as an input parameter. Once this is set to TRUE, + // the PDO can be used for such exports. + // + // No need to use a lock when comparing against this field. Once set, it + // will never revert back to FALSE. + // + // This field is always TRUE for FDOs (in relation to the PDO for its stack). + // + BOOLEAN m_PdoKnown; + + // + // If TRUE, then create/cleanup/close are forwarded down the stack + // If FALSE, then create/cleanup/close are completed at this device + // + BOOLEAN m_AutoForwardCleanupClose; + + // + // If TRUE, an Io Target to the client itself is created to support + // Self Io Targets. + // + BOOLEAN m_SelfIoTargetNeeded; + +private: + // + // bit-map of device info for Telemetry + // + USHORT m_DeviceTelemetryInfoFlags; + +public: + + WDF_FILEOBJECT_CLASS m_FileObjectClass; + + FxSpinLockTransactionedList m_IoTargetsList; + + // + // We'll maintain the prepreocess table "per device" so that it is possible + // to have different callbacks for each device. + // Note that each device may be associted with multiple class extension in the future. + // + LIST_ENTRY m_PreprocessInfoListHead; + + // + // Optional, list of additional class extension settings. + // + LIST_ENTRY m_CxDeviceInfoListHead; + +protected: + + // + // This is used by the FxFileObject class to manage + // the list of FxFileObject's for this FxDevice + // + LIST_ENTRY m_FileObjectListHead; + + // + // Lookaside list to allocate FxRequests from + // + NPAGED_LOOKASIDE_LIST m_RequestLookasideList; + + // + // Total size of an FxRequest + driver context LookasideList element. + // + size_t m_RequestLookasideListElementSize; + + // + // Object attributes to apply to each FxRequest* returned by + // m_RequestLookasideList + // + WDF_OBJECT_ATTRIBUTES m_RequestAttributes; + +public: + + // + // This is the set of packages used by this device. I am simply using + // FxPackage pointers rather than using the actual types because I want + // to allow fredom for FDOs, PDOs, and control objects to use + // differnet packages. + // + FxPkgIo* m_PkgIo; + FxPkgPnp* m_PkgPnp; + FxPkgGeneral* m_PkgGeneral; + FxWmiIrpHandler* m_PkgWmi; + FxDefaultIrpHandler* m_PkgDefault; + + // + // Note on approaches to having mode-agnoctic code that works for KM and UM + // and avoids code with lots of #ifdef which becomes a maintenance nightmare. + // To avoid #ifdef such as below, one approach would have been to have a + // base class with common data members and virtual funtions , and have + // derived classes for km and um,each having data members specific to their + // mode, implementing virtual funcions in mode specific manner. This + // approach was not taken for following reasons: + // + // 1. Avoid confusion between logical hierarchy and organizational hierarchy + // of objects. E.g. fdo and pdo package is derived from pnp package (logical + // hierarchy). However, both pdo and fdo package can also be organized into + // fdokm/fdoum deriving from fdo, and pdokm/pdoum deriving from pdo for km + // and um flavors, and that would be organizational hierarchy. Mixing these + // two approaches may create more confusion. If we were to extend the + // classes in future (for whatever reason), this may become more complex. + // + // 2. Even with organizational hierarchy, we need to have #ifdef at the + // point of creation. + // + // Luckily, we don't have many objects that need to be have mode specific + // data members (currently only FxDevice and interrupt to some extent). + // Note that member functions are already implemented in mode specific + // manner, for example, FxDevice::CreateDevice is implemented for UM and KM + // in FxDeviceUm.cpp and FxDeviceKm.cpp. So #ifdef usage is not a whole lot + // but we can definitely improve on it. + // + // With the current approach, we can do better by avoiding #ifdef as much as + // possible. We can achieve that with better abstraction, but also having + // host provide more interfaces so as to mimic closely those interfaces + // that kernel provides would also help (this way framework has to maintain + // less info, because it can always get it from host the way kernel + // framework would). + // +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +public: + // + // On failed create during AddDevice, KMDF sends a simulated remove event + // to pnp state machine and thereafter detaches from stack so that windows + // I/O manager can't send a remove irp. UMDF imitates windows I/O manager + // in that when AddDevice sent by host is failed by driver, host sends a + // simulated remove irp to Fx so that it can cleanup. + // + // This causes a conflict in merged code because for UMDF, Fx doesn't + // detach from stack as part of remove event (since lifetime of umdf stack + + // is controlled by host including detach and deletiton), so unless we + // prevent, Fx will end up processing remove event twice, once by Pnp sm's + // simulated event and another by host simulated remove irp. + // + // The solution is to allow one remove event to be processed and that would + // be Fx's remove event (to minimize disparity between KM and UM Fx). The + // field below tracks the fact that create failed and allows the Fx remove + // event to be processed and then also allows the device object to detach + // before returning from failure so that host is not able to send simulated + // remove to the device. + // + BOOLEAN m_CleanupFromFailedCreate; + + // + // This object implements the IFxMessageDispatch that contains entry points + // to driver, and is used by host to dispatch irp and other messages. + // + FxMessageDispatch* m_Dispatcher; + + // + //Weak reference to host side device stack + // + IWudfDeviceStack* m_DevStack; + + // + // PnP devinode hw key handle + // + HKEY m_PdoDevKey; + + // + // Device key registry path + // + PWSTR m_DeviceKeyPath; + + // + // Kernel redirector's side object name. + // + PWSTR m_KernelDeviceName; + + // + // PDO Instance ID + // + PWSTR m_DeviceInstanceId; + + // + // The retrieval mode and i/o type preferences requested + // by this device. Note that ReadWriteIoType is common to both KMDF and UMDF + // so no new UM-specific field is required. + // + UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL m_RetrievalMode; + WDF_DEVICE_IO_TYPE m_IoctlIoType; + ULONG m_DirectTransferThreshold; + + // + // Tells whether hardware access is allowed. + // + WDF_DIRECT_HARDWARE_ACCESS_TYPE m_DirectHardwareAccess; + + // + // Tells whether hardware register read/write is done using user-mode + // mapped virtual addresses + // + WDF_REGISTER_ACCESS_MODE_TYPE m_RegisterAccessMode; + + // + // File object policy set through INF directive + // + WDF_FILE_OBJECT_POLICY_TYPE m_FileObjectPolicy; + + // + // Fs context use policy set through INF directive + // + WDF_FS_CONTEXT_USE_POLICY_TYPE m_FsContextUsePolicy; + + // + // Thread pool for interrupt servicing + // + FxInterruptThreadpool* m_InteruptThreadpool; + +#endif // (FX_CORE_MODE == FX_CORE_USER_MODE) + +private: + // + // A method called by the constructor(s) to initialize the device state. + // + VOID + SetInitialState( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PreprocessIrp( + __in MdIrp Irp + ); + + _Must_inspect_result_ + NTSTATUS + DeleteDeviceFromFailedCreateNoDelete( + __in NTSTATUS FailedStatus, + __in BOOLEAN UseStateMachine + ); + + VOID + SetFilterIoType( + VOID + ); + + static + MdCompletionRoutineType + _CompletionRoutineForRemlockMaintenance; + + static + _Must_inspect_result_ + NTSTATUS + _AcquireOptinRemoveLock( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp + ); + + VOID + DestructorInternal( + VOID + ); + + NTSTATUS + WmiPkgRegister( + VOID + ); + + VOID + WmiPkgDeregister( + VOID + ); + + VOID + WmiPkgCleanup( + VOID + ); + +public: + + FxDevice( + __in FxDriver *ArgDriver + ); + + ~FxDevice( + VOID + ); + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDFDEVICE_INIT* DeviceInit, + __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + __out FxDevice** Device + ); + + _Must_inspect_result_ + NTSTATUS + DeleteDeviceFromFailedCreate( + __in NTSTATUS FailedStatus, + __in BOOLEAN UseStateMachine + ); + + __inline + FxPackage* + GetDispatchPackage( + __in UCHAR MajorFunction + ) + { + switch (MajorFunction) { + case IRP_MJ_CREATE: + case IRP_MJ_CLOSE: + case IRP_MJ_CLEANUP: + case IRP_MJ_SHUTDOWN: + return (FxPackage*) m_PkgGeneral; + + case IRP_MJ_READ: + case IRP_MJ_WRITE: + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + return (FxPackage*) m_PkgIo; + + case IRP_MJ_SYSTEM_CONTROL: + return (FxPackage*) m_PkgWmi; + + case IRP_MJ_PNP: + case IRP_MJ_POWER: + if (m_PkgPnp != NULL) { + return (FxPackage*) m_PkgPnp; + } + else { + return (FxPackage*) m_PkgDefault; + } + break; + + default: + return (FxPackage*) m_PkgDefault; + } + } + + MdRemoveLock + GetRemoveLock( + VOID + ); + + static + FxDeviceRemLockAction + __inline + _RequiresRemLock( + __in UCHAR MajorCode, + __in UCHAR MinorCode + ) + { + switch (MajorCode) { + // + // We require remove locks for power irps because they can show + // up after the device has been removed if the Power subysystem has + // taken a reference on the device object that raced with the + // remove irp (or if we are attached above the power policy owner + // and the power policy owner requests a power irp during remove + // processing. + // + // What it boils down to is that we do it for power because + // that is the only valid irp which can be sent with an outstanding + // reference w/out coordination to the device's pnp state. We + // assume that for all other irps, the sender has synchronized with + // the pnp state of the device. + // + // We also acquire the remove lock for WMI IRPs because they can + // come into the stack while we are processing a remove. For + // instance, a WMI irp can come into the stack to the attached + // device before it has a change to process the remove device and + // unregister with WMI. + // + // PNP irps can come in at any time as well. For instance, query + // device relations for removal or ejection relations can be sent + // at any time (and there are pnp stress tests which send them + // during remove). + // + case IRP_MJ_PNP: + // + // We special case remove device and only acquire the remove lock + // in the minor code handler itself. If handled remove device in + // the normal way and there was a preprocess routine for it, then + // we could deadlock if the irp was dispatched back to KMDF in the + // preprocess routine with an extra outstandling remlock acquire + // (which won't be released until the preprocess routine returns, + // which will be too late). + // + if (MinorCode == IRP_MN_REMOVE_DEVICE) { + return FxDeviceRemLockTestValid; + } + case IRP_MJ_POWER: + case IRP_MJ_SYSTEM_CONTROL: + return FxDeviceRemLockRequired; + + default: +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return FxDeviceRemLockOptIn; +#else + // + // There is no forseeable scenario where a UMDF driver would need to + // need to support remove lock for IO IRPs. While this ifdef can be safely + // removed and UMDF can also return FxDeviceRemLockOptIn, that is + // being avoided here so that the caller does not need to test the + // remove lock flags for IO which would never be set. + // + return FxDeviceRemLockNotRequired; +#endif + } + } + + static + FxDevice* + GetFxDevice( + __in MdDeviceObject DeviceObject + ); + + MdDeviceObject + __inline + GetSafePhysicalDevice( + VOID + ) + { + // + // Makes sure that the PDO we think we have is + // 1) reported to pnp (m_PdoKnown check) + // 2) actually there (m_PhysicalDevice != NULL check) + // + if (m_PdoKnown && m_PhysicalDevice.GetObject() != NULL) { + return m_PhysicalDevice.GetObject(); + } + else { + return NULL; + } + } + + static + _Must_inspect_result_ + NTSTATUS + Dispatch( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp + ); + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + static + VOID + DispatchUm( + _In_ MdDeviceObject DeviceObject, + _In_ MdIrp Irp, + _In_opt_ IUnknown* Context + ); + + static + VOID + DispatchWithLockUm( + _In_ MdDeviceObject DeviceObject, + _In_ MdIrp Irp, + _In_opt_ IUnknown* Context + ); + + VOID + SetInterruptThreadpool( + _In_ FxInterruptThreadpool* Pool + ) + { + m_InteruptThreadpool = Pool; + } + + FxInterruptThreadpool* + GetInterruptThreadpool( + VOID + ) + { + return m_InteruptThreadpool; + } + +#endif // (FX_CORE_MODE == FX_CORE_USER_MODE) + + static + _Must_inspect_result_ + NTSTATUS + DispatchWithLock( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchPreprocessedIrp( + __in MdIrp Irp, + __in PVOID DispatchContext + ); + + __inline + WDF_DEVICE_IO_TYPE + GetIoType( + VOID + ) + { + return m_ReadWriteIoType; + } + + __inline + WDF_DEVICE_IO_TYPE + GetIoTypeForReadWriteBufferAccess( + VOID + ) + { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return m_ReadWriteIoType; +#else + // + // For UM, both buffer-copy and direct-access i/o buffer access types + // follow the same storage and retrieval model in internal structures + // as in buffered I/O so always return WdfDeviceIoBuffered. + // + return WdfDeviceIoBuffered; +#endif + } + + __inline + CHAR + GetDefaultPriorityBoost( + VOID + ) + { + return m_DefaultPriorityBoost; + } + + // + // Return FileObjectClass + // + __inline + WDF_FILEOBJECT_CLASS + GetFileObjectClass( + VOID + ) + { + return m_FileObjectClass; + } + + // + // Configuration time fileobject support setting + // + __inline + VOID + SetFileObjectClass( + __in WDF_FILEOBJECT_CLASS FileObjectClass + ) + { + m_FileObjectClass = FileObjectClass; + } + + VOID + InstallPackage( + __inout FxPackage *Package + ); + + __inline + WDF_DEVICE_PNP_STATE + GetDevicePnpState( + ) + { + return m_CurrentPnpState; + } + + __inline + WDF_DEVICE_POWER_STATE + GetDevicePowerState( + ) + { + return m_CurrentPowerState; + } + + __inline + WDF_DEVICE_POWER_POLICY_STATE + GetDevicePowerPolicyState( + ) + { + return m_CurrentPowerPolicyState; + } + + __inline + VOID + SetDevicePnpState( + __in WDF_DEVICE_PNP_STATE DeviceState + ) + { + m_CurrentPnpState = DeviceState; + } + + __inline + VOID + SetDevicePowerState( + __in WDF_DEVICE_POWER_STATE DeviceState + ) + { + m_CurrentPowerState = DeviceState; + } + + __inline + VOID + SetDevicePowerPolicyState( + __in WDF_DEVICE_POWER_POLICY_STATE DeviceState + ) + { + m_CurrentPowerPolicyState = DeviceState; + } + + __inline + BOOLEAN + IsPnp( + VOID + ) + { + return m_PkgPnp != NULL ? TRUE : FALSE; + } + + __inline + BOOLEAN + IsLegacy( + VOID + ) + { + return m_Legacy; + } + + __inline + BOOLEAN + IsExclusive( + VOID + ) + { + return m_Exclusive; + } + + __inline + BOOLEAN + IsFdo( + VOID + ) + { + return m_PkgPnp->GetType() == FX_TYPE_PACKAGE_FDO; + } + + __inline + FxPkgFdo* + GetFdoPkg( + VOID + ) + { + return (FxPkgFdo*) m_PkgPnp; + } + + __inline + BOOLEAN + IsPdo( + VOID + ) + { + return (IsPnp() && m_PkgPnp->GetType() == FX_TYPE_PACKAGE_PDO); + } + + __inline + FxPkgPdo* + GetPdoPkg( + VOID + ) + { + return (FxPkgPdo*) m_PkgPnp; + } + + _Must_inspect_result_ + NTSTATUS + CreateDevice( + __in PWDFDEVICE_INIT DeviceInit + ); + + __inline + VOID + SetParentWaitingOnRemoval( + VOID + ) + { + m_ParentWaitingOnChild = TRUE; + } + + // + + // There are really three steps in device creation. + // + // - Creating the device + // - Creating the device object that goes with the device (Initialize) + // - Finilizing the initialization after packages are installed, attached, + // etc. + + + + + + VOID + FinishInitializing( + VOID + ); + + VOID + Destroy( + VOID + ); + + // FxObject overrides + virtual + VOID + DeleteObject( + VOID + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + // FxObject overrides + + __inline + PWDF_OBJECT_ATTRIBUTES + GetRequestAttributes( + VOID + ) + { + return &m_RequestAttributes; + } + + PVOID + AllocateRequestMemory( + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ); + + VOID + FreeRequestMemory( + __in FxRequest* Request + ); + + // begin FxDeviceBase overrides + virtual + _Must_inspect_result_ + NTSTATUS + AddIoTarget( + __inout FxIoTarget* IoTarget + ); + + virtual + VOID + RemoveIoTarget( + __inout FxIoTarget* IoTarget + ); + + virtual + _Must_inspect_result_ + NTSTATUS + AllocateEnumInfo( + VOID + ); + + virtual + VOID + AddChildList( + __inout FxChildList* List + ); + + virtual + VOID + RemoveChildList( + __inout FxChildList* List + ); + + virtual + _Must_inspect_result_ + NTSTATUS + AllocateDmaEnablerList( + VOID + ); + + virtual + VOID + AddDmaEnabler( + __inout FxDmaEnabler* Enabler + ); + + virtual + VOID + RemoveDmaEnabler( + __inout FxDmaEnabler* Enabler + ); + + virtual + FxIoTarget* + GetDefaultIoTarget( + VOID + ); + + FxIoTargetSelf* + GetSelfIoTarget( + VOID + ); + + virtual + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __inout FxQueryInterfaceParams* Params + ); + // end FxDeviceBase overrides + + // + // Filter Driver Support + // + __inline + BOOLEAN + IsFilter() + { + return m_Filter; + } + + _Must_inspect_result_ + NTSTATUS + SetFilter( + __in BOOLEAN Value + ); + + __inline + BOOLEAN + IsPowerPageableCapable( + VOID + ) + { + return m_PowerPageableCapable; + } + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDFDEVICE_INIT DeviceInit, + __in_opt PWDF_OBJECT_ATTRIBUTES DeviceAttributes + ); + + VOID + ConfigureAutoForwardCleanupClose( + __in PWDFDEVICE_INIT DeviceInit + ); + + _Must_inspect_result_ + NTSTATUS + PostInitialize( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PdoInitialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + _Must_inspect_result_ + NTSTATUS + FdoInitialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + _Must_inspect_result_ + NTSTATUS + ControlDeviceInitialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + VOID + ControlDeviceDelete( + VOID + ) + { + // + // FxDevice::DeleteObject() has already run, so we must call the super + // class's version of DeleteObject(); + // + ASSERT(m_DeviceObjectDeleted); + + __super::DeleteObject(); + } + + _Must_inspect_result_ + NTSTATUS + OpenSettingsKey( + __out HANDLE* Key, + __in ACCESS_MASK DesiredAccess = STANDARD_RIGHTS_ALL + ); + + VOID + DeleteSymbolicLink( + VOID + ); + + __inline + BYTE + GetCallbackFlagsLocked( + VOID + ) + { + return m_CallbackFlags; + } + + __inline + BYTE + GetCallbackFlags( + VOID + ) + { + BYTE flags; + KIRQL irql; + + Lock(&irql); + flags = GetCallbackFlagsLocked(); + Unlock(irql); + + return flags; + } + + __inline + VOID + SetCallbackFlagsLocked( + __in BYTE Flags + ) + { + m_CallbackFlags |= Flags; + } + + __inline + VOID + SetCallbackFlags( + __in BYTE Flags + ) + { + KIRQL irql; + + Lock(&irql); + SetCallbackFlagsLocked(Flags); + Unlock(irql); + } + + __inline + VOID + ClearCallbackFlagsLocked( + __in BYTE Flags + ) + { + m_CallbackFlags &= ~Flags; + } + + __inline + VOID + ClearCallbackFlags( + __in BYTE Flags + ) + { + KIRQL irql; + + Lock(&irql); + ClearCallbackFlagsLocked(Flags); + Unlock(irql); + } + + FxCxDeviceInfo* + GetCxDeviceInfo( + __in FxDriver* CxDriver + ) + { + FxCxDeviceInfo* cxDeviceInfo; + PLIST_ENTRY next; + + // + // Check if we are using I/O class extensions. + // + for (next = m_CxDeviceInfoListHead.Flink; + next != &m_CxDeviceInfoListHead; + next = next->Flink) { + + cxDeviceInfo = CONTAINING_RECORD(next, FxCxDeviceInfo, ListEntry); + if (cxDeviceInfo->Driver == CxDriver) { + return cxDeviceInfo; + } + } + + return NULL; + } + + __inline + BOOLEAN + IsCxDriverInIoPath( + __in FxDriver* CxDriver + ) + { + return (GetCxDeviceInfo(CxDriver) != NULL) ? TRUE : FALSE; + } + + __inline + BOOLEAN + IsCxInIoPath( + VOID + ) + { + return IsListEmpty(&m_CxDeviceInfoListHead) ? FALSE : TRUE; + } + +#if DBG + __inline + FxCxDeviceInfo* + GetFirstCxDeviceInfo( + VOID + ) + { + if (IsListEmpty(&m_CxDeviceInfoListHead)) { + return NULL; + } + else { + return CONTAINING_RECORD(m_CxDeviceInfoListHead.Flink, + FxCxDeviceInfo, + ListEntry); + } + } + + __inline + FxCxDeviceInfo* + GetNextCxDeviceInfo( + __in FxCxDeviceInfo* CxDeviceInfo + ) + { + ASSERT(CxDeviceInfo != NULL); + if (CxDeviceInfo->ListEntry.Flink == &m_CxDeviceInfoListHead) { + return NULL; + } + else { + return CONTAINING_RECORD(CxDeviceInfo->ListEntry.Flink, + FxCxDeviceInfo, + ListEntry); + } + } + +#endif + + __inline + static + CCHAR + GetCxDriverIndex( + __in FxCxDeviceInfo* CxDeviceInfo + ) + { + if (CxDeviceInfo != NULL) { + return CxDeviceInfo->Index; + } + else { + return 0; + } + } + + __inline + FxDriver* + GetCxDriver( + __in FxCxDeviceInfo* CxDeviceInfo + ) + { + if (CxDeviceInfo != NULL) { + return CxDeviceInfo->Driver; + } + else { + return GetDriver(); + } + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + + static + __inline + NTSTATUS + _OpenDeviceRegistryKey( + _In_ MdDeviceObject DeviceObject, + _In_ ULONG DevInstKeyType, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE DevInstRegKey + ); + + __inline + static + NTSTATUS + _GetDeviceProperty( + _In_ MdDeviceObject DeviceObject, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_ PULONG ResultLength + ); + +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + + static + NTSTATUS + _OpenDeviceRegistryKey( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ IWudfDeviceStack* DeviceStack, + _In_ PWSTR DriverName, + _In_ ULONG DevInstKeyType, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE DevInstRegKey + ); + + static + NTSTATUS + _GetDeviceProperty( + _In_ PVOID DeviceStack, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_ PULONG ResultLength + ); + +#endif + + static + _Must_inspect_result_ + NTSTATUS + _ValidateOpenKeyParams( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device + ); + + static + _Must_inspect_result_ + NTSTATUS + _OpenKey( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ ULONG DeviceInstanceKeyType, + _In_ ACCESS_MASK DesiredAccess, + _In_opt_ PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ WDFKEY* Key + ); + + static + _Must_inspect_result_ + NTSTATUS + _AllocAndQueryProperty( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_opt_ MdDeviceObject RemotePdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ POOL_TYPE PoolType, + _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ WDFMEMORY* PropertyMemory + ); + + static + _Must_inspect_result_ + NTSTATUS + _QueryProperty( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_opt_ MdDeviceObject RemotePdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_opt_ PULONG ResultLength + ); + + static + VOID + _InterfaceReferenceNoOp( + __in_opt PVOID Context + ) + { + // NoOp reference stub for query interface + UNREFERENCED_PARAMETER(Context); + } + + static + VOID + _InterfaceDereferenceNoOp( + __in_opt PVOID Context + ) + { + // NoOp dereference stub for query interface + UNREFERENCED_PARAMETER(Context); + } + + static + FxWdmDeviceExtension* + _GetFxWdmExtension( + __in MdDeviceObject DeviceObject + ); + + BOOLEAN + IsRemoveLockEnabledForIo( + VOID + ); + + VOID + FxLogDeviceStartTelemetryEvent( + VOID + ) + { + LogDeviceStartTelemetryEvent(GetDriverGlobals(), this); + } + + virtual + VOID + SetDeviceTelemetryInfoFlags( + _In_ FxDeviceInfoFlags Flag + ) + { + m_DeviceTelemetryInfoFlags |= Flag; + } + + USHORT + GetDeviceTelemetryInfoFlags( + VOID + ) + { + return m_DeviceTelemetryInfoFlags; + } + + __inline + CHAR + GetStackSize( + VOID + ) + { + return m_DeviceObject.GetStackSize(); + } + + __inline + VOID + SetStackSize( + _In_ CHAR Size + ) + { + m_DeviceObject.SetStackSize(Size); + } + + NTSTATUS + UpdateInterruptThreadpoolLimits( + VOID + ) + { + + + + + + return STATUS_SUCCESS; + } + + FxCmResList* + GetTranslatedResources( + ) + { + return m_PkgPnp->GetTranslatedResourceList(); + } + + VOID + DetachDevice( + VOID + ); + + VOID + InvalidateDeviceState( + VOID + ); + + NTSTATUS + CreateSymbolicLink( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ PCUNICODE_STRING SymbolicLinkName + ); + + VOID + SetCleanupFromFailedCreate( + BOOLEAN Value + ) + { +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + m_CleanupFromFailedCreate = Value; +#else + UNREFERENCED_PARAMETER(Value); +#endif + } + + BOOLEAN + IsInterfaceRegistered( + _In_ const GUID* InterfaceClassGUID, + _In_opt_ PCUNICODE_STRING RefString + ); + + static + _Must_inspect_result_ + NTSTATUS + _AllocAndQueryPropertyEx( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ POOL_TYPE PoolType, + _In_opt_ PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ WDFMEMORY* PropertyMemory, + _Out_ PDEVPROPTYPE PropertyType + ); + + static + _Must_inspect_result_ + NTSTATUS + _QueryPropertyEx( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ PWDFDEVICE_INIT DeviceInit, + _In_opt_ FxDevice* Device, + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ ULONG BufferLength, + _Out_ PVOID PropertyBuffer, + _Out_ PULONG ResultLength, + _Out_ PDEVPROPTYPE PropertyType + ); + + _Must_inspect_result_ + NTSTATUS + OpenDevicemapKeyWorker( + _In_ PFX_DRIVER_GLOBALS pFxDriverGlobals, + _In_ PCUNICODE_STRING KeyName, + _In_ ACCESS_MASK DesiredAccess, + _In_ FxRegKey* pKey + ); + + _Must_inspect_result_ + NTSTATUS + AssignProperty ( + _In_ PVOID PropertyData, + _In_ FxPropertyType FxPropertyType, + _In_ DEVPROPTYPE Type, + _In_ ULONG BufferLength, + _In_opt_ PVOID PropertyBuffer + ); + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + + _Must_inspect_result_ + NTSTATUS + FxValidateInterfacePropertyData( + _In_ PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData + ); + + VOID + GetDeviceStackIoType ( + _Out_ WDF_DEVICE_IO_TYPE* ReadWriteIoType, + _Out_ WDF_DEVICE_IO_TYPE* IoControlIoType + ); + + __inline + UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL + GetRetrievalMode( + VOID + ) + { + return m_RetrievalMode; + } + + __inline + WDF_DEVICE_IO_TYPE + GetPreferredRWTransferMode( + VOID + ) + { + return m_ReadWriteIoType; + } + + __inline + WDF_DEVICE_IO_TYPE + GetPreferredIoctlTransferMode( + VOID + ) + { + return m_IoctlIoType; + } + + __inline + ULONG + GetDirectTransferThreshold( + VOID + ) + { + return m_DirectTransferThreshold; + } + + static + VOID + GetPreferredTransferMode( + _In_ MdDeviceObject DeviceObject, + _Out_ UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL *RetrievalMode, + _Out_ WDF_DEVICE_IO_TYPE *RWPreference, + _Out_ WDF_DEVICE_IO_TYPE *IoctlPreference + ); + + NTSTATUS + ProcessWmiPowerQueryOrSetData ( + _In_ RdWmiPowerAction Action, + _Out_ BOOLEAN * QueryResult + ); + + static + WUDF_INTERFACE_CONTEXT + RemoteInterfaceArrival ( + _In_ IWudfDevice * DeviceObject, + _In_ LPCGUID DeviceInterfaceGuid, + _In_ PCWSTR SymbolicLink + ); + + static + void + RemoteInterfaceRemoval ( + _In_ IWudfDevice * DeviceObject, + _In_ WUDF_INTERFACE_CONTEXT RemoteInterfaceID + ); + + static + void + PoFxDevicePowerRequired ( + _In_ MdDeviceObject DeviceObject + ); + + static + void + PoFxDevicePowerNotRequired ( + _In_ MdDeviceObject DeviceObject + ); + + static + BOOL + TransportQueryId ( + _In_ IWudfDevice * DeviceObject, + _In_ DWORD Id, + _In_ PVOID DataBuffer, + _In_ SIZE_T cbDataBufferSize + ); + + static + NTSTATUS + NtStatusFromHr ( + _In_ IWudfDeviceStack * DevStack, + _In_ HRESULT Hr + ); + + NTSTATUS + NtStatusFromHr ( + _In_ HRESULT Hr + ); + + IWudfDeviceStack* + GetDeviceStack( + VOID + ); + + IWudfDeviceStack2 * + GetDeviceStack2( + VOID + ); + + VOID + RetrieveDeviceRegistrySettings( + VOID + ); + + BOOLEAN + IsDirectHardwareAccessAllowed( + ) + { + return (m_DirectHardwareAccess == WdfAllowDirectHardwareAccess); + } + + BOOLEAN + IsInterruptAccessAllowed( + VOID + ) + { + // + // Allow access to interrupts if the device has any connection resources, + // regardless of the UmdfDirectHardwareAccess INF directive. + // + return IsDirectHardwareAccessAllowed() || + GetTranslatedResources()->HasConnectionResources(); + } + + BOOLEAN + AreRegistersMappedToUsermode( + VOID + ) + { + return (m_RegisterAccessMode == WdfRegisterAccessUsingUserModeMapping); + } + + PVOID + GetPseudoAddressFromSystemAddress( + __in PVOID SystemAddress + ) + { + return SystemAddress; + } + + PVOID + GetSystemAddressFromPseudoAddress( + __in PVOID PseudoAddress + ) + { + return PseudoAddress; + } + + static + ULONG + __inline + GetLength( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size + ) + { + ULONG length = 0; + + switch(Size) { + case WdfDeviceHwAccessTargetSizeUchar: + length = sizeof(UCHAR); + break; + case WdfDeviceHwAccessTargetSizeUshort: + length = sizeof(USHORT); + break; + case WdfDeviceHwAccessTargetSizeUlong: + length = sizeof(ULONG); + break; + case WdfDeviceHwAccessTargetSizeUlong64: + length = sizeof(ULONG64); + break; + default: + ASSERT(FALSE); + } + + return length; + } + + BOOL + IsRegister( + __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type + ) + { + if (Type == WdfDeviceHwAccessTargetTypeRegister || + Type == WdfDeviceHwAccessTargetTypeRegisterBuffer) { + return TRUE; + } + + return FALSE; + } + + BOOL + IsPort( + __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type + ) + { + if (Type == WdfDeviceHwAccessTargetTypePort || + Type == WdfDeviceHwAccessTargetTypePortBuffer) { + return TRUE; + } + + return FALSE; + } + + BOOL + IsBufferType( + __in WDF_DEVICE_HWACCESS_TARGET_TYPE Type + ) + { + if (Type == WdfDeviceHwAccessTargetTypeRegisterBuffer || + Type == WdfDeviceHwAccessTargetTypePortBuffer) { + return TRUE; + } + + return FALSE; + } + + SIZE_T + ReadRegister( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register + ); + + VOID + ReadRegisterBuffer( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register, + __out_ecount_full(Count) PVOID Buffer, + __in ULONG Count + ); + + VOID + WriteRegister( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register, + __in SIZE_T Value + ); + + VOID + WriteRegisterBuffer( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register, + __in_ecount(Count) PVOID Buffer, + __in ULONG Count + ); + + VOID + RetrieveDeviceInfoRegistrySettings( + _Out_ PCWSTR* GroupId, + _Out_ PUMDF_DRIVER_REGSITRY_INFO DeviceRegInfo + ); + +#endif // (FX_CORE_MODE == FX_CORE_USER_MODE) + +}; + +class FxMpDevice : public FxDeviceBase { +public: + FxMpDevice( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxDriver* Driver, + __in MdDeviceObject DeviceObject, + __in MdDeviceObject AttachedDevice, + __in MdDeviceObject PDO + ) : + FxDeviceBase(FxDriverGlobals, Driver, FX_TYPE_MP_DEVICE, sizeof(*this)) + { + Init(DeviceObject, AttachedDevice, PDO); + m_DefaultTarget = NULL; + + Mx::MxReferenceObject(m_DeviceObject.GetObject()); + + MarkDisposeOverride(ObjectDoNotLock); + } + + // begin FxObject overrides + BOOLEAN + Dispose( + VOID + ) + { + // + // Important that the cleanup routine be called while the MdDeviceObject + // is valid! + // + CallCleanup(); + + // + // Manually destroy the children now so that by the time we wait on the + // dispose empty out, all of the children will have been added to it. + // + DestroyChildren(); + + if (m_DisposeList != NULL) { + m_DisposeList->WaitForEmpty(); + } + + // + // No device object to delete since the caller's own the + // WDM device. Simulate what FxDevice::Destroy does by NULL'ing out the + // device objects. + // + Mx::MxDereferenceObject(m_DeviceObject.GetObject()); + m_DeviceObject = NULL; + m_AttachedDevice = NULL; + + return FALSE; + } + // end FxObject overrides + + // begin FxDeviceBase overrides + virtual + FxIoTarget* + GetDefaultIoTarget( + VOID + ) + { + return m_DefaultTarget; + } + // end FxDeviceBase overrides + +public: + // + // Default I/O target for this miniport device + // + FxIoTarget *m_DefaultTarget; +}; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) +#include "FxDeviceKm.hpp" +#else +#include "FxDeviceUm.hpp" +#endif + + +#endif // _FXDEVICE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicecallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicecallbacks.hpp new file mode 100644 index 00000000000..6311794bb9b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicecallbacks.hpp @@ -0,0 +1,63 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceCallbacks.h + +Abstract: + + This module implements the FxDevice object callbacks + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDEVICECALLBACKS_H_ +#define _FXDEVICECALLBACKS_H_ + +// +// These delegates are in a seperate file +// + +// +// DrvDeviceInitialize callback delegate +// +class FxIoInCallerContext : public FxCallback { + +public: + PFN_WDF_IO_IN_CALLER_CONTEXT m_Method; + + FxIoInCallerContext( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : FxCallback(FxDriverGlobals), m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device, + __in WDFREQUEST Request + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device, Request); + CallbackEnd(); + } + } +}; + + + +#endif // _FXDEVICECALLBACKS_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinit.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinit.hpp new file mode 100644 index 00000000000..0608cd4a1fb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinit.hpp @@ -0,0 +1,330 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInit.hpp + +Abstract: + + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef __FXDEVICEINIT_HPP__ +#define __FXDEVICEINIT_HPP__ + +enum FxDeviceInitType { + FxDeviceInitTypeFdo = 0, + FxDeviceInitTypePdo, + FxDeviceInitTypeControlDevice +}; + +struct FileObjectInit { + WDF_FILEOBJECT_CLASS Class; + + WDF_OBJECT_ATTRIBUTES Attributes; + + WDF_FILEOBJECT_CONFIG Callbacks; + + WDF_TRI_STATE AutoForwardCleanupClose; + + BOOLEAN Set; +}; + +struct SecurityInit { + FxString* Sddl; + + GUID DeviceClass; + + BOOLEAN DeviceClassSet; +}; + +struct PnpPowerInit { + WDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks; + + WDF_POWER_POLICY_EVENT_CALLBACKS PolicyEventCallbacks; + + FxPnpStateCallback* PnpStateCallbacks; + + FxPowerStateCallback* PowerStateCallbacks; + + FxPowerPolicyStateCallback* PowerPolicyStateCallbacks; + + WDF_TRI_STATE PowerPolicyOwner; +}; + +struct FdoInit { + WDF_FDO_EVENT_CALLBACKS EventCallbacks; + + WDF_CHILD_LIST_CONFIG ListConfig; + + WDF_OBJECT_ATTRIBUTES ListConfigAttributes; + + BOOLEAN Filter; + + MdDeviceObject PhysicalDevice; +}; + + + + +#include "FxDeviceInitShared.hpp" + +struct ControlInit { + ControlInit( + VOID + ) + { + ShutdownNotification = NULL; + Flags = 0; + } + + PFN_WDF_DEVICE_SHUTDOWN_NOTIFICATION ShutdownNotification; + + UCHAR Flags; +}; + +// +// The typedef for a pointer to this structure is exposed in wdfdevice.h +// +struct WDFDEVICE_INIT : public FxStump { +public: + WDFDEVICE_INIT( + __in FxDriver* Driver + ); + + ~WDFDEVICE_INIT(); + + VOID + SetPdo( + __in FxDevice* Parent + ); + + BOOLEAN + IsFdoInit( + VOID + ) + { + return InitType == FxDeviceInitTypeFdo; + } + + BOOLEAN + IsNotFdoInit( + VOID + ) + { + return InitType != FxDeviceInitTypeFdo; + } + + BOOLEAN + IsPdoInit( + VOID + ) + { + return InitType == FxDeviceInitTypePdo; + } + + BOOLEAN + IsNotPdoInit( + VOID + ) + { + return InitType != FxDeviceInitTypePdo; + } + BOOLEAN + IsNotControlDeviceInit( + VOID + ) + { + return InitType != FxDeviceInitTypeControlDevice; + } + + BOOLEAN + IsControlDeviceInit( + VOID + ) + { + return InitType == FxDeviceInitTypeControlDevice; + } + + BOOLEAN + HasName( + VOID + ) + { + if (DeviceName != NULL || + (Characteristics & FILE_AUTOGENERATED_DEVICE_NAME)) { + return TRUE; + } + else { + return FALSE; + } + } + + BOOLEAN + ShouldCreateSecure( + VOID + ); + + BOOLEAN + IsPwrPolOwner( + VOID + ) + { + if (PnpPower.PowerPolicyOwner == WdfTrue) { + return TRUE; + } + else if (PnpPower.PowerPolicyOwner == WdfFalse) { + return FALSE; + } + else if (IsPdoInit()) { + // + // This is a PDO. If we are a raw PDO, we own pwr policy. + // + return Pdo.Raw; + } + else { + ASSERT(IsFdoInit()); + + // + // This is an FDO. If we are not a filter, we own pwr policy. + // + return (Fdo.Filter == FALSE ? TRUE : FALSE); + } + } + + _Must_inspect_result_ + NTSTATUS + AssignName( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in const UNICODE_STRING* Name + ); + + static + _Must_inspect_result_ + PWDFDEVICE_INIT + _AllocateControlDeviceInit( + __in FxDriver* Driver, + __in const UNICODE_STRING* SDDLString + ); + + VOID + AddCxDeviceInit( + __in PWDFCXDEVICE_INIT CxDeviceInit + ); + + VOID + AssignIoType( + _In_ PWDF_IO_TYPE_CONFIG IoTypeConfig + ); + +public: + PFX_DRIVER_GLOBALS DriverGlobals; + + FxDriver* Driver; + + FxDevice* CreatedDevice; + + BOOLEAN CreatedOnStack; + + BOOLEAN Exclusive; + + BOOLEAN PowerPageable; + + BOOLEAN Inrush; + + // + // If set, the Cx/Client intends to leverage Self IO Target + // + BOOLEAN RequiresSelfIoTarget; + + ULONG RemoveLockOptionFlags; + + FxDeviceInitType InitType; + + WDF_DEVICE_IO_TYPE ReadWriteIoType; + + DEVICE_TYPE DeviceType; + + FxString* DeviceName; + + ULONG Characteristics; + + FileObjectInit FileObject; + + SecurityInit Security; + + WDF_OBJECT_ATTRIBUTES RequestAttributes; + + FxIrpPreprocessInfo* PreprocessInfo; + + PFN_WDF_IO_IN_CALLER_CONTEXT IoInCallerContextCallback; + + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure; + + PnpPowerInit PnpPower; + FdoInit Fdo; + PdoInit Pdo; + ControlInit Control; + + // + // Class extension's device init. + // + LIST_ENTRY CxDeviceInitListHead; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // IoType preference for IOCTL + // + WDF_DEVICE_IO_TYPE DeviceControlIoType; + + // + // Direct I/O threshold + // + ULONG DirectTransferThreshold; + + // + // Weak reference to host side device stack + // + IWudfDeviceStack * DevStack; + + // + // Kernel redirector's side object name. + // + PWSTR KernelDeviceName; + + // + // PnP devinode hw key handle + // + HKEY PdoKey; + + // + // Registry sub-path name containing driver configuration information. + // The registry path name is relative to the "device key". + // + PWSTR ConfigRegistryPath; + + // + // PDO Instance ID + // + PWSTR DevInstanceID; + + // + // This ID is used by Host to associated host device and its driver info. + // + ULONG DriverID; +#endif + +}; + +#endif __FXDEVICEINIT_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinitshared.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinitshared.hpp new file mode 100644 index 00000000000..a2f0162e446 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinitshared.hpp @@ -0,0 +1,65 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInitShared.hpp + +Abstract: + + This header is split from FxDeviceInit.hpp to have definitions needed + in shared code. + +Author: + + +Environment: + + +Revision History: + +--*/ + +#ifndef __FXDEVICEINITSHARED_HPP__ +#define __FXDEVICEINITSHARED_HPP__ + +struct PdoInit { + + PdoInit( + VOID + ) + { + DeviceText.Next = NULL; + LastDeviceTextEntry = &DeviceText.Next; + } + + WDF_PDO_EVENT_CALLBACKS EventCallbacks; + + CfxDevice* Parent; + + FxString* DeviceID; + + FxString* InstanceID; + + FxCollectionInternal HardwareIDs; + + FxCollectionInternal CompatibleIDs; + + FxString* ContainerID; + + SINGLE_LIST_ENTRY DeviceText; + PSINGLE_LIST_ENTRY* LastDeviceTextEntry; + + FxDeviceDescriptionEntry* DescriptionEntry; + + LCID DefaultLocale; + + BOOLEAN Raw; + + BOOLEAN Static; + + BOOLEAN ForwardRequestToParent; +}; + +#endif //__FXDEVICEINITSHARED_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinterface.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinterface.hpp new file mode 100644 index 00000000000..1a9edd1eacb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdeviceinterface.hpp @@ -0,0 +1,98 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInterface.hpp + +Abstract: + + This module implements the device interface object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDEVICEINTERFACE_H_ +#define _FXDEVICEINTERFACE_H_ + +class FxDeviceInterface : public FxStump +{ +public: + GUID m_InterfaceClassGUID; + + UNICODE_STRING m_ReferenceString; + + UNICODE_STRING m_SymbolicLinkName; + + SINGLE_LIST_ENTRY m_Entry; + + BOOLEAN m_State; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // This is needed in UM to get hold of host interface + // + MdDeviceObject m_Device; + +#endif + +public: + FxDeviceInterface( + VOID + ); + + ~FxDeviceInterface( + VOID + ); + + static + FxDeviceInterface* + _FromEntry( + __in PSINGLE_LIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxDeviceInterface, m_Entry); + } + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CONST GUID* InterfaceGUID, + __in_opt PCUNICODE_STRING ReferenceString + ); + + VOID + SetState( + __in BOOLEAN State + ); + + _Must_inspect_result_ + NTSTATUS + Register( + __in MdDeviceObject Pdo + ); + + _Must_inspect_result_ + NTSTATUS + Register( + _In_ FxDevice* Device + ); + + NTSTATUS + GetSymbolicLinkName( + _In_ FxString* LinkString + ); +}; + +#endif // _FXDEVICEINTERFACE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicepwrreqstatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicepwrreqstatemachine.hpp new file mode 100644 index 00000000000..91c5cf00ea9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicepwrreqstatemachine.hpp @@ -0,0 +1,153 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXDEVICEPWRREQUIRESTATEMACHINE_H_ +#define _FXDEVICEPWRREQUIRESTATEMACHINE_H_ + +// +// This is a magical number based on inspection. If the queue overflows, +// it is OK to increase these numbers without fear of either dependencies or +// weird side affects. +// +const UCHAR FxDevicePwrRequirementEventQueueDepth = 8; + +enum FxDevicePwrRequirementEvents { + DprEventInvalid = 0x00, + DprEventRegisteredWithPox = 0x01, + DprEventUnregisteredWithPox = 0x02, + DprEventPoxRequiresPower = 0x04, + DprEventPoxDoesNotRequirePower = 0x08, + DprEventDeviceGoingToDx = 0x10, + DprEventDeviceReturnedToD0 = 0x20, + DprEventNull = 0xFF, +}; + +enum FxDevicePwrRequirementStates { + DprInvalid = 0, + DprUnregistered, + DprDevicePowerRequiredD0, + DprDevicePowerNotRequiredD0, + DprDevicePowerNotRequiredDx, + DprDevicePowerRequiredDx, + DprReportingDevicePowerAvailable, + DprWaitingForDevicePowerRequiredD0, + DprMax +}; + +// +// Forward declaration +// +class FxDevicePwrRequirementMachine; +class FxPoxInterface; + +typedef +_Must_inspect_result_ +FxDevicePwrRequirementStates +(*PFN_DEVICE_POWER_REQUIREMENT_STATE_ENTRY_FUNCTION)( + __in FxDevicePwrRequirementMachine* This + ); + +struct FxDevicePwrRequirementTargetState { + FxDevicePwrRequirementEvents DprEvent; + + FxDevicePwrRequirementStates DprState; + +#if FX_SUPER_DBG + BOOLEAN EventDebugged; +#endif +}; + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxDevicePwrRequirementMachineStateHistory { + struct { + FxDevicePwrRequirementStates State1 : 8; + FxDevicePwrRequirementStates State2 : 8; + FxDevicePwrRequirementStates State3 : 8; + FxDevicePwrRequirementStates State4 : 8; + FxDevicePwrRequirementStates State5 : 8; + FxDevicePwrRequirementStates State6 : 8; + FxDevicePwrRequirementStates State7 : 8; + FxDevicePwrRequirementStates State8 : 8; + } S; + + UCHAR History[FxDevicePwrRequirementEventQueueDepth]; +}; + +struct FxDevicePwrRequirementStateTable { + PFN_DEVICE_POWER_REQUIREMENT_STATE_ENTRY_FUNCTION StateFunc; + + const FxDevicePwrRequirementTargetState* TargetStates; + + ULONG TargetStatesCount; +}; + +class FxDevicePwrRequirementMachine : public FxThreadedEventQueue { + +public: + FxDevicePwrRequirementMachine( + __in FxPoxInterface * PoxInterface + ); + + VOID + ProcessEvent( + __in FxDevicePwrRequirementEvents Event + ); + + static + VOID + _ProcessEventInner( + __inout FxPkgPnp* PkgPnp, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ); + +private: + VOID + ProcessEventInner( + __inout FxPostProcessInfo* Info + ); + + static + FxDevicePwrRequirementStates + PowerNotRequiredD0( + __in FxDevicePwrRequirementMachine* This + ); + + static + FxDevicePwrRequirementStates + PowerRequiredDx( + __in FxDevicePwrRequirementMachine* This + ); + + static + FxDevicePwrRequirementStates + ReportingDevicePowerAvailable( + __in FxDevicePwrRequirementMachine* This + ); + +protected: + FxPoxInterface* m_PoxInterface; + + // uses FxDevicePwrRequirementStates values + BYTE m_CurrentState; + + // three extra padded bytes are put in here by the compiler + + FxDevicePwrRequirementEvents m_Queue[FxDevicePwrRequirementEventQueueDepth]; + FxDevicePwrRequirementMachineStateHistory m_States; + + static const FxDevicePwrRequirementStateTable m_StateTable[]; + + static const FxDevicePwrRequirementTargetState m_UnregisteredStates[]; + static const FxDevicePwrRequirementTargetState m_DevicePowerRequiredD0States[]; + static const FxDevicePwrRequirementTargetState m_DevicePowerNotRequiredD0States[]; + static const FxDevicePwrRequirementTargetState m_DevicePowerNotRequiredDxStates[]; + static const FxDevicePwrRequirementTargetState m_DevicePowerRequiredDxStates[]; + static const FxDevicePwrRequirementTargetState m_WaitingForDevicePowerRequiredD0States[]; +}; + +#endif // _FXDEVICEPWRREQUIRESTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicetext.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicetext.hpp new file mode 100644 index 00000000000..42561296e88 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicetext.hpp @@ -0,0 +1,85 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceText.hpp + +Abstract: + + This module implements the device text object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDEVICETEXT_H_ +#define _FXDEVICETEXT_H_ + +struct FxDeviceText : public FxStump { + SINGLE_LIST_ENTRY m_Entry; + PWCHAR m_Description; + PWCHAR m_LocationInformation; + LCID m_LocaleId; + + FxDeviceText( + VOID + ); + + ~FxDeviceText( + VOID + ); + + static + FxDeviceText* + _FromEntry( + __in PSINGLE_LIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxDeviceText, m_Entry); + } + + static + _CleanupList( + __inout PSINGLE_LIST_ENTRY Head + ) + { + PSINGLE_LIST_ENTRY ple; + + ple = Head->Next; + + if (ple != NULL) { + FxDeviceText* pText; + + pText = FxDeviceText::_FromEntry(ple); + ple = ple->Next; + + // + // Destructor verifies the entry is not on any list + // + pText->m_Entry.Next = NULL; + delete pText; + } + + Head->Next = NULL; + } + + VOID + operator delete( + __in PVOID Pool + ) + { + FxPoolFree(Pool); + } +}; + +#endif // _FXDEVICETEXT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicetomxinterface.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicetomxinterface.hpp new file mode 100644 index 00000000000..1034539bde7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdevicetomxinterface.hpp @@ -0,0 +1,59 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceToMxInterface.hpp + +Abstract: + + Classes in this file are there to enable reaching into those classes that + have not yet been made mode agnostic such as FxDevice, FxDeviceInit, FxPkgIo + and others. These will not be needed once all objects have been made mode + agnostic + + These classes will be implemented separately by respective frameworks + + Convention used: + - Typically the first parameter to a method exposed by these classes is a + pointer to the object that is being exposed. e.g. methods in FxDeviceToMx + class have FxDevice* as the first parameter. + + - The name of method is same as the original method wherever applicable. + + - For a method of another object that is a member of the object being + exposed, the name comprises member object's class name. + e.g. m_Device->m_PkgIo->StopProcessingForPower() is exposed as + FxDeviceToMx::FxPkgIo_StopProcessingForPower( ) + The name of method begins with FxPkgIo_ because StopProcessingForPower is + a method of FxPkgIo and not FxDevice. + +Author: + + + +Environment: + + +Revision History: + +--*/ + +#pragma once + + + + + +WDF_FILEOBJECT_CLASS +__inline +FxFileObjectClassNormalize( + __in WDF_FILEOBJECT_CLASS FileObjectClass + ); + +BOOLEAN +__inline +FxIsFileObjectOptional( + __in WDF_FILEOBJECT_CLASS FileObjectClass + ); diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdisposelist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdisposelist.hpp new file mode 100644 index 00000000000..4a44d1433f4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdisposelist.hpp @@ -0,0 +1,142 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDisposalList.hpp + +Abstract: + + This class implements a Disposal list for deferring Dispose + processing from dispatch to passive level. + +Author: + + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXDISPOSELIST_H_ +#define _FXDISPOSELIST_H_ + +/* + * Some objects can perform dispose/cleanup processing at DISPATCH_LEVEL, + * and must defer cleanup processing to PASSIVE_LEVEL. + * + * This is either due to use of page-able data or code, or a passive + * level callback constraint on the object. + * + * This class supports this by providing a list to enqueue objects on + * that need dispose, and an event that may be used by a calling thread + * such as the Pnp DeviceRemove thread that must synchronize all object + * rundown associated with an FxDevice before returning. + * + * This is designed to operate in an allocation free manner, and re-uses + * an FxObject entry that is not longer in use when an object is in + * a deferred dispose state. + * + */ + +class FxDisposeList : public FxNonPagedObject { + +private: + + // + // The List of items to cleanup + // + SINGLE_LIST_ENTRY m_List; + + // + // Pointer to the end of the list so appending does not require traversal + // of the entire list + // + SINGLE_LIST_ENTRY** m_ListEnd; + + // + // This is a pointer to thread object that invoked our workitem + // callback. This value will be used to avoid deadlock when we try + // to flush the workitem. + // + MxThread m_WorkItemThread; + + FxSystemWorkItem* m_SystemWorkItem; + + // + // WDM PDRIVER or PDEVICE_OBJECT for allocating PIO_WORKITEMS + // + PVOID m_WdmObject; + +private: + static + VOID + _WorkItemThunk( + __in PVOID Parameter + ); + + VOID + DrainListLocked( + PKIRQL PreviousIrql + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + +public: + + static + NTSTATUS + _Create( + PFX_DRIVER_GLOBALS FxDriverGlobals, + PVOID WdmObject, + FxDisposeList** pObject + ); + + FxDisposeList( + PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxDisposeList( + ); + + NTSTATUS + Initialize( + PVOID wdmObject + ); + + // + // Add an object to the list. + // + // The object's m_DisposeListEntry is used and must be initialized + // + VOID + Add( + FxObject* object + ); + + // + // Waits until the list is empty + // + VOID + WaitForEmpty( + VOID + ); + + DECLARE_INTERNAL_NEW_OPERATOR(); +}; + +#endif // _FXDISPOSELIST_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdriver.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdriver.hpp new file mode 100644 index 00000000000..0f9c1c472bd --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdriver.hpp @@ -0,0 +1,422 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriver.hpp + +Abstract: + + This is the definition of the FxDriver object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDRIVER_H_ +#define _FXDRIVER_H_ + +#include "FxDriverCallbacks.hpp" + + +// +// Unique value to retrieve the FxDriver* from the PDEVICE_OBJECT. +// +#define FX_TRACE_INFO_ID (FxDriver::_GetTraceInfoExtension) + +// +// Structure to hold WMI Callback info +// +struct FxTraceInfo { + MdDriverObject DriverObject; + PFN_WDF_TRACE_CALLBACK Callback; + PVOID Context; +}; + +// +// Unique value to retrieve the FxDriver* from the MdDriverObject. Use a value +// that is not exposed to the driver writer through the dispatch table or WDM. +// +#define FX_DRIVER_ID (FxDriver::GetFxDriver) + +// +// The following are support classes for FxDriver +// +class FxDriver : public FxNonPagedObject, public IFxHasCallbacks +{ +friend class FxDevice; +friend class FxPackage; +friend class FxWmiIrpHandler; + +private: + + MxDriverObject m_DriverObject; + UNICODE_STRING m_RegistryPath; + + BOOLEAN m_DebuggerConnected; + + // + // Callbacks to device driver + // + FxDriverDeviceAdd m_DriverDeviceAdd; + + // + // This represents any constraints on callbacks + // to the device driver that may be inherited + // by child devices and their objects + // + WDF_EXECUTION_LEVEL m_ExecutionLevel; + WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope; + + // + // Frameworks objects that raise event callbacks into the device + // driver provide spinlock and mutex based callback locks + // to allow proper synchronization between the driver and + // these callbacks. + // + // Some events must be passive level, while others at dispatch + // level, thus the need for two locks. + // + // The objects internal state is protected by the FxNonPagedObject + // lock inherited by the object, and is different from the callback + // locks. + // + FxCallbackMutexLock m_CallbackMutexLock; + + // + // These pointers allow the proper lock to be acquired + // based on the configuration with a minimal of runtime + // checks. This is configured by ConfigureConstraints() + // + FxCallbackLock* m_CallbackLockPtr; + FxObject* m_CallbackLockObjectPtr; + + // + // This is the Driver-wide configuration + // + WDF_DRIVER_CONFIG m_Config; + + // + // Deferred Disposal List + // + FxDisposeList* m_DisposeList; + +#if FX_IS_USER_MODE + // + // A handle to the driver service parameters key. + // The framework does not have permission to open it with + // write access from user mode, so we keep a pre-opened one. + // + HKEY m_DriverParametersKey; +#endif + +private: + + static + MdDriverAddDeviceType AddDevice; + +public: + + // This is public to allow the C function FxCoreDriverUnload to call it + FxDriverUnload m_DriverUnload; + + FxDriver( + __in MdDriverObject DriverObject, + __in PWDF_DRIVER_CONFIG DriverConfig, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxDriver(); + + static + VOID + _InitializeDriverName( + __in PFX_DRIVER_GLOBALS Globals, + __in PCUNICODE_STRING RegistryPath + ); + + static + VOID + _InitializeTag( + __in PFX_DRIVER_GLOBALS Globals, + __in PWDF_DRIVER_CONFIG Config + ); + + static + FxDriver* + GetFxDriver( + __in MdDriverObject DriverObject + ); + + _Must_inspect_result_ + NTSTATUS + AllocateDriverObjectExtensionAndStoreFxDriver( + VOID + ); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + __inline + WDFDRIVER + GetHandle( + VOID + ) + { + return (WDFDRIVER) GetObjectHandle(); + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + + _Must_inspect_result_ + NTSTATUS + AddDevice( + __in MdDeviceObject PhysicalDeviceObject + ); + +#else + + _Must_inspect_result_ + NTSTATUS + FxDriver::AddDevice( + _In_ IWudfDeviceStack * DevStack, + _In_ LPCWSTR KernelDeviceName, + _In_opt_ HKEY PdoKey, + _In_ LPCWSTR ServiceName, + _In_ LPCWSTR DevInstanceID, + _In_ ULONG DriverID + ); +#endif + + VOID + InitializeInternal( + VOID + ); + + _Must_inspect_result_ + FxString * + GetRegistryPath( + VOID + ); + + PUNICODE_STRING + GetRegistryPathUnicodeString( + VOID + ) + { + return &m_RegistryPath; + } + + __inline + MdDriverObject + GetDriverObject( + VOID + ) + { + return m_DriverObject.GetObject(); + } + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PCUNICODE_STRING RegistryPath, + __in PWDF_DRIVER_CONFIG Config, + __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes + ); + + // + // The following methods support the callback constraints + // and handle locking and deferral + // + VOID + ConfigureConstraints( + __in_opt PWDF_OBJECT_ATTRIBUTES DriverAttributes + ); + + // + // IFxHasCallbacks Support + // + + virtual + VOID + GetConstraints( + __out WDF_EXECUTION_LEVEL* ExecutionLevel, + __out WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) { + + if (ExecutionLevel != NULL) { + *ExecutionLevel = m_ExecutionLevel; + } + + if (SynchronizationScope != NULL) { + *SynchronizationScope = m_SynchronizationScope; + } + } + + virtual + FxCallbackLock* + GetCallbackLockPtr( + __deref_out FxObject** LockObject + ) { + + if (LockObject != NULL) { + *LockObject = m_CallbackLockObjectPtr; + } + + return m_CallbackLockPtr; + } + + // + // IFxAssociation Support + // + virtual + NTSTATUS + QueryInterface( + __inout FxQueryInterfaceParams* Params + ) + { + switch (Params->Type) { + case FX_TYPE_DRIVER: + *Params->Object = (FxDriver*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; + } + + virtual + VOID + DeleteObject( + VOID + ) + { + // + // If diposed at > PASSIVE, we will cause a deadlock in FxDriver::Dispose + // when we call into the dispose list to wait for empty when we are in + // the context of the dispose list's work item. + // + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + __super::DeleteObject(); + } + + virtual + BOOLEAN + Dispose( + VOID + ); + + __inline + FxDisposeList* + GetDisposeList( + ) + { + return m_DisposeList; + } + + __inline + PFN_WDF_DRIVER_DEVICE_ADD + GetDriverDeviceAddMethod( + ) + { + return m_DriverDeviceAdd.Method; + } + + static + MdDriverUnloadType Unload; + +#if FX_IS_USER_MODE +private: + + // + // Open the handle to the driver service parameters key + // that we keep opened for use from user mode. + // + NTSTATUS + OpenParametersKey( + VOID + ); + + VOID + ClearDriverObjectFxDriver( + VOID + ); + +public: + + __inline + HKEY + GetDriverParametersKey( + VOID + ) + { + return m_DriverParametersKey; + } +#endif + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + VOID + SetDriverObjectFlag( + _In_ FxDriverObjectUmFlags Flag + ) + { + m_DriverObject.SetDriverObjectFlag(Flag); + } + + BOOLEAN + IsDriverObjectFlagSet( + _In_ FxDriverObjectUmFlags Flag + ) + { + return m_DriverObject.IsDriverObjectFlagSet(Flag); + } + +#endif + +}; + +#endif // _FXDRIVER_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxdrivercallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdrivercallbacks.hpp new file mode 100644 index 00000000000..443cbabc020 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxdrivercallbacks.hpp @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDriverCallbacks.h + +Abstract: + + This module implements the FxDriver object callbacks + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXDRIVERCALLBACKS_H_ +#define _FXDRIVERCALLBACKS_H_ + +// +// These delegates are in a seperate file +// + +// +// DrvDeviceInitialize callback delegate +// +class FxDriverDeviceAdd : public FxLockedCallback { + +public: + PFN_WDF_DRIVER_DEVICE_ADD Method; + + FxDriverDeviceAdd( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDRIVER Driver, + __in PWDFDEVICE_INIT DeviceInit + ) + { + if (Method != NULL) { + NTSTATUS status; + KIRQL irql = 0; + + CallbackStart(&irql); + status = Method(Driver, DeviceInit); + CallbackEnd(irql); + + return status; + } + else { + return STATUS_UNSUCCESSFUL; + } + } +}; + +// +// DrvUnload callback delegate +// +class FxDriverUnload : public FxCallback { + +public: + + PFN_WDF_DRIVER_UNLOAD Method; + + FxDriverUnload( + VOID + ) : + FxCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFDRIVER Driver + ) + { + if (Method != NULL) { + + CallbackStart(); + Method(Driver); + CallbackEnd(); + return; + } + else { + return; + } + } +}; + +#endif // _FXDRIVERCALLBACKS_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxeventqueue.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxeventqueue.hpp new file mode 100644 index 00000000000..bca8bb36688 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxeventqueue.hpp @@ -0,0 +1,381 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXEVENTQUEUE_H_ +#define _FXEVENTQUEUE_H_ + +struct FxPostProcessInfo { + FxPostProcessInfo( + VOID + ) + { + m_Event = NULL; + m_DeleteObject = FALSE; + m_SetRemovedEvent = FALSE; + m_FireAndForgetIrp = NULL; + } + + BOOLEAN + SomethingToDo( + VOID + ) + { + return ((m_Event != NULL) || m_DeleteObject) ? TRUE : FALSE; + } + + VOID + Evaluate( + __inout FxPkgPnp* PkgPnp + ); + + FxCREvent* m_Event; + BOOLEAN m_DeleteObject; + BOOLEAN m_SetRemovedEvent; + MdIrp m_FireAndForgetIrp; +}; + +typedef +VOID +(*PFN_PNP_EVENT_WORKER)( + __in FxPkgPnp* PkgPnp, + __in FxPostProcessInfo* Info, + __in PVOID Context + ); + +enum FxEventQueueFlags { + FxEventQueueFlagWorkItemQueued = 0x01, + FxEventQueueFlagClosed = 0x02, + FxEventQueueFlagDelayDeletion = 0x04, +}; + +struct FxEventQueue : public FxStump { + FxEventQueue( + __in UCHAR QueueDepth + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PFX_DRIVER_GLOBALS DriverGlobals + ); + + _Acquires_lock_(this->m_QueueLock) + __drv_maxIRQL(DISPATCH_LEVEL) + __drv_setsIRQL(DISPATCH_LEVEL) + VOID + Lock( + __out __drv_deref(__drv_savesIRQL) + PKIRQL Irql + ) + { + m_QueueLock.Acquire(Irql); + } + + _Releases_lock_(this->m_QueueLock) + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + Unlock( + __in __drv_restoresIRQL + KIRQL Irql + ) + { + m_QueueLock.Release(Irql); + } + + BOOLEAN + IsFull( + VOID + ) + { + return ((m_QueueHead + m_QueueDepth - 1) % m_QueueDepth) == (m_QueueTail % m_QueueDepth); + } + + BOOLEAN + IsEmpty( + VOID + ) + { + return m_QueueHead == m_QueueTail; + } + + VOID + IncrementHead( + VOID + ) + { + m_QueueHead = (m_QueueHead + 1) % m_QueueDepth; + } + + UCHAR + GetHead( + VOID + ) + { + return m_QueueHead; + } + + UCHAR + InsertAtHead( + VOID + ) + { + m_QueueHead = (m_QueueHead + m_QueueDepth - 1) % m_QueueDepth; + return m_QueueHead; + } + + UCHAR + InsertAtTail( + VOID + ) + { + UCHAR index; + + // Save the index which is the current tail + index = m_QueueTail; + + // goto next slot + m_QueueTail = (m_QueueTail + 1) % m_QueueDepth; + + // return the old tail as the slot to insert at + return index; + } + + UCHAR + IncrementHistoryIndex( + VOID + ) + { + UCHAR cur; + + cur = m_HistoryIndex; + m_HistoryIndex = (m_HistoryIndex + 1) % m_QueueDepth; + + return cur; + } + + BOOLEAN + IsClosedLocked( + VOID + ) + { + return (m_QueueFlags & FxEventQueueFlagClosed) ? TRUE : FALSE; + } + + VOID + GetFinishedState( + __inout FxPostProcessInfo* Info + ) + { + if (IsIdleLocked()) { + if (m_QueueFlags & FxEventQueueFlagDelayDeletion) { + m_QueueFlags &= ~FxEventQueueFlagDelayDeletion; + Info->m_DeleteObject = TRUE; + } + + if (IsClosedLocked()) { + Info->m_Event = m_WorkItemFinished; + m_WorkItemFinished = NULL; + } + } + } + + BOOLEAN + SetFinished( + __in FxCREvent* Event + ); + + VOID + SetDelayedDeletion( + VOID + ); + +protected: + VOID + Configure( + __in FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine, + __in PVOID Context + ); + + BOOLEAN + QueueToThreadWorker( + VOID + ); + + VOID + EventQueueWorker( + VOID + ); + + BOOLEAN + IsIdleLocked( + VOID + ) + { + // + // We are idle if there is no work item queued, no work item running, + // and there are no events in the queue. Since m_WorkItemQueued is + // cleared before we enter the state machine, we must also track the + // number of work items running. + // + if ((m_QueueFlags & FxEventQueueFlagWorkItemQueued) == 0x00 && + m_WorkItemRunningCount == 0x0 && + IsEmpty()) { + return TRUE; + } + else { + return FALSE; + } + } + +protected: + // index into the beginning of the circular event ring buffer + UCHAR m_QueueHead; + + // index into the end of the circular event ring buffer + UCHAR m_QueueTail; + + // circular event ring buffer size + UCHAR m_QueueDepth; + + UCHAR m_HistoryIndex; + + FxPkgPnp* m_PkgPnp; + + // + // Context that is passed back to the the state machine as + // part of the event worker + // + PVOID m_EventWorkerContext; + + // + // Lock for the queue + // + MxLock m_QueueLock; + +public: + FxWaitLockInternal m_StateMachineLock; + +protected: + PFN_PNP_EVENT_WORKER m_EventWorker; + + // + // Guarded by m_QueueLock. Will be set to a valid pointer value when pnp + // wants to remove the device and we want to synchronize against the work + // item running. + // + FxCREvent* m_WorkItemFinished; + + // + // + union { + // + // See FxEventQueueFlags for values + // + UCHAR m_QueueFlags; + + struct { + UCHAR WorkItemQueued : 1; + UCHAR Closed : 1; + UCHAR DelayDeletion : 1; + } m_QueueFlagsByName; + }; + + // + // Count of times the work item is running. Since m_WorkItemQueued is + // cleared before we enter the state machine, we must also track the + // number of instances to make sure we know when we are idle or not. + // + UCHAR m_WorkItemRunningCount; +}; + +struct FxWorkItemEventQueue : public FxEventQueue { + FxWorkItemEventQueue( + __in UCHAR QueueDepth + ); + + ~FxWorkItemEventQueue(); + + _Must_inspect_result_ + NTSTATUS + Init( + __inout FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine, + __in PVOID WorkerContext = NULL + ); + + VOID + QueueToThread( + VOID + ) + { + if (QueueToThreadWorker()) { + QueueWorkItem(); + } + } + +protected: + VOID + QueueWorkItem( + VOID + ); + + static + MX_WORKITEM_ROUTINE + _WorkItemCallback; + + MxWorkItem m_WorkItem; +}; + +// +// struct that encapsulates posting a work item to the dedicated power thread +// or work item depending on the power pagable status of the stack. +// +struct FxThreadedEventQueue : public FxEventQueue { + FxThreadedEventQueue( + __in UCHAR QueueDepth + ); + + ~FxThreadedEventQueue( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Init( + __inout FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine, + __in PVOID WorkerContext = NULL + ); + + VOID + QueueToThread( + VOID + ) + { + if (QueueToThreadWorker()) { + QueueWorkItem(); + } + } + +protected: + static + WORKER_THREAD_ROUTINE + _WorkerThreadRoutine; + + static + MX_WORKITEM_ROUTINE + _WorkItemCallback; + + VOID + QueueWorkItem( + VOID + ); + + MxWorkItem m_WorkItem; + + // work item used to queue to the thread + WORK_QUEUE_ITEM m_EventWorkQueueItem; +}; + +#endif // _FXEVENTQUEUE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxfileobject.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxfileobject.hpp new file mode 100644 index 00000000000..f65420f9456 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxfileobject.hpp @@ -0,0 +1,255 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObject.hpp + +Abstract: + + This module implements a frameworks managed FileObject + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXFILEOBJECT_H_ +#define _FXFILEOBJECT_H_ + +class FxFileObject : public FxNonPagedObject, public IFxHasCallbacks { + +private: + + // Pointer to WDM FileObject + MxFileObject m_FileObject; + PVOID m_PkgContext; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // KMDF retrieves the name unicode string directly from wdm file object, + // and returns it to caller. UMDF doesn't provide a unicode string and + // therefore we allocate it in this object and return that to caller after + // populating it with name string retrieved from host. + // + UNICODE_STRING m_FileName; + + // + // Framework related file object + // + FxFileObject* m_RelatedFileObject; + +#endif + +public: + + // ListEntry for linking FileObjects off of the device + LIST_ENTRY m_Link; + +private: + + VOID + SetFileObjectContext( + _In_ MdFileObject WdmFileObject, + _In_ WDF_FILEOBJECT_CLASS NormalizedFileClass, + _In_ MdIrp Irp, + _In_ FxDevice* Device + ); + +public: + FxFileObject( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in MdFileObject pWdmFileObject, + __in FxDevice* Device + ); + + virtual + ~FxFileObject( + ); + + __inline + WDFFILEOBJECT + GetHandle( + VOID + ) + { + return (WDFFILEOBJECT) GetObjectHandle(); + } + + __inline + MdFileObject + GetWdmFileObject( + VOID + ) + { + return m_FileObject.GetFileObject(); + } + + __inline + CfxDevice* + GetDevice( + VOID + ) + { + return m_Device; + } + + __inline + PUNICODE_STRING + GetFileName( + VOID + ) + { + #if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return m_FileObject.GetFileName(NULL); + #else + return m_FileObject.GetFileName(&m_FileName); + #endif + } + + __inline + PLARGE_INTEGER + GetCurrentByteOffset( + VOID + ) + { + return m_FileObject.GetCurrentByteOffset(); + } + + __inline + ULONG + GetFlags( + VOID + ) + { + return m_FileObject.GetFlags(); + } + + __inline + VOID + SetPkgCleanupCloseContext( + PVOID Context + ) + { + m_PkgContext = Context; + } + + __inline + PVOID + GetPkgCleanupCloseContext( + VOID + ) + { + return m_PkgContext; + } + + // + // Create a WDFFILEOBJECT from the WDM PFILE_OBJECT + // and associate it with the WDM PFILE_OBJECT according + // to the FileObjectClass. + // + _Must_inspect_result_ + static + NTSTATUS + _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** ppFxFileObject + ); + + VOID + Initialize( + _In_ MdIrp CreateIrp + ); + + // + // Destroy (dereference) the WDFFILEOBJECT related to the + // WDM PFILE_OBJECT according to its FileObjectClass. + // + static + VOID + _DestroyFileObject( + __in FxDevice* pDevice, + __in WDF_FILEOBJECT_CLASS FileObjectClass, + __in_opt MdFileObject pWdmFileObject + ); + + // + // Return the FxFileObject* for the given WDM PFILE_OBJECT + // based on the FileObjectClass. + // + _Must_inspect_result_ + static + NTSTATUS + _GetFileObjectFromWdm( + __in FxDevice* pDevice, + __in WDF_FILEOBJECT_CLASS FileObjectClass, + __in_opt MdFileObject pWdmFileObject, + __deref_out_opt FxFileObject** ppFxFileObject + ); + + VOID + DeleteFileObjectFromFailedCreate( + VOID + ); + + // begin FxObject overrides + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ); + // end FxObject overrides + + // begin IFxHasCallbacks overrides + VOID + GetConstraints( + __in WDF_EXECUTION_LEVEL* ExecutionLevel, + __in WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) ; + + _Must_inspect_result_ + FxCallbackLock* + GetCallbackLockPtr( + __deref_out_opt FxObject** LockObject + ); + // end IFxHasCallbacks overrides + + // + // Update the process keep-alive count + // TRUE: increment, FALSE: decrement + // + _Must_inspect_result_ + NTSTATUS + UpdateProcessKeepAliveCount( + _In_ BOOLEAN Increment + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + FxFileObject* + GetRelatedFileObject( + VOID + ) + { + return m_RelatedFileObject; + } + +#endif + +}; + +#endif // _FXFILEOBJECT_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxfileobjectcallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxfileobjectcallbacks.hpp new file mode 100644 index 00000000000..482f19e215e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxfileobjectcallbacks.hpp @@ -0,0 +1,200 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectCallbacks.h + +Abstract: + + This module implements the I/O package queue object callbacks + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXFILEOBJECTCALLBACKS_H +#define _FXFILEOBJECTCALLBACKS_H + + +// +// EvtDeviceFileCreate callback delegate +// +class FxFileObjectFileCreate : public FxLockedCallback { + +public: + PFN_WDF_DEVICE_FILE_CREATE Method; + + FxFileObjectFileCreate( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + VOID + Invoke( + __in WDFDEVICE Device, + __in WDFREQUEST Request, + __in_opt WDFFILEOBJECT FileObject + ) + { + + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Device, Request, FileObject); + CallbackEnd(irql); + } + } +}; + +// +// EvtFileCleanup callback delegate +// +class FxFileObjectFileCleanup : public FxLockedCallback { + +public: + PFN_WDF_FILE_CLEANUP Method; + + FxFileObjectFileCleanup( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in_opt WDFFILEOBJECT FileObject + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(FileObject); + CallbackEnd(irql); + } + } +}; + +// +// EvtFileClose callback delegate +// +class FxFileObjectFileClose : public FxLockedCallback { + +public: + PFN_WDF_FILE_CLOSE Method; + + FxFileObjectFileClose( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in_opt WDFFILEOBJECT FileObject + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(FileObject); + CallbackEnd(irql); + } + } +}; + +// +// EvtDeviceFileCreate callback delegate +// +class FxCxFileObjectFileCreate : public FxLockedCallback { + +public: + PFN_WDFCX_DEVICE_FILE_CREATE Method; + + FxCxFileObjectFileCreate( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + BOOLEAN + Invoke( + __in WDFDEVICE Device, + __in WDFREQUEST Request, + __in_opt WDFFILEOBJECT FileObject + ) + { + BOOLEAN claimed = FALSE; + + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + claimed = Method(Device, Request, FileObject); + CallbackEnd(irql); + } + + return claimed; + } +}; + +// +// Collection of file-object callbacks. +// +struct FxFileObjectInfo : public FxStump { + + FxFileObjectInfo() : + FileObjectClass(WdfFileObjectInvalid), + AutoForwardCleanupClose(WdfUseDefault), + ClassExtension(FALSE), + CxDeviceInfo(NULL) + { + InitializeListHead(&ListEntry); + RtlZeroMemory(&Attributes, sizeof(Attributes)); + } + + ~FxFileObjectInfo() + { + ASSERT(IsListEmpty(&ListEntry)); + } + + LIST_ENTRY ListEntry; + + FxFileObjectFileCreate EvtFileCreate; + FxCxFileObjectFileCreate EvtCxFileCreate; + FxFileObjectFileCleanup EvtFileCleanup; + FxFileObjectFileClose EvtFileClose; + + WDF_FILEOBJECT_CLASS FileObjectClass; + WDF_OBJECT_ATTRIBUTES Attributes; + WDF_TRI_STATE AutoForwardCleanupClose; + + BOOLEAN ClassExtension; + + FxCxDeviceInfo* CxDeviceInfo; +}; + +#endif // _FXFILEOBJECTCALLBACKS_H + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxforward.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxforward.hpp new file mode 100644 index 00000000000..ac73b1ed26f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxforward.hpp @@ -0,0 +1,139 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXFORWARD_HPP_ +#define _FXFORWARD_HPP_ + +typedef struct _FX_DRIVER_GLOBALS *PFX_DRIVER_GLOBALS; + +struct FxAutoIrp; +class FxCallback; +class FxCallbackLock; +class FxCallbackMutexLock; +class FxCallbackSpinLock; +class FxChildList; +class FxCmResList; +class FxCollection; +struct FxCollectionInternal; +class FxCommonBuffer; +struct FxContextHeader; +class FxDevice; +class FxDeviceBase; +struct FxDeviceDescriptionEntry; +class FxDeviceInterface; +struct FxDeviceText; +struct FxCxDeviceInfo; +class FxDefaultIrpHandler; +class FxDisposeList; +class FxDmaEnabler; +class FxDmaTransactionBase; +class FxDmaPacketTransaction; +class FxDmaScatterGatherTransaction; +class FxDriver; +class FxFileObject; +struct FxFileObjectInfo; +struct FxGlobalsStump; +class FxInterrupt; +struct FxIoQueueNode; +class FxIoQueue; +class FxIoResList; +class FxIoResReqList; +class FxIoTarget; +class FxIoTargetSelf; +class FxIrp; +struct FxIrpPreprocessInfo; +struct FxIrpDynamicDispatchInfo; +class FxIrpQueue; +class FxLock; +class FxLookasideList; +class FxLookasideListFromPool; +class FxMemoryBuffer; +class FxMemoryBufferFromLookaside; +class FxMemoryBufferFromPool; +class FxMemoryBufferFromPoolLookaside; +class FxMemoryBufferPreallocated; +class FxMemoryObject; +class FxNonPagedObject; +class FxNPagedLookasideList; +class FxNPagedLookasideListFromPool; +class FxObject; +class FxPackage; +class FxPagedLookasideListFromPool; +class FxPagedObject; +class FxPkgFdo; +class FxPkgGeneral; +class FxPkgIo; +class FxPkgPdo; +class FxPkgPnp; +struct FxPnpMachine; +struct FxPnpStateCallback; +struct FxPowerMachine; +struct FxPostProcessInfo; +class FxPowerIdleMachine; +struct FxPowerPolicyMachine; +struct FxPowerPolicyStateCallback; +struct FxPowerStateCallback; +struct FxQueryInterface; +class FxRequest; +class FxRequestBase; +struct FxRequestBuffer; +struct FxRequestContext; +class FxRequestFromLookaside; +class FxRequestMemory; +struct FxRequestOutputBuffer; +struct FxRequestSystemBuffer; +class FxRelatedDevice; +class FxRelatedDeviceList; +class FxResourceCm; +class FxResourceIo; +class FxSelfManagedIoMachine; +class FxSpinLock; +class FxString; +struct FxStump; +class FxSyncRequest; +class FxSystemWorkItem; +class FxSystemThread; +class FxTagTracker; +class FxTimer; +struct FxTraceInfo; +class FxTransactionedList; +struct FxTransactionedEntry; +class FxUsbDevice; +struct FxUsbIdleInfo; +class FxUsbInterface; +class FxUsbPipe; +struct FxUsbPipeContinuousReader; +class FxVerifierLock; +struct FxWatchdog; +class FxWaitLock; +class FxWmiProvider; +class FxWmiInstance; +class FxWmiInstanceExternal; +class FxWmiInstanceInternal; +struct FxWmiInstanceInternalCallbacks; +class FxWmiIrpHandler; +class FxWorkItem; + +class IFxHasCallbacks; +class IFxMemory; + +enum FxObjectType; +enum FxWmiInstanceAction; +enum FxDriverObjectUmFlags : USHORT; + +PVOID +FxObjectHandleAlloc( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in POOL_TYPE PoolType, + __in size_t Size, + __in ULONG Tag, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in USHORT ExtraSize, + __in FxObjectType ObjectType + ); + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) +#include "FxForwardUm.hpp" +#endif + +#endif // _FXFORWARD_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxglobals.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxglobals.h new file mode 100644 index 00000000000..606a40ad037 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxglobals.h @@ -0,0 +1,1101 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxGlobals.h + +Abstract: + + This module contains globals definitions for the frameworks. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + Made it mode agnostic + Moved km specific portions to FxGlobalsKm.h + + + + + + + + + + New failure paths: + AllocatedTagTrackersLock initialization - + If this fails we free debug extensions structure and not use it + ThreadTableLock initialization - + If this fails we turn off lock verification + FxDriverGlobalsListLock initialization - + If this fails we fail FxLibraryGlobalsCommission + +--*/ + +#ifndef _FXGLOBALS_H +#define _FXGLOBALS_H + +#include "wdfglobals.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct FxLibraryGlobalsType; + +class CWudfDriverGlobals; //UMDF driver globals + +// +// NOTE: any time you add a value to this enum, you must add a field to the +// union in FxObjectDebugInfo. +// +enum FxObjectDebugInfoFlags { + FxObjectDebugTrackReferences = 0x0001, +}; + +typedef enum FxTrackPowerOption : UCHAR { + FxTrackPowerNone = 0, + FxTrackPowerRefs, + FxTrackPowerRefsAndStack, + FxTrackPowerMaxValue +}; + +typedef enum FxVerifierDownlevelOption { + NotOkForDownLevel = 0, + OkForDownLevel = 1, +} FxVerifierDownLevelOption; + +typedef enum WaitSignalFlags { + WaitSignalBreakUnderVerifier = 0x01, + WaitSignalBreakUnderDebugger = 0x02, + WaitSignalAlwaysBreak = 0x04 +} WaitSignalFlags; + + +struct FxObjectDebugInfo { + // + // FX_OBJECT_TYPES enum value + // + USHORT ObjectType; + + union { + // + // Combo of values from FxObjectDebugInfoFlags + // + USHORT DebugFlags; + + // + // Break out of DebugFlags as individual fields. This is used by the + // debugger extension to reference the values w/out knowing the actual + // enum values. + // + struct { + USHORT TrackReferences : 1; + } Bits; + } u; +}; + +struct FxDriverGlobalsDebugExtension { + // + // Debug information per object. List is sorted by + // FxObjectDebugInfo::ObjectType, length is the same as FxObjectsInfo. + // + FxObjectDebugInfo* ObjectDebugInfo; + + // + // Track allocated Mdls only in kernel mode version + // +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + FxAllocatedMdls AllocatedMdls; + + KSPIN_LOCK AllocatedMdlsLock; +#endif + + // + // List of all allocated tag trackers for this driver. This is used to keep + // track of orphaned objects due to leaked reference counts in the debugger + // extension. + // + LIST_ENTRY AllocatedTagTrackersListHead; + + // + // Synchronizes access to AllocatedTagTrackersListHead + // + MxLock AllocatedTagTrackersLock; + + // + // Whether we track power references for WDFDEVICE objects + // and optionally capture stack frames. + // + FxTrackPowerOption TrackPower; +}; + +// +// A telemetry context that is allocated if the telemetry provider is enabled. +// +typedef struct _FX_TELEMETRY_CONTEXT{ + // + // A GUID representing the driver session + // + GUID DriverSessionGUID; + + // + // A general purpose bitmap that can be used + // by various telemetry events that may want to + // fire once per driver session. + // + volatile LONG DoOnceFlagsBitmap; +} FX_TELEMETRY_CONTEXT, *PFX_TELEMETRY_CONTEXT; + +typedef struct _FX_DRIVER_GLOBALS { +public: + ULONG + __inline + AddRef( + __in_opt PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + ULONG c; + + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(File); + + c = InterlockedIncrement(&Refcnt); + + // + // Catch the transition from 0 to 1. Since the RefCount starts off at 1, + // we should never have to increment to get to this value. + // + ASSERT(c > 1); + return c; + } + + ULONG + __inline + Release( + __in_opt PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + ULONG c; + + UNREFERENCED_PARAMETER(Tag); + UNREFERENCED_PARAMETER(Line); + UNREFERENCED_PARAMETER(File); + + c = InterlockedDecrement(&Refcnt); + ASSERT((LONG)c >= 0); + if (c == 0) { + DestroyEvent.Set(); + } + + return c; + } + + BOOLEAN + IsPoolTrackingOn( + VOID + ) + { + return (FxPoolTrackingOn) ? TRUE : FALSE; + } + + BOOLEAN + IsObjectDebugOn( + VOID + ) + { + if (FxVerifierHandle) { + return TRUE; + } + else { + return FALSE; + } + } + + VOID + SetVerifierState( + __in BOOLEAN State + ) + { + // + // Master switch + // + FxVerifierOn = State; + + FxVerifierHandle = State; + FxVerifierIO = State; + FxVerifierLock = State; + FxPoolTrackingOn = State; + + // + // Following two can be overridden by the registry settings + // WDFVERIFY matches the state of the verifier. + // + FxVerifyOn = State; + FxVerifierDbgBreakOnError = State; + FxVerifierDbgBreakOnDeviceStateError = FALSE; + + // + // Set the public flags for consumption by client drivers. + // + if (State) { + Public.DriverFlags |= (WdfVerifyOn | WdfVerifierOn); + } + } + + _Must_inspect_result_ + BOOLEAN + IsVersionGreaterThanOrEqualTo( + __in ULONG Major, + __in ULONG Minor + ); + + _Must_inspect_result_ + BOOLEAN + IsCorrectVersionRegistered( + _In_ PCUNICODE_STRING ServiceKeyName + ); + + VOID + RegisterClientVersion( + _In_ PCUNICODE_STRING ServiceKeyName + ); + + _Must_inspect_result_ + BOOLEAN + IsVerificationEnabled( + __in ULONG Major, + __in ULONG Minor, + __in FxVerifierDownlevelOption DownLevel + ) + { + // + // those verifier checks that are restricted to specific version can be + // applied to previous version drivers if driver opts-in by setting a + // reg key (whose value is stored in FxVerifyDownlevel) + // + if (FxVerifierOn && + (IsVersionGreaterThanOrEqualTo(Major, Minor) || + (DownLevel ? FxVerifyDownlevel : FALSE))) { + return TRUE; + } + else { + return FALSE; + } + } + + // + // To be used in code path where it is already determined that the driver + // is down-level, otherwise use IsVerificationEnabled. + // + __inline + _Must_inspect_result_ + BOOLEAN + IsDownlevelVerificationEnabled( + ) + { + return FxVerifyDownlevel; + } + + VOID + WaitForSignal( + __in MxEvent* Event, + __in PCSTR ReasonForWaiting, + __in PVOID Handle, + __in ULONG WarningTimeoutInSec, + __in ULONG WaitSignalFlags + ); + + _Must_inspect_result_ + BOOLEAN + IsDebuggerAttached( + VOID + ); + +public: + // + // Link list of driver FxDriverGlobals on this WDF Version. + // + LIST_ENTRY Linkage; + + // + // Reference count is operated on with interlocked operations + // + LONG Refcnt; + + // + // This event is signaled when globals can be freed. Unload thread waits + // on this event to make sure driver's threads are done and driver unload + // can proceed. + // + MxEvent DestroyEvent; + + // + // Mask to XOR all outgoing handles against + // + ULONG_PTR WdfHandleMask; + + // + // If verifier is on, this is the count of allocations + // to fail at + // + LONG WdfVerifierAllocateFailCount; + + // + // Tag to be used for allocations on behalf of the driver writer. This is + // based off of the service name (which might be different than the binary + // name). + // + ULONG Tag; + + // + // Backpointer to Fx driver object + // + FxDriver* Driver; + + FxDriverGlobalsDebugExtension* DebugExtension; + + FxLibraryGlobalsType* LibraryGlobals; + + // + // WDF internal In-Flight Recorder (IFR) log + // + PVOID WdfLogHeader; + + // + // The driver's memory pool header + // + FX_POOL FxPoolFrameworks; + + // + // Framworks Pool Tracking + // + BOOLEAN FxPoolTrackingOn; + + // + // FxVerifierLock per driver state + // + MxLock ThreadTableLock; + + PLIST_ENTRY ThreadTable; + + // + // Embedded pointer to driver's WDF_BIND_INFO structure (in stub) + // + PWDF_BIND_INFO WdfBindInfo; + + // + // The base address of the image. + // + PVOID ImageAddress; + + // + // The size of the image. + // + ULONG ImageSize; + + // + // Top level verifier flag. + // + BOOLEAN FxVerifierOn; + + // + // Apply latest-version-restricted verifier checks to downlevel drivers. + // Drivers set this value in registry. + // + BOOLEAN FxVerifyDownlevel; + + // + // Breakpoint on errors. + // + BOOLEAN FxVerifierDbgBreakOnError; + + // + // Breakpoint on device state errors. + // + BOOLEAN FxVerifierDbgBreakOnDeviceStateError; + + // + // Handle verifier. + // + BOOLEAN FxVerifierHandle; + + // + // I/O verifier. + // + BOOLEAN FxVerifierIO; + + // + // Lock verifier. + // + BOOLEAN FxVerifierLock; + + // + // Not a verifier option. Rather, controls whether WDFVERIFY macros are + // live. + // + BOOLEAN FxVerifyOn; + + // + // Capture IFR Verbose messages. + // + BOOLEAN FxVerboseOn; + + // + // Parent queue presented requests (to device). + // + BOOLEAN FxRequestParentOptimizationOn; + + // + // Enable/Disable support for device simulation framework (DSF). + // + BOOLEAN FxDsfOn; + + // + // Force copy of IFR data to mini-dump when a bugcheck happens. + // + BOOLEAN FxForceLogsInMiniDump; + + // + // TRUE to enable run-time driver tracking. The dump callback logic + // uses this info for finding the right log to write in the minidump. + // + BOOLEAN FxTrackDriverForMiniDumpLog; + + // + // TRUE if compiled for user-mode + // + BOOLEAN IsUserModeDriver; + + // + // Remove lock options, these are also specified through + // WdfDeviceInitSetRemoveLockOptions. + // + ULONG RemoveLockOptionFlags; + + // + // Bug check callback data for kernel mode only + + + + // +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // 0-based index into the BugCheckDriverInfo holding this driver info. + // + ULONG BugCheckDriverInfoIndex; + + // + // Bug check callback record for processing bugchecks. + // + KBUGCHECK_REASON_CALLBACK_RECORD BugCheckCallbackRecord; + +#endif + + // + // Enhanced Verifier Options. + // + ULONG FxEnhancedVerifierOptions; + + // + // If FxVerifierDbgBreakOnError is true, WaitForSignal interrupts the + // execution of the system after waiting for the specified number + // of seconds. Developer will have an opportunity to validate the state + // of the driver when breakpoint is hit. Developer can continue to wait + // by entering 'g' in the debugger. + // + ULONG FxVerifierDbgWaitForSignalTimeoutInSec; + + // + // Timeout used by the wake interrupt ISR in WaitForSignal to catch + // scenarios where the interrupt ISR is blocked because the device stack + // is taking too long to power up + // + ULONG DbgWaitForWakeInterruptIsrTimeoutInSec; + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + CWudfDriverGlobals * UfxDriverGlobals; +#endif + + PFX_TELEMETRY_CONTEXT TelemetryContext; + + // + // The public version of WDF_DRIVER_GLOBALS + // + DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) WDF_DRIVER_GLOBALS Public; + +} FX_DRIVER_GLOBALS, *PFX_DRIVER_GLOBALS; + +__bcount(Size) +PVOID +FORCEINLINE +FxPoolAllocate( + __in PFX_DRIVER_GLOBALS Globals, + __in POOL_TYPE Type, + __in size_t Size + ) +{ + // + // Always pass in the return address, regardless of the value of + // Globals->WdfPoolTrackingOn. + // + return FxPoolAllocator( + Globals, + &Globals->FxPoolFrameworks, + Type, + Size, + Globals->Tag, + _ReturnAddress() + ); +} + +__bcount(Size) +PVOID +FORCEINLINE +FxPoolAllocateWithTag( + __in PFX_DRIVER_GLOBALS Globals, + __in POOL_TYPE Type, + __in size_t Size, + __in ULONG Tag + ) +{ + return FxPoolAllocator( + Globals, + &Globals->FxPoolFrameworks, + Type, + Size, + Tag, + Globals->FxPoolTrackingOn ? _ReturnAddress() : NULL + ); +} + +// +// Get FxDriverGlobals from api's DriverGlobals +// +__inline +PFX_DRIVER_GLOBALS +GetFxDriverGlobals( + __in PWDF_DRIVER_GLOBALS DriverGlobals + ) +{ + return CONTAINING_RECORD( DriverGlobals, FX_DRIVER_GLOBALS, Public ); +} + +typedef struct _WDF_DRIVER_CONFIG *PWDF_DRIVER_CONFIG; + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +VOID +LockVerifierSection( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ PCUNICODE_STRING RegistryPath + ); + +VOID +UnlockVerifierSection( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ); +#endif + +BOOLEAN +IsWindowsVerifierOn( + _In_ MdDriverObject DriverObject + ); + +_Must_inspect_result_ +NTSTATUS +FxInitialize( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in MdDriverObject DriverObject, + __in PCUNICODE_STRING RegistryPath, + __in_opt PWDF_DRIVER_CONFIG DriverConfig //optional in user mode + ); + +VOID +FxDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +_Must_inspect_result_ +NTSTATUS +FxLibraryGlobalsCommission( + VOID + ); + +VOID +FxLibraryGlobalsDecommission( + VOID + ); + +VOID +FxCheckAssumptions( + VOID + ); + +void +FxVerifierLockInitialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +void +FxVerifierLockDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +_Must_inspect_result_ +BOOLEAN +FxVerifierGetTrackReferences( + __in FxObjectDebugInfo* DebugInfo, + __in WDFTYPE ObjectType + ); + +PCSTR +FxObjectTypeToHandleName( + __in WDFTYPE ObjectType + ); + +typedef +NTSTATUS +(*PFN_WMI_QUERY_TRACE_INFORMATION)( + __in TRACE_INFORMATION_CLASS TraceInformationClass, + __out PVOID TraceInformation, + __in ULONG TraceInformationLength, + __out_opt PULONG RequiredLength, + __in_opt PVOID Buffer + ); + +typedef +NTSTATUS +(*PFN_WMI_TRACE_MESSAGE_VA)( + __in TRACEHANDLE LoggerHandle, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + __in va_list MessageArgList + ); + +enum FxMachineSleepStates { + FxMachineS1Index = 0, + FxMachineS2Index, + FxMachineS3Index, + FxMachineSleepStatesMax, +}; + +// +// Private Globals for the entire DLL + +// +struct FxLibraryGlobalsType { + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + + // + // The driver object for the library. + + + + + + // + PDRIVER_OBJECT DriverObject; + + // + // As long as this device object is around, the library cannot be unloaded. + // This prevents the following scenario from unloading the service + // 1 wdfldr.sys loads the library + // 2 user tries to run "net stop " while there are outstanding clients + // through wdfldr + // + PDEVICE_OBJECT LibraryDeviceObject; + + PFN_IO_CONNECT_INTERRUPT_EX IoConnectInterruptEx; + + PFN_IO_DISCONNECT_INTERRUPT_EX IoDisconnectInterruptEx; + + PFN_KE_QUERY_ACTIVE_PROCESSORS KeQueryActiveProcessors; + + PFN_KE_SET_TARGET_PROCESSOR_DPC KeSetTargetProcessorDpc; + + PFN_KE_SET_COALESCABLE_TIMER KeSetCoalescableTimer; + + PFN_IO_UNREGISTER_PLUGPLAY_NOTIFICATION_EX IoUnregisterPlugPlayNotificationEx; + + PFN_POX_REGISTER_DEVICE PoxRegisterDevice; + + PFN_POX_START_DEVICE_POWER_MANAGEMENT PoxStartDevicePowerManagement; + + PFN_POX_UNREGISTER_DEVICE PoxUnregisterDevice; + + PFN_POX_ACTIVATE_COMPONENT PoxActivateComponent; + + PFN_POX_IDLE_COMPONENT PoxIdleComponent; + + PFN_POX_REPORT_DEVICE_POWERED_ON PoxReportDevicePoweredOn; + + PFN_POX_COMPLETE_IDLE_STATE PoxCompleteIdleState; + + PFN_POX_COMPLETE_IDLE_CONDITION PoxCompleteIdleCondition; + + PFN_POX_COMPLETE_DEVICE_POWER_NOT_REQUIRED PoxCompleteDevicePowerNotRequired; + + PFN_POX_SET_DEVICE_IDLE_TIMEOUT PoxSetDeviceIdleTimeout; + + PFN_IO_REPORT_INTERRUPT_ACTIVE IoReportInterruptActive; + + PFN_IO_REPORT_INTERRUPT_INACTIVE IoReportInterruptInactive; + + PFN_VF_CHECK_NX_POOL_TYPE VfCheckNxPoolType; + +#endif + + RTL_OSVERSIONINFOEXW OsVersionInfo; + + MxLockNoDynam FxDriverGlobalsListLock; + + LIST_ENTRY FxDriverGlobalsList; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // Index to first free entry in BugCheckDriverInfo array. + // + ULONG BugCheckDriverInfoIndex; + + // + // # of entries in BugCheckDriverInfo array. + // + ULONG BugCheckDriverInfoCount; + + // + // Array of info about loaded driver. The library bugcheck callback + // writes this data into the minidump. + // + PFX_DUMP_DRIVER_INFO_ENTRY BugCheckDriverInfo; + + // + // Library bug-check callback record for processing bugchecks. + // + KBUGCHECK_REASON_CALLBACK_RECORD BugCheckCallbackRecord; + + BOOLEAN ProcessorGroupSupport; + +#endif + // + // WPP tracing. + // + BOOLEAN InternalTracingInitialized; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // The following field is used by the debug dump callback routine for + // finding which driver's dump log file to write in the minidump if an + // exact match is not found. + // + FX_DRIVER_TRACKER_CACHE_AWARE DriverTracker; + + // + // Best driver match for the mini-dump log. + // + PFX_DRIVER_GLOBALS BestDriverForDumpLog; +#endif + + BOOLEAN PassiveLevelInterruptSupport; + + // + // TRUE if compiled for user-mode + // + BOOLEAN IsUserModeFramework; + + // + + + + + + + // + + BOOLEAN MachineSleepStates[FxMachineSleepStatesMax]; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // used for locking/unlocking Enhanced-verifier image section + // + PVOID VerifierSectionHandle; + + // + // This keeps track of the # of times we pinned the paged memory down. + // This is only used to aid debugging. + // + volatile LONG VerifierSectionHandleRefCount; + + // + // Routines provided by the kernel SystemTraceProvider for perf + // tracing of WDF operations. The size member of this structure + // allows versioning across multiple OS versions. + // + PWMI_WDF_NOTIFY_ROUTINES PerfTraceRoutines; + + // + // PerfTraceRoutines points here if the SystemTraceProvider failed + // to provide trace routines. + // + WMI_WDF_NOTIFY_ROUTINES DummyPerfTraceRoutines; + +#endif + + // + // Registry setting to disable IFR on low-memory systems. + // + BOOLEAN IfrDisabled; +}; + +extern FxLibraryGlobalsType FxLibraryGlobals; + + +typedef struct _FX_OBJECT_INFO { + // + // The name of the object, ie "FxObject" + // + const CHAR* Name; + + // + // The name of the external WDF handle that represents the object, ie + // WDFDEVICE. If the object does not have an external handle, this field + // may be NULL. + // + const CHAR* HandleName; + + // + // The minimum size of the object, ie sizeof(FxObject). There are objects + // which allocate more than their sizeof() length. + // + USHORT Size; + + // + // FX_OBJECT_TYPES value + // + USHORT ObjectType; + +} FX_OBJECT_INFO, *PFX_OBJECT_INFO; + +// +// Define to declare an internal entry. An internal entry has no external WDF +// handle. +// +#define FX_INTERNAL_OBJECT_INFO_ENTRY(_obj, _type) \ + { #_obj, NULL, sizeof(_obj), _type, } + +// +// Define to declare an external entry. An external entry has an external WDF +// handle. +// +// By casting #_handletype to a (_handletype), we make sure that _handletype is +// actually a valid WDF handle name. The cast forces the parameter to be +// evaluated as true handle type vs a string (ie the # preprocesor operator). +// For instance, this would catch the following error: +// +// FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDevice, FX_TYPE_DEVICE, WDFDEVICES), +// +// because the statement would evaluate to (const CHAR*) (WDFDEVICES) "WDFDEVICES" +// and WDFDEVICES is not a valid type (WDFDEVICE is though). +// +#define FX_EXTERNAL_OBJECT_INFO_ENTRY(_obj, _type, _handletype) \ + { #_obj, \ + (const CHAR*) (_handletype) #_handletype, \ + sizeof(_obj), \ + _type, \ + } + +_Must_inspect_result_ +BOOLEAN +FxVerifyObjectTypeInTable( + __in USHORT ObjectType + ); + +VOID +FxFlushQueuedDpcs( + VOID + ); + +VOID +FxFreeAllocatedMdlsDebugInfo( + __in FxDriverGlobalsDebugExtension* DebugExtension + ); + +// + + + + + + + + + + + + + +// + +_Must_inspect_result_ +__inline +BOOLEAN +FxIsClassExtension( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_DRIVER_GLOBALS ExtDriverGlobals + ) +{ + return (FxDriverGlobals == ExtDriverGlobals) ? FALSE : TRUE; +} + + +_Must_inspect_result_ +BOOLEAN +__inline +FxIsEqualGuid( + __in CONST GUID* Lhs, + __in CONST GUID* Rhs + ) +{ + return RtlCompareMemory(Lhs, Rhs, sizeof(GUID)) == sizeof(GUID); +} + +__inline +size_t +FxSizeTMax( + __in size_t A, + __in size_t B + ) +{ + return A > B ? A : B; +} + +__inline +size_t +FxSizeTMin( + __in size_t A, + __in size_t B + ) +{ + return A < B ? A : B; +} + +__inline +LONG +FxInterlockedIncrementFloor( + __inout LONG volatile *Target, + __in LONG Floor + ) +{ + LONG startVal; + LONG currentVal; + + currentVal = *Target; + + do { + if (currentVal <= Floor) { + return currentVal; + } + + startVal = currentVal; + + // + // currentVal will be the value that used to be Target if the exchange was made + // or its current value if the exchange was not made. + // + currentVal = InterlockedCompareExchange(Target, startVal+1, startVal); + + // + // If startVal == currentVal, then no one updated Target in between the deref at the top + // and the InterlockedCompareExchange afterward. + // + } while (startVal != currentVal); + + // + // startVal is the old value of Target. Since InterlockedIncrement returns the new + // incremented value of Target, we should do the same here. + // + return startVal+1; +} + +__inline +LONG +FxInterlockedIncrementGTZero( + __inout LONG volatile *Target + ) +{ + return FxInterlockedIncrementFloor(Target, 0); +} + +__inline +ULONG +FxRandom( + __inout PULONG RandomSeed + ) +/*++ + +Routine Description: + + Simple threadsafe random number generator to use at DISPATCH_LEVEL + (in kernel mode) because the system provided function RtlRandomEx + can be called at only passive-level. + + This function requires the user to provide a variable used to seed + the generator, and it must be valid and initialized to some number. + +Return Value: + + ULONG + +--*/ +{ + *RandomSeed = *RandomSeed * 1103515245 + 12345; + return (ULONG)(*RandomSeed / 65536) % 32768; +} + +_Must_inspect_result_ +__inline +BOOLEAN +FxIsPassiveLevelInterruptSupported( + VOID + ) +{ + // + // Passive-level interrupt handling is supported in Win 8 and forward. + // + return FxLibraryGlobals.PassiveLevelInterruptSupport; +} + +__inline +_Must_inspect_result_ +BOOLEAN +IsOsVersionGreaterThanOrEqualTo( + __in ULONG Major, + __in ULONG Minor + ) +{ + return ((FxLibraryGlobals.OsVersionInfo.dwMajorVersion > Major) || + ((FxLibraryGlobals.OsVersionInfo.dwMajorVersion == Major) && + (FxLibraryGlobals.OsVersionInfo.dwMinorVersion >= Minor))); +} + +#ifdef __cplusplus +} +#endif +#endif // _FXGLOBALS_H + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxhandle.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxhandle.h new file mode 100644 index 00000000000..811ceac52bf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxhandle.h @@ -0,0 +1,482 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxhandle.h + +Abstract: + + Private interfaces for Driver Frameworks handle functions. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _WDFPHANDLE_H_ +#define _WDFPHANDLE_H_ + +/** + + Framework Object Memory Layout (x86 32 bit) + + Note: The handle is XOR'ed with (-1) to scramble it + + ---------------------- handle + sizeof(ContextSize) + | | + | Drivers Context | + | Memory | + | | +WDFOBJECT handle -> ---------------------- this + sizeof(C++_OBJECT) + _extrasize + sizeof(FxContextHeader) + | | + | FxContextHeader | + | | + ---------------------- this + sizeof(C++_OBJECT) + _extrasize (m_ObjectSize) + | | + | C++ Object | + | "extra" memory | + | | + |--------------------| this + sizeof(C++_OBJECT) + | | + | C++ Object | + | | + | | +Base Pool Allocation -> ---------------------- this +C++ this pointer + +**/ + +struct FxContextHeader; + +struct FxContextHeader { + // + // Backpointer to the object that this is a context for + // + FxObject* Object; + + // + // Next context in the chain + // + FxContextHeader* NextHeader; + + // + // Function to call when object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the object's memory is destroyed + // when the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Type associated with this context + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO ContextTypeInfo; + + // + // Start of client's context + // + DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) ULONG_PTR Context[1]; +}; + +// +// We want all the way up to the aligned field, but not the field itself +// +#define FX_CONTEXT_HEADER_SIZE FIELD_OFFSET(FxContextHeader, Context) + +#define COMPUTE_RAW_OBJECT_SIZE(_rawObjectSize) \ + ((USHORT) WDF_ALIGN_SIZE_UP(_rawObjectSize, MEMORY_ALLOCATION_ALIGNMENT)) + +// +// Computes the size required for a fixed size object plus any extra buffer space +// it requires. The extra buffer space is aligned on a process natural boundary. +// +#define COMPUTE_OBJECT_SIZE(_rawObjectSize, _extraSize) \ + (COMPUTE_RAW_OBJECT_SIZE(_rawObjectSize) + (USHORT) WDF_ALIGN_SIZE_UP(_extraSize, MEMORY_ALLOCATION_ALIGNMENT)) + +// +// Gets size of the context associated with the specified attributes structure. +// +size_t +FxGetContextSize( + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ); + +// +// Computes the total size of an object taking into account its fixed size, +// any additional size after the fixed, and an object header, so the memory looks +// like: +// +// Object +// additional optional memory +// WDF_HANDLE_HEADER +// +_Must_inspect_result_ +NTSTATUS +FxCalculateObjectTotalSize2( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT RawObjectSize, + __in USHORT ExtraSize, + __in size_t ContextSize, + __out size_t* Total + ); + +_Must_inspect_result_ +NTSTATUS +FxCalculateObjectTotalSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT RawObjectSize, + __in USHORT ExtraSize, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out size_t* Total + ); + +PVOID +FxObjectHandleAlloc( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in POOL_TYPE PoolType, + __in size_t Size, + __in ULONG Tag, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in USHORT ExtraSize, + __in FxObjectType ObjectType + ); + +VOID +FxContextHeaderInit( + __in FxContextHeader* Header, + __in FxObject* Object, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ); + +PVOID +FxObjectAndHandleHeaderInit( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID AllocationStart, + __in USHORT ObjectSize, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObjectType ObjectType + ); + +VOID +__inline +FxObjectHandleCreate( + __in FxObject* Object, + __out PWDFOBJECT Handle + ) +{ +#if FX_SUPER_DBG + if (Object->GetDriverGlobals()->FxVerifierHandle) { + + + + + + + ASSERT(Object->GetObjectSize() > 0); + ASSERT(Object == Object->GetContextHeader()->Object); + } +#endif + + ASSERT((((ULONG_PTR) Object) & FxHandleFlagMask) == 0x0); + *Handle = Object->GetObjectHandle(); +} + +/*++ + +Routine Description: + + Retrieves the object pointer from the handle if valid. + + This does not change an objects reference count. + +Arguments: + + handle - The object handle created by WdfObjectCreateHandle + + type - Type of the object from FxTypes.h + + ppObj - Pointer to location to store the returned object. + +Returns: + + NTSTATUS + +--*/ + +VOID +FxObjectHandleGetPtrQI( + __in FxObject* Object, + __out PVOID* PPObject, + __in WDFOBJECT Handle, + __in WDFTYPE Type, + __in WDFOBJECT_OFFSET Offset + ); + +_Must_inspect_result_ +NTSTATUS +FxObjectAllocateContext( + __in FxObject* Object, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in BOOLEAN AllowCallbacksOnly, + __deref_opt_out PVOID* Context + ); + +__inline +BOOLEAN +FxObjectCheckType( + __in FxObject* Object, + __in WDFTYPE Type + ) +/*++ + +Routine Description: + Checks if the FxObject is of a the Type. + +Arguments: + FxObject - the object being checked + Type - The type value to be checked + +Returns: + TRUE if the Object is of the type 'Type' + FALSE otherwise + --*/ +{ + NTSTATUS status; + PVOID tmpObject; + FxQueryInterfaceParams params = {&tmpObject, Type, 0}; + + // + // Do a quick non virtual call for the type and only do the slow QI if + // the first types do not match + // + + if (Object->GetType() == Type) { + return TRUE; + } + + status = Object->QueryInterface(¶ms); + + if (!NT_SUCCESS(status)) { + return FALSE; + } + + return TRUE; + +} + +__inline +VOID +FxObjectHandleGetPtr( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFOBJECT Handle, + __in WDFTYPE Type, + __out PVOID* PPObject + ) +/*++ + +Routine Description: + Converts an externally facing WDF handle into its internal object. + +Arguments: + FxDriverGlobals - caller's globals + Handle - handle to convert into an object + Type - required type of the underlying object + PPObject - pointer to receive the underlying object + + --*/ +{ + WDFOBJECT_OFFSET offset; + FxObject* pObject; + + if (Handle == NULL) { + + + + + + FxVerifierBugCheck(FxDriverGlobals, + WDF_INVALID_HANDLE, + (ULONG_PTR) Handle, + Type); + + /* NOTREACHED */ + return; + } + + offset = 0; + pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + + // + // The only DDI you can call on an object which has a ref count of zero is + // WdfObjectGetTypedContextWorker(). + // + ASSERT(pObject->GetRefCnt() > 0); + + // + // Do a quick non virtual call for the type and only do the slow QI if + // the first types do not match + // + if (pObject->GetType() == Type) { + *PPObject = pObject; + ASSERT(offset == 0x0); + return; + } + else { + FxObjectHandleGetPtrQI(pObject, PPObject, Handle, Type, offset); + } +} + +__inline +VOID +FxObjectHandleGetPtrOffset( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFOBJECT Handle, + __in WDFTYPE Type, + __out PVOID* PPObject, + __out PWDFOBJECT_OFFSET Offset + ) +/*++ + +Routine Description: + This function probably should be removed and the optional Offset paramter + moved into the signature for FxObjectHandleGetPtr(). The distinction + between these 2 functions was important when both of them were *not* + FORCEINLINE functions (since there was an additional parameter to push onto + the stack). Now that they are both __inlined, there is no longer a + parameter to push, eliminating this optimization. + +Arguments: + FxDriverGlobals - caller's globals + Handle - handle to convert into an object + Type - required type of the underlying object + PPObject - pointer to receive the underlying object + Offset - offset into the object which the handle resided. Nearly all objects + will have a zero offset + + --*/ +{ + FxObject* pObject; + + if (Handle == NULL) { + + + + + + FxVerifierBugCheck(FxDriverGlobals, + WDF_INVALID_HANDLE, + (ULONG_PTR) Handle, + Type); + + /* NOTREACHED */ + return; + } + + *Offset = 0; + pObject = FxObject::_GetObjectFromHandle(Handle, Offset); + + // + // The only DDI you can call on an object which has a ref count of zero is + // WdfObjectGetTypedContextWorker(). + // + ASSERT(pObject->GetRefCnt() > 0); + + // + // Do a quick non virtual call for the type and only do the slow QI if + // the first types do not match + // + if (pObject->GetType() == Type) { + *PPObject = pObject; + ASSERT(*Offset == 0x0); + return; + } + else { + FxObjectHandleGetPtrQI(pObject, PPObject, Handle, Type, *Offset); + } +} + +VOID +__inline +FxObjectHandleGetPtrAndGlobals( + __in PFX_DRIVER_GLOBALS CallersGlobals, + __in WDFOBJECT Handle, + __in WDFTYPE Type, + __out PVOID* PPObject, + __out PFX_DRIVER_GLOBALS* ObjectGlobals + ) +/*++ + +Routine Description: + Converts an externally facing WDF handle into its internal object. + +Arguments: + FxDriverGlobals - caller's globals + Handle - handle to convert into an object + Type - required type of the underlying object + PPObject - pointer to receive the underlying object + ObjectGlobals - pointer to receive the underlying object's globals. + + --*/ +{ + // + // All FX_TYPEs except for IFX_TYPE_MEMORY derive from FxObject, so our cast + // below will work with all types but IFX_TYPE_MEMORY (in which case the caller + // should call FxObjectHandleGetPtr and then get the globals on their own + // from the IFxMemory interface). + // + ASSERT(Type != IFX_TYPE_MEMORY); + + FxObjectHandleGetPtr(CallersGlobals, + Handle, + Type, + PPObject); + + *ObjectGlobals = ((FxObject*) (*PPObject))->GetDriverGlobals(); +} + +VOID +__inline +FxObjectHandleGetGlobals( + __in PFX_DRIVER_GLOBALS CallersGlobals, + __in WDFOBJECT Handle, + __out PFX_DRIVER_GLOBALS* ObjectGlobals + ) +/*++ + +Routine Description: + Converts an externally facing WDF handle into its internal object and + returns its globals. + +Arguments: + FxDriverGlobals - caller's globals + Handle - handle to convert into an object + ObjectGlobals - pointer to receive the underlying object's globals. + + --*/ +{ + PVOID pObject; + + FxObjectHandleGetPtrAndGlobals(CallersGlobals, + Handle, + FX_TYPE_OBJECT, + &pObject, + ObjectGlobals); + + UNREFERENCED_PARAMETER(pObject); +} + +#endif // _WDFPHANDLE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxifr.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxifr.h new file mode 100644 index 00000000000..8bf31748154 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxifr.h @@ -0,0 +1,123 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIFR.h + +Abstract: + + This module contains the private IFR tracing definitions + The structures are common to the In-Flight Recorder (IFR) + and the IFR-related debug commands in wdfkd.dll. + +Environment: + + kernel mode and debug extensions + +Revision History: + + +--*/ + +#ifndef _FXIFR_H +#define _FXIFR_H + +// +// This is maximum number of arguments a single message can capture. +// It reflects WPP_MAX_MOF_FIELDS value of 8 found in WPP trace support. +// +#define WDF_MAX_LOG_FIELDS (8) + +// +// This is the longest allowable message retained in the IFR log. +// +#define WDF_MAX_IFR_MESSAGE_SIZE (256) + + +// +// This is the maximum name length for the driver. +// +#define WDF_IFR_HEADER_NAME_LEN (32) + +// +// Access macro for trace GUID BITs. +// +#define TRACE_BIT(a) WPP_BIT_ ## a + +// +// Various GUIDs needed. +// + +// +// (Keep synch-ed with "KmdfTraceGuid" in fxtrace.h) +// +DEFINE_GUID (WdfTraceGuid, + 0x544d4c9d, 0x942c, 0x46d5, 0xbf, 0x50, 0xdf, 0x5c, 0xd9, 0x52, 0x4a, 0x50); + +// +// GUID used to tag IFR log in crash dump. +// +DEFINE_GUID (WdfDumpGuid, + 0x54c84888, 0x01d1, 0x4c1e, 0xbe, 0xd6, 0x28, 0x2c, 0x98, 0x24, 0x13, 0x03); + +// +// GUID used to tag drivers info in crash dump. +// +// {F87E4A4C-C5A1-4d2f-BFF0-D5DE63A5E4C3} +DEFINE_GUID(WdfDumpGuid2, +0xf87e4a4c, 0xc5a1, 0x4d2f, 0xbf, 0xf0, 0xd5, 0xde, 0x63, 0xa5, 0xe4, 0xc3); + +// +// This structure hold the current and previous 16-bit offsets into +// the IFR log. These variable must be access together as a LONG +// via the InterlockedCompareExchange(). +// +typedef struct _WDF_IFR_OFFSET { + union { + struct { + USHORT Current; + USHORT Previous; + } s; + LONG AsLONG; + } u; +} WDF_IFR_OFFSET, *PWDF_IFR_OFFSET; + + +#define WDF_IFR_LOG_TAG 'gLxF' // 'FxLg' + +// +// This is the IFR log header structure. It is immediately followed +// by the log area itself. +// +typedef struct _WDF_IFR_HEADER { + + GUID Guid; // WDF's GUID (WDF_TRACE_GUID) + PUCHAR Base; // log data area base (not header) + ULONG Size; // size of the log (1 page by default) + WDF_IFR_OFFSET Offset; // current/previous offsets + LONG Sequence; // local sequence number +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + PLONG SequenceNumberPointer; // Global IFR Sequence Number +#endif + CHAR DriverName[WDF_IFR_HEADER_NAME_LEN]; + +} WDF_IFR_HEADER, *PWDF_IFR_HEADER; + + +#define WDF_IFR_RECORD_SIGNATURE 'RL' // 'LR' + +typedef struct _WDF_IFR_RECORD { + + USHORT Signature; // 'LR' Log Record signature + USHORT Length; + LONG Sequence; + USHORT PrevOffset; // offset to previous record + USHORT MessageNumber; // message number see .tmf + GUID MessageGuid; // message GUID see .tmf + +} WDF_IFR_RECORD, *PWDF_IFR_RECORD; + + +#endif // _FXIFR_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxifrkm.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxifrkm.h new file mode 100644 index 00000000000..31963b9f10b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxifrkm.h @@ -0,0 +1,83 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef __FXIFRKM_H__ +#define __FXIFRKM_H__ + +#define FX_IFR_MAX_BUFFER_SIZE (0x10000) // 64k + +#if (PAGE_SIZE > 0x1000) +#define FX_IFR_AVG_BUFFER_SIZE (3 * PAGE_SIZE) // ia64 +#else +#define FX_IFR_AVG_BUFFER_SIZE (5 * PAGE_SIZE) // x86, amd64 +#endif + +// +// Log Size should be in whole pages. +// +enum FxIFRValues { + FxIFRMinLogPages = 1, + FxIFRMaxLogPages = FX_IFR_MAX_BUFFER_SIZE/PAGE_SIZE, + FxIFRAvgLogPages = FX_IFR_AVG_BUFFER_SIZE/PAGE_SIZE, + + FxIFRMinLogSize = FxIFRMinLogPages * PAGE_SIZE, + FxIFRMaxLogSize = FxIFRMaxLogPages * PAGE_SIZE, + FxIFRAvgLogSize = FxIFRAvgLogPages * PAGE_SIZE, + + FxIFRMaxMessageSize = 256, + + FxIFRRecordSignature = WDF_IFR_RECORD_SIGNATURE, +}; + +// +// Verify the following: +// - max_log_size must be <= 64k. +// - min_log_size must be >= page_size. +// - max_log_size >= avg_log_size >= min_log_size. +// - max_log_pages >= avg_log_pages >= min_log_pages. +// +C_ASSERT(FxIFRMaxLogSize <= 0x10000); +C_ASSERT(FxIFRMinLogSize >= PAGE_SIZE); +C_ASSERT(FxIFRMaxLogSize >= FxIFRAvgLogSize && + FxIFRAvgLogSize >= FxIFRMinLogSize); +C_ASSERT(FxIFRMaxLogPages >= FxIFRAvgLogPages && + FxIFRAvgLogPages >= FxIFRMinLogPages); + + +__inline +VOID +FxVerifyLogHeader( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_IFR_HEADER Header + ) +/*++ + +Routine Description: + This routine is added to track the down IFR header corruption + + + +--*/ +{ + WDFCASSERT(WDF_IFR_HEADER_NAME_LEN == WDF_DRIVER_GLOBALS_NAME_LEN); + + if (FxDriverGlobals->FxVerifierOn + && + (strncmp(Header->DriverName, FxDriverGlobals->Public.DriverName, + WDF_IFR_HEADER_NAME_LEN) != 0 + || + FxIsEqualGuid((LPGUID)&(Header->Guid), (LPGUID)&WdfTraceGuid) == FALSE + || + Header->Base != (PUCHAR) &Header[1] + || + Header->Offset.u.s.Current > Header->Size + || + Header->Offset.u.s.Previous > Header->Size + || + Header->Size >= FxIFRMaxLogSize)) // size doesn't include header. + { + FxVerifierDbgBreakPoint(FxDriverGlobals); + } +} + +#endif // __FXIFRKM_H__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxinterrupt.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxinterrupt.hpp new file mode 100644 index 00000000000..ab0d9b97f55 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxinterrupt.hpp @@ -0,0 +1,869 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxInterrupt.hpp + +Abstract: + + This module implements a frameworks managed interrupt object + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXINTERRUPT_H_ +#define _FXINTERRUPT_H_ + +#include "FxWakeInterruptStateMachine.hpp" + +// +// We need two parameters for KeSynchronizeExecution when enabling +// and disabling interrupts, so we use this structure on the stack since its +// a synchronous call. +// +struct FxInterruptEnableParameters { + FxInterrupt* Interrupt; + NTSTATUS ReturnVal; +}; + +typedef FxInterruptEnableParameters FxInterruptDisableParameters; + + +class FxInterrupt : public FxNonPagedObject { + + friend FxPkgPnp; + +private: + + // + // User supplied configuration + // + WDF_TRI_STATE m_ShareVector; + + // + // Kernel Interupt object + // + struct _KINTERRUPT* m_Interrupt; + + // + // Kernel spinlock for Interrupt + // + MdLock* m_SpinLock; + + KIRQL m_OldIrql; + volatile KIRQL m_SynchronizeIrql; + + // + // Built in SpinLock/PassiveLock + // + MxLock m_BuiltInSpinLock; + + // + // Passive-level interrupt handling. + // + FxWaitLock* m_WaitLock; + + // + // DpcForIsr and WorkItemForIsr support. Note that a DPC is still + // needed even if the driver opts to use WorkItemForIsr when + // driver handles interrupts at DIRQL. + // +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + KDPC m_Dpc; +#endif + FxSystemWorkItem* m_SystemWorkItem; + + // + // Automatic serialization: this is the callback lock for the object the DPC or + // work-item will synchronize with. + // + FxCallbackLock* m_CallbackLock; + + // + // Set to TRUE when WDF is responsible for disposing the wait-lock. + // + BOOLEAN m_DisposeWaitLock; + + // + // Value provided by driver. When TRUE we use IoReportActive/Inactive to + // do soft connect/disconnect on explicit power transitions. + // + BOOLEAN m_UseSoftDisconnect; + + // + // Set to TRUE for passive-level interrupt handling. + // + BOOLEAN m_PassiveHandling; + + // set to TRUE once the interrupt has been added to the pnp package's + // interrupt list + BOOLEAN m_AddedToList; + + // + // Indicates whether the driver has forced a disconnect. If so, then + // we should stop automatically managing the connected state. + // + BOOLEAN m_Connected; + BOOLEAN m_ForceDisconnected; + + // + // Indicates whether the m_EvtInterruptPostEnable succeeded or not. + // + BOOLEAN m_Enabled; + + // + // Save floating point when the ISR runs + // + BOOLEAN m_FloatingSave; + + // + // Set to TRUE if interrupt is created in the prepare hardware callback. + // + BOOLEAN m_CreatedInPrepareHardware; + + // + // State machine to manage a wake capable interrupt + // + FxWakeInterruptMachine* m_WakeInterruptMachine; + + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // Set to true on successful connect or when driver reports active. + // (this field is mainly for aid in debugging) + // + BOOLEAN m_Active; +#endif + + // + // Interrupt policy + // + BOOLEAN m_SetPolicy; + WDF_INTERRUPT_POLICY m_Policy; + WDF_INTERRUPT_PRIORITY m_Priority; + GROUP_AFFINITY m_Processors; + + // + // Callbacks + // + PFN_WDF_INTERRUPT_ENABLE m_EvtInterruptEnable; + PFN_WDF_INTERRUPT_DISABLE m_EvtInterruptDisable; + + PFN_WDF_INTERRUPT_ISR m_EvtInterruptIsr; + PFN_WDF_INTERRUPT_DPC m_EvtInterruptDpc; + PFN_WDF_INTERRUPT_WORKITEM m_EvtInterruptWorkItem; + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) + // + // Rd interrupt object + // + RD_INTERRUPT_CONTEXT m_RdInterruptContext; + + // + // Each interrupt object has this structure which comprises an event and a + // wait structure. The wait struture is associted with interrupt's callback + // and the event, and is queued to threadpool. The callback is invoked when + // the event is set. + // + FxInterruptWaitblock* m_InterruptWaitblock; + + // + // True if the interrupt callback can queue another interrupt wait. + // Set to true when interrupt is connected and false when interrupts + // callbacks and waits are flushed. + // + BOOLEAN m_CanQueue; + + // + // UMDF's handling of interrupt is split in two parts: + // 1. framwork code- runs at passive always and therefore uses mode-agnostic + // code meant for passive-level handling, tracked through m_PassiveLevel + // field of interrupt object. + // 2. redirector code- does passive handling of all of level-triggered + // interrupt and DIRQL handing of all others (edge and msi). Driver + // doesn't have any choice in that. The PassiveHandling field in the + // interrupt config is always set for passive for UMDF (through UMDF's + // init function). + // + // This field stores the type of handling done by redirector as opposed to + // m_PassiveHandling which stores user's choice. + // + BOOLEAN m_PassiveHandlingByRedirector; +#endif + + // + // PnP data about the interrupt. + // + WDF_INTERRUPT_INFO m_InterruptInfo; + + // + // Weak ref to the translated resource interrupt descriptor. + // It is valid from prepare hardware callback to release hardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR m_CmTranslatedResource; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // Callback used to set m_Disconnecting, synchronized to running ISRs. + // Only runs if m_IsEdgeTriggeredNonMsiInterrupt is TRUE. + // + static + MdInterruptSynchronizeRoutineType _InterruptMarkDisconnecting; + + // + // Backup KINTERRUPT pointer, captured from the KMDF ISR thunk. We need it + // because valid interrupts may arrive before IoConnectInterruptEx sets + // FxInterrupt.m_Interrupt. Non-NULL only if m_IsEdgeTriggeredNonMsiInterrupt is TRUE. + // + struct _KINTERRUPT* m_InterruptCaptured; +#endif + + // + // Used to mark the interrupt disconnect window, and to discard interrupts + // that arrive within this window. Only set if m_IsEdgeTriggeredNonMsiInterrupt is TRUE. + // + BOOLEAN m_Disconnecting; + + // + // Set if this is an Edge-Triggered non-MSI interrupt. These interrupts are + // stateful and it is important not to drop any around the connection window. + // + BOOLEAN m_IsEdgeTriggeredNonMsiInterrupt; + +protected: + + LIST_ENTRY m_PnpList; + +public: + FxInterrupt( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + ~FxInterrupt( + VOID + ); + + _Must_inspect_result_ + static + NTSTATUS + _CreateAndInit( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice * Device, + __in_opt FxObject * Parent, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_INTERRUPT_CONFIG Configuration, + __out FxInterrupt ** Interrupt + ); + + _Must_inspect_result_ + NTSTATUS + FxInterrupt::CreateWakeInterruptMachine( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in CfxDevice* Device, + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ); + + _Must_inspect_result_ + NTSTATUS + InitializeWorker( + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ); + + _Must_inspect_result_ + NTSTATUS + InitializeInternal( + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + virtual + VOID + DeleteObject( + VOID + ); + + VOID + OnPostReleaseHardware( + VOID + ); + + VOID + DpcHandler( + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ); + + BOOLEAN + QueueDpcForIsr( + VOID + ); + + BOOLEAN + Synchronize( + __in PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + __in WDFCONTEXT Context + ); + + struct _KINTERRUPT* + GetInterruptPtr( + VOID + ); + + __inline + BOOLEAN + IsWakeCapable( + VOID + ) + { + return ((m_WakeInterruptMachine != NULL) ? TRUE:FALSE); + } + + VOID + SetActiveForWake( + __in BOOLEAN ActiveForWake + ) + { + m_WakeInterruptMachine->m_ActiveForWake = ActiveForWake; + } + + BOOLEAN + IsActiveForWake( + VOID + ) + { + if ((m_WakeInterruptMachine != NULL) && + (m_WakeInterruptMachine->m_ActiveForWake)) { + return TRUE; + } else { + return FALSE; + } + } + + VOID + ProcessWakeInterruptEvent( + __in FxWakeInterruptEvents Event + ) + { + m_WakeInterruptMachine->ProcessEvent(Event); + } + + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + + VOID + ReportActive( + _In_ BOOLEAN Internal = FALSE + ); + + VOID + ReportInactive( + _In_ BOOLEAN Internal = FALSE + ); + + BOOLEAN + IsSoftDisconnectCapable( + VOID + ) + { + if (m_UseSoftDisconnect && + FxLibraryGlobals.IoReportInterruptInactive != NULL && + m_Interrupt != NULL && + m_Connected) { + return TRUE; + } + else { + return FALSE; + } + } + +#elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) + + BOOLEAN + IsSoftDisconnectCapable( + VOID + ) + { + // + // Not implemented for UMDF + // + return FALSE; + } + + VOID + ReportActive( + _In_ BOOLEAN Internal = FALSE + ) + { + UNREFERENCED_PARAMETER(Internal); + // + // Not implemented for UMDF + // + } + + VOID + ReportInactive( + _In_ BOOLEAN Internal = FALSE + ) + { + UNREFERENCED_PARAMETER(Internal); + // + // Not implemented for UMDF + // + } + +#endif + + VOID + WorkItemHandler( + VOID + ); + + BOOLEAN + QueueWorkItemForIsr( + VOID + ); + + __inline + BOOLEAN + IsPassiveHandling( + VOID + ) + { + return m_PassiveHandling; + } + + __inline + BOOLEAN + IsPassiveConnect( + VOID + ) + { + // + // UMDF's handling of interrupt is split in two parts: + // 1. framework code that runs at passive always in host process and + // therefore uses mode-agnostic code meant for passive-level handling, + // tracked through m_PassiveHandling member. + // field of interrupt object. + // 2. redirector code that does passive handling of all of level-triggered + // interrupt and DIRQL handing of all others (edge and msi). Driver + // doesn't have any choice in that. The m_PassiveHandling field in the + // interrupt config is always set for passive for UMDF (through UMDF's + // init function). m_PasiveHandlingByRedirector member is present to + // this part of code. + // In summary, m_PassiveHandling and m_PasiveHandlingByRedirector + // effectively maintain how the interrupt is connected (passive or DIRQL), + // for KMDF and UMDF respectively. This routine tells how the + // interrupt is connnected by looking at these members. + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return IsPassiveHandling(); +#else + return m_PassiveHandlingByRedirector; +#endif + } + + __inline + BOOLEAN + IsAutomaticSerialization( + VOID + ) + { + return m_CallbackLock != NULL ? TRUE : FALSE; + } + + VOID + AcquireLock( + VOID + ); + + BOOLEAN + TryToAcquireLock( + VOID + ); + + VOID + ReleaseLock( + VOID + ); + + CfxDevice* + GetDevice( + VOID + ) + { + return m_Device; + } + + PWDF_INTERRUPT_INFO + GetInfo( + VOID + ); + + WDFINTERRUPT + GetHandle( + VOID + ) + { + return (WDFINTERRUPT) GetObjectHandle(); + } + + BOOLEAN + IsSharedSpinLock( + VOID + ) + { + return m_SpinLock != &m_BuiltInSpinLock.Get() ? TRUE : FALSE; + } + + BOOLEAN + IsSyncIrqlSet( + VOID + ) + { + return m_SynchronizeIrql != PASSIVE_LEVEL ? TRUE : FALSE; + } + + KIRQL + GetSyncIrql( + VOID + ) + { + return m_SynchronizeIrql; + } + + KIRQL + GetResourceIrql( + VOID + ) + { + return m_InterruptInfo.Irql; + } + + BOOLEAN + SharesLock( + FxInterrupt* Interrupt + ) + { + return m_SpinLock == Interrupt->m_SpinLock ? TRUE : FALSE; + } + +private: + VOID + Reset( + VOID + ); + + VOID + ResetInternal( + VOID + ); + + VOID + SetSyncIrql( + KIRQL SyncIrql + ) + { + m_SynchronizeIrql = SyncIrql; + } + + // + // Called from workitem to perform final flushing of any + // outstanding DPC's and dereferencing of objects. + // + VOID + FlushAndRundown( + VOID + ); + + VOID + FlushAndRundownInternal( + VOID + ); + + static + MdInterruptServiceRoutineType _InterruptThunk; + + static + EVT_SYSTEMWORKITEM _InterruptWorkItemCallback; + + static + MdInterruptSynchronizeRoutineType _InterruptSynchronizeThunk; + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + + static + MdDeferredRoutineType _InterruptDpcThunk; + +#elif ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) + + static + MX_WORKITEM_ROUTINE _InterruptWorkItemThunk; + + VOID + ThreadpoolWaitCallback( + VOID + ); + + VOID + QueueSingleWaitOnInterruptEvent( + VOID + ); + + VOID + StartThreadpoolWaitQueue( + VOID + ); + + VOID + StopAndFlushThreadpoolWaitQueue( + VOID + ); + +#endif + + // + // Helper functions to enable an interrupt. + // Sequence: + // (1) InterruptEnable + // (2) _InterruptEnableThunk + // (3) InterruptEnableInvokeCallback + // + NTSTATUS + InterruptEnable( + VOID + ); + + static + MdInterruptSynchronizeRoutineType _InterruptEnableThunk; + + + NTSTATUS + InterruptEnableInvokeCallback( + VOID + ); + + // + // Helper functions to disable an interrupt. + // Sequence: + // (1) InterruptDisable + // (2) _InterruptDisableThunk + // (3) InterruptDisableInvokeCallback + // + NTSTATUS + InterruptDisable( + VOID + ); + + static + MdInterruptSynchronizeRoutineType _InterruptDisableThunk; + + + NTSTATUS + InterruptDisableInvokeCallback( + VOID + ); +public: + static + BOOLEAN + _IsMessageInterrupt( + __in USHORT ResourceFlags + ) + { + if (ResourceFlags & CM_RESOURCE_INTERRUPT_MESSAGE) { + return TRUE; + } + else { + return FALSE; + } + } + + static + BOOLEAN + _IsWakeHintedInterrupt( + __in USHORT ResourceFlags + ) + { + if (ResourceFlags & CM_RESOURCE_INTERRUPT_WAKE_HINT) { + return TRUE; + } + else { + return FALSE; + } + } + + _Must_inspect_result_ + NTSTATUS + Connect( + __in ULONG NotifyFlags + ); + + _Must_inspect_result_ + NTSTATUS + ConnectInternal( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Disconnect( + __in ULONG NotifyFlags + ); + + VOID + DisconnectInternal( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + ForceDisconnect( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + ForceReconnect( + VOID + ); + + VOID + FilterResourceRequirements( + __inout PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor + ); + + VOID + AssignResources( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans + ); + + PCM_PARTIAL_RESOURCE_DESCRIPTOR + GetResources( + VOID + ) + { + // Weak ref to the translated resource interrupt descriptor. + // It is valid from prepare hardware callback to release hardware callback. + return m_CmTranslatedResource; + } + + VOID + AssignResourcesInternal( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans, + __in PWDF_INTERRUPT_INFO InterruptConfig + ); + + VOID + RevokeResources( + VOID + ); + + VOID + RevokeResourcesInternal( + VOID + ); + + VOID + SetPolicy( + __in WDF_INTERRUPT_POLICY Policy, + __in WDF_INTERRUPT_PRIORITY Priority, + __in PGROUP_AFFINITY TargetProcessorSet + ); + + VOID + SetPolicyInternal( + __in WDF_INTERRUPT_POLICY Policy, + __in WDF_INTERRUPT_PRIORITY Priority, + __in PGROUP_AFFINITY TargetProcessorSet + ); + + VOID + FlushQueuedDpcs( + VOID + ); + + VOID + FlushQueuedWorkitem( + VOID + ); + + VOID + InvokeWakeInterruptEvtIsr( + VOID + ); + + BOOLEAN + WakeInterruptIsr( + VOID + ); + + BOOLEAN + IsLevelTriggered( + __in ULONG Flags + ) + { + return ((Flags & CM_RESOURCE_INTERRUPT_LEVEL_LATCHED_BITS) + == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE); + } + + __inline + BOOLEAN + QueueDeferredRoutineForIsr( + VOID + ) + { + // + // Queue DPC for KMDF and workitem for UMDF. Note that driver can either + // specify EvtInterruptDpc or EvtInterruptWorkItem, and therefore it can + // either call WdfInterruptQueueDpcForisr or WdfInterruptQueueWorkitemForIsr. + // + + + + + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return QueueDpcForIsr(); +#else + return QueueWorkItemForIsr(); +#endif + } + +}; + +BOOLEAN +_SynchronizeExecution( + __in MdInterrupt Interrupt, + __in MdInterruptSynchronizeRoutine SynchronizeRoutine, + __in PVOID SynchronizeContext + ); + +#endif // _FXINTERRUPT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueue.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueue.hpp new file mode 100644 index 00000000000..ed403dba3ce --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueue.hpp @@ -0,0 +1,1714 @@ + +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxIoQueue.h + +Abstract: + + This module implements the I/O package queue object + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXIOQUEUE_H_ +#define _FXIOQUEUE_H_ + +#include "FxIoQueueCallbacks.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoQueue.hpp.tmh" +#endif +} + + +// +// These FxIoQueue public Enum and Struct are used to tie the queue +// with FxPkgIo. +// +enum FxIoQueueNodeType { + FxIoQueueNodeTypeInvalid = 0, + FxIoQueueNodeTypeQueue, + FxIoQueueNodeTypeBookmark, + FxIoQueueNodeTypeLast, +}; + +struct FxIoQueueNode { +public: + // + // Data members. + // + LIST_ENTRY m_ListEntry; + FxIoQueueNodeType m_Type; + +public: + // + // Manager functions. + // + FxIoQueueNode( + FxIoQueueNodeType NodeType + ) : + m_Type(NodeType) + { + ASSERT(_IsValidNodeType(m_Type)); + InitializeListHead(&m_ListEntry); + } + + ~FxIoQueueNode() + { + ASSERT(IsListEmpty(&m_ListEntry) == TRUE); + } + +private: + // + // Turn off unsupported manager functions. + // + FxIoQueueNode(); + + // + // Block default behavior to shallow copy the object because it contains + // a double-link entry; shallow copying the object produces an invalid + // copy because the double-link entry is not properly re-initialized. + // + FxIoQueueNode(const FxIoQueueNode&); + + FxIoQueueNode& operator=(const FxIoQueueNode&); + +public: + // + // Helper functions. + // + static + FxIoQueueNode* + _FromListEntry( + __in PLIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxIoQueueNode, m_ListEntry); + } + + static + BOOLEAN + _IsValidNodeType( + __in FxIoQueueNodeType NodeType + ) + { + return ((NodeType > FxIoQueueNodeTypeInvalid) && + (NodeType < FxIoQueueNodeTypeLast)) ? TRUE : FALSE; + } + + __inline + BOOLEAN + IsNodeType( + __in FxIoQueueNodeType NodeType + ) + { + return (NodeType == m_Type) ? TRUE : FALSE; + } +}; + +// +// These FxIoQueue private Enum's control the internal state machine +// + +// begin_wpp enum +typedef enum FxIoQueuePowerState { + FxIoQueuePowerInvalid = 0, + FxIoQueuePowerOn, + FxIoQueuePowerOff, + FxIoQueuePowerStartingTransition, + FxIoQueuePowerStopping, + FxIoQueuePowerStoppingNotifyingDriver, + FxIoQueuePowerStoppingDriverNotified, + FxIoQueuePowerPurge, + FxIoQueuePowerPurgeNotifyingDriver, + FxIoQueuePowerPurgeDriverNotified, + FxIoQueuePowerRestarting, + FxIoQueuePowerRestartingNotifyingDriver, + FxIoQueuePowerRestartingDriverNotified, + FxIoQueuePowerLast, +} FXIOQUEUE_POWER_STATE; +// end_wpp + +typedef struct _FXIO_FORWARD_PROGRESS_CONTEXT { + // + // Total Number of Reserved requests + // + ULONG m_NumberOfReservedRequests; + // + // Callback invoked to allocate resources for reserved requests at init time + // + FxIoQueueForwardProgressAllocateResourcesReserved m_IoReservedResourcesAllocate; + // + // Callback invoked to allocate resources for non-reserved requests at run time + // + FxIoQueueForwardProgressAllocateResources m_IoResourcesAllocate; + // + // Callback invoked to Examine the IRP and decide whether to fail it or not + // + FxIoQueueForwardProgressExamineIrp m_IoExamineIrp; + // + // Policy configured for forward progress + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY m_Policy; + // + // List of available reserved requests + // + LIST_ENTRY m_ReservedRequestList; + + // + // List of in use reserved requests + // + LIST_ENTRY m_ReservedRequestInUseList; + + // + // List of all pended IRPs + // + LIST_ENTRY m_PendedIrpList; + // + // This lock is used to add new entreies to the pended IRP list + // or the add the request back to the Reserved List + // + MxLockNoDynam m_PendedReserveLock; + +} FXIO_FORWARD_PROGRESS_CONTEXT, *PFXIO_FORWARD_PROGRESS_CONTEXT; + +// +// This defines the valid arguments to the +// SetStatus call. +// +typedef enum _FX_IO_QUEUE_SET_STATE { + FxIoQueueSetAcceptRequests = 0x80000001, + FxIoQueueClearAcceptRequests = 0x80000002, + FxIoQueueSetDispatchRequests = 0x80000004, + FxIoQueueClearDispatchRequests = 0x80000008, + FxIoQueueSetShutdown = 0x80010000, + FxIoQueueClearShutdown = 0x80020000, +} FX_IO_QUEUE_SET_STATE; + + +// +// This defines the internal queue state. +// +typedef enum _FX_IO_QUEUE_STATE { + // + // private == public values (low word). + // + FxIoQueueAcceptRequests = WdfIoQueueAcceptRequests, // 0x00000001 + FxIoQueueDispatchRequests = WdfIoQueueDispatchRequests, // 0x00000002 + FxIoQueueNoRequests = WdfIoQueueNoRequests, // 0x00000004 + FxIoQueueDriverNoRequests = WdfIoQueueDriverNoRequests, // 0x00000008 + FxIoQueuePnpHeld = WdfIoQueuePnpHeld, // 0x00000010 + // + // private values only (high word). + // + // Queue is being shut down. Flag on means do not queue any request + // even if the accept request state is set. This flag prevents the + // following scenarios: + // (1) a race condition where a dispatch queue handler changes the + // state of the queue to accept_requests while we are in the + // middle of a power stopping (purge) operation (Win7 719587). + // (2) another thread calling Stop or Start on a queue that is in the + // middle of a power stopping (purge) operation. + // + FxIoQueueShutdown = 0x00010000 +} FX_IO_QUEUE_STATE; + +class FxIoQueue : public FxNonPagedObject, IFxHasCallbacks { + + friend VOID GetTriageInfo(VOID); + +private: + + // + // forward progress fields + // + PFXIO_FORWARD_PROGRESS_CONTEXT m_FwdProgContext; + + // + // This is a true indicator whether the Queue is ready for forward progress + // + BOOLEAN m_SupportForwardProgress; + + // + // Specifies that the queue has been configured + // with driver callbacks and presentation serialization + // + BOOLEAN m_Configured; + + // + // TRUE if this is a power managed queue. If TRUE, it is reported + // as a power managed queue, and will automatically start/resume + // based on power management requests. + // + // If false, the device driver has manual control on start/resume. + // + BOOLEAN m_PowerManaged; + + // + // This is TRUE if we have an outstanding reference to the + // Pnp package about having I/O in our queue. + // + volatile BOOLEAN m_PowerReferenced; + + // + // If TRUE, zero length read/writes are allowed to the driver. + // Otherwise, they are completed automatically with STATUS_SUCCESS. + // + BOOLEAN m_AllowZeroLengthRequests; + + // + // True if callback operations to the driver occur at + // PASSIVE_LEVEL. Also marked in FxObject, but this cache + // avoids acquiring FxObject state lock. + // + BOOLEAN m_PassiveLevel; + + // + // This is set before m_FinishDisposing is signalled to + // allow the Dispose thread to continue deletion of + // queue resources. Once this is set, no thread is + // allowed to run thru DispatchEvents. + // + volatile BOOLEAN m_Deleted; + + // + // This is set when the I/O package marks the queue + // for deleting, but the I/O queue deferrs its final + // dereference until all outstanding I/O's to the + // device driver are completed. + // + volatile BOOLEAN m_Disposing; + MxEvent m_FinishDisposing; + + // + // Power State of the Queue + // + FXIOQUEUE_POWER_STATE m_PowerState; + + // + // This is the type of queue, and is configured by the + // user at initial queue creation time. + // + WDF_IO_QUEUE_DISPATCH_TYPE m_Type; + + // + // Maximum number of driver presented Requests on a parallel Queue + // + ULONG m_MaxParallelQueuePresentedRequests; + + // + // This is the current processing status of the queue. + // + FX_IO_QUEUE_STATE m_QueueState; + + // + // The FxIoQueue tracks a request from the time it arrives by being + // enqueued, until it leaves by being completed, or forwarded. + // + // At any given time, a request may be in one the following five states: + // + // 1) Request is queued and cancelable + // + // It is on the FxIrpQueue m_Queue using the LIST_ENTRY + // FxRequest::m_Irp->Tail.Overlay.ListEntry + // + // 2) Request has been passed to the driver, and is not cancelable + // + // It is on the LIST_ENTRY m_DriverNonCancelable using the LIST_ENTRY + // FxRequest::m_OwnerListEntry + // + // It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY + // FxRequest::m_InFlightListEntry + // + // 3) Request has been passed to the driver, and is cancelable + // + // It is on the FxIrpQueue m_DriverCancelable using the LIST_ENTRY + // FxRequest::m_Irp->Tail.Overlay.ListEntry + // + // It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY + // FxRequest::m_InFlightListEntry + // + // 4) Request has been cancelled, but the driver has not been notified + // + // It is on the LIST_ENTRY m_Cancelled using the LIST_ENTRY + // FxRequest::m_OwnerListEntry + // + // 5) Request has been cancelled, driver has been notified, but has + // not completed it yet + // + // It is on the LIST_ENTRY m_DriverNonCancelable using the LIST_ENTRY + // FxRequest::m_OwnerListEntry + // + // It is also on the LIST_ENTRY m_DriverInFlight using the LIST_ENTRY + // FxRequest::m_InFlightListEntry + // + + // + // This is the Queue of current requests that have not + // been presented to the driver + // + FxIrpQueue m_Queue; + + // + // This is the list of requests that driver has accepted + // and is working on, but wants to be cancelable. + // + FxIrpQueue m_DriverCancelable; + + // + // This is a list of cancelled requests to be notified to the driver. + // + // FxListEntryQueueOwned of FxRequest is used for linkage + // + LIST_ENTRY m_Cancelled; + + // + // This is a list of request cancelled on queue waiting + // to be notified to the driver. + // + // FxListEntryQueueOwned of FxRequest is used for linkage + // + LIST_ENTRY m_CanceledOnQueueList; + + // + // This is a list of requests that the driver has accepted + // and is working on, but has not been completed. + // + // They may, or may not be cancelable. + // + // FxListEntryDriverOwned of FxRequest is used for linkage + // + LIST_ENTRY m_DriverOwned; + + // + // This is the list of power stop/start requests to be notified to + // the driver. + // + // FxListEntryDriverOwned of FxRequest is used for linkage + // + LIST_ENTRY m_PowerNotify; + + // + // This is the list of power stop requests in which the driver + // has been notified, and must be zero before power code can + // resume the power thread. + // + // FxListEntryDriverOwned of FxRequest is used for linkage + // + LIST_ENTRY m_PowerDriverNotified; + + // + // Pointer to FxPkgIo object that contains this queue. + // (No additional reference count) + // + FxPkgIo* m_PkgIo; + + // + // Weak pointer to the associated FxCxDeviceInfo struct. + // + FxCxDeviceInfo* m_CxDeviceInfo; + + // + // This is the count of currently executing callback + // handlers into the device driver. + // + // It is used to control the dispatch state to prevent stack + // recursions, as well as to handle notification when a queue + // is idle and has no callbacks outstanding. + // + volatile ULONG m_Dispatching; + + // + // This is set when a queue goes from empty to + // having requests and allows a callback to the driver + // when a queue is ready. + // + volatile BOOLEAN m_TransitionFromEmpty; + + // + // This flag is set when the we return no_more_requests from + // WdfRequesdtGetNextRequest but the queue actually holds one or + // more requests in cancellation state (their cancellation routine + // are already running). + // This flag insures that we call the ReadyNotify callback when a new + // request is inserted in the queue. + // + volatile BOOLEAN m_ForceTransitionFromEmptyWhenAddingNewRequest; + + // + // This is set when the driver starts a WdfIoQueueStopAndPurge operation. + // This is cleared in the following conditions: + // (a) there are no more driver owned requests. + // (b) driver re-enables the dispatch gate. + // When set any requeued requests will be automatically deleted. + // + volatile BOOLEAN m_CancelDispatchedRequests; + + BOOLEAN m_IsDevicePowerPolicyOwner; + + // + // This is the number of requests the driver + // currently is processing both cancellable and noncancellable. + // + // For serial queue dispatch mode, this is used + // to control when a request can be presented to the driver. + // This is also used to implement counted Queues to make + // sure the count doesn't exceed max. allowed on the + // parallel Queue. + // + volatile LONG m_DriverIoCount; + + // + // This is the number of requests that are about to be completed using two + // phase completion technique (to support queued-by-driver requests). + // + volatile LONG m_TwoPhaseCompletions; + + // + // These are the driver configured callbacks to send + // I/O events to the driver + // + FxIoQueueIoDefault m_IoDefault; + FxIoQueueIoStop m_IoStop; + FxIoQueueIoResume m_IoResume; + FxIoQueueIoRead m_IoRead; + FxIoQueueIoWrite m_IoWrite; + FxIoQueueIoDeviceControl m_IoDeviceControl; + FxIoQueueIoInternalDeviceControl m_IoInternalDeviceControl; + FxIoQueueIoCanceledOnQueue m_IoCanceledOnQueue; + + FxCallbackLock* m_IoCancelCallbackLockPtr; + + // + // These are status events registered by the device driver + // + FxIoQueueIoState m_IdleComplete; + WDFCONTEXT m_IdleCompleteContext; + + FxIoQueueIoState m_PurgeComplete; + WDFCONTEXT m_PurgeCompleteContext; + + FxIoQueueIoState m_ReadyNotify; + WDFCONTEXT m_ReadyNotifyContext; + + // + // The following items support the callback constraints + // and handle locking and deferral + // + WDF_EXECUTION_LEVEL m_ExecutionLevel; + WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope; + + // + // These are the passive and dispatch level presentation locks + // + FxCallbackSpinLock m_CallbackSpinLock; + FxCallbackMutexLock m_CallbackMutexLock; + + // + // This pointer allows the proper lock to be acquired + // based on the configuration with a minimal of runtime + // checks. This is configured by ConfigureLocking() + // + FxCallbackLock* m_CallbackLockPtr; + FxObject* m_CallbackLockObjectPtr; + + // + // The IoQueue must sometimes defer event delivery to the + // device driver due to interactions with current locks held, + // and the device driver configured callback constraints. + // + // When a deferral occurs, a DPC or FxSystemWorkItem is used + // to post an event to later deliver the event(s) to the device + // driver. Whether a DPC or WorkItem is used depends + // on the drivers configured execution level constraints. + // + // The IoQueue is designed to be robust in that multiple events + // may occur while the queued DPC or WorkItem is outstanding, + // and they will be properly processed without having to enqueue + // one for each event. Basically, they are just a signal that + // an IoQueue needs some attention that could result in device + // driver notification. + // + // KDPC is only needed in kernel mode + // + + + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + KDPC m_Dpc; +#endif + + FxSystemWorkItem* m_SystemWorkItem; + + // + // These are true if the associated Dpc or Work Item is queued + // + BOOLEAN m_DpcQueued; + BOOLEAN m_WorkItemQueued; + + // + // Track whether the above DPC and WorkItem needs to be requeued. + // + BOOLEAN m_RequeueDeferredDispatcher; + + // This is set when the Queue is power idle + MxEvent m_PowerIdle; + + + + + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + MxEvent m_RequestWaitEventUm; +#endif + +public: + + // + // List node to tie the queue with FxPkgIo. + // + FxIoQueueNode m_IoPkgListNode; + // + // List entry is used by FxPkgIo to iterate list all the queues without + // holding a lock. + // + SINGLE_LIST_ENTRY m_PowerSListEntry; + +public: + // Factory function + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_IO_QUEUE_CONFIG Config, + __in_opt FxDriver* Caller, + __in FxPkgIo* PkgIo, + __in BOOLEAN InitialPowerStateOn, + __deref_out FxIoQueue** Object + ); + + FxIoQueue( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxPkgIo* PkgIo + ); + + virtual + ~FxIoQueue( + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDF_IO_QUEUE_CONFIG pConfig, + __in_opt PWDF_OBJECT_ATTRIBUTES QueueAttributes, + __in_opt FxDriver* Caller, + __in BOOLEAN InitialPowerStateOn + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + VOID + CancelForQueue( + __in FxRequest* pRequest, + __in __drv_restoresIRQL KIRQL PreviousIrql + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + VOID, + VerifyCancelForDriver, + _In_ FxRequest* + ); + + VOID + CancelForDriver( + __in FxRequest* pRequest + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + VOID, + VerifyValidateCompletedRequest, + _In_ FxRequest* + ); + + __inline + VOID + RequestCompletedCallback( + __in FxRequest* Request + ) + { + // + // This is called when a FxRequest object completes based + // on the callback event registered by the I/O queue support + // routines. + // + + KIRQL irql; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p", + GetObjectHandle(),Request->GetHandle()); +#endif + VerifyValidateCompletedRequest(GetDriverGlobals(), Request); + + Lock(&irql); + + // + // I/O has been completed by the driver + // + RemoveFromDriverOwnedList(Request); + + // + // Don't run the event dispatcher if we come from a Request + // complete callback in order to prevent stack recursion. + // + // Since some other thread (possibly this thread higher on + // the stack) is running the dispatcher, no events will get lost. + // + DispatchInternalEvents(irql); + } + + __inline + VOID + PreRequestCompletedCallback( + __in FxRequest* Request + ) + { + // + // This is called when a driver created request is about to be completed. + // This callback removes the FxRequest object from the internal queue linked + // lists. A call to PostRequestCompletedCallback must be made after irp is + // completed. + // + + KIRQL irql; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p", + GetObjectHandle(),Request->GetHandle()); +#endif + + VerifyValidateCompletedRequest(GetDriverGlobals(), Request); + + Lock(&irql); + + // + // I/O has been completed by the driver + // + PreRemoveFromDriverOwnedList(Request); + + Unlock(irql); + } + + __inline + VOID + PostRequestCompletedCallback( + __in FxRequest* Request + ) + { + // Do not acccess Request, at this point the object may have already been + // deleted or reused. + + // + // This is called when a queued-by-driver request (driver created) is + // completed or sent to a lower driver with 'send-and-forget' option. + // This callback allows the queue to schedule another request for delivery. + // + + KIRQL irql; + +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Enter: WDFQUEUE 0x%p, WDFREQUEST 0x%p", + GetObjectHandle(), FxRequest::_ToHandle(Request)); +#else + UNREFERENCED_PARAMETER(Request); +#endif + + Lock(&irql); + + // + // I/O has been completed by the driver + // + PostRemoveFromDriverOwnedList(); + + // + // Don't run the event dispatcher if we come from a Request + // complete callback in order to prevent stack recursion. + // + // Since some other thread (possibly this thread higher on + // the stack) is running the dispatcher, no events will get lost. + // + DispatchInternalEvents(irql); + } + + __inline + FxDriver* + GetDriver(VOID) { + return m_PkgIo->GetDriver(); + } + + __inline + CfxDevice* + GetDevice(VOID) + { + return m_Device; + } + + __inline + FxPkgIo* + GetPackage(VOID) { + return m_PkgIo; + } + + WDFQUEUE + __inline + GetHandle( + VOID + ) + { + return (WDFQUEUE) GetObjectHandle(); + } + + __inline + BOOLEAN + IsPowerManaged() { + return m_PowerManaged; + } + + VOID + StartPowerTransitionOn( + VOID + ); + + VOID + StartPowerTransitionOff( + VOID + ); + + VOID + StopProcessingForPower( + __in FxIoStopProcessingForPowerAction Action + ); + + VOID + ResumeProcessingForPower( + VOID + ); + + VOID + SetStateForShutdown( + VOID + ); + + VOID + ResetStateForRestart( + VOID + ); + + WDF_IO_QUEUE_STATE + GetState( + __out_opt PULONG pQueueCount, + __out_opt PULONG pDriverCount + ); + + VOID + SetState( + __in FX_IO_QUEUE_SET_STATE NewStatus + ); + + + __inline + BOOLEAN + IsState( + __in WDF_IO_QUEUE_STATE State + ) + { + ASSERT(!(State & 0x80000000)); // Don't allow FX_IO_QUEUE_SET states + return (((int)m_QueueState & (int) (State)) != 0); + } + + __inline + BOOLEAN + IsState( + __in FX_IO_QUEUE_STATE State + ) + { + ASSERT(!(State & 0x80000000)); // Don't allow FX_IO_QUEUE_SET states + return (((int)m_QueueState & (int) (State)) != 0); + } + + // GetRequest Verifiers + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifyGetRequestUpdateFlags, + _In_ FxRequest* + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + VOID, + VerifyGetRequestRestoreFlags, + _In_ FxRequest* + ); + + _Must_inspect_result_ + NTSTATUS + GetRequest( + __in_opt MdFileObject FileObject, + __in_opt FxRequest* TagRequest, + __deref_out FxRequest** pOutRequest + ); + + // PeekRequest Verifiers + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifyPeekRequest, + _In_ FxRequest* + ); + + _Must_inspect_result_ + NTSTATUS + PeekRequest( + __in_opt FxRequest* TagRequest, + __in_opt MdFileObject FileObject, + __out_opt PWDF_REQUEST_PARAMETERS Parameters, + __deref_out FxRequest** pOutRequest + ); + + // ForwardRequest Verifiers + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P2( + NTSTATUS, + VerifyForwardRequest, + _In_ FxIoQueue*, + _In_ FxRequest* + ); + + _Must_inspect_result_ + NTSTATUS + ForwardRequest( + __in FxIoQueue* pDestQueue, + __in FxRequest* pRequest + ); + + // QueueDriverCreatedRequest + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P2( + NTSTATUS, + VerifyQueueDriverCreatedRequest, + _In_ FxRequest*, + _Inout_ SHORT* + ); + + _Must_inspect_result_ + NTSTATUS + QueueDriverCreatedRequest( + __in FxRequest* Request, + __in BOOLEAN ParentQueue + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + ProcessAcknowledgedRequests( + __in FxRequest* Request, + __out PKIRQL PreviousIrql + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifyRequeue, + _In_ FxRequest* + ); + + _Must_inspect_result_ + NTSTATUS + Requeue( + __in FxRequest* pRequest + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P2( + NTSTATUS, + VerifyRequestCancelable, + _In_ FxRequest*, + _In_ BOOLEAN + ); + + _Must_inspect_result_ + NTSTATUS + RequestCancelable( + __in FxRequest* pRequest, + __in BOOLEAN Cancelable, + __in_opt PFN_WDF_REQUEST_CANCEL EvtRequestCancel, + __in BOOLEAN FailIfIrpIsCancelled + ); + + _Must_inspect_result_ + NTSTATUS + RequestCompleteEvent( + __in FxRequest* Request + ); + + + _Must_inspect_result_ + NTSTATUS + QueueRequest( + __in FxRequest* pRequest + ); + + _Must_inspect_result_ + NTSTATUS + QueueRequestFromForward( + __in FxRequest* pRequest + ); + + _Must_inspect_result_ + BOOLEAN + CanThreadDispatchEventsLocked( + __in KIRQL PreviousIrql + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + DispatchEvents( + __in __drv_restoresIRQL KIRQL PreviousIrql, + __in_opt FxRequest* NewRequest = NULL + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + VOID + DispatchInternalEvents( + __in __drv_restoresIRQL KIRQL PreviousIrql + ) + /*++ + + Routine Description: + + Dispatch events and requests from the queue to the driver. + + The IoQueue object lock must be held on entry, but this + routine returns to the caller with the lock released. + + To avoid recursion, this routine checks to see if this or another + thread is already in the dispatch-event loop. If so, it + doesn't re-enter the dispatch-even loop. + + --*/ + { + if(m_Dispatching == 0) { + // + // Nobody is dispatching events so we must + // call the main DispatchEvents function because + // the caller of this function might have affected the + // state of the queue. + // + (VOID) DispatchEvents(PreviousIrql); + + } else { + + Unlock(PreviousIrql); + } + } + + + VOID + DispatchRequestToDriver( + __in FxRequest* pRequest + ); + + virtual + VOID + GetConstraints( + __out WDF_EXECUTION_LEVEL* ExecutionLevel, + __out WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) { + + if (ExecutionLevel != NULL) { + *ExecutionLevel = m_ExecutionLevel; + } + + if (SynchronizationScope != NULL) { + *SynchronizationScope = m_SynchronizationScope; + } + } + + virtual + FxCallbackLock* + GetCallbackLockPtr( + __deref_out FxObject** LockObject + ) + { + if (LockObject != NULL) { + *LockObject = m_CallbackLockObjectPtr; + } + + return m_CallbackLockPtr; + } + + _Must_inspect_result_ + virtual + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ) + { + switch (Params->Type) { + case FX_TYPE_QUEUE: + *Params->Object = (FxIoQueue*) this; + break; + + case FX_TYPE_IHASCALLBACKS: + *Params->Object = (IFxHasCallbacks*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; + } + + virtual + BOOLEAN + Dispose( + VOID + ); + + // + // Start the Queue + // + VOID + QueueStart( + VOID + ); + + // + // Idle/Stop the Queue + // + _Must_inspect_result_ + NTSTATUS + QueueIdle( + __in BOOLEAN CancelQueueRequests, + __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete, + __in_opt WDFCONTEXT Context + ); + + // + // Idle the Queue + // + _Must_inspect_result_ + NTSTATUS + QueueIdleSynchronously( + __in BOOLEAN CancelRequests + ); + + // + // Purge the Queue + // + _Must_inspect_result_ + NTSTATUS + QueuePurge( + __in BOOLEAN CancelQueueRequests, + __in BOOLEAN CancelDriverRequests, + __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete, + __in_opt WDFCONTEXT Context + ); + + _Must_inspect_result_ + NTSTATUS + QueuePurgeSynchronously( + VOID + ); + + // + // Idle the Queue + // + _Must_inspect_result_ + NTSTATUS + QueueDrain( + __in_opt PFN_WDF_IO_QUEUE_STATE DrainComplete, + __in_opt WDFCONTEXT Context + ); + + // + // Idle the Queue + // + _Must_inspect_result_ + NTSTATUS + QueueDrainSynchronously( + VOID + ); + + // + // Notify the driver through a callback when the queue transitions + // from no requests to having a request. + // + _Must_inspect_result_ + NTSTATUS + ReadyNotify( + __in PFN_WDF_IO_QUEUE_STATE QueueReady, + __in_opt WDFCONTEXT Context + ); + + + VOID + FlushByFileObject( + __in MdFileObject FileObject + ); + + // + // Return count of queued and driver pending requests. + // + VOID + GetRequestCount( + __out_opt PULONG pQueuedRequests, + __out_opt PULONG pDriverPendingRequests + ); + + + _Must_inspect_result_ + NTSTATUS + ConfigureConstraints( + __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes, + __in_opt FxDriver* Caller + ); + + VOID + DeferredDispatchRequestsFromDpc( + VOID + ); + + VOID + DeferredDispatchRequestsFromWorkerThread( + VOID + ); + + __inline + static + FxIoQueue* + _FromIoPkgListEntry( + __in PLIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxIoQueue, m_IoPkgListNode.m_ListEntry); + } + + __inline + static + FxIoQueue* + _FromPowerSListEntry( + __in PSINGLE_LIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxIoQueue, m_PowerSListEntry); + } + + __declspec(noreturn) + VOID + FatalError( + __in NTSTATUS Status + ); + + BOOLEAN + IsIoEventHandlerRegistered( + __in WDF_REQUEST_TYPE RequestType + ); + + __inline + VOID + SetPowerState( + __in FXIOQUEUE_POWER_STATE PowerState + ) + { + if (m_PowerManaged) { + m_PowerState = PowerState; + } + } + + _Must_inspect_result_ + NTSTATUS + GetReservedRequest( + __in MdIrp Irp, + __deref_out_opt FxRequest **ReservedRequest + ); + + __inline + BOOLEAN + IsForwardProgressQueue( + VOID + ) + { + return m_SupportForwardProgress; + } + + __inline + NTSTATUS + InvokeAllocateResourcesCallback( + __in FxRequest *Request + ) + /*++ + + Routine Description: + Give callback to allocate resources at runtime for a general request + (not a reserved request). + + --*/ + { + NTSTATUS status; + + ASSERT(Request->IsReserved() == FALSE); + + status = STATUS_SUCCESS; + if (m_FwdProgContext->m_IoResourcesAllocate.Method != NULL) { + Request->SetPresented(); + status = m_FwdProgContext->m_IoResourcesAllocate.Invoke( + GetHandle(), Request->GetHandle()); + } + + return status; + } + + VOID + ReturnReservedRequest( + __in FxRequest *ReservedRequest + ); + + _Must_inspect_result_ + NTSTATUS + AllocateReservedRequest( + __deref_out FxRequest** Request + ); + + _Must_inspect_result_ + NTSTATUS + AssignForwardProgressPolicy( + __in PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Policy + ); + + // ForwardRequestWorker verifiers + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1_EX( + , + SHORT, + 0, + VerifyForwardRequestUpdateFlags, + _In_ FxRequest* + ); + + _Must_inspect_result_ + NTSTATUS + ForwardRequestWorker( + __in FxRequest* Request, + __in FxIoQueue* DestQueue + ); + + // ForwardRequestToParent Verifiers + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P2( + NTSTATUS, + VerifyForwardRequestToParent, + _In_ FxIoQueue*, + _In_ FxRequest* + ); + + _Must_inspect_result_ + NTSTATUS + ForwardRequestToParent( + __in FxIoQueue* DestQueue, + __in FxRequest* Request, + __in PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions + ); + + __inline + VOID + SetCxDeviceInfo( + __in FxCxDeviceInfo* CxDeviceInfo + ) + { + m_CxDeviceInfo = CxDeviceInfo; + } + + __inline + FxCxDeviceInfo* + GetCxDeviceInfo( + VOID + ) + { + return m_CxDeviceInfo; + } + + __inline + VOID + SetInterruptQueue( + VOID + ) + { + MarkNoDeleteDDI(ObjectLock); + } + + VOID + FlushQueuedDpcs( + VOID + ); + + VOID + InsertQueueDpc( + VOID + ); + +private: + + // + // Helper functions for event processing loop DispatchEvents() + // + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + ProcessIdleComplete( + __out PKIRQL PreviousIrql + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + ProcessPurgeComplete( + __out PKIRQL PreviousIrql + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + ProcessReadyNotify( + __out PKIRQL PreviousIrql + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + ProcessCancelledRequests( + __out PKIRQL PreviousIrql + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + ProcessCancelledRequestsOnQueue( + __out PKIRQL PreviousIrql + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + ProcessPowerEvents( + __out PKIRQL PreviousIrql + ); + + __inline + BOOLEAN + IsPowerStateNotifyingDriver( + VOID + ) + { + if (m_PowerState == FxIoQueuePowerStoppingNotifyingDriver || + m_PowerState == FxIoQueuePowerPurgeNotifyingDriver || + m_PowerState == FxIoQueuePowerRestartingNotifyingDriver) { + return TRUE; + } + else { + return FALSE; + } + } + + // + // Insert in the list of requests that the driver is operating + // on. + // + // Must be called with the FxIoQueue lock held. + // + __inline + VOID + InsertInDriverOwnedList( + __in FxRequest* Request + ) + { + m_DriverIoCount++; + + InsertTailList(&m_DriverOwned, Request->GetListEntry(FxListEntryDriverOwned)); + return; + } + + // + // Remove the request from the list that the driver is operating + // on. + // + // Must be called with the FxIoQueue lock held. + // + // Note: ForwardRequest and two phase completions (queued-by-driver) cases breaks + // this up and manipulates the list entry and m_DriverIoCount separately. + // + __inline + VOID + RemoveFromDriverOwnedList( + __in FxRequest* Request + ) + { + PLIST_ENTRY listEntry; + + listEntry = Request->GetListEntry(FxListEntryDriverOwned); + + RemoveEntryList(listEntry); + InitializeListHead(listEntry); + + m_DriverIoCount--; + ASSERT(m_DriverIoCount >= 0); + + return; + } + + // + // Pre-Remove the request from the list that the driver is operating on + // (the first of two phase completion). + // + // Must be called with the FxIoQueue lock held. + // + __inline + VOID + PreRemoveFromDriverOwnedList( + __in FxRequest* Request + ) + { + PLIST_ENTRY listEntry; + + listEntry = Request->GetListEntry(FxListEntryDriverOwned); + + RemoveEntryList(listEntry); + InitializeListHead(listEntry); + + m_TwoPhaseCompletions++; + ASSERT(m_TwoPhaseCompletions > 0); + + return; + } + + // + // Post-Remove the request from the list that the driver is operating on + // (the second of two phase completion). + // + // Must be called with the FxIoQueue lock held. + // + __inline + VOID + PostRemoveFromDriverOwnedList( + VOID + ) + { + m_TwoPhaseCompletions--; + ASSERT(m_TwoPhaseCompletions >= 0); + + m_DriverIoCount--; + ASSERT(m_DriverIoCount >= 0); + return; + } + + // + // This is called after inserting a new request in the IRP queue. + // + // Must be called with the FxIoQueue lock held. + // + __inline + VOID + CheckTransitionFromEmpty( + VOID + ) + { + if (m_Queue.GetRequestCount() == 1L || + m_ForceTransitionFromEmptyWhenAddingNewRequest) { + + SetTransitionFromEmpty(); + } + } + + // + // Indicate that the queue went from empty to having one or more requests. + // + // Must be called with the FxIoQueue lock held. + // + __inline + VOID + SetTransitionFromEmpty( + VOID + ) + { + m_TransitionFromEmpty = TRUE; + m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE; + + if(m_IsDevicePowerPolicyOwner && + m_PowerManaged && + m_PowerReferenced == FALSE) { + + if (NT_SUCCESS(m_Device->m_PkgPnp->PowerReference(FALSE))) { + m_PowerReferenced = TRUE; + } + } + } + + NTSTATUS + InsertNewRequestLocked( + __deref_in FxRequest** Request, + __in KIRQL PreviousIrql + ); + + __inline + NTSTATUS + InsertNewRequest( + __in FxRequest** Request, + __in KIRQL PreviousIrql + ) + { + NTSTATUS status; + + if (*Request != NULL) { + status = InsertNewRequestLocked(Request, PreviousIrql); + } + else { + status = STATUS_SUCCESS; // nothing to do. + } + + return status; + } + + VOID + FreeAllReservedRequests( + __in BOOLEAN Verify + ); + + _Must_inspect_result_ + NTSTATUS + QueueForwardProgressIrpLocked( + __in MdIrp Irp + ); + + _Must_inspect_result_ + MdIrp + GetForwardProgressIrpLocked( + __in_opt PFILE_OBJECT FileObject + ); + + BOOLEAN + IsPagingIo( + __in MdIrp Irp + ); + + VOID + PutBackReservedRequest( + __in FxRequest *ReservedRequest + ) + { + KIRQL oldIrql; + PLIST_ENTRY listEntry; + + ASSERT(m_Deleted == FALSE); + + listEntry = ReservedRequest->GetListEntry(FxListEntryForwardProgress); + + m_FwdProgContext->m_PendedReserveLock.Acquire(&oldIrql); + + RemoveEntryList(listEntry); + InitializeListHead(listEntry); + + InsertTailList(&m_FwdProgContext->m_ReservedRequestList, listEntry); + + if (GetDriverGlobals()->FxVerifierIO) { + VerifierVerifyFwdProgListsLocked(); + } + + m_FwdProgContext->m_PendedReserveLock.Release(oldIrql); + } + + + VOID + GetForwardProgressIrps( + __in PLIST_ENTRY IrpListHead, + __in_opt MdFileObject FileObject + ); + + VOID + CancelIrps( + __in PLIST_ENTRY IrpListHead + ); + + VOID + PurgeForwardProgressIrps( + __in_opt MdFileObject FileObject + ); + + VOID + VerifierVerifyFwdProgListsLocked( + VOID + ); + +protected: + static + EVT_IRP_QUEUE_CANCEL + _IrpCancelForQueue; + + // + // This is our Cancel Safe Queue Callback from + // FxIrpQueue notifying us of an I/O cancellation + // on a driver owned request (driver queue) + // + static + EVT_IRP_QUEUE_CANCEL + _IrpCancelForDriver; + + static + EVT_SYSTEMWORKITEM + _DeferredDispatchThreadThunk; + + static + MdDeferredRoutineType + _DeferredDispatchDpcThunk; + + static + EVT_WDF_IO_QUEUE_STATE + _PurgeComplete; + + static + EVT_WDF_IO_QUEUE_STATE + _IdleComplete; + + static + MdCancelRoutineType + _WdmCancelRoutineForReservedIrp; + +}; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) +#include "FxIoQueueKm.hpp" +#else +#include "FxIoQueueUm.hpp" +#endif + + +#endif // _FXIOQUEUE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueuecallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueuecallbacks.hpp new file mode 100644 index 00000000000..66a2f33ef76 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxioqueuecallbacks.hpp @@ -0,0 +1,416 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoQueueCallbacks.h + +Abstract: + + This module implements the I/O package queue object callbacks + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXIOQUEUECALLBACKS_H_ +#define _FXIOQUEUECALLBACKS_H_ + +// +// These delegates are in a seperate file since there are many +// + +// +// EvtIoDefault callback delegate +// +class FxIoQueueIoDefault : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_DEFAULT Method; + + FxIoQueueIoDefault( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Request); + CallbackEnd(irql); + } + } +}; + + +// +// EvtIoStop callback delegate +// +class FxIoQueueIoStop : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_STOP Method; + + FxIoQueueIoStop( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request, + __in ULONG ActionFlags + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Request, ActionFlags); + CallbackEnd(irql); + } + } +}; + +// +// EvtIoResume callback delegate +// +class FxIoQueueIoResume : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_RESUME Method; + + FxIoQueueIoResume( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Request); + CallbackEnd(irql); + } + } +}; + +// +// EvtIoRead callback delegate +// +class FxIoQueueIoRead : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_READ Method; + + FxIoQueueIoRead( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request, + __in ULONG Length + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Request, Length); + CallbackEnd(irql); + } + } +}; + +// +// EvtIoWrite callback delegate +// +class FxIoQueueIoWrite : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_WRITE Method; + + FxIoQueueIoWrite( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request, + __in ULONG Length + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Request, Length); + CallbackEnd(irql); + } + } +}; + +// +// EvtIoIoctl callback delegate +// +class FxIoQueueIoDeviceControl : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL Method; + + FxIoQueueIoDeviceControl( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request, + __in ULONG OutputBufferLength, + __in ULONG InputBufferLength, + __in ULONG IoControlCode + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method( + Queue, + Request, + OutputBufferLength, + InputBufferLength, + IoControlCode + ); + CallbackEnd(irql); + } + } +}; + +// +// EvtIoInternalIoctl callback delegate +// +class FxIoQueueIoInternalDeviceControl : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL Method; + + FxIoQueueIoInternalDeviceControl( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request, + __in ULONG OutputBufferLength, + __in ULONG InputBufferLength, + __in ULONG IoInternalControlCode + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method( + Queue, + Request, + OutputBufferLength, + InputBufferLength, + IoInternalControlCode + ); + CallbackEnd(irql); + } + } +}; + +// +// EvtIoQueueStatus callback delegate +// +class FxIoQueueIoState : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_STATE Method; + + FxIoQueueIoState( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFCONTEXT Context + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Context); + CallbackEnd(irql); + } + } +}; + +class FxIoQueueIoCanceledOnQueue : public FxLockedCallback { + +public: + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE Method; + + FxIoQueueIoCanceledOnQueue( + VOID + ) : + FxLockedCallback() + { + Method = NULL; + } + + void + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request + ) + { + if (Method != NULL) { + KIRQL irql = 0; + + CallbackStart(&irql); + Method(Queue, Request); + CallbackEnd(irql); + } + } +}; + + +class FxIoQueueForwardProgressAllocateResourcesReserved : public FxCallback { + +public: + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST Method; + + FxIoQueueForwardProgressAllocateResourcesReserved( + VOID + ) : + FxCallback() + { + Method = NULL; + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request + ) + { + ASSERT(Method != NULL); + return Method(Queue, Request); + } +}; + +class FxIoQueueForwardProgressAllocateResources : public FxCallback { + +public: + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES Method; + + FxIoQueueForwardProgressAllocateResources( + VOID + ) : + FxCallback() + { + Method = NULL; + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFQUEUE Queue, + __in WDFREQUEST Request + ) + { + ASSERT(Method != NULL); + return Method(Queue, Request); + } +}; + +class FxIoQueueForwardProgressExamineIrp : public FxCallback { +public: + PFN_WDF_IO_WDM_IRP_FOR_FORWARD_PROGRESS Method; + + FxIoQueueForwardProgressExamineIrp( + VOID + ) : + FxCallback() + { + Method = NULL; + } + + WDF_IO_FORWARD_PROGRESS_ACTION + Invoke( + __in WDFQUEUE Queue, + __in PIRP Irp + ) + { + ASSERT(Method != NULL); + return Method(Queue, Irp); + } +}; + + + +#endif // _FXIOQUEUECALLBACKS_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotarget.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotarget.hpp new file mode 100644 index 00000000000..af69d77113e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotarget.hpp @@ -0,0 +1,966 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxIoTarget.hpp + +Abstract: + + Encapsulation of the target to which FxRequest are sent to. For example, + an FxTarget could represent the next device object in the pnp stack. + Derivations from this class could include bus specific formatters or device + objects outside of the pnp stack of the device. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXIOTARGET_H_ +#define _FXIOTARGET_H_ + + +struct FxIoContext : public FxRequestContext { + + FxIoContext( + VOID + ); + + virtual + ~FxIoContext( + VOID + ); + + VOID + StoreAndReferenceOtherMemory( + __in FxRequestBuffer* Buffer + ) + { + _StoreAndReferenceMemoryWorker(this, &m_OtherMemory, Buffer); + } + + virtual + VOID + ReleaseAndRestore( + __in FxRequestBase* Request + ); + + VOID + ClearBuffer( + VOID + ); + + VOID + SetBufferAndLength( + __in PVOID Buffer, + __in size_t BufferLength, + __in BOOLEAN CopyBackToBuffer + ); + + VOID + CopyParameters( + __in FxRequestBase* Request + ); + + VOID + CaptureState( + __in FxIrp* Irp + ); + + VOID + SwapIrpBuffer( + _In_ FxRequestBase* Request, + _In_ ULONG NewInputBufferCb, + _In_reads_bytes_opt_(NewInputBufferCb) PVOID NewInputBuffer, + _In_ ULONG NewOutputBufferCb, + _In_reads_bytes_opt_(NewOutputBufferCb) PVOID NewOutputBuffer + ); + +public: + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + PVOID m_BufferToFree; + PVOID m_OriginalSystemBuffer; + PVOID m_OriginalUserBuffer; + PMDL m_MdlToFree; + union { + PMDL m_OriginalMdl; + PFX_DRIVER_GLOBALS m_DriverGlobals; + }; + + ULONG m_OriginalFlags; + + size_t m_BufferToFreeLength; + size_t m_MdlToFreeSize; + BOOLEAN m_CopyBackToBuffer; + BOOLEAN m_UnlockPages; +#else + // + // Captured state of the IRP before buffers are modified by Format + // + WUDFX_IRP_BUFFER_INFO m_OriginalBufferInfo; +#endif + + BOOLEAN m_RestoreState; + UCHAR m_MajorFunction; + IFxMemory* m_OtherMemory; +}; + +struct FxInternalIoctlOthersContext : public FxRequestContext { + + FxInternalIoctlOthersContext( + VOID + ) : + FxRequestContext(FX_RCT_INTERNAL_IOCTL_OTHERS) + { + RtlZeroMemory(&m_MemoryObjects[0], sizeof(m_MemoryObjects)); + } + + VOID + StoreAndReferenceOtherMemories( + __in FxRequestBuffer* Buffer1, + __in FxRequestBuffer* Buffer2, + __in FxRequestBuffer* Buffer4 + ) + { + StoreAndReferenceMemory(Buffer1); + _StoreAndReferenceMemoryWorker(this, &m_MemoryObjects[0], Buffer2); + _StoreAndReferenceMemoryWorker(this, &m_MemoryObjects[1], Buffer4); + } + + virtual + VOID + ReleaseAndRestore( + __in FxRequestBase* Request + ) + { + ULONG i; + + for (i = 0; + i < sizeof(m_MemoryObjects)/sizeof(m_MemoryObjects[0]); + i++) { + + if (m_MemoryObjects[i] != NULL) { + m_MemoryObjects[i]->RELEASE(this); + m_MemoryObjects[i] = NULL; + } + } + + __super::ReleaseAndRestore(Request); + } + +private: + virtual + VOID + StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ) + { + __super::StoreAndReferenceMemory(Buffer); + } + +public: + // + // __super has a field for one IFxMemory, so we don't need to store all + // 3 in the derivative, reuse the __super's field for one of them. + // + IFxMemory* m_MemoryObjects[FX_REQUEST_NUM_OTHER_PARAMS-1]; +}; + +struct FxTargetSubmitSyncParams { + // + // Event to set if the request is synchronous after the request has completed + // + FxCREvent SynchEvent; + + // + // Status of the request if it was synchronous + // + NTSTATUS Status; + + // + // Original completion routine to be called in the synchronous case + // + PFN_WDF_REQUEST_COMPLETION_ROUTINE OrigTargetCompletionRoutine; + + // + // Original completion context to be passed in the synchronous case + // + WDFCONTEXT OrigTargetCompletionContext; +}; + +enum SubmitActionFlags { + SubmitSend = 0x00000001, + SubmitQueued = 0x00000002, + SubmitSent = 0x00000004, + SubmitWait = 0x00000008, + SubmitTimeout = 0x00000010, + SubmitSyncCallCompletion = 0x00000020, +}; + +class FxIoTarget : public FxNonPagedObject { + + friend FxRequestBase; + +public: + + FxIoTarget( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize + ); + + FxIoTarget( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in WDFTYPE WdfType + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Start( + VOID + ); + + virtual + VOID + Stop( + __in WDF_IO_TARGET_SENT_IO_ACTION Action + ); + + virtual + VOID + Purge( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action + ); + + virtual + VOID + Remove( + VOID + ); + + // + // IFxObject override + // + NTSTATUS + _Must_inspect_result_ + QueryInterface( + __inout FxQueryInterfaceParams* Params + ); + + __inline + WDF_IO_TARGET_STATE + GetState( + VOID + ) + { + return m_State; + } + + __inline + MdDeviceObject + GetTargetDevice( + VOID + ) + { + return m_TargetDevice; + } + + __inline + MdDeviceObject + GetTargetPDO( + VOID + ) + { + return m_TargetPdo; + } + + __inline + MdFileObject + GetTargetFileObject( + VOID + ) + { + return m_TargetFileObject; + } + + __inline + WDFDEVICE + GetDeviceHandle( + VOID + ) + { + return m_Device->GetHandle(); + } + + WDFIOTARGET + GetHandle( + VOID + ) + { + return (WDFIOTARGET) GetObjectHandle(); + } + + __inline + FxDriver* + GetDriver( + VOID + ) + { + return m_Driver; + } + + virtual + _Must_inspect_result_ + MdDeviceObject + GetTargetDeviceObject( + _In_ CfxDeviceBase* Device + ) + { + return Device->GetAttachedDevice(); + } + + _Must_inspect_result_ + NTSTATUS + Init( + __in CfxDeviceBase* Device + ); + + ULONG + Submit( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options, + __in_opt ULONG Flags + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifySubmitLocked, + _In_ FxRequestBase* + ); + + ULONG + SubmitLocked( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options, + __in ULONG Flags + ); + + _Must_inspect_result_ + NTSTATUS + SubmitSync( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options = NULL, + __out_opt PULONG Action = NULL + ); + + VOID + TimerCallback( + __in FxRequestBase* Request + ); + + VOID + CompleteCanceledRequest( + __in FxRequestBase* Request + ); + + VOID + SubmitPendedRequest( + __in FxRequestBase* Request + ); + + VOID + CompletePendedRequest( + __in FxRequestBase* Request + ); + + static + VOID + _CancelSentRequest( + __in FxRequestBase* Request + ); + + BOOLEAN + __inline + HasEnoughStackLocations( + __in FxIrp* Irp + ) + { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // Check to make sure there are enough current stack locations available. + // When a IRP is initially created, Irp->CurrentLocation is set to + // StackSize + 1. When comparing against the target device, subtract + // off the extra space to see how many locations are left. + // + // Say Target->m_TargetStackSize == 1, then: + // irp = IoAllocateIrp(Target->m_TargetStackSize, FALSE); + // ASSERT(irp->CurrentLocation == 2); + // + return (Irp->GetCurrentIrpStackLocationIndex() - 1 >= m_TargetStackSize) ? TRUE : FALSE; +#else // FX_CORE_USER_MODE + // + // For UMDF, host does the necessary checks to ensure there are enough + // stack locations. In addition, UMDF drivers can't create WDM IRPs + // so they don't get to dictate the number of stack locations in the irp + // so this kind of check in framework for UMDF is redundant. Return TRUE + // always. + // + return TRUE; +#endif + } + + _Must_inspect_result_ + NTSTATUS + FormatIoRequest( + __inout FxRequestBase* Request, + __in UCHAR MajorCode, + __in FxRequestBuffer* IoBuffer, + __in_opt PLONGLONG StartingOffset, + __in_opt FxFileObject* FileObject = NULL + ); + + _Must_inspect_result_ + NTSTATUS + FormatIoctlRequest( + __in FxRequestBase* Request, + __in ULONG Ioctl, + __in BOOLEAN Internal, + __in FxRequestBuffer* InputBuffer, + __in FxRequestBuffer* OutputBuffer, + __in_opt FxFileObject* FileObject = NULL + ); + + _Must_inspect_result_ + NTSTATUS + FormatInternalIoctlOthersRequest( + __in FxRequestBase* Request, + __in ULONG Ioctl, + __in FxRequestBuffer* Buffers + ); + + static + FxIoTarget* + _FromEntry( + __in FxTransactionedEntry* Entry + ) + { + return CONTAINING_RECORD(Entry, FxIoTarget, m_TransactionedEntry); + } + + VOID + CancelSentIo( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + SubmitSyncRequestIgnoreTargetState( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + + VOID + UpdateTargetIoType( + VOID + ); + + BOOLEAN + HasValidStackSize( + VOID + ); + + virtual + VOID + Send( + _In_ MdIrp Irp + ); + +protected: + // + // Hide destructor since we are reference counted object + // + ~FxIoTarget(); + + _Must_inspect_result_ + NTSTATUS + InitModeSpecific( + __in CfxDeviceBase* Device + ); + + // FxObject overrides + virtual + BOOLEAN + Dispose( + VOID + ); + // FxObject overrides + + VOID + FailPendedRequest( + __in FxRequestBase* Request, + __in NTSTATUS Status + ); + + VOID + DrainPendedRequestsLocked( + __in PLIST_ENTRY RequestListHead, + __in BOOLEAN RequestWillBeResent + ); + + VOID + CompletePendedRequestList( + __in PLIST_ENTRY RequestListHead + ); + + VOID + SubmitPendedRequests( + __in PLIST_ENTRY RequestListHeadHead + ); + + VOID + GetSentRequestsListLocked( + __in PSINGLE_LIST_ENTRY RequestListHead, + __in PLIST_ENTRY SendList, + __out PBOOLEAN AddedToList + ); + + static + VOID + _CancelSentRequests( + __in PSINGLE_LIST_ENTRY RequestListHead + ); + + virtual + _Must_inspect_result_ + NTSTATUS + GotoStartState( + __in PLIST_ENTRY RequestListHead, + __in BOOLEAN Lock = TRUE + ); + + virtual + VOID + GotoStopState( + __in WDF_IO_TARGET_SENT_IO_ACTION Action, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ); + + virtual + VOID + GotoPurgeState( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ); + + _Must_inspect_result_ + NTSTATUS + PendRequestLocked( + __in FxRequestBase* Request + ); + + __inline + VOID + CompleteRequest( + __in FxRequestBase* Request + ) + { + // + // This will remove the reference taken by this object on the request + // + Request->CompleteSubmitted(); + } + + // + // Completion routine to handle the case when re-submitting a pended + // request fails. + // + VOID + HandleFailedResubmit( + __in FxRequestBase* Request + ); + + // + // Generic I/O completion routine and its static caller. + // + VOID + RequestCompletionRoutine( + __in FxRequestBase* Request + ); + + static + MdCompletionRoutineType + _RequestCompletionRoutine; + + BOOLEAN + RemoveCompletedRequestLocked( + __in FxRequestBase* Request + ); + + virtual + VOID + ClearTargetPointers( + VOID + ) + { + m_TargetDevice = NULL; + m_TargetPdo = NULL; + m_TargetFileObject = NULL; + + m_TargetStackSize = 0; + m_TargetIoType = WdfDeviceIoUndefined; + } + + UCHAR + GetTargetIoType( + VOID + ) + { + ULONG flags; + MxDeviceObject deviceObject(m_TargetDevice); + + flags = deviceObject.GetFlags(); + + if (flags & DO_BUFFERED_IO) { + return WdfDeviceIoBuffered; + } + else if (flags & DO_DIRECT_IO) { + return WdfDeviceIoDirect; + } + else { + return WdfDeviceIoNeither; + } + } + + static + VOID + _RequestCancelled( + __in FxIrpQueue* Queue, + __in MdIrp Irp, + __in PMdIoCsqIrpContext pCsqContext, + __in KIRQL CallerIrql + ); + + static + EVT_WDF_REQUEST_COMPLETION_ROUTINE + _SyncCompletionRoutine; + + virtual + VOID + GotoRemoveState( + __in WDF_IO_TARGET_STATE NewState, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __in BOOLEAN Lock, + __out PBOOLEAN Wait + ); + + virtual + VOID + WaitForSentIoToComplete( + VOID + ) + { + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + m_SentIoEvent.EnterCRAndWaitAndLeave(); + } + + virtual + VOID + WaitForDisposeEvent( + VOID + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + //Making it a virtual function so that derived classes can override it + //For example, CWdfIoTargetLocal overrides it to set the file object + //before forwarding the request + // + virtual + VOID + Forward( + __in MdIrp Irp + ) + { + // + // Ignore the return value because once we have sent the request, we + // want all processing to be done in the completion routine. + // + (void) Irp->Forward(); + } +#endif + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + __inline + VOID + CopyFileObjectAndFlags( + __in FxRequestBase* Request + ) + { + FxIrp* irp = Request->GetSubmitFxIrp(); + + if (Request->IsAllocatedFromIo()) { + irp->SetNextStackFlags(irp->GetCurrentStackFlags()); + irp->SetNextStackFileObject(irp->GetCurrentStackFileObject()); + } + + // + // Use the target's fileobject if present, otherwise use the current + // stack location's fileobject (if there is a current stack location). + // + if (m_InStack == FALSE) { + irp->SetNextStackFileObject(m_TargetFileObject); + } + } + + + + __inline + VOID + IncrementIoCount( + VOID + ) + { + LONG ret; + + ret = InterlockedIncrement(&m_IoCount); + +#if DBG + ASSERT(ret > 1); +#else + UNREFERENCED_PARAMETER(ret); +#endif + } + + + __inline + VOID + DecrementIoCount( + VOID + ) + { + LONG ret; + + ret = InterlockedDecrement(&m_IoCount); + ASSERT(ret >= 0); + + if (ret == 0) { + PrintDisposeMessage(); + ASSERT(m_DisposeEvent != NULL); + m_DisposeEvent->Set(); + } + } + + VOID + PrintDisposeMessage( + VOID + ); + +private: + + VOID + Construct( + VOID + ); + + VOID + ClearCompletedRequestVerifierFlags( + __in FxRequestBase* Request + ) + { + if (GetDriverGlobals()->FxVerifierOn && + GetDriverGlobals()->FxVerifierIO) { + KIRQL irql; + + Request->Lock(&irql); + // + // IF we are completing a request that was pended in the target, + // this flag was not set. + // + // ASSERT(Request->GetVerifierFlagsLocked() & FXREQUEST_FLAG_SENT_TO_TARGET); + Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_SENT_TO_TARGET); + Request->Unlock(irql); + } + } + + VOID + SetCompletionRoutine( + __in FxRequestBase* Request + ) + { + FxIrp* irp = Request->GetSubmitFxIrp(); + + irp->SetCompletionRoutineEx( + m_InStackDevice, + _RequestCompletionRoutine, + Request, + TRUE, + TRUE, + TRUE); + } + +public: + // + // Transaction entry for FxDevice to queue this target on + // + FxTransactionedEntry m_TransactionedEntry; + + BOOLEAN m_InStack; + + // + // TRUE when FxDevice::AddIoTarget has been called + // + BOOLEAN m_AddedToDeviceList; + + static const PVOID m_SentRequestTag; + +protected: + // + // List of requests that have been sent to the target + // + LIST_ENTRY m_SentIoListHead; + + // + // List of requests which were sent ignoring the state of the target + // + LIST_ENTRY m_IgnoredIoListHead; + + // + // Event used to wait for sent I/O to complete + // + FxCREvent m_SentIoEvent; + + // + // Event used to wait by Dispose to make sure all I/O's are completed. + // This is required to make sure that all the I/O are completed before + // disposing the target. This acts like remlock. + // + FxCREvent *m_DisposeEvent; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // Eventy initialization can fail in user-mode so we define one as + // part of object. + // + FxCREvent m_DisposeEventUm; +#endif + + FxIrpQueue m_PendedQueue; + + // + // Back link to the object that represents our devobj + // + FxDriver* m_Driver; + + // + // The PDEVICE_OBJECT that is owned by m_Device + // + MdDeviceObject m_InStackDevice; + + // + // The device object which is our "target" + // + MdDeviceObject m_TargetDevice; + + // + // The PDO for m_TargetDevice. For this class, it would be the same PDO + // as the owning WDFDEVICE. In a derived class (like FxIoTargetRemote), + // this would not be the PDO of the owning WDFDEVICE, rather the PDO for + // the other stack. + // + MdDeviceObject m_TargetPdo; + + // + // File object that is attached to all I/O sent to m_TargetDevice + // + MdFileObject m_TargetFileObject; + + // + // Current state + // + WDF_IO_TARGET_STATE m_State; + + // + // This is used to track the I/O's sent to the lower driver + // and is used to make sure all I/Os are completed before disposing the + // Iotarget. + // + LONG m_IoCount; + + // + // Cached value of m_TargetDevice->StackSize. The value is cached so that + // we can still format to the target during query remove transitions. + // + CCHAR m_TargetStackSize; + + // + // Cached value of m_TargetDevice->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO) + // which uses WDF_DEVICE_IO_TYPE to indicate state. + // + UCHAR m_TargetIoType; + + // + // TRUE if we are in the processing of stopping/purging and there are + // requests that have been sent and must be waited upon for completion. + // + BOOLEAN m_WaitingForSentIo; + + BOOLEAN m_Removing; + +}; + + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#include "FxIoTargetKm.hpp" +#else if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#include "FxIoTargetUm.hpp" +#endif + +#endif //_FXIOTARGET_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotargetremote.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotargetremote.hpp new file mode 100644 index 00000000000..c2010ca6ebb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotargetremote.hpp @@ -0,0 +1,440 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxIoTargetRemote.hpp + +Abstract: + + Derivation of FxIoTarget specializing in targets remote to this device + stack. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXIOTARGETREMOTE_H_ +#define _FXIOTARGETREMOTE_H_ + +enum FxIoTargetRemoteCloseReason { + FxIoTargetRemoteCloseReasonQueryRemove = 1, + FxIoTargetRemoteCloseReasonPlainClose, + FxIoTargetRemoteCloseReasonDelete +}; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +typedef PVOID MdTargetNotifyHandle; +#else +typedef WUDF_TARGET_CONTEXT MdTargetNotifyHandle; +#endif + +class FxIoTargetRemoteNotificationCallback; + +struct FxIoTargetQueryRemove : public FxCallback { + + FxIoTargetQueryRemove( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFIOTARGET IoTarget + ) + { + NTSTATUS status; + + CallbackStart(); + status = m_Method(IoTarget); + CallbackEnd(); + + return status; + } + + PFN_WDF_IO_TARGET_QUERY_REMOVE m_Method; +}; + +struct FxIoTargetRemoveCanceled : public FxCallback { + + FxIoTargetRemoveCanceled( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFIOTARGET Target + ) + { + CallbackStart(); + m_Method(Target); + CallbackEnd(); + } + + PFN_WDF_IO_TARGET_REMOVE_CANCELED m_Method; +}; + +struct FxIoTargetRemoveComplete : public FxCallback { + + FxIoTargetRemoveComplete( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFIOTARGET Target + ) + { + CallbackStart(); + m_Method(Target); + CallbackEnd(); + } + + PFN_WDF_IO_TARGET_REMOVE_COMPLETE m_Method; +}; + +enum FxIoTargetRemoteOpenState { + FxIoTargetRemoteOpenStateClosed = 1, + FxIoTargetRemoteOpenStateOpening, + FxIoTargetRemoteOpenStateOpen, +}; + +struct FxIoTargetRemoveOpenParams { + + FxIoTargetRemoveOpenParams() + { + RtlZeroMemory(this, sizeof(FxIoTargetRemoveOpenParams)); + } + + VOID + Set( + __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams, + __in PUNICODE_STRING Name, + __in PVOID Ea, + __in ULONG EaLength + ); + + VOID + Clear( + VOID + ); + + UNICODE_STRING TargetDeviceName; + + WDF_IO_TARGET_OPEN_TYPE OpenType; + + ACCESS_MASK DesiredAccess; + + ULONG ShareAccess; + + ULONG FileAttributes; + + ULONG CreateDisposition; + + ULONG CreateOptions; + + __field_bcount(EaBufferLength) PVOID EaBuffer; + + ULONG EaBufferLength; + + LARGE_INTEGER AllocationSize; + + PLARGE_INTEGER AllocationSizePointer; + +}; + +struct FxIoTargetClearedPointers { + MdDeviceObject TargetPdo; + MdFileObject TargetFileObject; + HANDLE TargetHandle; +}; + +class FxIoTargetRemote : public FxIoTarget { + +public: + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxDeviceBase* Device, + __out FxIoTargetRemote** Target + ); + + ~FxIoTargetRemote(); + + NTSTATUS + InitRemote( + __in FxDeviceBase* Device + ); + + NTSTATUS + InitRemoteModeSpecific( + __in FxDeviceBase* Device + ); + + _Must_inspect_result_ + NTSTATUS + Open( + __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ); + + VOID + Close( + __in FxIoTargetRemoteCloseReason Reason + ); + + NTSTATUS + GetTargetDeviceRelations( + _Out_ BOOLEAN* Close + ); + + BOOLEAN + CanRegisterForPnpNotification( + VOID + ) + { + BOOLEAN canRegister = FALSE; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (m_TargetFileObject != NULL) { + canRegister = TRUE; + } +#else // FX_CORE_USER_MODE + if (m_TargetHandle != NULL) { + canRegister = TRUE; + } +#endif + return canRegister; + } + + VOID + ResetTargetNotifyHandle( + VOID + ) + { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_TargetNotifyHandle = NULL; +#else // FX_CORE_USER_MODE + m_TargetNotifyHandle = WUDF_TARGET_CONTEXT_INVALID; +#endif + } + + NTSTATUS + OpenTargetHandle( + _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams, + _Inout_ FxIoTargetRemoveOpenParams* pParams + ); + + VOID + CloseTargetHandle( + VOID + ); + + HANDLE + GetTargetHandle( + VOID + ); + + NTSTATUS + RegisterForPnpNotification( + VOID + ); + + VOID + UnregisterForPnpNotification( + _In_ MdTargetNotifyHandle Handle + ); + + __inline + WDFIOTARGET + GetHandle( + VOID + ) + { + return (WDFIOTARGET) GetObjectHandle(); + } + + virtual + VOID + Remove( + VOID + ); + + VOID + RemoveModeSpecific( + VOID + ); + +protected: + FxIoTargetRemote( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + VOID + ClearTargetPointers( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ) + { + if (Params->Type == FX_TYPE_IO_TARGET_REMOTE) { + *Params->Object = (FxIoTargetRemote*) this; + return STATUS_SUCCESS; + } + else { + return __super::QueryInterface(Params); + } + } + + _Must_inspect_result_ + NTSTATUS + FxIoTargetRemote::OpenLocalTargetByFile( + _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + static + DRIVER_NOTIFICATION_CALLBACK_ROUTINE + _PlugPlayNotification; + +#else // FX_CORE_USER_MODE + // + // I/O dispatcher to be used for IRPs forwarded to this remote target. It is + // created when the CWdfRemoteTarget is created. The win32 handle is + // associated with it via a call to m_pRemoteDispatcher->BindToHandle() + // right after we call CreateFile(...). We must call + // m_pRemoteDispatcher->CloseHandle() to close the handle. + // + // Because of the plug-in pattern of the IoDispatcher, we need two + // interface pointers (one to the outer object, and one to the plug-in. + // + IWudfIoDispatcher * m_pIoDispatcher; + IWudfRemoteDispatcher * m_pRemoteDispatcher; + + // + // Implements host's callback interface for pnp notification + // + FxIoTargetRemoteNotificationCallback* m_NotificationCallback; + + VOID + Forward( + _In_ MdIrp Irp + ) + { + if (m_OpenParams.OpenType == WdfIoTargetOpenLocalTargetByFile) { + // + // Ignore the return value because once we have sent the request, we + // want all processing to be done in the completion routine. + // + (void) Irp->Forward(); + } + else { + IWudfIoIrp* pSubmitIrp = FxIrp(Irp).GetIoIrp(); + + // + // Move the stack location to the next location + // + pSubmitIrp->SetNextIrpStackLocation(); + + // + // Route it using Remote dispatcher + // + m_pIoDispatcher->Dispatch(pSubmitIrp, NULL); + } + } + +private: + + NTSTATUS + BindToHandle( + VOID + ); + + VOID + UnbindHandle( + _In_ FxIoTargetClearedPointers* TargetPointers + ); + + NTSTATUS + CreateWdfFileObject( + _In_opt_ PUNICODE_STRING FileName, + _Out_ MdFileObject* FileObject + ); + + VOID + CloseWdfFileObject( + _In_ MdFileObject FileObject + ); + +#endif // FX_CORE_USER-MODE) + +public: + // + // File handle for m_TargetHandle + // + HANDLE m_TargetHandle; + + // + // Notification handle returned by IoRegisterPlugPlayNotification for KMDF, + // or host's notification registartion interface for UMDf. Note that host + // uses the term RegistrationId for the same (with WUDF_CONTEXT_TYPE which + // is UINT64). + // + MdTargetNotifyHandle m_TargetNotifyHandle; + + // + // Driver writer callbacks to indicate state changes + // + FxIoTargetQueryRemove m_EvtQueryRemove; + FxIoTargetRemoveCanceled m_EvtRemoveCanceled; + FxIoTargetRemoveComplete m_EvtRemoveComplete; + + FxCREvent m_OpenedEvent; + + FxIoTargetClearedPointers* m_ClearedPointers; + + // + // Value from FxIoTargetRemoteOpenState + // + UCHAR m_OpenState; + +protected: + FxIoTargetRemoveOpenParams m_OpenParams; +}; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#include "FxIoTargetRemoteKm.hpp" +#else +#include "FxIoTargetRemoteUm.hpp" +#endif + +#endif // _FXIOTARGETREMOTE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotargetself.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotargetself.hpp new file mode 100644 index 00000000000..081771cf2a9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxiotargetself.hpp @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxIoTargetSelf.hpp + +Abstract: + + Encapsulation of the Self target to which FxRequest are sent to. + FxSelfTarget represents the client itself and is used to send IO to + itself. + + Unlike the the local and remote targets, the IO sent to an Self IO + target is routed to the sender's own top level queues. A dedicated queue + may also be configured as the target for requests dispatched to the Self + Io targets. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXIOTARGETSELF_H_ +#define _FXIOTARGETSELF_H_ + +class FxIoTargetSelf : public FxIoTarget { + +public: + + FxIoTargetSelf( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ USHORT ObjectSize + ); + + virtual + _Must_inspect_result_ + MdDeviceObject + GetTargetDeviceObject( + _In_ CfxDeviceBase* Device + ) + /*++ + Routine Description: + Returns the target device object of the Device. In case of an Self + Io Target it is the device itself. + + Arguments: + + Device - Handle to the Device Object + + Returns: + + MdDeviceObject for the Device. + + --*/ + { + return Device->GetDeviceObject(); + } + + FxIoQueue* + GetDispatchQueue( + _In_ UCHAR MajorFunction + ); + + VOID + SetDispatchQueue( + _In_ FxIoQueue* DispatchQueue + ) + /*++ + Routine Description: + Sets a disapatch queue for the IO send to the Self IO Target. + --*/ + { + ASSERT(m_DispatchQueue == NULL); + m_DispatchQueue = DispatchQueue; + } + + virtual + VOID + Send( + _In_ MdIrp Irp + ); + +protected: + // + // Hide destructor since we are reference counted object + // + ~FxIoTargetSelf(); + +private: + + // + // A Queue configured to dispatch IO sent to the Self IO Target. + // + FxIoQueue* m_DispatchQueue; + +}; + +#endif //_FXIOTARGETSELF_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxirp.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirp.hpp new file mode 100644 index 00000000000..d8cf80a88f4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirp.hpp @@ -0,0 +1,844 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIrp.hpp + +Abstract: + + This module implements a class for handling irps. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + // A function for when not assigning + + MdIrp + GetIrp( + VOID + ); + + + VOID + CompleteRequest( + __in_opt CCHAR PriorityBoost=IO_NO_INCREMENT + ); + + + NTSTATUS + CallDriver( + __in MdDeviceObject DeviceObject + ); + + + + + + + + NTSTATUS + PoCallDriver( + __in MdDeviceObject DeviceObject + ); + + + VOID + StartNextPowerIrp( + ); + + MdCompletionRoutine + GetNextCompletionRoutine( + VOID + ); + + VOID + SetCompletionRoutine( + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess = TRUE, + __in BOOLEAN InvokeOnError = TRUE, + __in BOOLEAN InvokeOnCancel = TRUE + ); + + VOID + SetCompletionRoutineEx( + __in MdDeviceObject DeviceObject, + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess = TRUE, + __in BOOLEAN InvokeOnError = TRUE, + __in BOOLEAN InvokeOnCancel = TRUE + ); + + MdCancelRoutine + SetCancelRoutine( + __in_opt MdCancelRoutine CancelRoutine + ); + + // + // SendIrpSynchronously achieves synchronous behavior by waiting on an + // event after submitting the IRP. The event creation can fail in UM, but + // not in KM. Hence, in UM the return code could either indicate event + // creation failure or it could indicate the status set on the IRP by the + // lower driver. In KM, the return code only indicates the status set on + // the IRP by the lower lower, because event creation cannot fail. + // + CHECK_RETURN_IF_USER_MODE + NTSTATUS + SendIrpSynchronously( + __in MdDeviceObject DeviceObject + ); + + + VOID + CopyCurrentIrpStackLocationToNext( + VOID + ); + + VOID + CopyToNextIrpStackLocation( + __in PIO_STACK_LOCATION Stack + ); + + VOID + SetNextIrpStackLocation( + VOID + ); + + UCHAR + GetMajorFunction( + VOID + ); + + UCHAR + GetMinorFunction( + VOID + ); + + UCHAR + GetCurrentStackFlags( + VOID + ); + + MdFileObject + GetCurrentStackFileObject( + VOID + ); + + KPROCESSOR_MODE + GetRequestorMode( + VOID + ); + + VOID + SetContext( + __in ULONG Index, + __in PVOID Value + ); + + VOID + SetSystemBuffer( + __in PVOID Value + ); + + VOID + SetUserBuffer( + __in PVOID Value + ); + + VOID + SetMdlAddress( + __in PMDL Value + ); + + VOID + SetFlags( + __in ULONG Flags + ); + + PVOID + GetContext( + __in ULONG Index + ); + + ULONG + GetFlags( + VOID + ); + + PIO_STACK_LOCATION + GetCurrentIrpStackLocation( + VOID + ); + + + PIO_STACK_LOCATION + GetNextIrpStackLocation( + VOID + ); + + static + PIO_STACK_LOCATION + _GetAndClearNextStackLocation( + __in MdIrp Irp + ); + + + VOID + SkipCurrentIrpStackLocation( + VOID + ); + + + VOID + MarkIrpPending( + ); + + + BOOLEAN + PendingReturned( + ); + + + VOID + PropagatePendingReturned( + VOID + ); + + + VOID + SetStatus( + __in NTSTATUS Status + ); + + + NTSTATUS + GetStatus( + ); + + + BOOLEAN + Cancel( + VOID + ); + + VOID + SetCancel( + __in BOOLEAN Cancel + ); + + + BOOLEAN + IsCanceled( + ); + + + KIRQL + GetCancelIrql( + ); + + + VOID + SetInformation( + __in ULONG_PTR Information + ); + + + ULONG_PTR + GetInformation( + ); + + + CCHAR + GetCurrentIrpStackLocationIndex( + ); + + CCHAR + GetStackCount( + ); + + PLIST_ENTRY + ListEntry( + ); + + + PVOID + GetSystemBuffer( + ); + + PVOID + GetOutputBuffer( + ); + + PMDL + GetMdl( + ); + + PMDL* + GetMdlAddressPointer( + ); + + PVOID + GetUserBuffer( + ); + + VOID + Reuse( + __in NTSTATUS Status = STATUS_SUCCESS + ); + + // + // Methods for IO_STACK_LOCATION members + // + + VOID + SetMajorFunction( + __in UCHAR MajorFunction + ); + + + VOID + SetMinorFunction( + __in UCHAR MinorFunction + ); + + // + // Get Methods for IO_STACK_LOCATION.Parameters.Power + // + + SYSTEM_POWER_STATE_CONTEXT + GetParameterPowerSystemPowerStateContext( + ); + + + POWER_STATE_TYPE + GetParameterPowerType( + ); + + POWER_STATE + GetParameterPowerState( + ); + + + DEVICE_POWER_STATE + GetParameterPowerStateDeviceState( + ); + + + SYSTEM_POWER_STATE + GetParameterPowerStateSystemState( + ); + + + POWER_ACTION + GetParameterPowerShutdownType( + ); + + + MdFileObject + GetFileObject( + VOID + ); + + + // + // Get/Set Method for IO_STACK_LOCATION.Parameters.QueryDeviceRelations + // + + DEVICE_RELATION_TYPE + GetParameterQDRType( + ); + + VOID + SetParameterQDRType( + __in DEVICE_RELATION_TYPE DeviceRelation + ); + + // + // Get/Set Methods for IO_STACK_LOCATION.Parameters.DeviceCapabilities + // + + PDEVICE_CAPABILITIES + GetParameterDeviceCapabilities( + ); + + VOID + SetCurrentDeviceObject( + __in MdDeviceObject DeviceObject + ); + + MdDeviceObject + GetDeviceObject( + VOID + ); + + VOID + SetParameterDeviceCapabilities( + __in PDEVICE_CAPABILITIES DeviceCapabilities + ); + + + // + // Get/Set Methods for IO_STACK_LOCATION.Parameters.Write.ByteOffset.QuadPart + // + + LONGLONG + GetParameterWriteByteOffsetQuadPart( + ); + + + VOID + SetNextParameterWriteByteOffsetQuadPart( + __in LONGLONG DeviceOffset + ); + + // + // Get/Set Methods for IO_STACK_LOCATION.Parameters.Write.Length + // + + ULONG + GetCurrentParameterWriteLength( + ); + + VOID + SetNextParameterWriteLength( + __in ULONG IoLength + ); + + PVOID* + GetNextStackParameterOthersArgument1Pointer( + ); + + VOID + SetNextStackParameterOthersArgument1( + __in PVOID Argument1 + ); + + PVOID* + GetNextStackParameterOthersArgument2Pointer( + ); + + PVOID* + GetNextStackParameterOthersArgument4Pointer( + ); + + // + // Get/Set Methods for IO_STACK_LOCATION.Parameters.StartDevice + // + + PCM_RESOURCE_LIST + GetParameterAllocatedResources( + ); + + + VOID + SetParameterAllocatedResources( + __in PCM_RESOURCE_LIST AllocatedResources + ); + + + PCM_RESOURCE_LIST + GetParameterAllocatedResourcesTranslated( + ); + + + VOID + SetParameterAllocatedResourcesTranslated( + __in PCM_RESOURCE_LIST AllocatedResourcesTranslated + ); + + // + // Get Method for IO_STACK_LOCATION.Parameters.QueryDeviceText + // + + LCID + GetParameterQueryDeviceTextLocaleId( + ); + + + DEVICE_TEXT_TYPE + GetParameterQueryDeviceTextType( + ); + + // + // Get Method for IO_STACK_LOCATION.Parameters.SetLock + // + + BOOLEAN + GetParameterSetLockLock( + ); + + // + // Get Method for IO_STACK_LOCATION.Parameters.QueryId + // + + BUS_QUERY_ID_TYPE + GetParameterQueryIdType( + ); + + // + // Get/Set Methods for IO_STACK_LOCATION.Parameters.QueryInterface + // + + PINTERFACE + GetParameterQueryInterfaceInterface( + ); + + + const GUID* + GetParameterQueryInterfaceType( + ); + + + USHORT + GetParameterQueryInterfaceVersion( + ); + + + USHORT + GetParameterQueryInterfaceSize( + ); + + + PVOID + GetParameterQueryInterfaceInterfaceSpecificData( + ); + + VOID + SetParameterQueryInterfaceInterface( + __in PINTERFACE Interface + ); + + VOID + SetParameterQueryInterfaceType( + __in const GUID* InterfaceType + ); + + VOID + SetParameterQueryInterfaceVersion( + __in USHORT Version + ); + + VOID + SetParameterQueryInterfaceSize( + __in USHORT Size + ); + + VOID + SetParameterQueryInterfaceInterfaceSpecificData( + __in PVOID InterfaceSpecificData + ); + + // + // Get Method for IO_STACK_LOCATION.Parameters.UsageNotification + // + + DEVICE_USAGE_NOTIFICATION_TYPE + GetParameterUsageNotificationType( + ); + + + BOOLEAN + GetParameterUsageNotificationInPath( + ); + + + VOID + SetParameterUsageNotificationInPath( + __in BOOLEAN InPath + ); + + + BOOLEAN + GetNextStackParameterUsageNotificationInPath( + ); + + ULONG + GetParameterIoctlCode( + VOID + ); + + ULONG + GetParameterIoctlCodeBufferMethod( + VOID + ); + + ULONG + GetParameterIoctlInputBufferLength( + VOID + ); + + ULONG + GetParameterIoctlOutputBufferLength( + VOID + ); + + PVOID + GetParameterIoctlType3InputBuffer( + VOID + ); + + // + // Set Methods for IO_STACK_LOCATION.Parameters.DeviceControl members + // + + VOID + SetParameterIoctlCode( + __in ULONG DeviceIoControlCode + ); + + VOID + SetParameterIoctlInputBufferLength( + __in ULONG InputBufferLength + ); + + VOID + SetParameterIoctlOutputBufferLength( + __in ULONG OutputBufferLength + ); + + VOID + SetParameterIoctlType3InputBuffer( + __in PVOID Type3InputBuffer + ); + + ULONG + GetParameterReadLength( + VOID + ); + + ULONG + GetParameterWriteLength( + VOID + ); + + VOID + SetNextStackFlags( + __in UCHAR Flags + ); + + VOID + SetNextStackFileObject( + _In_ MdFileObject FileObject + ); + + PVOID + GetCurrentParametersPointer( + VOID + ); + + // + // Methods for IO_STACK_LOCATION + // + + VOID + ClearNextStack( + VOID + ); + + VOID + ClearNextStackLocation( + VOID + ); + + VOID + InitNextStackUsingStack( + __in FxIrp* Irp + ); + + ULONG + GetCurrentFlags( + VOID + ); + + VOID + FreeIrp( + VOID + ); + + MdEThread + GetThread( + VOID + ); + + BOOLEAN + Is32bitProcess( + VOID + ); + +private: + + static + NTSTATUS + _IrpSynchronousCompletion( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in PVOID Context + ); + +public: + + _Must_inspect_result_ + static + MdIrp + AllocateIrp( + _In_ CCHAR StackSize, + _In_opt_ FxDevice* Device = NULL + ); + + static + MdIrp + GetIrpFromListEntry( + __in PLIST_ENTRY Ple + ); + + _Must_inspect_result_ + static + NTSTATUS + RequestPowerIrp( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in MdRequestPowerComplete CompletionFunction, + __in PVOID Context + ); + + PIO_STATUS_BLOCK + GetStatusBlock( + VOID + ); + + PVOID + GetDriverContext( + ); + + ULONG + GetDriverContextSize( + ); + + VOID + CopyParameters( + _Out_ PWDF_REQUEST_PARAMETERS Parameters + ); + + VOID + CopyStatus( + _Out_ PIO_STATUS_BLOCK StatusBlock + ); + + BOOLEAN + HasStack( + _In_ UCHAR StackCount + ); + + BOOLEAN + IsCurrentIrpStackLocationValid( + VOID + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + IWudfIoIrp* + GetIoIrp( + VOID + ); + + IWudfPnpIrp* + GetPnpIrp( + VOID + ); +#endif + +}; + +// +// FxAutoIrp adds value to FxIrp by automatically freeing the associated MdIrp +// when it goes out of scope +// +struct FxAutoIrp : public FxIrp { + + FxAutoIrp( + __in_opt MdIrp Irp = NULL + ) : + FxIrp(Irp) + { + } + + + ~FxAutoIrp(); +}; + +#endif // _FXIRP_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxirpdynamicdispatchinfo.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirpdynamicdispatchinfo.hpp new file mode 100644 index 00000000000..68eef8c82b8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirpdynamicdispatchinfo.hpp @@ -0,0 +1,94 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXIRPDYNAMICDISPATCHINFO_H_ +#define _FXIRPDYNAMICDISPATCHINFO_H_ + +// +// Placeholder macro for a no-op +// +#ifndef DO_NOTHING +#define DO_NOTHING() (0) +#endif + +struct FxIrpDynamicDispatchInfo : public FxStump { + FxIrpDynamicDispatchInfo() : + CxDeviceInfo(NULL) + { + InitializeListHead(&ListEntry); + RtlZeroMemory(Dispatch, sizeof(Dispatch)); + } + + ~FxIrpDynamicDispatchInfo() + { + ASSERT(IsListEmpty(&ListEntry)); + } + + enum DynamicDispatchType { + DynamicDispatchRead = 0, + DynamicDispatchWrite = 1, + DynamicDispatchIoctl = 2, + DynamicDispatchInternalIoctl = 3, + DynamicDispatchMax + }; + + struct Info { + Info() : + EvtDeviceDynamicDispatch(NULL), + DriverContext(NULL) + { + } + + ~Info() + { + DO_NOTHING(); + } + + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceDynamicDispatch; + WDFCONTEXT DriverContext; + }; + + __inline + static + int + Mj2Index( + UCHAR MajorFunction + ) + { + DynamicDispatchType type; + + switch (MajorFunction) { + case IRP_MJ_READ: + type = DynamicDispatchRead; + break; + + case IRP_MJ_WRITE: + type = DynamicDispatchWrite; + break; + + case IRP_MJ_DEVICE_CONTROL: + type = DynamicDispatchIoctl; + break; + + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + type = DynamicDispatchInternalIoctl; + break; + + default: + type = DynamicDispatchMax; + break; + } + + return (int)type; + } + + LIST_ENTRY ListEntry; + Info Dispatch[DynamicDispatchMax]; + + // + // If not null, weak ref to class extension info struct. + // + FxCxDeviceInfo* CxDeviceInfo; +}; + +#endif // _FXIRPDYNAMICDISPATCHINFO_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxirppreprocessinfo.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirppreprocessinfo.hpp new file mode 100644 index 00000000000..7d72596efa7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirppreprocessinfo.hpp @@ -0,0 +1,49 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXIRPPREPROCESSINFO_H_ +#define _FXIRPPREPROCESSINFO_H_ + +struct FxIrpPreprocessInfo : public FxStump { + FxIrpPreprocessInfo() : + ClassExtension(FALSE) + { + InitializeListHead(&ListEntry); + } + + ~FxIrpPreprocessInfo() + { + ASSERT(IsListEmpty(&ListEntry)); + } + + struct Info { + Info() : + EvtDevicePreprocess(NULL), + NumMinorFunctions(0), + MinorFunctions(NULL) + { + } + + ~Info() + { + if (MinorFunctions != NULL) { + FxPoolFree(MinorFunctions); + } + } + + union { + PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDevicePreprocess; + PFN_WDFCXDEVICE_WDM_IRP_PREPROCESS EvtCxDevicePreprocess; + }; + + ULONG NumMinorFunctions; + PUCHAR MinorFunctions; + }; + + LIST_ENTRY ListEntry; + Info Dispatch[IRP_MJ_MAXIMUM_FUNCTION+1]; + BOOLEAN ClassExtension; +}; + + +#endif // _FXIRPPREPROCESSINFO_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxirpqueue.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirpqueue.hpp new file mode 100644 index 00000000000..31c09cfa3d9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxirpqueue.hpp @@ -0,0 +1,297 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIrpQueue.hpp + +Abstract: + + This module implements a common queue structure for the + driver frameworks built around the Cancel Safe Queues pattern + +Author: + + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXIRPQUEUE_H_ +#define _FXIRPQUEUE_H_ + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#include "FxIrpKm.hpp" +#else +#include "FxIrpUm.hpp" +#endif + + +// +// IRP DriverContext[] entry used. +// +// We use the same entry that the CSQ package does +// which is OK since we can't use CSQ if we implement the +// cancel handler ourselves +// +#define FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY 3 + +// +// FxIrpQueue entry identifier +// +#define FX_IRP_QUEUE_ENTRY_IDENTIFIER 1 + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#include "FxIrpKm.hpp" +#else if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#include "FxIrpUm.hpp" +#endif + + +// +// This is the cancel function callback for the IrpQueue to its caller/parent +// This is called holding the lock of the object owning the IrpQueue, and it +// is responsible for completing the IRP. +// + +extern "C" { +__drv_functionClass(EVT_IRP_QUEUE_CANCEL) +__drv_requiresIRQL(DISPATCH_LEVEL) +typedef +VOID +EVT_IRP_QUEUE_CANCEL ( + __in FxIrpQueue* Queue, + __in MdIrp Irp, + __in PMdIoCsqIrpContext pCsqContext, + __in KIRQL CallerIrql + ); + +typedef EVT_IRP_QUEUE_CANCEL *PFN_IRP_QUEUE_CANCEL; +} + +class FxIrpQueue { + + friend VOID GetTriageInfo(VOID); + +private: + + // + // The Queue + // + LIST_ENTRY m_Queue; + + // + // The object whose lock controls the queue. + // Provided by the client object. + // + FxNonPagedObject* m_LockObject; + + // + // Callers registered cancel callback + // + PFN_IRP_QUEUE_CANCEL m_CancelCallback; + + // + // Count of requests in the Queue + // + LONG m_RequestCount; + +public: + + FxIrpQueue( + VOID + ); + + ~FxIrpQueue( + VOID + ); + + VOID + Initialize( + __in FxNonPagedObject* LockObject, + __in PFN_IRP_QUEUE_CANCEL Callback + ); + + _Must_inspect_result_ + NTSTATUS + InsertTailRequest( + __inout MdIrp Irp, + __in_opt PMdIoCsqIrpContext CsqContext, + __out_opt ULONG* pRequestCount + ); + + _Must_inspect_result_ + NTSTATUS + InsertHeadRequest( + __inout MdIrp Irp, + __in_opt PMdIoCsqIrpContext CsqContext, + __out_opt ULONG* pRequestCount + ); + + MdIrp + GetNextRequest( + __out PMdIoCsqIrpContext* pCsqContext + ); + + _Must_inspect_result_ + NTSTATUS + GetNextRequest( + __in_opt PMdIoCsqIrpContext TagContext, + __in_opt MdFileObject FileObject, + __out FxRequest** ppOutRequest + ); + + _Must_inspect_result_ + NTSTATUS + PeekRequest( + __in_opt PMdIoCsqIrpContext TagContext, + __in_opt MdFileObject FileObject, + __out FxRequest** ppOutRequest + ); + + MdIrp + RemoveRequest( + __in PMdIoCsqIrpContext Context + ); + + // + // Return whether the queue is empty + // (for optimizing the non-pending case in the caller) + // + inline + BOOLEAN + IsQueueEmpty() { + + if( IsListEmpty(&m_Queue) ) { + + ASSERT(m_RequestCount == 0); + + return TRUE; + } + else { + ASSERT(m_RequestCount != 0); + + return FALSE; + } + } + + // + // Return count of queued and driver pending requests. + // + inline + LONG + GetRequestCount() { + return m_RequestCount; + } + + BOOLEAN + IsIrpInQueue( + __in PMdIoCsqIrpContext Context + ); + + +private: + + // + // Insert an IRP on the cancel list + // + _Must_inspect_result_ + NTSTATUS + InsertIrpInQueue( + __inout MdIrp Irp, + __in_opt PMdIoCsqIrpContext Context, + __in BOOLEAN InsertInHead, + __out_opt ULONG* pRequestCount + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + VOID, + VerifyRemoveIrpFromQueueByContext, + __in PMdIoCsqIrpContext + ); + + // + // Ask to remove an IRP from the cancel list by Context, + // and return NULL if its been cancelled + // + MdIrp + RemoveIrpFromQueueByContext( + __in PMdIoCsqIrpContext Context + ); + + // + // Remove a request from the head of the queue if PeekContext == NULL, + // or the next request after PeekContext if != NULL + // + MdIrp + RemoveNextIrpFromQueue( + __in_opt PVOID PeekContext, + __out_opt PMdIoCsqIrpContext* pCsqContext + ); + + // + // Peek an IRP in the queue + // + MdIrp + PeekNextIrpFromQueue( + __in_opt MdIrp Irp, + __in_opt PVOID PeekContext + ); + + // + // Unconditionally remove the IRP from the list entry + // + inline + VOID + RemoveIrpFromListEntry( + __inout FxIrp* Irp + ) + { + PLIST_ENTRY entry = Irp->ListEntry(); + RemoveEntryList(entry); + InitializeListHead(entry); + m_RequestCount--; + ASSERT(m_RequestCount >= 0); + } + + // + // WDM IRP cancel function + // + static + MdCancelRoutineType + _WdmCancelRoutineInternal; + + // + // Lock functions accessed from WDM cancel callback + // + __inline + void + LockFromCancel( + __out PKIRQL PreviousIrql + ) + { + m_LockObject->Lock(PreviousIrql); + } + + __inline + void + UnlockFromCancel( + __in KIRQL PreviousIrql + ) + { + m_LockObject->Unlock(PreviousIrql); + } +}; + +#endif // _FXIRPQUEUE_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxldr.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxldr.h new file mode 100644 index 00000000000..46c196e07b2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxldr.h @@ -0,0 +1,249 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxldr.h + +Abstract: + This module contains private interfaces to the WDF loader. This interface + is used by + a) the stub code in the client driver + b) the framework + c) the framework loader +--*/ +#ifndef __FXLDR_H__ +#define __FXLDR_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define WDF_COMPONENT_NAME(a) L#a + +// +// Bind info structures are aligned on memory allocation boundaries on 64-bit +// platforms, pointer boundaries on 32-bit. The alignment __declspec didn't +// fix this for Itanium builds, so we must accomodate this. +// +// This "marker type" allows us to declare a leading boundary that will always +// have the proper alignment. It may "waste" 4 to 8 bytes (0-4 to align the +// marker, and 4 more because the alignment isn't necessary, making the marker +// bigger than needed) on 32-bit, but that's not a large price to pay. +// + +typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _MARKER_TYPE { + UCHAR Pad[MEMORY_ALLOCATION_ALIGNMENT]; +} MARKER_TYPE; + +typedef struct _LIBRARY_MODULE *PLIBRARY_MODULE; +typedef struct _WDF_LIBRARY_INFO *PWDF_LIBRARY_INFO; + +typedef +VOID +(*WDFFUNC)( + VOID + ); + +typedef +_Must_inspect_result_ +NTSTATUS +(*PFNLIBRARYCOMMISSION)( + VOID + ); + +typedef +_Must_inspect_result_ +NTSTATUS +(*PFNLIBRARYDECOMMISSION)( + VOID + ); + +typedef +_Must_inspect_result_ +NTSTATUS +(*PFNLIBRARYREGISTERCLIENT)( + __in PWDF_BIND_INFO Info, + __deref_out PWDF_COMPONENT_GLOBALS * ComponentGlobals, + __deref_inout PVOID * Context + ); + +typedef +_Must_inspect_result_ +NTSTATUS +(*PFNLIBRARYUNREGISTERCLIENT)( + __in PWDF_BIND_INFO Info, + __in PWDF_COMPONENT_GLOBALS DriverGlobals + ); + +typedef +_Must_inspect_result_ +NTSTATUS +(*PWDF_REGISTER_LIBRARY)( + __in PWDF_LIBRARY_INFO LibraryInfo, + __in PUNICODE_STRING ServicePath, + __in PCUNICODE_STRING LibraryDeviceName + ) ; + +typedef +_Must_inspect_result_ +NTSTATUS +(*PWDF_VERSION_BIND)( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath, + __in PWDF_BIND_INFO Info, + __out PWDF_COMPONENT_GLOBALS * Globals + ) ; + +typedef +NTSTATUS +(*PWDF_VERSION_UNBIND)( + __in PUNICODE_STRING RegistryPath, + __in PWDF_BIND_INFO Info, + __in PWDF_COMPONENT_GLOBALS Globals + ); + +#define WDF_LIBRARY_COMMISSION LibraryCommission +#define WDF_LIBRARY_DECOMMISSION LibraryDecommission +#define WDF_LIBRARY_REGISTER_CLIENT LibraryRegisterClient +#define WDF_LIBRARY_UNREGISTER_CLIENT LibraryUnregisterClient + +#define WDF_REGISTRY_DBGPRINT_ON L"DbgPrintOn" + + +// +// Version container +// +typedef struct _WDF_VERSION { + WDF_MAJOR_VERSION Major; + WDF_MINOR_VERSION Minor; + WDF_BUILD_NUMBER Build; +} WDF_VERSION; + +// +// WDF bind information structure. +// +typedef struct _WDF_BIND_INFO { + ULONG Size; + PWCHAR Component; + WDF_VERSION Version; + ULONG FuncCount; + __field_bcount(FuncCount*sizeof(WDFFUNC)) WDFFUNC* FuncTable; + PLIBRARY_MODULE Module; // Mgmt and diagnostic use only +} WDF_BIND_INFO, * PWDF_BIND_INFO; + +typedef struct _WDF_LIBRARY_INFO { + ULONG Size; + PFNLIBRARYCOMMISSION LibraryCommission; + PFNLIBRARYDECOMMISSION LibraryDecommission; + PFNLIBRARYREGISTERCLIENT LibraryRegisterClient; + PFNLIBRARYUNREGISTERCLIENT LibraryUnregisterClient; + WDF_VERSION Version; +} WDF_LIBRARY_INFO, *PWDF_LIBRARY_INFO; + +// {49215DFF-F5AC-4901-8588-AB3D540F6021} +DEFINE_GUID(GUID_WDF_LOADER_INTERFACE_STANDARD, \ + 0x49215dff, 0xf5ac, 0x4901, 0x85, 0x88, 0xab, 0x3d, 0x54, 0xf, 0x60, 0x21); + +typedef struct _WDF_LOADER_INTERFACE { + WDF_INTERFACE_HEADER Header; + PWDF_REGISTER_LIBRARY RegisterLibrary; + PWDF_VERSION_BIND VersionBind; + PWDF_VERSION_UNBIND VersionUnbind; + PWDF_LDR_DIAGNOSTICS_VALUE_BY_NAME_AS_ULONG DiagnosticsValueByNameAsULONG; +} WDF_LOADER_INTERFACE, *PWDF_LOADER_INTERFACE; + +VOID +__inline +WDF_LOADER_INTERFACE_INIT( + PWDF_LOADER_INTERFACE Interface + ) +{ + RtlZeroMemory(Interface, sizeof(WDF_LOADER_INTERFACE)); + Interface->Header.InterfaceSize = sizeof(WDF_LOADER_INTERFACE); + Interface->Header.InterfaceType = &GUID_WDF_LOADER_INTERFACE_STANDARD; +} + +// +// Client Driver information structure. This is used by loader when +// registering client with library to provide some additional info to +// library that is not already present in WDF_BIND_INFO (also passed to library +// during client registration) +// +typedef struct _CLIENT_INFO { + // + // Size of this structure + // + ULONG Size; + + // + // registry service path of client driver + // + PUNICODE_STRING RegistryPath; + +} CLIENT_INFO, *PCLIENT_INFO; + +//----------------------------------------------------------------------------- +// WDFLDR.SYS exported function prototype definitions +//----------------------------------------------------------------------------- +_Must_inspect_result_ +NTSTATUS +WdfVersionBind( + __in PDRIVER_OBJECT DriverObject, + __in PUNICODE_STRING RegistryPath, + __inout PWDF_BIND_INFO BindInfo, + __out PWDF_COMPONENT_GLOBALS* ComponentGlobals + ); + +NTSTATUS +WdfVersionUnbind( + __in PUNICODE_STRING RegistryPath, + __in PWDF_BIND_INFO BindInfo, + __in PWDF_COMPONENT_GLOBALS ComponentGlobals + ); + +_Must_inspect_result_ +NTSTATUS +WdfRegisterLibrary( + __in PWDF_LIBRARY_INFO LibraryInfo, + __in PUNICODE_STRING ServicePath, + __in PCUNICODE_STRING LibraryDeviceName + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (PAGE, WdfVersionBind) +#pragma alloc_text (PAGE, WdfVersionUnbind) +#pragma alloc_text (PAGE, WdfRegisterLibrary) +#pragma alloc_text (PAGE, WdfRegisterClassLibrary) +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +// +// Event name: WdfCensusEvtLinkClientToCx +// +// Source: WdfLdr +// Description: Written when a client is binding to a class extension. +// WdfVersionBindClass which is called from the client's stub, +// will load/reference the Cx and add it to the fx library's +// list of clients. The client driver's class extension list is +// also updated at that time, which is when this event is written. +// +// Frequency: Everytime a client driver binds to a class extension. +// +// +#define WDF_CENSUS_EVT_WRITE_LINK_CLIENT_TO_CX(TraceHandle, CxImageName, ClientImageName) \ + TraceLoggingWrite(TraceHandle, \ + "WdfCensusEvtLinkClientToCx", \ + WDF_TELEMETRY_EVT_KEYWORDS, \ + TraceLoggingWideString(CxImageName, "CxImageName"), \ + TraceLoggingWideString(ClientImageName, "ClientImageName" ) \ + ); + +#endif __FXLDR_H__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxlock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxlock.hpp new file mode 100644 index 00000000000..85e5d072cfa --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxlock.hpp @@ -0,0 +1,150 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxLock.hpp + +Abstract: + + This is the C++ header for the FxLock + + This represents a container for handling locking + +Author: + + + + +Revision History: + + +--*/ + +#ifndef _FXLOCK_H_ +#define _FXLOCK_H_ + +/** + * This is the base lock object implementation + * + * This is intended to be embedded in an FxNonPagedObject + * rather than forcing a separate allocation for + * non-verifier mode. + * + * In order to reduce the runtime memory cost of + * building in verifier support for a retail version, + * a single pointer it stored to FxVerifierLock + * if verifier is on. If this pointer is != NULL, + * lock calls are proxied to this lock function, + * leaving our internal spinlock redundent. + * + * The decision is to minimize the non-verifier + * memory footprint so we do not have to compile + * it out for retail builds, but always have it + * available through a driver debug setting. + */ + +class FxLock { + +private: + MxLock m_lock; + + // For Verifier + FxVerifierLock* m_Verifier; + +public: + FxLock( + VOID + ) + { + + + + + m_lock.Initialize(); + m_Verifier = NULL; + } + + VOID + Initialize( + __in FxObject * ParentObject + ); + + ~FxLock() + { + if (m_Verifier != NULL) { + delete m_Verifier; + } + } + + _When_(this->m_Verifier == NULL, _Acquires_lock_(this->m_lock)) + inline + VOID + Lock( + __out PKIRQL PreviousIrql + ) + { + if (m_Verifier != NULL) { + m_Verifier->Lock(PreviousIrql, FALSE); + } + // else if (PreviousIrql == NULL) { + // KeAcquireSpinLockAtDpcLevel(&m_lock); + // } + else { + m_lock.Acquire(PreviousIrql); + } + } + + _When_(this->m_Verifier == NULL, _Releases_lock_(this->m_lock)) + inline + void + Unlock( + __in KIRQL PreviousIrql + ) + { + if (m_Verifier != NULL) { + m_Verifier->Unlock(PreviousIrql, FALSE); + } + // else if (AtDpc) { + // KeReleaseSpinLockFromDpcLevel(&m_lock); + // } + else { + m_lock.Release(PreviousIrql); + } + } + + _When_(this->m_Verifier == NULL, _Acquires_lock_(this->m_lock)) + inline + VOID + LockAtDispatch( + VOID + ) + { + if (m_Verifier != NULL) { + KIRQL previousIrql; + + m_Verifier->Lock(&previousIrql, TRUE); + } + else { + m_lock.AcquireAtDpcLevel(); + } + } + + _When_(this->m_Verifier == NULL, _Releases_lock_(this->m_lock)) + inline + void + UnlockFromDispatch( + VOID + ) + { + if (m_Verifier != NULL) { + m_Verifier->Unlock(DISPATCH_LEVEL, TRUE); + } + else { + m_lock.ReleaseFromDpcLevel(); + } + } +}; + +#endif // _FXLOCK_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxlookasidelist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxlookasidelist.hpp new file mode 100644 index 00000000000..0f84ec33562 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxlookasidelist.hpp @@ -0,0 +1,126 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxLookasideList.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + + +--*/ + +#ifndef _FXLOOKASIDELIST_H_ +#define _FXLOOKASIDELIST_H_ + +class FxLookasideList : public FxObject { + + friend FxMemoryBufferFromLookaside; + +public: + FxLookasideList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in ULONG PoolTag + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ) =0; + + virtual + _Must_inspect_result_ + NTSTATUS + Allocate( + __out FxMemoryObject** PPMemory + ) =0; + + size_t + GetBufferSize( + VOID + ) + { + return m_BufferSize; + } + +protected: + virtual + ~FxLookasideList( + ); + + // + // Function used by IFxMemoryBuffer to return itself to the lookaside list + // + virtual + VOID + Reclaim( + __in FxMemoryBufferFromLookaside* Memory + ) =0; + + _Must_inspect_result_ + NTSTATUS + InitializeLookaside( + __in USHORT BufferSize, + __in USHORT MemoryObjectSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ); + + PVOID + InitObjectAlloc( + __out_bcount(this->m_MemoryObjectSize) PVOID Alloc + ); + + static + VOID + _Reclaim( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout PNPAGED_LOOKASIDE_LIST List, + __in FxMemoryBufferFromLookaside* Memory + ); + +public: + WDF_OBJECT_ATTRIBUTES m_MemoryAttributes; + +protected: + size_t m_BufferSize; + + size_t m_MemoryObjectSize; + + ULONG m_PoolTag; +}; + +class FxLookasideListFromPool : public FxLookasideList { + friend FxMemoryBufferFromPoolLookaside; + +public: + FxLookasideListFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in ULONG PoolTag + ) : FxLookasideList(FxDriverGlobals, ObjectSize, PoolTag) + { + } + +protected: + virtual + VOID + ReclaimPool( + __inout PVOID Pool + ) =0; +}; + + +#endif // _FXLOOKASIDELIST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmacros.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmacros.hpp new file mode 100644 index 00000000000..55636b10a69 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmacros.hpp @@ -0,0 +1,319 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FX_MACROS_H_ +#define _FX_MACROS_H_ + +// +// at is for argument type +// a is for argument +// rt is for return type +// fn or FN is for function +// qf is for qualifiers +// rtDef is for return type default value +// +#define WDF_FX_VF_SECTION_NAME PAGEWdfV +#define QUOTE_EXPANSION(tok) #tok +#define FX_VF_SECTION_NAME_QUOTED(tok) QUOTE_EXPANSION(tok) + + + + + + + +#if defined(_M_ARM) +#define FX_VF_PAGING +#else +#define FX_VF_PAGING __declspec(code_seg(FX_VF_SECTION_NAME_QUOTED(WDF_FX_VF_SECTION_NAME))) +#endif + +#define FX_VF_NAME_TO_IMP_NAME( fnName ) Vf_##fnName +#define FX_VF_NAME_TO_SCOPED_IMP_NAME( classname, fnName ) classname##::Vf_##fnName +#define FX_VF_QF_VOID +#define FX_VF_QF_NTSTATUS _Must_inspect_result_ +#define FX_VF_DEFAULT_RT_VOID +#define FX_VF_DEFAULT_RT_NTSTATUS STATUS_SUCCESS + +#define FX_VF_FUNCTION_PROTOTYPE( qf, rt, fnName, ...) \ +qf \ +rt \ +FX_VF_FUNCTION( fnName )( _In_ PFX_DRIVER_GLOBALS, ##__VA_ARGS__ ); + +#define FX_VF_METHOD( classname, fnName ) \ +FX_VF_PAGING \ +FX_VF_NAME_TO_SCOPED_IMP_NAME( classname, fnName ) + +#define FX_VF_FUNCTION( fnName ) \ +FX_VF_PAGING \ +FX_VF_NAME_TO_IMP_NAME( fnName ) + +#define FX_VF_GLOBAL_CHECK_SCOPE( rt, rtDef, fnName, params ) \ +{ \ + if( FxDriverGlobals->FxVerifierOn ) { \ + return FX_VF_NAME_TO_IMP_NAME( fnName ) params; \ + } \ + else { \ + return rtDef; \ + } \ +} + +// +// zero parameters +// +#define FX_VF_STUB( qf, rt, rtDef, fnName ) \ +__inline \ +qf \ +rt \ +fnName( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals ) \ +FX_VF_GLOBAL_CHECK_SCOPE( rt, rtDef, fnName, ( FxDriverGlobals ) ) + +#define FX_DECLARE_VF_FUNCTION_EX( qf, rt, rtDef, fnName ) \ +FX_VF_FUNCTION_PROTOTYPE( qf, rt, fnName ) \ +FX_VF_STUB( qf, rt, rtDef, fnName ) + +#define FX_DECLARE_VF_FUNCTION( rt, fnName ) \ +FX_DECLARE_VF_FUNCTION_EX( FX_VF_QF_ ## rt, rt, FX_VF_DEFAULT_RT_ ## rt, fnName ) + +// +// 1-Parameter Stub Macro +// +#define FX_VF_STUB_P1( qf, rt, rtDef, fnName, at1 ) \ +__inline \ +qf \ +rt \ +fnName( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, at1 a1 ) \ +FX_VF_GLOBAL_CHECK_SCOPE( rt, rtDef, fnName, (FxDriverGlobals, a1 )) + +// 1-Parameter Extended FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P1_EX( qf, rt, rtDef, fnName, at1 ) \ +FX_VF_FUNCTION_PROTOTYPE( qf, rt, fnName, at1 ) \ +FX_VF_STUB_P1( qf, rt, rtDef, fnName, at1 ) + +// 1-Parameter FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P1( rt, fnName, at1 ) \ +FX_DECLARE_VF_FUNCTION_P1_EX( FX_VF_QF_ ## rt, rt, FX_VF_DEFAULT_RT_ ## rt, fnName, at1 ) + +// +// 2-Parameter Stub Macro +// +#define FX_VF_STUB_P2( qf, rt, rtDef, fnName, at1, at2 ) \ +__inline \ +qf \ +rt \ +fnName( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, at1 a1, at2 a2 ) \ +FX_VF_GLOBAL_CHECK_SCOPE( rt, rtDef, fnName, (FxDriverGlobals, a1, a2 )) + +// 2-Parameter Extended FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P2_EX( qf, rt, rtDef, fnName, at1, at2 ) \ +FX_VF_FUNCTION_PROTOTYPE( qf, rt, fnName, at1, at2 ) \ +FX_VF_STUB_P2( qf, rt, rtDef, fnName, at1, at2 ) + +// 2-Parameter FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P2( rt, fnName, at1, at2 ) \ +FX_DECLARE_VF_FUNCTION_P2_EX( FX_VF_QF_ ## rt, rt, FX_VF_DEFAULT_RT_ ## rt, fnName, at1, at2 ) + +// +// 3-Parameter Stub Macro +// +#define FX_VF_STUB_P3( qf, rt, rtDef, fnName, at1, at2, at3 ) \ +__inline \ +qf \ +rt \ +fnName( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, at1 a1, at2 a2, at3 a3 ) \ +FX_VF_GLOBAL_CHECK_SCOPE( rt, rtDef, fnName, (FxDriverGlobals, a1, a2, a3)) + +// 3-Parameter Extended FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P3_EX( qf, rt, rtDef, fnName, at1, at2, at3 ) \ +FX_VF_FUNCTION_PROTOTYPE( qf, rt, fnName, at1, at2, at3) \ +FX_VF_STUB_P3( qf, rt, rtDef, fnName, at1, at2, at3 ) + +// 3-Parameter FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P3( rt, fnName, at1, at2, at3 ) \ +FX_DECLARE_VF_FUNCTION_P3_EX( FX_VF_QF_ ## rt, rt, FX_VF_DEFAULT_RT_ ## rt, fnName, at1, at2, at3 ) + +// +// 4-Parameter Stub Macro +// +#define FX_VF_STUB_P4( qf, rt, rtDef, fnName, at1, at2, at3, at4 ) \ +__inline \ +qf \ +rt \ +fnName( _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, at1 a1, at2 a2, at3 a3, at4 a4 ) \ +FX_VF_GLOBAL_CHECK_SCOPE( rt, rtDef, fnName, (FxDriverGlobals, a1, a2, a3, a4)) + +// 4-Parameter Extended FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P4_EX( qf, rt, rtDef, fnName, at1, at2, at3, at4 ) \ +FX_VF_FUNCTION_PROTOTYPE( qf, rt, fnName, at1, at2, at3, at4 ) \ +FX_VF_STUB_P4( qf, rt, rtDef, fnName, at1, at2, at3, at4 ) + +// 4-Parameter FUNCTION Declaration Macro +#define FX_DECLARE_VF_FUNCTION_P4( rt, fnName, at1, at2, at3, at4 ) \ +FX_DECLARE_VF_FUNCTION_P4_EX( FX_VF_QF_ ## rt, rt, FX_VF_DEFAULT_RT_ ## rt, fnName, at1, at2, at3, at4 ) + + +#define FX_TAG 'rDxF' + +#define WDFEXPORT(a) imp_ ## a +#define VFWDFEXPORT(a) imp_Vf ## a + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(_x) (sizeof((_x))/sizeof((_x)[0])) +#endif + +// VOID +// FXVERIFY( +// PFX_DRIVER_GLOBALS FxDriverGlobals, +// +// ); + +#define FXVERIFY(_globals, exp) \ +{ \ + if (!(exp)) { \ + RtlAssert( #exp, __FILE__, __LINE__, NULL );\ + } \ +} + +// These 2 macros are the equivalent of WDF_ALIGN_SIZE_DOWN and +// WDF_ALIGN_SIZE_UP. The difference is that these can evaluate to a constant +// while the WDF versions will on a fre build, but not on a chk build. By +// evaluating to a constant, we can use this in WDFCASSERT. + +// size_t +// __inline +// FX_ALIGN_SIZE_DOWN_CONSTANT( +// IN size_t Length, +// IN size_t AlignTo +// ) +#define FX_ALIGN_SIZE_DOWN_CONSTANT(Length, AlignTo) ((Length) & ~((AlignTo) - 1)) + +// size_t +// __inline +// FX_ALIGN_SIZE_UP_CONSTANT( +// IN size_t Length, +// IN size_t AlignTo +// ) +#define FX_ALIGN_SIZE_UP_CONSTANT(Length, AlignTo) \ + FX_ALIGN_SIZE_DOWN_CONSTANT((Length) + (AlignTo) - 1, (AlignTo)) + +// +// Macro which will declare a field within a structure. This field can then be +// used to return a WDF handle to the driver since it contains the required +// FxContextHeader alongside the object itself. +// +// DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) is required because FxObject +// rounds up m_ObjectSize to be a multiple of MEMORY_ALLOCATION_ALIGNMENT. +// Since we cannot compute this value at runtime in operator new, we must +// be very careful here and force the alignment ourselves. +// +#define DEFINE_EMBEDDED_OBJECT_HANDLE(_type, _fieldname) \ +DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _type _fieldname; \ +DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) FxContextHeader _fieldname##Context + +// +// Computes the size of an embedded object in a structure. To be used on a +// _embeddedFieldName declared with DEFINE_EMBEDDED_OBJECT_HANDLE. +// +#define EMBEDDED_OBJECT_SIZE(_owningClass, _embeddedFieldName) \ + (FIELD_OFFSET(_owningClass, _embeddedFieldName ## Context) - \ + FIELD_OFFSET(_owningClass, _embeddedFieldName)) +// +// Placeholder macro for a no-op +// +#define DO_NOTHING() (0) + +// 4127 -- Conditional Expression is Constant warning +#define WHILE(constant) \ +__pragma(warning(suppress: 4127)) while(constant) + +#if DBG + #if defined(_X86_) + #define TRAP() {_asm {int 3}} + #else + #define TRAP() DbgBreakPoint() + #endif +#else // DBG + #define TRAP() +#endif // DBG + +#if FX_SUPER_DBG + #if defined(_X86_) + #define COVERAGE_TRAP() {_asm {int 3}} + #else + #define COVERAGE_TRAP() DbgBreakPoint() + #endif +#else // FX_SUPER_DBG + #define COVERAGE_TRAP() +#endif // FX_SUPER_DBG + +// +// This is a macro to keep it as cheap as possible. +// +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#define FxPointerNotNull(FxDriverGlobals, Ptr) \ + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(Ptr), \ + FxDriverGlobals->Public.DriverName) +#else +#define FxPointerNotNull(FxDriverGlobals, Ptr) \ + (((Ptr) == NULL) ? \ + FxVerifierNullBugCheck(FxDriverGlobals, _ReturnAddress()), FALSE : \ + TRUE ) +#endif + +#define FX_MAKE_WSTR_WORKER(x) L ## #x +#define FX_MAKE_WSTR(x) FX_MAKE_WSTR_WORKER(x) + +#define FX_LITERAL_WORKER(a) # a +#define FX_LITERAL(a) FX_LITERAL_WORKER(a) + +// +// In some cases we assert for some condition to hold (such as asserting a ptr +// to be non-NULL before accessing it), but prefast will still complain +// (e.g., in the example given, about NULL ptr access). +// +// This macro combines the assert with corresponding assume for prefast. +// +#ifdef _PREFAST_ +#define FX_ASSERT_AND_ASSUME_FOR_PREFAST(b) \ +{ \ + bool result=(b); \ + ASSERTMSG(#b, result); \ + __assume(result == true); \ +} +#else +#define FX_ASSERT_AND_ASSUME_FOR_PREFAST(b) \ +{ \ + ASSERT(b); \ +} +#endif + +// +// Macro to make sure that the code is not invoked for UM. +// +// Although it is usually preferable to move such code to *um file +// so that it does not get compiled at all for um, in some cases such approach +// might fragment the code too much. In such situation this macro can be used. +// +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#define WDF_VERIFY_KM_ONLY_CODE() \ + Mx::MxAssertMsg("Unexpected invocation in user mode", FALSE); +#else +#define WDF_VERIFY_KM_ONLY_CODE() +#endif + +// +// MIN, MAX macros. +// +#ifndef MAX +#define MAX(x,y) ((x) > (y) ? (x) : (y)) +#endif + +#ifndef MIN +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#endif + +#ifndef SAFE_RELEASE +#define SAFE_RELEASE(p) if( NULL != p ) { ( p )->Release(); p = NULL; } +#endif + +#endif // _FX_MACROS_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmdl.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmdl.h new file mode 100644 index 00000000000..a0fe56abe8f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmdl.h @@ -0,0 +1,91 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef __FXMDL_H__ +#define __FXMDL_H__ + +PMDL +FxMdlAllocateDebug( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* Owner, + __in PVOID VirtualAddress, + __in ULONG Length, + __in BOOLEAN SecondaryBuffer, + __in BOOLEAN ChargeQuota, + __in PVOID CallersAddress + ); + +VOID +FxMdlFreeDebug( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PMDL Mdl + ); + +VOID +FxMdlDump( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +PMDL +FORCEINLINE +FxMdlAllocate( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* Owner, + __in PVOID VirtualAddress, + __in ULONG Length, + __in BOOLEAN SecondaryBuffer, + __in BOOLEAN ChargeQuota + ) +{ + if (FxDriverGlobals->FxVerifierOn) { + return FxMdlAllocateDebug(FxDriverGlobals, + Owner, + VirtualAddress, + Length, + SecondaryBuffer, + ChargeQuota, + _ReturnAddress()); + } + else { + return IoAllocateMdl(VirtualAddress, + Length, + SecondaryBuffer, + ChargeQuota, + NULL); + } +} + +VOID +__inline +FxMdlFree( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PMDL Mdl + ) +{ + if (FxDriverGlobals->FxVerifierOn) { + FxMdlFreeDebug(FxDriverGlobals, Mdl); + } + else { + IoFreeMdl(Mdl); + } +} + +VOID +__inline +FxIrpMdlFree( + __in PMDL Mdl + ) +{ + IoFreeMdl(Mdl); +} + +// Do not allow accidental usage by redefining these DDIs to uncompilable names. +// Do this after we define our own functions so that our own functions use +// the correct DDI. +#undef IoAllocateMdl +#undef IoFreeMdl + +#define IoAllocateMdl use_FxMdlAllocate_instead +#define IoFreeMdl use_FxMdlFree_instead + +#endif __FXMDL_H__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybuffer.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybuffer.hpp new file mode 100644 index 00000000000..e2f61c17ecf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybuffer.hpp @@ -0,0 +1,93 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBuffer.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + + +--*/ + +#ifndef _FXMEMORYBUFFER_H_ +#define _FXMEMORYBUFFER_H_ + +class FxMemoryBuffer : public FxMemoryObject { + +public: + + // Factory function + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in ULONG PoolTag, + __in size_t BufferSize, + __in POOL_TYPE PoolType, + __out FxMemoryObject** Object + ); + + FxMemoryBuffer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize + ); + + PVOID + GetBuffer( + VOID + ); + + PVOID + __inline + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in USHORT ExtraSize, + __in ULONG Tag, + __in POOL_TYPE PoolType + ) + { + // + // PoolType must be non paged pool but it can be NonPagedPool + // or NonPagedPoolNx or their variants + // + ASSERT(!FxIsPagedPoolType(PoolType)); + + // + // Specialize operator new so that we can use the caller's tag when + // making the object allocation vs using the default driver-wide tag. + // + return FxObjectHandleAlloc(FxDriverGlobals, + PoolType, + Size, + Tag, + Attributes, + ExtraSize, + FxObjectTypeExternal); + } + +protected: + + FxMemoryBuffer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in size_t BufferSize + ); + + ~FxMemoryBuffer(); +}; + +#endif // _FXMEMORYBUFFER_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferfromlookaside.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferfromlookaside.hpp new file mode 100644 index 00000000000..847fe915ba7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferfromlookaside.hpp @@ -0,0 +1,136 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferFromLookaside.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXMEMORYBUFFERFROMLOOKASIDE_H_ +#define _FXMEMORYBUFFERFROMLOOKASIDE_H_ + +class FxMemoryBufferFromLookaside : public FxMemoryObject { + +public: + FxMemoryBufferFromLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize + ); + + _Must_inspect_result_ + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout PVOID ValidMemory, + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES Attributes + ); + + virtual + PVOID + GetBuffer( + VOID + ); + +protected: + FxMemoryBufferFromLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in USHORT ObjectSize + ); + + ~FxMemoryBufferFromLookaside( + ); + + VOID + Init( + VOID + ); + + virtual + VOID + SelfDestruct( + VOID + ); + + FxLookasideList* m_pLookaside; +}; + +class FxMemoryBufferFromPoolLookaside : public FxMemoryBufferFromLookaside { +public: + FxMemoryBufferFromPoolLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in_bcount(BufferSize) PVOID Buffer + ); + + _Must_inspect_result_ + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout PVOID ValidMemory, + __in PWDF_OBJECT_ATTRIBUTES Attributes + ); + + virtual + PVOID + GetBuffer( + VOID + ) + { + return m_Pool; + } + +protected: + FxMemoryBufferFromPoolLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in_bcount(BufferSize) PVOID Buffer, + __in USHORT ObjectSize + ); + + virtual + VOID + SelfDestruct( + VOID + ); + + PVOID m_Pool; +}; + +class FxMemoryPagedBufferFromPoolLookaside : public FxMemoryBufferFromPoolLookaside { +public: + FxMemoryPagedBufferFromPoolLookaside( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __inout FxLookasideList* Lookaside, + __in size_t BufferSize, + __in_bcount(BufferSize) PVOID Buffer, + __in FxDeviceBase* DeviceBase + ) : FxMemoryBufferFromPoolLookaside(FxDriverGlobals, + Lookaside, + BufferSize, + Buffer, + sizeof(*this)) + { + SetDeviceBase(DeviceBase); + } +}; +#endif // _FXMEMORYBUFFERFROMLOOKASIDE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferfrompool.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferfrompool.hpp new file mode 100644 index 00000000000..38b3d5a36ad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferfrompool.hpp @@ -0,0 +1,88 @@ + +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferBif.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXMEMORYBUFFERFROMPOOL_H_ +#define _FXMEMORYBUFFERFROMPOOL_H_ + +class FxMemoryBufferFromPool : public FxMemoryObject { + +public: + FxMemoryBufferFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize + ); + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in POOL_TYPE PoolType, + __in ULONG PoolTag, + __in size_t BufferSize, + __out FxMemoryObject** Buffer + ); + + virtual + PVOID + GetBuffer( + VOID + ) + { + return m_Pool; + } + + BOOLEAN + AllocateBuffer( + __in POOL_TYPE Type, + __in ULONG Tag + ) + { + m_Pool = MxMemory::MxAllocatePoolWithTag(Type, GetBufferSize(), Tag); + return m_Pool != NULL ? TRUE : FALSE; + } + +protected: + FxMemoryBufferFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize, + __in USHORT ObjectSize + ); + + ~FxMemoryBufferFromPool(); + + PVOID m_Pool; +}; + +class FxMemoryPagedBufferFromPool : public FxMemoryBufferFromPool { +public: + FxMemoryPagedBufferFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize, + __in CfxDeviceBase* DeviceBase + ) : FxMemoryBufferFromPool(FxDriverGlobals, BufferSize, sizeof(*this)) + { + SetDeviceBase(DeviceBase); + } +}; + +#endif // _FXMEMORYBUFFERFROMPOOL_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferpreallocated.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferpreallocated.hpp new file mode 100644 index 00000000000..c429aafc250 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemorybufferpreallocated.hpp @@ -0,0 +1,72 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryBufferPreallocated.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXMEMORYBUFFERPREALLOCATED_H_ +#define _FXMEMORYBUFFERPREALLOCATED_H_ + +class FxMemoryBufferPreallocated : public FxMemoryObject { +public: + + FxMemoryBufferPreallocated( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ size_t BufferSize + ); + + virtual + PVOID + GetBuffer( + VOID + ) + { + return m_pBuffer; + } + + VOID + UpdateBuffer( + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ size_t BufferSize + ); + + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __inout FxQueryInterfaceParams* Params + ); + +protected: + // for derived classes + FxMemoryBufferPreallocated( + __in USHORT ObjectSize, + __in PFX_DRIVER_GLOBALS Globals + ); + + FxMemoryBufferPreallocated( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ USHORT ObjectSize, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ size_t BufferSize + ); + + ~FxMemoryBufferPreallocated(); + + PVOID m_pBuffer; +}; +#endif // _FXMEMORYBLOCKPREALLOCATED_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemoryobject.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemoryobject.hpp new file mode 100644 index 00000000000..3d664989fd8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmemoryobject.hpp @@ -0,0 +1,199 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxMemoryObject.hpp + +Abstract: + This is the base class for a whole host of memory objects which serve + different purposes: The hierarchy is this + + FxMemoryObject : public FxObject, public IFxMemory + FxMemoryBuffer + FxMemoryBufferFromPool + FxMemoryPagedBufferFromPool + FxMemoryBufferFromLookaside + FxMemoryBufferFromPoolLookaside + FxMemoryPagedBufferFromPoolLookaside + FxMemoryBufferPreallocated + FxRequestMemory + + Here is quick overview of what each object does/brings to the table: + + FxMemoryObject: provides an implementation for almost all of IFxMemory's + abstract functions. It also provides a static _Create function which + can create non lookaside based memory objects + + FxMemoryBuffer: memory object which can hold the external buffer within its + own object allocation. This means that the sizeof(FxMemoryBuffer) + + external bufer size + extra computations < PAGE_SIZE + + FxMemoryBufferFromPool: memory object whose external buffer is a separate + allocation. The external buffer can be either paged or non paged. + + FxMemoryPagedBufferFromPool: same as FxMemoryBufferFromPool. In addition, + it has a back pointer to the owning FxDeviceBase so that the object + can be disposed on the correct dispose list. + + FxMemoryBufferFromLookaside: same as FxMemoryBuffer. In addition, the + object knows how to return itself to the lookaside which created it. + + FxMemoryBufferFromPoolLookaside: same as FxMemoryBufferFromPool. In + addtion, the object knows how to return itself to the lookaside which + created it. + + FxMemoryPagedBufferFromPoolLookaside: same as + FxMemoryBufferFromPoolLookaside. In addtion, it has a back pointer to + the owning FxDeviceBase so that the object can be disposed on the + correct dispose list. + + FxMemoryBufferPreallocated: a memory object which does not own the external + buffer's lifetime. It is a wrapper object to allow existing buffers to + be used as a WDFMEMORY. + + FxRequestMemory: same as FxMemoryBufferPreallocated. In addtion, it knows + about PMDLs and is tied to the lifetime of a WDFREQUEST. + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXMEMORYOBJECT_H_ +#define _FXMEMORYOBJECT_H_ + +class FxMemoryObject : public FxObject, public IFxMemory { +public: + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in POOL_TYPE PoolType, + __in ULONG PoolTag, + __in size_t BufferSize, + __out FxMemoryObject** Object + ); + + // begin IFxMemory derivations + virtual + size_t + GetBufferSize( + VOID + ) + { + return m_BufferSize; + } + + virtual + PMDL + GetMdl( + VOID + ) + { + // + // This function or its derivatives do not allocate the PMDL, they just + // return one if there is one in the object already. + // + return NULL; + } + + virtual + WDFMEMORY + GetHandle( + VOID + ) + { + return (WDFMEMORY) GetObjectHandle(); + } + + virtual + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ) + { + return FxObject::GetDriverGlobals(); + } + + virtual + ULONG + AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) + { + return FxObject::AddRef(Tag, Line, File); + } + + virtual + ULONG + Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) + { + return FxObject::Release(Tag, Line, File); + } + + virtual + VOID + Delete( + VOID + ) + { + DeleteObject(); + } + + virtual + USHORT + GetFlags( + VOID + ) + { + // + // By default, memory is readable and writable + return 0; + } + // end IFxMemory derivations + +protected: + + FxMemoryObject( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in size_t BufferSize + ); + + virtual + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __inout FxQueryInterfaceParams* Params + ) + { + switch (Params->Type) { + case IFX_TYPE_MEMORY: + // cast is necessary for necessary this pointer offset to be computed + *Params->Object = (IFxMemory*) this; + return STATUS_SUCCESS; + + default: + return __super::QueryInterface(Params); + } + } + + size_t m_BufferSize; +}; + +#endif // _FXMEMORYOBJECT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxmin.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmin.hpp new file mode 100644 index 00000000000..866a63e680f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxmin.hpp @@ -0,0 +1,385 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxMin.hpp + +Abstract: + + This is the minimal version of driver framework include file + that is needed to build FxObject + + + + + + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXMIN_HPP +#define _FXMIN_HPP + +extern "C" { +#include "mx.h" +} +#include "FxMacros.hpp" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +// +// Undef METHOD_FROM_CTL_CODE so that it is prevented from being used +// inadvertently in mode-agnostic code. Irp->GetParameterIoctlCodeBufferMethod +// should be used instead. +// +#ifdef METHOD_FROM_CTL_CODE +#undef METHOD_FROM_CTL_CODE +#endif +#endif // FX_CORE_USER_MODE + +typedef struct _WDF_BIND_INFO *PWDF_BIND_INFO; + +extern "C" { + +/////////////////// +// Basic definitions (abridged version of wdf.h) + +#ifdef __cplusplus + #define WDF_EXTERN_C extern "C" + #define WDF_EXTERN_C_START extern "C" { + #define WDF_EXTERN_C_END } +#else + #define WDF_EXTERN_C + #define WDF_EXTERN_C_START + #define WDF_EXTERN_C_END +#endif + +WDF_EXTERN_C_START + +typedef VOID (*WDFFUNC) (VOID); +extern const WDFFUNC *WdfFunctions; + +#include "wdftypes.h" +#include "wdfglobals.h" +#include "wdffuncenum.h" +#include "wdfstatus.h" +#include "wdfassert.h" +#include "wdfverifier.h" + +// generic object +#include "wdfobject.h" + +#include "wdfcore.h" +#include "wdfdevice.h" +#include "wdfdevicepri.h" +#include "wdfiotargetpri.h" +#include "wdfdriver.h" + +#include "wdfmemory.h" + +#include "wdfrequest.h" +#include "wdfwmi.h" +#include "wdfChildList.h" +#include "wdfpdo.h" +#include "wdffdo.h" +#include "wdfiotarget.h" +#include "wdfcontrol.h" +#include "wdfcx.h" +#include "wdfio.h" +#include "wdfqueryinterface.h" +#include "wdfworkitem.h" + +#include "wdfcollection.h" + +#include "wdffileobject.h" +#include "wdfinterrupt.h" +#include "wdfregistry.h" +#include "wdfresource.h" +#include "wdfstring.h" +#include "wdfsync.h" +#include "wdftimer.h" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "wdfhid.h" +#endif + +#pragma warning(disable:4200) // suppress nameless struct/union warning +#pragma warning(disable:4201) // suppress nameless struct/union warning +#pragma warning(disable:4214) // suppress bit field types other than int warning +#include +#include +#include "wdfusb.h" +#include +#include +#include + +#include "wdfbugcodes.h" + +WDF_EXTERN_C_END + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#define KMDF_ONLY_CODE_PATH_ASSERT() FX_VERIFY(INTERNAL, TRAPMSG("Not implemented")); +#define UMDF_ONLY_CODE_PATH_ASSERT() +#else +#define KMDF_ONLY_CODE_PATH_ASSERT() +#define UMDF_ONLY_CODE_PATH_ASSERT() ASSERTMSG("Not implemented for KMDF", FALSE); +#endif + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_0; + +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V1_0; + +#include "cobbled.hpp" + +} //extern "C" + +#include +#include +#include +#include + +#if FX_CORE_MODE==FX_CORE_USER_MODE +typedef enum _TRACE_INFORMATION_CLASS { + TraceIdClass, + TraceHandleClass, + TraceEnableFlagsClass, + TraceEnableLevelClass, + GlobalLoggerHandleClass, + EventLoggerHandleClass, + AllLoggerHandlesClass, + TraceHandleByNameClass, + LoggerEventsLostClass, + TraceSessionSettingsClass, + MaxTraceInformationClass +} TRACE_INFORMATION_CLASS; + +#include +#endif // FX_CORE_MODE==FX_CORE_USER_MODE + +#include "FxForward.hpp" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "HostFxUtil.h" +#include "wdfplatform.h" +#include "wdfplatformimpl.h" +#include "debug.h" +#include "devreg.h" +#include "wudfx_namespace_on.h" +#include "wudfx.h" +#include "wudfx_namespace_off.h" +#include "DriverFrameworks-UserMode-UmEvents.h" +#endif + +#include "fxtypedefs.hpp" + +#if defined(EVENT_TRACING) +#include "fxwmicompat.h" +#include "FxTrace.h" +#else +#include "DbgTrace.h" +#endif // EVENT_TRACING + +#include "FxTypes.h" +#include "fxrequestcontexttypes.h" +#include "FxPool.h" + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) +#include "FxGlobalsKm.h" +#include "FxPerfTraceKm.hpp" +#include "DriverFrameworks-KernelMode-KmEvents.h" +#else +#include "FxGlobalsUm.h" +#endif +#include "FxPoolInlines.hpp" +#include "fxverifier.h" +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) +#include "FxVerifierKm.h" +#else +#include "FxVerifierUm.h" +#include "device_common.h" +#endif +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) +#include "FxMdl.h" +#endif + +#include "FxProbeAndLock.h" +//#include "FxPerfTraceKm.hpp" +//#include + +#include "FxStump.hpp" +#include "FxRequestBuffer.hpp" +#include "FxTagTracker.hpp" + +// internal locks +#include "FxVerifierLock.hpp" +#include "FxLock.hpp" + +// base objects +#include "FxObject.hpp" +#include "FxPagedObject.hpp" +#include "FxNonPagedObject.hpp" + +#include "fxhandle.h" + +// external locks +#include "FxWaitLock.hpp" +//#include "FxSpinLock.hpp" + +// utitilty classes and functions +#include "FxTransactionedList.hpp" +#include "FxRelatedDeviceList.hpp" +#include "FxDisposeList.hpp" +#include "FxCollection.hpp" +#include "StringUtil.hpp" + +// abstract classes +#include "IFxHasCallbacks.hpp" + +// callback delegation and locking +#include "FxSystemThread.hpp" +#include "FxSystemWorkItem.hpp" +#include "FxCallbackLock.hpp" +#include "FxCallbackSpinLock.hpp" +#include "FxCallbackMutexLock.hpp" +#include "FxCallback.hpp" +#include "FxSystemThread.hpp" + +#include "IFxMemory.hpp" +#include "FxLookasideList.hpp" +//#include "FxNPagedLookasideList.hpp" +//#include "FxPagedLookasideList.hpp" +#include "FxMemoryObject.hpp" +#include "FxMemoryBuffer.hpp" +#include "FxMemoryBufferFromPool.hpp" +#include "FxMemoryBufferPreallocated.hpp" +//#include "FxMemoryBufferFromLookaside.hpp" +#include "FxRequestMemory.hpp" +#include "FxRegKey.hpp" +#include "FxAutoRegistry.hpp" +#include "FxAutoString.hpp" +#include "FxString.hpp" + +#include "FxValidateFunctions.hpp" + +#include "FxResource.hpp" +#include "FxRelatedDevice.hpp" +#include "FxDeviceInterface.hpp" +#include "FxQueryInterface.hpp" +#include "FxDeviceText.hpp" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "FxIrpUm.hpp" +#include "FxInterruptThreadpoolUm.hpp" +#else +#include "FxIrpKm.hpp" +#endif +#include "FxDriver.hpp" + +// generic package interface +#include "FxPackage.hpp" +#include "FxPkgGeneral.hpp" +#include "FxDefaultIrpHandler.hpp" +//#include "FxPoxKm.hpp" +#include "FxPkgPnp.hpp" +#include "FxWatchDog.hpp" + +// Device supportfx +#include "FxChildList.hpp" +#include "FxCxDeviceInfo.hpp" + +#include "FxDevice.hpp" + +#include "FxPkgIo.hpp" + +#include "FxDeviceToMxInterface.hpp" + +#include "FxIrpQueue.hpp" +#include "FxRequestContext.hpp" +#include "FxRequestCallbacks.hpp" +#include "FxRequestBase.hpp" +#include "FxRequest.hpp" +#include "FxSyncRequest.hpp" + +#include "FxRequestValidateFunctions.hpp" + +// specialized irp handlers (ie packages) +#include "FxPkgFdo.hpp" +#include "FxPkgPdo.hpp" + +//#include "FxWmiIrpHandler.hpp" +//#include "FxWmiProvider.hpp" +//#include "FxWmiInstance.hpp" + +// queus for read, write, (internal) IOCTL +#include "FxIoQueue.hpp" +#include "FxFileObject.hpp" +#include "FxIrpPreprocessInfo.hpp" +#include "FxIrpDynamicDispatchInfo.hpp" + +//#include "FxDpc.hpp" +#include "FxWorkItem.hpp" +#include "FxTimer.hpp" +#if FX_CORE_MODE==FX_CORE_USER_MODE +#include "FxInterruptUm.hpp" +#include "FxMessageDispatchUm.hpp" +#else +#include "FxInterruptKm.hpp" +#endif + +// IO targets (device lower edge interface) +#include "FxIoTarget.hpp" +#include "FxIoTargetRemote.hpp" +#include "FxIoTargetSelf.hpp" + +#include "FxUsbDevice.hpp" +#include "FxUsbInterface.hpp" +#include "FxUsbPipe.hpp" + +// DMA support +//#include "FxDmaEnabler.hpp" +//#include "FxDmaTransaction.hpp" +//#include "FxCommonBuffer.hpp" + +// Triage info. +#include "wdftriage.h" + + +#include "FxPkgIoShared.hpp" + +#if FX_CORE_MODE==FX_CORE_USER_MODE +#include "UfxVerifier.h" +#endif + + +#endif // _FXMIN_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxnonpagedobject.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxnonpagedobject.hpp new file mode 100644 index 00000000000..259a4544036 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxnonpagedobject.hpp @@ -0,0 +1,229 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxNonPagedObject.hpp + +Abstract: + + This module defines the abstract FxNonPagedObject class. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + Made mode agnostic + + IMPORTANT: Common code must call Initialize method of + FxNonPagedObject before using it + + Cannot put CreateAndInitialize method on this class as it + cannot be instantiated + +--*/ + +#ifndef _FXNONPAGEDOBJECT_H_ +#define _FXNONPAGEDOBJECT_H_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxNonPagedObject.hpp.tmh" +#endif + +} + +class FxNonPagedObject : public FxObject +{ +private: + + MxLock m_NPLock; + +public: + FxNonPagedObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxObject(Type, Size, FxDriverGlobals) + { + if (IsDebug()) { + if (GetDriverGlobals()->FxVerifierLock) { + // + // VerifierLock CreateAndInitialize failure is not fatal, + // we just won't track anything + // + FxVerifierLock * verifierLock = NULL; + (void) FxVerifierLock::CreateAndInitialize(&verifierLock, + GetDriverGlobals(), + this); + GetDebugExtension()->VerifierLock = verifierLock; + } + } + } + + FxNonPagedObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObjectType ObjectType + ) : + FxObject(Type, Size, FxDriverGlobals, ObjectType) + { + if (IsDebug()) { + if (GetDriverGlobals()->FxVerifierLock) { + // + // VerifierLock CreateAndInitialize failure is not fatal, + // we just won't track anything + // + FxVerifierLock * verifierLock = NULL; + (void) FxVerifierLock::CreateAndInitialize(&verifierLock, + GetDriverGlobals(), + this); + GetDebugExtension()->VerifierLock = verifierLock; + } + } + } + + virtual + ~FxNonPagedObject( + VOID + ) + { + if (IsDebug()) { + FxObjectDebugExtension* pExtension; + + pExtension = GetDebugExtension(); + + if (pExtension->VerifierLock != NULL) { + delete pExtension->VerifierLock; + pExtension->VerifierLock = NULL; + } + } + } + + _Acquires_lock_(this->m_NPLock.m_Lock) + __drv_maxIRQL(DISPATCH_LEVEL) + __drv_setsIRQL(DISPATCH_LEVEL) + VOID + Lock( + __out __drv_deref(__drv_savesIRQL) PKIRQL PreviousIrql + ) + { + if (IsDebug()) { + FxObjectDebugExtension* pExtension; + + pExtension = GetDebugExtension(); + + if (pExtension->VerifierLock != NULL) { + pExtension->VerifierLock->Lock(PreviousIrql, FALSE); + // + // return here so that we don't acquire the non verified lock + // below + // + return; + } + } + + m_NPLock.Acquire(PreviousIrql); + } + + _Releases_lock_(this->m_NPLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + VOID + Unlock( + __in __drv_restoresIRQL KIRQL PreviousIrql + ) + { + if (IsDebug()) { + FxObjectDebugExtension* pExtension; + + pExtension = GetDebugExtension(); + + if (pExtension->VerifierLock != NULL) { + pExtension->VerifierLock->Unlock(PreviousIrql, FALSE); + + // + // return here so that we don't release the non verified lock + // below + // + return; + } + } + + m_NPLock.Release(PreviousIrql); + } + +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE + + _Acquires_lock_(this->m_NPLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + LockAtDispatch( + VOID + ) + { + if (IsDebug()) { + FxObjectDebugExtension* pExtension; + + pExtension = GetDebugExtension(); + + if (pExtension->VerifierLock != NULL) { + KIRQL previousIrql; + + pExtension->VerifierLock->Lock(&previousIrql, TRUE); + + ASSERT(previousIrql == DISPATCH_LEVEL); + // + // return here so that we don't acquire the non verified lock + // below + // + return; + } + } + + m_NPLock.AcquireAtDpcLevel(); + } + + _Requires_lock_held_(this->m_NPLock.m_Lock) + _Releases_lock_(this->m_NPLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + __inline + VOID + UnlockFromDispatch( + VOID + ) + { + if (IsDebug()) { + FxObjectDebugExtension* pExtension; + + pExtension = GetDebugExtension(); + + if (pExtension->VerifierLock != NULL) { + pExtension->VerifierLock->Unlock(DISPATCH_LEVEL, TRUE); + + // + // return here so that we don't acquire the non verified lock + // below + // + return; + } + } + + m_NPLock.ReleaseFromDpcLevel(); + } + +#endif //FX_CORE_MODE==FX_CORE_KERNEL_MODE +}; + +#endif // _FXNONPAGEDOBJECT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxnpagedlookasidelist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxnpagedlookasidelist.hpp new file mode 100644 index 00000000000..ee55199c3c7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxnpagedlookasidelist.hpp @@ -0,0 +1,110 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxNPagedLookasideList.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXNPAGEDLOOKASIDELIST_H_ +#define _FXNPAGEDLOOKASIDELIST_H_ + +class FxNPagedLookasideList : public FxLookasideList { +public: + FxNPagedLookasideList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Allocate( + __out FxMemoryObject** PPMemory + ); + +protected: + ~FxNPagedLookasideList(); + + virtual + VOID + Reclaim( + __in FxMemoryBufferFromLookaside* Memory + ); + +protected: + NPAGED_LOOKASIDE_LIST m_ObjectLookaside; +}; + +class FxNPagedLookasideListFromPool : public FxLookasideListFromPool { + + friend FxMemoryBufferFromPoolLookaside; + +public: + FxNPagedLookasideListFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Allocate( + __out FxMemoryObject** PPMemory + ); + +protected: + ~FxNPagedLookasideListFromPool( + VOID + ); + + virtual + VOID + Reclaim( + __in FxMemoryBufferFromLookaside* Memory + ); + + virtual + VOID + ReclaimPool( + __inout PVOID Pool + ) + { + FxFreeToNPagedLookasideList(&m_PoolLookaside, Pool); + } + + NPAGED_LOOKASIDE_LIST m_ObjectLookaside; + + NPAGED_LOOKASIDE_LIST m_PoolLookaside; +}; + + +#endif // __FX_NPAGED_LOOKASIDE_LIST_H__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxobject.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxobject.hpp new file mode 100644 index 00000000000..a830c7d1116 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxobject.hpp @@ -0,0 +1,1506 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObject.hpp + +Abstract: + + This is the C++ header for the FxObject + +Author: + + + + +Revision History: + + + Made mode agnostic + + IMPORTANT: Common code must call Initialize method of + FxObject before using it + + Cannot put CreateAndInitialize method on this class as it + cannot be instantiated + + +--*/ + +#ifndef _FXOBJECT_H_ +#define _FXOBJECT_H_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxObject.hpp.tmh" +#endif + +} + +// +// Macros to pass line and file information to AddRef and Release calls. +// +// NOTE: ADDREF and RELEASE can be used by any class derived from FxObject or +// IFxMemory while the OFFSET only works with an FxObject derivation +// +#define ADDREF(_tag) AddRef(_tag, __LINE__, __FILE__) +#define RELEASE(_tag) Release(_tag, __LINE__, __FILE__) + +#define ADDREF_OFFSET(_tag, offset) AddRefOverride(offset, _tag, __LINE__, __FILE__) +#define RELEASE_OFFSET(_tag, offset) ReleaseOverride(offset, _tag, __LINE__, __FILE__) + +// +// This assumes that the bottom 3 bits of an FxObject are clear, ie that the +// FxObject is 8 byte aligned. The conversion from and to a handle value +// will set / clear these bits as appropriate. +// +enum FxHandleFlags { + FxHandleFlagIsOffset = 0x1, + FxHandleFlagMask = 0x7, // bottom 3 bits are free +}; + +// +// We cannot define FxHandleValueMask as an enumerant in FxHandleFlags because +// an enum is limited to sizeof(ULONG), which doesn't work for us on a 64 bit OS +// +extern __declspec(selectany) const ULONG_PTR FxHandleValueMask = (~((ULONG_PTR) FxHandleFlagMask)); + +// +// The type itself is aligned, but the pointer is not b/c those interested in the +// offset do not need it to be aligned. +// +// The offset is aligned on an 8 byte boundary so that we have the lower 3 bits +// of the low byte to use for a bit field +// +typedef DECLSPEC_ALIGN(8) USHORT WDFOBJECT_OFFSET_ALIGNED; + +typedef USHORT WDFOBJECT_OFFSET, *PWDFOBJECT_OFFSET; + +struct FxQueryInterfaceParams { + // + // We intentionally do not declare a constructor for this structure. + // Instead, code should use an inline initializer list. This reduces the + // number of cycles on hot paths by removing a funciton call. + // + // FxQueryInterfaceParams( + // PVOID* Object, + // WDFTYPE Type + // ) : + // Type(Type), Object(Object), Offset(0) {if (Object != NULL) *Object = NULL; }} + + // + // Object to query for + // + PVOID* Object; + + // + // Type for the object to query for + // + WDFTYPE Type; + + // + // Offset of handle within its owning object. If zero, the Object was the + // handle. If not zero, ((PUCHAR) Object)-Offset will yield the owning + // Object. + // + WDFOBJECT_OFFSET Offset; +}; + +// +// type of object being allocated. An internal object does *NOT* +// 1) have its size rounded up to an alignment value +// 2) extra size and context header appended to the allocation +// +enum FxObjectType { + FxObjectTypeInvalid = 0, + FxObjectTypeInternal, + FxObjectTypeExternal, + FxObjectTypeEmbedded, +}; + +// Ensures that a BOOL type is generated from a flag mask +#define FLAG_TO_BOOL(_Flags, _FlagMask) (!!((_Flags) & (_FlagMask))) + +enum FxObjectLockState { + ObjectDoNotLock = 0, + ObjectLock = 1 +}; + +// +// Defines for FxObject::m_ObjectFlags +// +// NOTE: if you modify (add, remove, reassign a value) this enum in any way +// you must also change FxObject::m_ObjectFlagsByName.* to match your changes!! +// +enum FXOBJECT_FLAGS { + FXOBJECT_FLAGS_PASSIVE_CALLBACKS = 0x00000001, // Object must have all callbacks at passive level + // implies passive destroy + FXOBJECT_FLAGS_NODELETEDDI = 0x00000002, // The WdfObjectDelete DDI is invalid + FXOBJECT_FLAGS_DELETECALLED = 0x00000004, // DeleteObject method called + FXOBJECT_FLAGS_COMMITTED = 0x00000008, // Commit called + FXOBJECT_FLAGS_PASSIVE_DISPOSE = 0x00000010, // Object must be Dispose()'d at passive level + FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD = 0x00000020, // Object is always disposed in the dispose thread + // UNUSED = 0x00000040, + FXOBJECT_FLAGS_HAS_DEBUG = 0x00000080, // has FxObjectDebugExtension before object pointer + FXOBJECT_FLAGS_EARLY_DISPOSED_EXT = 0x00000100, // Early disposed externally to the state machine + FXOBJECT_FLAGS_TRACE_STATE = 0x00000200, // log state changes to the IFR + FXOBJECT_FLAGS_HAS_CLEANUP = 0x00000400, + FXOBJECT_FLAGS_DISPOSE_OVERRIDE = 0x00000800, +}; + +// +// FxObject state represents whether an object is +// tearing down, and what phase its in. +// +enum FxObjectState { + FxObjectStateInvalid = 0, + FxObjectStateCreated, + FxObjectStateDisposed, + FxObjectStateDisposingEarly, + FxObjectStateDisposingDisposeChildren, + FxObjectStateDeferedDisposing, + FxObjectStateDeferedDeleting, + FxObjectStateWaitingForEarlyDispose, + FxObjectStateWaitingForParentDeleteAndDisposed, + FxObjectStateDeletedDisposing, + FxObjectStateDeletedAndDisposed, + FxObjectStateDeferedDestroy, + FxObjectStateDestroyed, + FxObjectStateMaximum, +}; + +enum FxObjectDroppedEvent { + FxObjectDroppedEventAssignParentObject = 0, + FxObjectDroppedEventAddChildObjectInternal, + FxObjectDroppedEventRemoveChildObjectInternal, + FxObjectDroppedEventDeleteObject, + FxObjectDroppedEventPerformEarlyDispose, + FxObjectDroppedEventRemoveParentAssignment, + FxObjectDroppedEventParentDeleteEvent, +}; + +// begin_wpp config +// CUSTOM_TYPE(FxObjectState, ItemEnum(FxObjectState)); +// CUSTOM_TYPE(FxObjectDroppedEvent, ItemEnum(FxObjectDroppedEvent)); +// end_wpp + +#define DECLARE_INTERNAL_NEW_OPERATOR() \ + PVOID \ + __inline \ + operator new( \ + __in size_t Size, \ + __in PFX_DRIVER_GLOBALS FxDriverGlobals \ + ) \ + { \ + return FxObjectHandleAlloc(FxDriverGlobals, \ + NonPagedPool, \ + Size, \ + 0, \ + WDF_NO_OBJECT_ATTRIBUTES,\ + 0, \ + FxObjectTypeInternal); \ + } + +struct FxObjectDebugExtension { + FxTagTracker* TagTracker; + + FxVerifierLock* VerifierLock; + + BYTE StateHistory[8]; + + LONG StateHistoryIndex; + + // + // Signature lives after all the fields to avoid byte padding if it is + // first on 64 bit systems. + // + ULONG Signature; + + DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) ULONG AllocationStart[1]; +}; + +enum FxObjectDebugExtensionValues { + FxObjectDebugExtensionSize = FIELD_OFFSET(FxObjectDebugExtension, AllocationStart), + FxObjectDebugExtensionSignature = 'DOxF', +}; + +class UfxObject; + +class FxObject { + + friend UfxObject; //UMDF object wrapper + + friend FxDisposeList; + friend VOID GetTriageInfo(VOID); + +private: + +#if FX_CORE_MODE==FX_CORE_USER_MODE +#ifndef INLINE_WRAPPER_ALLOCATION + PVOID m_COMWrapper; +#endif +#endif + + WDFTYPE m_Type; + + // + // This is the already computed value of + // WDF_ALIGN_SIZE_UP(sizeof(derived object), MEMORY_ALLOCATION_ALIGNMENT) + + // WDF_ALIGN_SIZE_UP(extraContext, MEMORY_ALLOCATION_ALIGNMENT) + // + USHORT m_ObjectSize; + + // Reference count is operated on with interlocked operations + LONG m_Refcnt; + + PFX_DRIVER_GLOBALS m_Globals; + + // Flags are protected by m_SpinLock, bits defined by the enum FXOBJECT_FLAGS + union { + USHORT m_ObjectFlags; + + // Each field in this struct correspond to ascending enumerant values + // in FXOBJECT_FLAGS. + // + // NOTE: you should never touch these fields in any code, they are here + // strictly for use by the debugger extension so that it doesn't + // have to result FXOBJECT_FLAGS enumerant name strings into values. + // + struct { + USHORT PassiveCallbacks : 1; + USHORT NoDeleteDDI : 1; + USHORT DeleteCalled : 1; + USHORT Committed : 1; + USHORT PassiveDispose : 1; + USHORT ForceDisposeThread : 1; + USHORT Unused : 1; + USHORT HasDebug : 1; + USHORT EarlyDisposedExt : 1; + USHORT TraceState : 1; + } m_ObjectFlagsByName; + }; + + // + // m_ObjectState is protected by m_SpinLock. Contains values in the + // FxObjectState enum. + // + USHORT m_ObjectState; + + // List of Child Objects + LIST_ENTRY m_ChildListHead; + + // SpinLock protects m_ObjectState, m_ObjectFlags, m_ChildListHead, and m_ParentObject + MxLock m_SpinLock; + + // + // Parent object when this object is a child. + // + // This is protected by the child objects m_SpinLock + // + FxObject* m_ParentObject; + + // + // Link for when this object is a child + // + // This is accessed by the parent of this object, and + // protected by the parents spinlock. + // + LIST_ENTRY m_ChildEntry; + + // + // + // + SINGLE_LIST_ENTRY m_DisposeSingleEntry; + +protected: + union { + // + // This field is set when the object is being contructed or before + // Commit() and from then on is read only. + // + // FxDeviceBase* is used by the core object state machine. Derived + // objects might need the fuller FxDevice* (and they can safely get at + // it since they know they are a part of the derived FxDevice*). + // + CfxDeviceBase* m_DeviceBase; + CfxDevice* m_Device; + }; + +private: + FxObject( + VOID + ) + { + // Always make the caller supply a type and size + } + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + VOID, + VerifyConstruct, + _In_ BOOLEAN + ); + + VOID + __inline + Construct( + __in BOOLEAN Embedded + ) + { + m_Refcnt = 1; + m_ObjectState = FxObjectStateCreated; + m_ObjectFlags = 0; + m_ParentObject = NULL; + + InitializeListHead(&m_ChildListHead); + InitializeListHead(&m_ChildEntry); + m_DisposeSingleEntry.Next = NULL; + + m_DeviceBase = NULL; + + VerifyConstruct(m_Globals, Embedded); + } + + VOID + __inline + SetObjectStateLocked( + __in FxObjectState NewState + ) + { + if (m_ObjectFlags & FXOBJECT_FLAGS_TRACE_STATE) { + DoTraceLevelMessage( + m_Globals, TRACE_LEVEL_VERBOSE, TRACINGOBJECT, + "Object %p, WDFOBJECT %p transitioning from %!FxObjectState! to " + "%!FxObjectState!", this, GetObjectHandleUnchecked(), + m_ObjectState, NewState); + if (IsDebug()) { + FxObjectDebugExtension* pExtension; + + pExtension = GetDebugExtension(); + pExtension->StateHistory[ + InterlockedIncrement(&pExtension->StateHistoryIndex)] = + (BYTE) NewState; + } + } + + m_ObjectState = (USHORT) NewState; + } + +protected: + FxObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObjectType ObjectType + ); + + FxObjectDebugExtension* + GetDebugExtension( + VOID + ) + { + return CONTAINING_RECORD(this, FxObjectDebugExtension, AllocationStart); + } + + BOOLEAN + IsDebug( + VOID + ) + { + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_HAS_DEBUG); + } + + static + PVOID + _GetBase( + __in FxObject* Object + ) + { + if (Object->IsDebug()) { + return _GetDebugBase(Object); + } + else { + return (PVOID) Object; + } + } + + VOID + AllocateTagTracker( + __in WDFTYPE Type + ); + + virtual + VOID + SelfDestruct( + VOID + ) + { + delete this; + } + + PVOID + __inline + GetObjectHandleUnchecked( + VOID + ) + { + // + // We don't support offset handles in the base FxObject implementation. + // Offsets are specialized to internal objects of an FxObject + // + if (m_ObjectSize > 0) { + return _ToHandle(this); + } + else { + return NULL; + } + } + + VOID + __inline + DestroyChildren( + VOID + ) + { + PLIST_ENTRY ple; + FxObject *pChild; + + while (!IsListEmpty(&m_ChildListHead)) { + ple = RemoveHeadList(&m_ChildListHead); + + pChild = CONTAINING_RECORD(ple, FxObject, m_ChildEntry); + + // + // Mark entry as unlinked + // + InitializeListHead(&pChild->m_ChildEntry); + + // + // Inform child object of destruction. Object may be gone after return. + // + pChild->ParentDeleteEvent(); + } + } + +public: + +#ifdef INLINE_WRAPPER_ALLOCATION + +#if FX_CORE_MODE==FX_CORE_USER_MODE + static + USHORT + GetWrapperSize( + ); + + virtual + PVOID + GetCOMWrapper( + ) = 0; + +#else + static + USHORT + __inline + GetWrapperSize( + ) + { + return 0; + } + +#endif + +#else + +#if FX_CORE_MODE==FX_CORE_USER_MODE + PVOID GetCOMWrapper(){ return m_COMWrapper; } + + void SetCOMWrapper(__drv_aliasesMem PVOID Wrapper){ m_COMWrapper = Wrapper; } +#endif + +#endif + + FxObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + ~FxObject( + VOID + ); + + PVOID + __inline + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObjectType Type + ) + { + UNREFERENCED_PARAMETER(Type); + + return FxObjectHandleAlloc(FxDriverGlobals, + NonPagedPool, + Size, + 0, + WDF_NO_OBJECT_ATTRIBUTES, + 0, + Type); + } + + PVOID + __inline + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in USHORT ExtraSize = 0 + ) + { + return FxObjectHandleAlloc(FxDriverGlobals, + NonPagedPool, + Size, + 0, + Attributes, + ExtraSize, + FxObjectTypeExternal); + } + + VOID + operator delete( + __in PVOID Memory + ); + + static + FxObject* + _FromDisposeEntry( + __in PSINGLE_LIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxObject, m_DisposeSingleEntry); + } + + // + // m_ObjectSize contains the size of the object + extra size. m_ObjectSize + // was already rounded up to the correct alignment when it was contructed. + // + #define GET_CONTEXT_HEADER() WDF_PTR_ADD_OFFSET_TYPE(this, m_ObjectSize, FxContextHeader*) + + VOID + SetNoContextHeader( + VOID + ) + { + m_ObjectSize = 0; + } + + PVOID + __inline + GetObjectHandle( + VOID + ) + { + ASSERT(GetRefCnt() > 0); + return GetObjectHandleUnchecked(); + } + + static + FxObject* + _GetObjectFromHandle( + __in WDFOBJECT Handle, + __inout PWDFOBJECT_OFFSET ObjectOffset + ) + { + ULONG_PTR handle, flags; + + handle = (ULONG_PTR) Handle; + + // + // store the flags and then clear them off so we have a valid value + // + flags = FxHandleFlagMask & handle; + handle &= ~FxHandleFlagMask; + + // + // It is assumed the caller has already set the offset to zero + // + // *ObjectOffset = 0; + + // + // We always apply the mask + // + handle = handle ^ FxHandleValueMask; + + if (flags & FxHandleFlagIsOffset) { + // + // The handle is a pointer to an offset value. Return the offset + // to the caller and then compute the object since the pointer + // to the offset is part of the object we are returning. + // + *ObjectOffset = *(PWDFOBJECT_OFFSET) handle; + + return (FxObject*) (((PUCHAR) handle) - *ObjectOffset); + } + else { + // + // No offset, no verification. We pass the FxObject as the handle + // + return (FxObject*) handle; + } + } + + static + PVOID + __inline + _ToHandle( + __in FxObject* Object + ) + { + // + // Always XOR the constant. Faster than checking + // FxDriverGlobals->FxVerifierHandle. + // + return (PVOID) (((ULONG_PTR) Object) ^ FxHandleValueMask); + } + + static + VOID + __inline + _ReferenceActual( + __in WDFOBJECT Object, + __in_opt PVOID Tag, + __in LONG Line, + __in PSTR File + ) + { + FxObject* pObject; + WDFOBJECT_OFFSET offset; + + offset = 0; + pObject = FxObject::_GetObjectFromHandle(Object, &offset); + + if (offset == 0) { + pObject->AddRef(Tag, Line, File); + } + else { + pObject->AddRefOverride(offset, Tag, Line, File); + } + } + + static + VOID + __inline + _DereferenceActual( + __in WDFOBJECT Object, + __in_opt PVOID Tag, + __in LONG Line, + __in PSTR File + ) + { + FxObject* pObject; + WDFOBJECT_OFFSET offset; + + offset = 0; + pObject = FxObject::_GetObjectFromHandle(Object, &offset); + + if (offset == 0) { + pObject->Release(Tag, Line, File); + } + else { + pObject->ReleaseOverride(offset, Tag, Line, File); + } + } + + __inline + FxContextHeader* + GetContextHeader( + VOID + ) + { + if (m_ObjectSize == 0) { + return NULL; + } + else { + return GET_CONTEXT_HEADER(); + } + } + + __inline + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ) + { + return m_Globals; + } + + WDFTYPE + GetType( + VOID + ) + { + return m_Type; + } + + USHORT + GetObjectSize( + VOID + ) + { + return m_ObjectSize; + } + + LONG + GetRefCnt( + VOID + ) + { + return m_Refcnt; + } + + FxTagTracker* + GetTagTracker( + VOID + ) + { + if (IsDebug()) { + return CONTAINING_RECORD(this, + FxObjectDebugExtension, + AllocationStart)->TagTracker; + } + else { + return NULL; + } + } + + CfxDevice* + GetDevice( + VOID + ) + { + return m_Device; + } + + CfxDeviceBase* + GetDeviceBase( + VOID + ) + { + return m_DeviceBase; + } + + VOID + SetDeviceBase( + __in CfxDeviceBase* DeviceBase + ) + { + m_DeviceBase = DeviceBase; + } + + static + PVOID + _GetDebugBase( + __in FxObject* Object + ) + { + return CONTAINING_RECORD(Object, FxObjectDebugExtension, AllocationStart); + } + + __inline + VOID + CallCleanup( + VOID + ) + { + if (m_ObjectFlags & FXOBJECT_FLAGS_HAS_CLEANUP) { + CallCleanupCallbacks(); + } + } + + ULONG + __inline + AddRef( + __in_opt PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + FxTagTracker* pTagTracker; + ULONG c; + + c = InterlockedIncrement(&m_Refcnt); + + // + // Catch the transition from 0 to 1. Since the REF_OBJ starts off at 1, + // we should never have to increment to get to this value. + // + ASSERT(c > 1); + + pTagTracker = GetTagTracker(); + if (pTagTracker != NULL) { + pTagTracker->UpdateTagHistory(Tag, Line, File, TagAddRef, c); + } + + return c; + } + + virtual + ULONG + Release( + __in_opt PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + FxTagTracker* pTagTracker; + ULONG c; + + pTagTracker = GetTagTracker(); + if (pTagTracker != NULL) { + pTagTracker->UpdateTagHistory(Tag, Line, File, TagRelease, m_Refcnt - 1); + } + + c = InterlockedDecrement(&m_Refcnt); + + if (c == 0) { + FinalRelease(); + } + + return c; + } + + virtual + ULONG + AddRefOverride( + __in WDFOBJECT_OFFSET Offset, + __in_opt PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + UNREFERENCED_PARAMETER(Offset); + + return AddRef(Tag, Line, File); + } + + virtual + ULONG + ReleaseOverride( + __in WDFOBJECT_OFFSET Offset, + __in_opt PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + UNREFERENCED_PARAMETER(Offset); + + return Release(Tag, Line, File); + } + + _Must_inspect_result_ + virtual + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ); + + VOID + MarkTraceState( + VOID + ) + { + m_ObjectFlags |= FXOBJECT_FLAGS_TRACE_STATE; + } + + BOOLEAN + __inline + IsTraceState( + VOID + ) + { + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_TRACE_STATE); + } + + VOID + __inline + TraceDroppedEvent( + __in FxObjectDroppedEvent Event + ) + { + if (IsTraceState()) { + DoTraceLevelMessage( + m_Globals, TRACE_LEVEL_INFORMATION, TRACINGOBJECT, + "Object %p, WDFOBJECT %p, state %!FxObjectState! dropping event" + " %!FxObjectDroppedEvent!", + this, GetObjectHandleUnchecked(), m_ObjectState, Event); + } + } + + VOID + MarkPassiveDispose( + __in FxObjectLockState State = ObjectLock + ) + { + // + // Object which can have > passive level locks, but needs to be Dispose()'d + // at passive level. This means that the object's client cleanup + // routines will also be guaranteed to run at passive. + // + if (State == ObjectLock) { + KIRQL oldIrql; + + m_SpinLock.Acquire(&oldIrql); + m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_DISPOSE; + m_SpinLock.Release(oldIrql); + } + else { + m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_DISPOSE; + } + } + + // + // Sets that the object is a passive level only object who + // accesses page-able pool, routines, or has a driver + // specified passive constraint on callbacks such as + // Cleanup and Destroy. + // + VOID + MarkPassiveCallbacks( + __in FxObjectLockState State = ObjectLock + ) + { + if (State == ObjectLock) { + KIRQL oldIrql; + + m_SpinLock.Acquire(&oldIrql); + m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_CALLBACKS | FXOBJECT_FLAGS_PASSIVE_DISPOSE; + m_SpinLock.Release(oldIrql); + } + else { + m_ObjectFlags |= FXOBJECT_FLAGS_PASSIVE_CALLBACKS | FXOBJECT_FLAGS_PASSIVE_DISPOSE; + } + } + + VOID + MarkForceDisposeThread( + __in FxObjectLockState State = ObjectLock + ) + { + // + // Object must always be disposed in a separate thread + // to allow waiting for some outstanding async + // operation to complete. + // + if (State == ObjectLock) { + KIRQL oldIrql; + + m_SpinLock.Acquire(&oldIrql); + m_ObjectFlags |= FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD; + m_SpinLock.Release(oldIrql); + } + else { + m_ObjectFlags |= FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD; + } + } + + BOOLEAN + IsPassiveCallbacks( + __in BOOLEAN AcquireLock = TRUE + ) + { + BOOLEAN result; + KIRQL oldIrql = PASSIVE_LEVEL; + + if (AcquireLock) { + m_SpinLock.Acquire(&oldIrql); + } + + result = IsPassiveCallbacksLocked(); + + if (AcquireLock) { + m_SpinLock.Release(oldIrql); + } + + return result; + } + + BOOLEAN + IsPassiveDispose( + __in BOOLEAN AcquireLock = TRUE + ) + { + BOOLEAN result; + KIRQL oldIrql = PASSIVE_LEVEL; + + if (AcquireLock) { + m_SpinLock.Acquire(&oldIrql); + } + + result = IsPassiveDisposeLocked(); + + if (AcquireLock) { + m_SpinLock.Release(oldIrql); + } + + return result; + } + + BOOLEAN + IsForceDisposeThread( + __in BOOLEAN AcquireLock = TRUE + ) + { + BOOLEAN result; + KIRQL oldIrql = PASSIVE_LEVEL; + + if (AcquireLock) { + m_SpinLock.Acquire(&oldIrql); + } + + result = IsForceDisposeThreadLocked(); + + if (AcquireLock) { + m_SpinLock.Release(oldIrql); + } + + return result; + } + + VOID + MarkCommitted( + VOID + ) + { + // + // Since no client code is accessing the handle yet, we don't need to + // acquire the object state lock to set the flag since this will be + // the only thread touching m_ObjectFlags. + // + m_ObjectFlags |= FXOBJECT_FLAGS_COMMITTED; + } + + BOOLEAN + IsCommitted( + VOID + ) + { + // + // No need to acquire the lock because it is assumed the caller is + // calling on an object whose ref count has gone to zero so there are + // no other callers to contend with who might set this flag or modify + // m_ObjectFlags. + // + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_COMMITTED); + } + + VOID + MarkDisposeOverride( + __in FxObjectLockState State = ObjectLock + ) + { + if (State == ObjectLock) { + KIRQL irql; + + m_SpinLock.Acquire(&irql); + m_ObjectFlags |= FXOBJECT_FLAGS_DISPOSE_OVERRIDE; + m_SpinLock.Release(irql); + } + else { + m_ObjectFlags |= FXOBJECT_FLAGS_DISPOSE_OVERRIDE; + } + } + + VOID + MarkNoDeleteDDI( + __in FxObjectLockState State = ObjectLock + ) + { + if (State == ObjectLock) { + KIRQL irql; + + m_SpinLock.Acquire(&irql); + m_ObjectFlags |= FXOBJECT_FLAGS_NODELETEDDI; + m_SpinLock.Release(irql); + } + else { + m_ObjectFlags |= FXOBJECT_FLAGS_NODELETEDDI; + } + } + + BOOLEAN + IsNoDeleteDDI( + VOID + ) + { + // No need for lock since its only set in constructor/init + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_NODELETEDDI); + } + + // + // Commit the WDF object before returning handle to the caller. + // + _Must_inspect_result_ + NTSTATUS + Commit( + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out_opt WDFOBJECT* ObjectHandle, + __in_opt FxObject* Parent = NULL, + __in BOOLEAN AssignDriverAsDefaultParent = TRUE + ); + + VOID + DeleteFromFailedCreate( + VOID + ); + + VOID + ClearEvtCallbacks( + VOID + ); + + BOOLEAN + EarlyDispose( + VOID + ); + + // + // Request that an object be deleted. + // + // This can be the result of a WDF API or a WDM event. + // + virtual + VOID + DeleteObject( + VOID + ); + + // + // Invoked by FxObject *once* when the object is either + // being deleted, or rundown due to its parent object + // being deleted. + // + // An object can override this to perform per object + // cleanup if required. + // + // TRUE means that the cleanup callbacks should be called when the function + // returns. FALSE indicates that the caller will take care of calling the + // cleanup callbacks on behalf of the state machine. + // + virtual + BOOLEAN + Dispose( + VOID + ); + + // + // Request to make ParentObject the parent for this object. + // + _Must_inspect_result_ + NTSTATUS + AssignParentObject( + __in FxObject* ParentObject + ); + + _Must_inspect_result_ + NTSTATUS + AddContext( + __in FxContextHeader *Header, + __in PVOID* Context, + __in PWDF_OBJECT_ATTRIBUTES Attributes + ); + + // + // Request that this Object be removed from the child association + // list for its parent + // + _Must_inspect_result_ + NTSTATUS + RemoveParentAssignment( + VOID + ); + + // + // Adds a reference to the parent object pointer if != NULL + // + _Must_inspect_result_ + FxObject* + GetParentObjectReferenced( + __in PVOID Tag + ); + + // + // This is public to allow debug code to assert that + // an object has been properly disposed either through + // calling DeleteObject, or being disposed by its parent. + // + BOOLEAN + IsDisposed( + VOID + ) + { + KIRQL oldIrql; + BOOLEAN disposed; + + if (m_Globals->FxVerifierOn && + m_Globals->FxVerifierHandle) { + m_SpinLock.Acquire(&oldIrql); + + if (m_ObjectState == FxObjectStateCreated) { + disposed = FALSE; + } + else { + // + // Parent is disposing us, or we are being disposed + // + disposed = TRUE; + } + + m_SpinLock.Release(oldIrql); + + return disposed; + } + else { + return TRUE; + } + } + + static + PFX_POOL_HEADER + _CleanupPointer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* Object + ) + { + PFX_POOL_HEADER pHeader; + PVOID pObjectBase; + + pObjectBase = _GetBase(Object); + + pHeader = CONTAINING_RECORD(pObjectBase, FX_POOL_HEADER, AllocationStart); + + // + // If PoolTracker is on then do.... + // + if (FxDriverGlobals->IsPoolTrackingOn()) { + // + // Decommission this NonPaged Allocation tracker + // + FxPoolRemoveNonPagedAllocateTracker((PFX_POOL_TRACKER) pHeader->Base); + } + + return pHeader; + } + + _Must_inspect_result_ + static + NTSTATUS + _GetEffectiveLock( + __in FxObject* Object, + __in_opt IFxHasCallbacks* Callbacks, + __in BOOLEAN AutomaticLocking, + __in BOOLEAN PassiveCallbacks, + __out FxCallbackLock** CallbackLock, + __out_opt FxObject** CallbackLockObject + ); + + // + // Implementation for WdfObjectQuery + // + _Must_inspect_result_ + static + NTSTATUS + _ObjectQuery( + _In_ FxObject* Object, + _In_ CONST GUID* Guid, + _In_ ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ); + +protected: + VOID + DeleteEarlyDisposedObject( + VOID + ); + +private: + VOID + FinalRelease( + VOID + ); + + // + // This is used by verifier to ensure that DeleteObject + // is only called once. + // + // It must be accessed under the m_SpinLock. + // + // It returns TRUE if this is the first call. + // + BOOLEAN + MarkDeleteCalledLocked( + VOID + ) + { + BOOLEAN retval; + + retval = !(m_ObjectFlags & FXOBJECT_FLAGS_DELETECALLED); + + m_ObjectFlags |= FXOBJECT_FLAGS_DELETECALLED; + + return retval; + } + + BOOLEAN + IsPassiveCallbacksLocked( + VOID + ) + { + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_PASSIVE_CALLBACKS); + } + + BOOLEAN + IsPassiveDisposeLocked( + VOID + ) + { + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_PASSIVE_DISPOSE); + } + + BOOLEAN + IsForceDisposeThreadLocked( + VOID + ) + { + return FLAG_TO_BOOL(m_ObjectFlags, FXOBJECT_FLAGS_FORCE_DISPOSE_THREAD); + } + + BOOLEAN + ShouldDeferDisposeLocked( + __out_opt PKIRQL PreviousIrql = NULL + ) + { + if (IsForceDisposeThreadLocked()) { + return TRUE; + } + else if (IsPassiveDisposeLocked()) { + // + // Only call KeGetCurrentIrql() if absolutely necessary. It is an + // expensive call and we want to minimize the cycles required when + // destroying an object that requires passive rundown + // + + // + // Cases: + // 1) Caller does not know the current IRQL, so we must query for it + // + // 2) Caller knew prev IRQL, so we used the caller's value + // + if (PreviousIrql == NULL) { // case 1 + if (Mx::MxGetCurrentIrql() != PASSIVE_LEVEL) { + return TRUE; + } + } + else if (*PreviousIrql != PASSIVE_LEVEL) { // case 2 + return TRUE; + } + } + + return FALSE; + } + + VOID + ParentDeleteEvent( + VOID + ); + + BOOLEAN + PerformEarlyDispose( + VOID + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + PerformEarlyDisposeWorkerAndUnlock( + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + PerformDisposingDisposeChildrenLocked( + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + DeleteWorkerAndUnlock( + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ); + + VOID + QueueDeferredDisposeLocked( + __in FxObjectState NewDeferedState + ); + + VOID + DeferredDisposeWorkItem( + VOID + ); + + _Releases_lock_(this->m_SpinLock.m_Lock) + __drv_requiresIRQL(DISPATCH_LEVEL) + BOOLEAN + DisposeChildrenWorker( + __in FxObjectState NewDeferedState, + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ); + + _When_(Unlock, _Releases_lock_(this->m_SpinLock.m_Lock)) + __drv_when(Unlock, __drv_requiresIRQL(DISPATCH_LEVEL)) + VOID + DeletedAndDisposedWorkerLocked( + __in __drv_when(Unlock, __drv_restoresIRQL) KIRQL OldIrql, + __in BOOLEAN Unlock = TRUE + ); + + _Must_inspect_result_ + NTSTATUS + RemoveParentAssociation( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + AddChildObjectInternal( + __in FxObject* ChildObject + ); + + _Must_inspect_result_ + NTSTATUS + RemoveChildObjectInternal( + __in FxObject* ChildObject + ); + + VOID + ProcessDestroy( + VOID + ); + + VOID + CallCleanupCallbacks( + VOID + ); +}; + +#endif // _FXOBJECT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpackage.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpackage.hpp new file mode 100644 index 00000000000..c17826f4011 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpackage.hpp @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxPackage.hpp + +Abstract: + + This is the definition of the FxPackage object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXPACKAGE_H_ +#define _FXPACKAGE_H_ + +class FxPackage : public FxNonPagedObject +{ +public: + + FxPackage( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device, + __in WDFTYPE Type + ); + + virtual + NTSTATUS + Dispatch( + __in MdIrp Irp + ) = 0; + + __inline + CfxDevice* + GetDevice( + VOID + ) + { + return m_Device; + } + + DECLARE_INTERNAL_NEW_OPERATOR(); +}; + +#endif // _FXPACKAGE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpagedlookasidelist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpagedlookasidelist.hpp new file mode 100644 index 00000000000..acb78a584ad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpagedlookasidelist.hpp @@ -0,0 +1,127 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPagedLookasideList.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXPAGEDLOOKASIDELIST_H_ +#define _FXPAGEDLOOKASIDELIST_H_ + +class FxPagedLookasideListFromPool : public FxLookasideListFromPool { + + friend FxMemoryBufferFromPoolLookaside; + +public: + FxPagedLookasideListFromPool( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in ULONG PoolTag, + __in FxDeviceBase* DeviceBase, + __in FxDeviceBase* MemoryDeviceBase + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Initialize( + __in size_t BufferSize, + __in PWDF_OBJECT_ATTRIBUTES MemoryAttributes + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Allocate( + __out FxMemoryObject** PPMemory + ); + +protected: + ~FxPagedLookasideListFromPool( + VOID + ); + + virtual + VOID + Reclaim( + __in FxMemoryBufferFromLookaside* Memory + ); + + virtual + VOID + ReclaimPool( + __inout PVOID Pool + ) + { + if (m_BufferSize < PAGE_SIZE) { + PFX_POOL_HEADER pHeader; + + // + // For < PAGE_SIZE, we track the allocation + // + pHeader = CONTAINING_RECORD(Pool, FX_POOL_HEADER, AllocationStart); + + // + // If PoolTracker is on then do.... + // + if (GetDriverGlobals()->IsPoolTrackingOn()) { + // + // Decommission this Paged Allocation tracker + // +#pragma prefast(suppress:__WARNING_BUFFER_UNDERFLOW, "Accessing pool's header to reclaim pool"); + FxPoolRemovePagedAllocateTracker((PFX_POOL_TRACKER) pHeader->Base); + } + +#pragma prefast(suppress:__WARNING_BUFFER_UNDERFLOW, "Accessing pool's header to reclaim pool"); + FxFreeToPagedLookasideList(&m_PoolLookaside, pHeader->Base); + } + else { + // + // Page or greater size has no allocation tracking info prepended + // to the allocation. + // + FxFreeToPagedLookasideList(&m_PoolLookaside, Pool); + } + } + + PVOID + InitPagedAlloc( + __out_bcount(this->m_RawBufferSize) PVOID Alloc + ); + + BOOLEAN + UsePagedBufferObject( + VOID + ) + { + return m_MemoryDeviceBase != NULL ? TRUE : FALSE; + } + +protected: + // + // m_BufferSize is the size of the allocation that client sees. + // m_RawBufferSize is m_BufferSize + whatever else we need to track the + // allocation. + // + size_t m_RawBufferSize; + + FxDeviceBase* m_MemoryDeviceBase; + + NPAGED_LOOKASIDE_LIST m_ObjectLookaside; + + PAGED_LOOKASIDE_LIST m_PoolLookaside; +}; + +#endif // _FXPAGEDLOOKASIDELIST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpagedobject.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpagedobject.hpp new file mode 100644 index 00000000000..3c794241b7a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpagedobject.hpp @@ -0,0 +1,90 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPagedObject.hpp + +Abstract: + + This module defines the abstract FxPagedObject class. + +Author: + + + +--*/ + +#ifndef _FXPAGEDOBJECT_H_ +#define _FXPAGEDOBJECT_H_ + +class FxPagedObject : public FxObject +{ +private: + MxPagedLock* m_Lock; + +public: + + FxPagedObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxObject(Type, Size, FxDriverGlobals) + { + m_Lock = NULL; + + // no need to hold the lock while the object is being constructed + MarkPassiveCallbacks(ObjectDoNotLock); + } + + virtual + ~FxPagedObject( + VOID + ) + { + if (m_Lock != NULL) { + FxPoolFree(m_Lock); + m_Lock = NULL; + } + } + + VOID + Lock( + VOID + ) + { + m_Lock->Acquire(); + } + + VOID + Unlock( + VOID + ) + { + m_Lock->Release(); + } + + _Must_inspect_result_ + NTSTATUS + Initialize( + VOID + ) + { + PFX_DRIVER_GLOBALS fxDriverGlobals; + + fxDriverGlobals = GetDriverGlobals(); + m_Lock = (MxPagedLock*) FxPoolAllocate(fxDriverGlobals, + NonPagedPool, + sizeof(MxPagedLock)); + if (m_Lock != NULL) { + return m_Lock->Initialize(); + } + else { + return STATUS_INSUFFICIENT_RESOURCES; + } + } +}; + +#endif // _FXPAGEDOBJECT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgfdo.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgfdo.hpp new file mode 100644 index 00000000000..6d689bf435c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgfdo.hpp @@ -0,0 +1,486 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgFdo.hpp + +Abstract: + + This module implements the pnp package for Fdo objects. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXPKGFDO_H_ +#define _FXPKGFDO_H_ + +struct FxStaticChildDescription { + WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Header; + + CfxDevice* Pdo; +}; + +class FxPkgFdo : public FxPkgPnp +{ +public: + // + // Pnp Properties + // + FxChildList* m_DefaultDeviceList; + + FxChildList* m_StaticDeviceList; + + // + // Default target to the attached device in the stack + // + FxIoTarget* m_DefaultTarget; + + // + // A virtual target to yourself. This allows a cx to send + // the client. It may also be used by the client to send IO to itself. + // + FxIoTargetSelf* m_SelfTarget; + +private: + + REENUMERATE_SELF_INTERFACE_STANDARD m_SurpriseRemoveAndReenumerateSelfInterface; + + // + // The following structure contains the function pointer table + // for the "events" this package can raise. + // + FxPnpDeviceFilterResourceRequirements m_DeviceFilterAddResourceRequirements; + + FxPnpDeviceFilterResourceRequirements m_DeviceFilterRemoveResourceRequirements; + + FxPnpDeviceRemoveAddedResources m_DeviceRemoveAddedResources; + + BOOLEAN m_Filter; + + // + // Table of internal methods to handle PnP minor function codes. + // + static const PFN_PNP_POWER_CALLBACK m_FdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1]; + + // + // Table of internal methods to handle power minor function codes. + // + static const PFN_PNP_POWER_CALLBACK m_FdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1]; + + FxPkgFdo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ); + +public: + + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS pGlobals, + __in CfxDevice * Device, + __deref_out FxPkgFdo ** PkgFdo + ); + + _Must_inspect_result_ + NTSTATUS + RegisterCallbacks( + __in PWDF_FDO_EVENT_CALLBACKS DispatchTable + ); + + _Must_inspect_result_ + NTSTATUS + CreateDefaultDeviceList( + __in PWDF_CHILD_LIST_CONFIG ListConfig, + __in PWDF_OBJECT_ATTRIBUTES ListAttributes + ); + + _Must_inspect_result_ + virtual + NTSTATUS + Initialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + _Must_inspect_result_ + NTSTATUS + PostCreateDeviceInitialize( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + SetFilter( + __in BOOLEAN Value + ); + + BOOLEAN + IsFilter( + VOID + ) + { + return m_Filter; + } + +private: + + _Must_inspect_result_ + virtual + NTSTATUS + SendIrpSynchronously( + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + virtual + NTSTATUS + FireAndForgetIrp( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpPassDown( + __in FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpSurpriseRemoval( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryDeviceRelations( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpQueryDeviceRelations( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryInterface( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryCapabilities( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpQueryCapabilities( + __inout FxIrp *Irp + ); + + VOID + HandleQueryCapabilities( + __inout FxIrp *Irp + ); + + VOID + HandleQueryCapabilitiesCompletion( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryCapabilitiesCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpFilterResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpFilterResourceRequirements( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryPnpDeviceState( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryPnpDeviceStateCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ); + + VOID + HandleQueryPnpDeviceStateCompletion( + __inout FxIrp *Irp + ); + + virtual + BOOLEAN + PnpSendStartDeviceDownTheStackOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventEjectHardwareOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventCheckForDevicePresenceOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventPdoRemovedOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpGetPostRemoveState( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventFdoRemovedOverload( + VOID + ); + + static + _Must_inspect_result_ + NTSTATUS + _PowerPassDown( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ); + + static + _Must_inspect_result_ + NTSTATUS + _DispatchSetPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ); + + static + _Must_inspect_result_ + NTSTATUS + _DispatchQueryPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ); + + virtual + _Must_inspect_result_ + NTSTATUS + PowerCheckParentOverload( + __out BOOLEAN* ParentOn + ); + + virtual + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeOverload( + VOID + ); + + virtual + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeNPOverload( + VOID + ); + + virtual + VOID + PowerParentPowerDereference( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + DispatchSystemSetPower( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchDeviceSetPower( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchSystemQueryPower( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchDeviceQueryPower( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + RaiseDevicePower( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + LowerDevicePower( + __in FxIrp *Irp + ); + + virtual + VOID + PowerReleasePendingDeviceIrp( + __in BOOLEAN IrpMustBePresent = TRUE + ); + + _Must_inspect_result_ + virtual + NTSTATUS + ProcessRemoveDeviceOverload( + __inout FxIrp* Irp + ); + + virtual + VOID + DeleteSymbolicLinkOverload( + __in BOOLEAN GracefulRemove + ); + + virtual + VOID + QueryForReenumerationInterface( + VOID + ); + + virtual + VOID + ReleaseReenumerationInterface( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + AskParentToRemoveAndReenumerate( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + QueryForPowerThread( + VOID + ); + + virtual + const PFN_PNP_POWER_CALLBACK* + GetDispatchPnp( + VOID + ) + { + return m_FdoPnpFunctionTable; + } + + virtual + const PFN_PNP_POWER_CALLBACK* + GetDispatchPower( + VOID + ) + { + return m_FdoPowerFunctionTable; + } + + _Must_inspect_result_ + NTSTATUS + QueryForDsfInterface( + VOID + ); + +public: + + static + MdCompletionRoutineType + RaiseDevicePowerCompletion; + +protected: + ~FxPkgFdo(); + + static + MdCompletionRoutineType + _SystemPowerS0Completion; + + static + MdCompletionRoutineType + _SystemPowerSxCompletion; + + _Must_inspect_result_ + static + NTSTATUS + _PnpFilteredStartDeviceCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpStartDeviceCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ); +}; + +#endif // _FXPKGFDO_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkggeneral.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkggeneral.hpp new file mode 100644 index 00000000000..a28f42e158c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkggeneral.hpp @@ -0,0 +1,230 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgGeneral.hpp + +Abstract: + + This module implements a package to handle general dispath entry points + such as IRP_MJ_CREATE and IRP_MJ_CLOSE. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXPKGGENERAL_H_ +#define _FXPKGGENERAL_H_ + +#include "FxFileObjectCallbacks.hpp" + +class FxShutDown : public FxCallback { + +public: + PFN_WDF_DEVICE_SHUTDOWN_NOTIFICATION m_Method; + + FxShutDown( + VOID + ) : + FxCallback(), + m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +#define FX_PKG_GENERAL_FLAG_CX_INFO 0x00000001 +#define FX_PKG_GENERAL_FLAG_CLIENT_INFO 0x00000002 +#define FX_PKG_GENERAL_FLAG_CX_CREATE 0x00000004 +#define FX_PKG_GENERAL_FLAG_CLIENT_CREATE 0x00000008 + +#define FX_PKG_GENERAL_FLAG_CREATE \ + (FX_PKG_GENERAL_FLAG_CX_CREATE | FX_PKG_GENERAL_FLAG_CLIENT_CREATE) + + +class FxPkgGeneral : public FxPackage { + +private: + + // + // FileObject attributes + // + LONG m_OpenHandleCount; + + // + // List of file objects info (driver and cx). + // + LIST_ENTRY m_FileObjectInfoHeadList; + + FxIoQueue* m_DefaultQueueForCreates; + FxIoQueue* m_DriverCreatedQueue; + + // + // Generic file object flags. + // + ULONG m_Flags; + + // + // Execution and synchronization for cx and client driver. + // + WDF_EXECUTION_LEVEL m_ExecutionLevel; + WDF_SYNCHRONIZATION_SCOPE m_SynchronizationScope; + + // + // This pointer allows the proper lock to be acquired + // based on the configuration with a minimal of runtime + // checks. This is configured by ConfigureConstraints(). + // We basically inherit device's lock. + // + FxCallbackLock* m_CallbackLockPtr; + FxObject* m_CallbackLockObjectPtr; + + FxShutDown m_EvtDeviceShutdown; + +private: + _Must_inspect_result_ + NTSTATUS + OnCreate( + __inout FxIrp* FxIrp + ); + + _Must_inspect_result_ + NTSTATUS + OnClose( + __inout FxIrp* FxIrp + ); + + BOOLEAN + AcquireRemoveLockForClose( + __inout FxIrp* FxIrp + ); + + _Must_inspect_result_ + NTSTATUS + OnCleanup( + __inout FxIrp* FxIrp + ); + + _Must_inspect_result_ + NTSTATUS + OnShutdown( + __inout FxIrp* FxIrp + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureConstraints( + __in PLIST_ENTRY FileObjInfoList + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureFileObjectClass( + __in PLIST_ENTRY FileObjInfoList + ); + + VOID + DecrementOpenHandleCount( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + ForwardCreateRequest( + __in FxIrp* FxIrp, + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context + ); + + static + MdCompletionRoutineType _CreateCompletionRoutine; + + static + MdCompletionRoutineType _CreateCompletionRoutine2; + +public: + + FxPkgGeneral( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ); + + ~FxPkgGeneral(); + + _Must_inspect_result_ + virtual + NTSTATUS + Dispatch( + __inout MdIrp Irp + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + _Must_inspect_result_ + NTSTATUS + PostCreateDeviceInitialize( + __in PWDFDEVICE_INIT Init + ); + + VOID + CreateCompleted( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureForwarding( + __in FxIoQueue *FxQueue + ); + + BOOLEAN + CanDestroyControlDevice( + VOID + ); + + VOID + GetConstraintsHelper( + __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, + __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) ; + + FxCallbackLock* + GetCallbackLockPtrHelper( + __deref_out_opt FxObject** LockObject + ); + + __inline + FxIoQueue* + GetDeafultInternalCreateQueue( + ) + { + return m_DefaultQueueForCreates; + } +}; + +#endif // _FXPKGGENERAL_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgio.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgio.hpp new file mode 100644 index 00000000000..41bcec1fa78 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgio.hpp @@ -0,0 +1,446 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgIo.hpp + +Abstract: + + This module implements the I/O package for the driver frameworks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXPKGIO_H_ +#define _FXPKGIO_H_ + + + + +#include "FxPkgIoShared.hpp" +#include "FxIrpDynamicDispatchInfo.hpp" +#include "FxDeviceCallbacks.hpp" +#include "FxCxDeviceInfo.hpp" + +// +// This flag is or-ed with a pointer value that is ptr aligned, only lower 2 bits are available. +// +#define FX_IN_DISPATCH_CALLBACK 0x00000001 + +enum FxIoIteratorList { + FxIoQueueIteratorListInvalid = 0, + FxIoQueueIteratorListPowerOn, + FxIoQueueIteratorListPowerOff, +}; + +#define IO_ITERATOR_FLUSH_TAG (PVOID) 'sulf' +#define IO_ITERATOR_POWER_TAG (PVOID) 'ewop' + +// +// This class is allocated by the driver frameworks manager +// PER DEVICE, and is not package global, but per device global, +// data. +// +// This is similar to the NT DeviceExtension. +// +class FxPkgIo : public FxPackage +{ + +private: + + FxIoQueue* m_DefaultQueue; + + // + // This is the list of IoQueue objects allocated by the driver + // and associated with this device. The IoPackage instance + // will release these references automatically when the device + // is removed. + // + LIST_ENTRY m_IoQueueListHead; + + // + // This is the forwarding table + // + FxIoQueue* m_DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1]; + + // + // This is the seed value used to pass to the + // FxRandom for testing forward progress + // + ULONG m_RandomSeed; + + // TRUE if behave as a filter (forward default requests) + BOOLEAN m_Filter; + + BOOLEAN m_PowerStateOn; + + // + // TRUE if queues are shutting down (surprise_remove/remove in progress). + // + BOOLEAN m_QueuesAreShuttingDown; + + // + // We'll maintain the dynamic dispatch table "per device" so that it is possible + // to have different callbacks for each device. + // Note that each device may be associted with multiple class extension in the future. + // + LIST_ENTRY m_DynamicDispatchInfoListHead; + + // + // If !=NULL, a pre-process callback was registered + // + FxIoInCallerContext m_InCallerContextCallback; + +public: + + FxPkgIo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ); + + ~FxPkgIo(); + + // + // Package manager dispatch entries + // + _Must_inspect_result_ + virtual + NTSTATUS + Dispatch( + __inout MdIrp Irp + ); + + // + // Returns the Top level queue for the Io based on the Irp MajorFunction + // + FxIoQueue* + GetDispatchQueue( + _In_ UCHAR MajorFunction + ) + { + return m_DispatchTable[MajorFunction]; + } + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifyDispatchContext, + _In_ WDFCONTEXT + ); + + // + // Api's supplied by this package + // + _Must_inspect_result_ + NTSTATUS + __fastcall + DispatchStep1( + __inout MdIrp Irp, + __in WDFCONTEXT DispatchContext + ); + + _Must_inspect_result_ + NTSTATUS + __fastcall + DispatchStep2( + __inout MdIrp Irp, + __in_opt FxIoInCallerContext* IoInCallerCtx, + __in_opt FxIoQueue* Queue + ); + +/*++ + + Routine Description: + + Initializes the default queue, and allows the driver to + pass configuration information. + + The driver callbacks registered in this call are used + to supply the callbacks for the driver default I/O queue. + +Arguments: + + hDevice - Pointer Device Object + +Return Value: + + NTSTATUS + +--*/ + _Must_inspect_result_ + NTSTATUS + InitializeDefaultQueue( + __in CfxDevice * Device, + __inout FxIoQueue * Queue + ); + + // + // Register the I/O in-caller context callback + // + __inline + VOID + SetIoInCallerContextCallback( + __inout PFN_WDF_IO_IN_CALLER_CONTEXT EvtIoInCallerContext + ) + { + m_InCallerContextCallback.m_Method = EvtIoInCallerContext; + } + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P2( + NTSTATUS, + VerifyEnqueueRequestUpdateFlags, + _In_ FxRequest*, + _Inout_ SHORT* + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P2( + VOID, + VerifyEnqueueRequestRestoreFlags, + _In_ FxRequest*, + _In_ SHORT + ); + + // + // Enqueue a request to the I/O processing pipeline + // from the device driver + // + _Must_inspect_result_ + NTSTATUS + EnqueueRequest( + __in CfxDevice* Device, + __inout FxRequest* pRequest + ); + + FxDriver* + GetDriver( + VOID + ); + + __inline + CfxDevice* + GetDevice( + VOID + ) + { + return m_Device; + } + + __inline + FxIoQueue* + GetDefaultQueue( + VOID + ) + { + return m_DefaultQueue; + } + + __inline + BOOLEAN + IsFilter( + VOID + ) + { + return m_Filter; + } + + // + // This is called as a result of a power management state + // that requests that all I/O in progress stop. + // + // + // 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. + // + // FxIoStopProcessingForPowerPurge: + // the function returns when all requests have been completed and/or + // cancelled., and there are no more in-flight requests. + // + // Any queues not marked as PowerManaged will be left alone. + // + // This is called on a PASSIVE_LEVEL thread that can block until + // I/O has been stopped, or completed/cancelled. + // + _Must_inspect_result_ + NTSTATUS + StopProcessingForPower( + __in FxIoStopProcessingForPowerAction Action + ); + + // + // This is called to start, or resume processing when PNP/Power + // resources have been supplied to the device driver. + // + // The driver is notified of resumption for any in-flight I/O. + // + _Must_inspect_result_ + NTSTATUS + ResumeProcessingForPower(); + + // + // 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. + // + VOID + ResetStateForRestart( + VOID + ); + + // + // Called by CfxDevice when WdfDeviceSetFilter is called. + // + _Must_inspect_result_ + NTSTATUS + SetFilter( + __in BOOLEAN Value + ); + + // + // Create an IoQueue and associate it with the FxIoPkg per device + // instance. + // + _Must_inspect_result_ + NTSTATUS + CreateQueue( + __in PWDF_IO_QUEUE_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES QueueAttributes, + __in_opt FxDriver* Caller, + __deref_out FxIoQueue** ppQueue + ); + + VOID + RemoveQueueReferences( + __inout FxIoQueue* pQueue + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureDynamicDispatching( + __in UCHAR MajorFunction, + __in_opt FxCxDeviceInfo* CxDeviceInfo, + __in PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch, + __in_opt WDFCONTEXT DriverContext + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureForwarding( + __inout FxIoQueue* TargetQueue, + __in WDF_REQUEST_TYPE RequestType + ); + + _Must_inspect_result_ + NTSTATUS + FlushAllQueuesByFileObject( + __in MdFileObject FileObject + ); + + __inline + VOID + RequestCompletedCallback( + __in FxRequest* Request + ) + { + UNREFERENCED_PARAMETER(Request); + + // + // If this is called, the driver called WDFREQUEST.Complete + // from the PreProcess callback handler. + // + // Since we have a handler, the FXREQUEST object will + // dereference itself upon return from this callback, which + // will destroy the final reference count. + // + } + + __inline + BOOLEAN + IsTopLevelQueue( + __in FxIoQueue* Queue + ) + { + UCHAR index; + + for (index = 0; index <= IRP_MJ_MAXIMUM_FUNCTION; index++) { + if (m_DispatchTable[index] == Queue) { + return TRUE; + } + } + return FALSE; + } + + NTSTATUS + DispathToInCallerContextCallback( + __in FxIoInCallerContext *InCallerContextInfo, + __in FxRequest *Request, + __inout MdIrp Irp + ); + + __inline + FxIoInCallerContext* + GetIoInCallerContextCallback( + __in_opt FxCxDeviceInfo* CxDeviceInfo + ) + { + if (CxDeviceInfo != NULL) { + return &CxDeviceInfo->IoInCallerContextCallback; + } + else { + return &m_InCallerContextCallback; + } + } + +private: + + VOID + AddIoQueue( + __inout FxIoQueue* IoQueue + ); + + VOID + RemoveIoQueue( + __inout FxIoQueue* IoQueue + ); + + FxIoQueue* + GetFirstIoQueueLocked( + __in FxIoQueueNode* QueueBookmark, + __in PVOID Tag + ); + + FxIoQueue* + GetNextIoQueueLocked( + __in FxIoQueueNode* QueueBookmark, + __in PVOID Tag + ); + + VOID + GetIoQueueListLocked( + __in PSINGLE_LIST_ENTRY SListHead, + __inout FxIoIteratorList ListType + ); + + _Must_inspect_result_ + NTSTATUS + VerifierFreeRequestToTestForwardProgess( + __in FxRequest* Request + ); + +}; + +#endif // _FXPKGIO_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgioshared.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgioshared.hpp new file mode 100644 index 00000000000..1ec575e0ba9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgioshared.hpp @@ -0,0 +1,36 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgIoShared.hpp + +Abstract: + + This file contains portion of FxPkgIo.hpp that is need in shared code. + +Author: + +Environment: + +Revision History: + + + +--*/ + +#ifndef _FXPKGIOSHARED_HPP_ +#define _FXPKGIOSHARED_HPP_ + +enum FxIoStopProcessingForPowerAction { + FxIoStopProcessingForPowerHold = 1, + FxIoStopProcessingForPowerPurgeManaged, + FxIoStopProcessingForPowerPurgeNonManaged, +}; + +// begin_wpp config +// CUSTOM_TYPE(FxIoStopProcessingForPowerAction, ItemEnum(FxIoStopProcessingForPowerAction)); +// end_wpp + +#endif // _FXPKGIOSHARED_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgpdo.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgpdo.hpp new file mode 100644 index 00000000000..74da9ae19fd --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgpdo.hpp @@ -0,0 +1,592 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxPkgPdo.hpp + +Abstract: + + This module implements the pnp package for Pdo objects. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXPKGPDO_H_ +#define _FXPKGPDO_H_ + +typedef NTSTATUS (FxPkgPdo::*PFN_PDO_HANDLER)(FxIrp *Irp); + +class FxPkgPdo : public FxPkgPnp +{ +public: + // + // Properties used in handling IRP_MN_QUERY_DEVICE_TEXT + // + SINGLE_LIST_ENTRY m_DeviceTextHead; + LCID m_DefaultLocale; + + FxDeviceDescriptionEntry* m_Description; + + FxChildList* m_OwningChildList; + + // + // The following structure contains the function pointer table + // for the "events" this package can raise. + // + FxPnpDeviceResourcesQuery m_DeviceResourcesQuery; + FxPnpDeviceResourceRequirementsQuery m_DeviceResourceRequirementsQuery; + FxPnpDeviceEject m_DeviceEject; + FxPnpDeviceSetLock m_DeviceSetLock; + + FxPowerDeviceEnableWakeAtBus m_DeviceEnableWakeAtBus; + FxPowerDeviceDisableWakeAtBus m_DeviceDisableWakeAtBus; + + // added in 1.11 + FxPnpDeviceReportedMissing m_DeviceReportedMissing; + + BOOLEAN m_RawOK; + + BOOLEAN m_Static; + + BOOLEAN m_AddedToStaticList; + + // + // This field is used to indicate that Requests on this PDO could be + // forwarded to the parent. + // + BOOLEAN m_AllowForwardRequestToParent; + +protected: + // + // Pointer to a null terminated string which is the device ID. This is + // not a pointer that can be freed. m_IDsAllocation is the beginning of + // the allocation that can be freed. + // + PWSTR m_DeviceID; + + // + // Pointer to a null terminated string which is the instance ID. This is + // not a pointer that can be freed. m_IDsAllocation is the beginning of + // the allocation that can be freed. + // + PWSTR m_InstanceID; + + // + // Pointer to a multi sz which is the hardware IDs. This is + // not a pointer that can be freed. m_IDsAllocation is the beginning of + // the allocation that can be freed. + // + PWSTR m_HardwareIDs; + + // + // Pointer to a multi sz which is the compatible IDs. This is + // not a pointer that can be freed. m_IDsAllocation is the beginning of + // the allocation that can be freed. + // + PWSTR m_CompatibleIDs; + + // + // Pointer to a null terminated string which is the unique ID. This is + // not a pointer that can be freed. m_IDsAllocation is the beginning of + // the allocation that can be freed. + // + PWSTR m_ContainerID; + + // + // Single allocation for all static ID strings (device, instance, hw, compat) + // for the device + // + PWSTR m_IDsAllocation; + + FxRelatedDeviceList* m_EjectionDeviceList; + + // + // IRP_MN_EJECT needs to be handled synchronously because PnP manager does + // not serialize it with other state changing PnP irps if not handled + // synchronously. This event is used to signal the completion of + // IRP_MN_EJECT processing. + // + MxEvent* m_DeviceEjectProcessed; + + BOOLEAN m_CanBeDeleted; + + // + // Parameter to track whether the EvtDeviceEnableWakeAtBus callback was + // invoked and to determine whether the EvtDeviceDisableWakeAtBus callback + // should be invoked or not. The EnableWakeAtBus callback may not get + // invoked if an upper driver in the stack completed the wait wake irp + // instead of passing it down the stack and the power policy owner is + // a PDO. + // + // This parameter can be referenced by either the power state machine or + // the power policy state machine when a PDO is the power policy owner + // but there is no locking mechanism necessary to synchronize access to + // the field. This is because the arrival of a Dx irp will move the power + // state machine to a state where it can no longer affect the value of + // this field and hence provides an implicit guard that allows the power + // policy state machine to use this field while processing the Dx irp. + // + BOOLEAN m_EnableWakeAtBusInvoked; + +private: + // + // Table of internal methods to handle PnP minor function codes. + // + static const PFN_PNP_POWER_CALLBACK m_PdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1]; + + // + // Table of internal methods to handle power minor function codes. + // + static const PFN_PNP_POWER_CALLBACK m_PdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1]; + +public: + + FxPkgPdo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ); + + ~FxPkgPdo(); + + _Must_inspect_result_ + virtual + NTSTATUS + Initialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + virtual + VOID + FinishInitialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + VOID + RegisterCallbacks( + __in PWDF_PDO_EVENT_CALLBACKS DispatchTable + ); + + _Must_inspect_result_ + NTSTATUS + AddEjectionDevice( + __in MdDeviceObject DependentDevice + ); + + VOID + RemoveEjectionDevice( + __in MdDeviceObject DependentDevice + ); + + VOID + ClearEjectionDevicesList( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + HandleQueryInterfaceForReenumerate( + __in FxIrp* Irp, + __out PBOOLEAN CompleteRequest + ); + + __inline + BOOLEAN + IsForwardRequestToParentEnabled( + VOID + ) + { + return m_AllowForwardRequestToParent; + } + + +private: + _Must_inspect_result_ + virtual + NTSTATUS + SendIrpSynchronously( + __in FxIrp* Irp + ); + + _Must_inspect_result_ + virtual + NTSTATUS + FireAndForgetIrp( + __inout FxIrp* Irp + ); + + // + // The following are static member function. The only reason + // I've defined them as member functions at all is so they can see + // the private data in this class. + // + + _Must_inspect_result_ + static + NTSTATUS + _PnpCompleteIrp( + __in FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryDeviceRelations( + __in FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpQueryDeviceRelations( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryInterface( + IN FxPkgPnp* This, + IN FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryCapabilities( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpQueryCapabilities( + __inout FxIrp *Irp + ); + + VOID + HandleQueryCapabilities( + __inout PDEVICE_CAPABILITIES ReportedCaps, + __in PDEVICE_CAPABILITIES ParentCaps + ); + + static + VOID + _QueryCapsWorkItem( + __in MdDeviceObject DeviceObject, + __in PVOID Context + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryResources( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpQueryResources( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpQueryResourceRequirements( + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryDeviceText( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpFilterResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpEject( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + virtual + BOOLEAN + PnpSendStartDeviceDownTheStackOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventEjectHardwareOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventCheckForDevicePresenceOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventPdoRemovedOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventFdoRemovedOverload( + VOID + ); + + virtual + VOID + PnpEventSurpriseRemovePendingOverload( + VOID + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpGetPostRemoveState( + VOID + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpSetLock( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryId( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryPnpDeviceState( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryBusInformation( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpSurpriseRemoval( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ); + + static + _Must_inspect_result_ + NTSTATUS + _DispatchPowerSequence( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ); + + static + _Must_inspect_result_ + NTSTATUS + _DispatchSetPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchSystemSetPower( + __in FxIrp *Irp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchDeviceSetPower( + __in FxIrp *Irp + ); + + static + _Must_inspect_result_ + NTSTATUS + _DispatchQueryPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ); + + virtual + _Must_inspect_result_ + NTSTATUS + PowerCheckParentOverload( + __in BOOLEAN* ParentOn + ); + + virtual + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeOverload( + VOID + ); + + virtual + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeNPOverload( + VOID + ); + + virtual + _Must_inspect_result_ + NTSTATUS + PowerEnableWakeAtBusOverload( + VOID + ); + + virtual + VOID + PowerDisableWakeAtBusOverload( + VOID + ); + + virtual + VOID + PowerParentPowerDereference( + VOID + ); + + virtual + VOID + PowerReleasePendingDeviceIrp( + __in BOOLEAN IrpMustBePresent = TRUE + ); + + _Must_inspect_result_ + virtual + NTSTATUS + ProcessRemoveDeviceOverload( + __inout FxIrp* Irp + ); + + virtual + VOID + DeleteSymbolicLinkOverload( + __in BOOLEAN GracefulRemove + ); + + virtual + VOID + QueryForReenumerationInterface( + VOID + ) + { + // + // As the PDO, we already have the interface built in + // + DO_NOTHING(); + } + + virtual + VOID + ReleaseReenumerationInterface( + VOID + ) + { + // + // As the PDO, we already have the interface built in + // + DO_NOTHING(); + } + + _Must_inspect_result_ + virtual + NTSTATUS + AskParentToRemoveAndReenumerate( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + QueryForPowerThread( + VOID + ); + + virtual + const PFN_PNP_POWER_CALLBACK* + GetDispatchPnp( + VOID + ) + { + return m_PdoPnpFunctionTable; + } + + virtual + const PFN_PNP_POWER_CALLBACK* + GetDispatchPower( + VOID + ) + { + return m_PdoPowerFunctionTable; + } + + static + VOID + _RemoveAndReenumerateSelf( + __in PVOID Context + ); + + VOID + PowerNotifyParentChildWakeArmed( + VOID + ); + + VOID + PowerNotifyParentChildWakeDisarmed( + VOID + ); +}; + +#endif // _FXPKGPDO_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgpnp.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgpnp.hpp new file mode 100644 index 00000000000..c8a79ca07f5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpkgpnp.hpp @@ -0,0 +1,4588 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxPkgPnp.hpp + +Abstract: + + This module implements the pnp package for the driver frameworks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXPKGPNP_H_ +#define _FXPKGPNP_H_ + +// +// These are all magical numbers based on inspection. If the queue overflows, +// it is OK to increase these numbers without fear of either dependencies or +// weird side effects. +// +const UCHAR PnpEventQueueDepth = 8; +const UCHAR PowerEventQueueDepth = 8; +const UCHAR FxPowerPolicyEventQueueDepth = 8; + +// @@SMVERIFY_SPLIT_BEGIN + +// +// DEBUGGED_EVENT is a TRUE value rather then a FALSE value (and having the field +// name be TrapOnEvent) so that the initializer for the entry in the table has +// to explicitly set this value, otherwise, if left out, the compiler will zero +// out the field, which would lead to mistakenly saying the event was debugged +// if DEBUGGED_EVENT is FALSE. +// +// Basically, we are catching folks who update the table but forget to specify +// TRAP_ON_EVENT when they add the new entry. +// +#if FX_SUPER_DBG + #define DEBUGGED_EVENT , TRUE + #define TRAP_ON_EVENT , FALSE + + #define DO_EVENT_TRAP(x) if ((x)->EventDebugged == FALSE) { COVERAGE_TRAP(); } + + #define EVENT_TRAP_FIELD BOOLEAN EventDebugged; + +#else // FX_SUPER_DBG + + #define DEBUGGED_EVENT + #define TRAP_ON_EVENT + #define DO_EVENT_TRAP(x) (0) + + // intentionally blank + #define EVENT_TRAP_FIELD + +#endif // FX_SUPER_DBG + +#if FX_STATE_MACHINE_VERIFY +enum FxStateMachineDeviceType { + FxSmDeviceTypeInvalid = 0, + FxSmDeviceTypePnp, + FxSmDeviceTypePnpFdo, + FxSmDeviceTypePnpPdo, +}; +#endif // FX_STATE_MACHINE_VERIFY + +// @@SMVERIFY_SPLIT_END + +#include "FxPnpCallbacks.hpp" + +#include "FxEventQueue.hpp" + +// +// Bit-flags for tracking which callback is currently executing. +// +enum FxDeviceCallbackFlags { + // Prepare hardware callback is running. + FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE = 0x01, +}; + +typedef +VOID +(*PFN_POWER_THREAD_ENQUEUE)( + __in PVOID Context, + __in PWORK_QUEUE_ITEM WorkItem + ); + +// +// workaround overloaded definition (rpc generated headers all define INTERFACE +// to match the class name). +// +#undef INTERFACE + +typedef struct _POWER_THREAD_INTERFACE { + // + // generic interface header + // + INTERFACE Interface; + + PFN_POWER_THREAD_ENQUEUE PowerThreadEnqueue; + +} POWER_THREAD_INTERFACE, *PPOWER_THREAD_INTERFACE; + +// +// What follows here is a series of structures that define three state +// machines. The first is the PnP state machine, followed by the +// Power state machine, followed by the Power Policy state machine. +// The first two will be instantiated in every driver. The third will +// be instantiated only in drivers which are the power policy owners +// for their device stacks, which usually amounts to the being the FDO. +// +#include "FxPnpStateMachine.hpp" +#include "FxPowerStateMachine.hpp" +#include "FxPowerPolicyStateMachine.hpp" + +#include "FxSelfManagedIoStateMachine.hpp" + +// +// Group these here instead of in the individual headers because, for some reason, +// tracewpp.exe, can't handle such an arrangement. +// +// begin_wpp config +// CUSTOM_TYPE(FxPnpEvent, ItemEnum(FxPnpEvent)); +// CUSTOM_TYPE(FxPowerEvent, ItemEnum(FxPowerEvent)); +// CUSTOM_TYPE(FxPowerPolicyEvent, ItemEnum(FxPowerPolicyEvent)); +// CUSTOM_TYPE(FxPowerIdleFlags, ItemEnum(FxPowerIdleFlags)); +// CUSTOM_TYPE(FxPowerIdleStates, ItemEnum(FxPowerIdleStates)); +// CUSTOM_TYPE(FxPowerIdleEvents, ItemEnum(FxPowerIdleEvents)); +// CUSTOM_TYPE(FxDevicePwrRequirementEvents, ItemEnum(FxDevicePwrRequirementEvents)); +// CUSTOM_TYPE(FxDevicePwrRequirementStates, ItemEnum(FxDevicePwrRequirementStates)); +// CUSTOM_TYPE(FxWakeInterruptEvents, ItemEnum(FxWakeInterruptEvents)); +// CUSTOM_TYPE(FxWakeInterruptStates, ItemEnum(FxWakeInterruptStates)); + +// CUSTOM_TYPE(FxSelfManagedIoEvents, ItemEnum(FxSelfManagedIoEvents)); +// CUSTOM_TYPE(FxSelfManagedIoStates, ItemEnum(FxSelfManagedIoStates)); +// end_wpp + +// +// These are defined in ntddk.h so its wpp custom type should be +// added to a common header along with other public enums. Howeever until that +// is done, define custom type here. +// +// begin_wpp config +// CUSTOM_TYPE(DEVICE_POWER_STATE, ItemEnum(_DEVICE_POWER_STATE)); +// CUSTOM_TYPE(SYSTEM_POWER_STATE, ItemEnum(_SYSTEM_POWER_STATE)); +// CUSTOM_TYPE(BUS_QUERY_ID_TYPE, ItemEnum(BUS_QUERY_ID_TYPE)); +// CUSTOM_TYPE(DEVICE_RELATION_TYPE, ItemEnum(_DEVICE_RELATION_TYPE)); +// CUSTOM_TYPE(pwrmn, ItemListByte(IRP_MN_WAIT_WAKE,IRP_MN_POWER_SEQUENCE,IRP_MN_SET_POWER,IRP_MN_QUERY_POWER)); +// end_wpp + +// +// Information shared between the power and power policy state machines. +// +struct SharedPowerData { + // + // Current wait wake irp in this device object. Access to this field is + // determined by m_WaitWakeOwner. + // + // m_WaitWakeOwner == TRUE, access is guarded by + // FxPowerMachine::m_WaitWakeLock + // + // + // m_WaitWakeOwner == FALSE, access is guarded InterlockedExchange operations + // and the ability to cancel the request is guarded through + // FxPowerPolicyMachine::m_WaitWakeCancelCompletionOwnership + // + // Any devobj can be both the power policy owner and the wait wake owner, + // but usually this dual role would only be for raw PDOs. + // + MdIrp m_WaitWakeIrp; + + // + // Indication whether this power machine owns wait wake irps (and calls + // (dis)arm at bus level callbacks and handles cancellation logic. + // + BOOLEAN m_WaitWakeOwner; + + // + // If TRUE the watchdog timer should be extended to a very long period of + // time during debugging for a NP power operation. + // + // NOTE: nowhere in the code do we set this value to TRUE. The debugger + // extension !wdfextendwatchdog will set it to TRUE, so the field must + // stay. If moved, the extension must obviously be updated as well. + // + BOOLEAN m_ExtendWatchDogTimer; +}; + +const UCHAR DeviceWakeStates = PowerSystemHibernate - PowerSystemWorking + 1; + +enum SendDeviceRequestAction { + NoRetry = 0, + Retry, +}; + +enum NotifyResourcesFlags { + NotifyResourcesNoFlags = 0x00, + NotifyResourcesNP = 0x01, + NotifyResourcesSurpriseRemoved = 0x02, + NotifyResourcesForceDisconnect = 0x04, + NotifyResourcesExplicitPowerup = 0x08, + NotifyResourcesExplicitPowerDown = 0x10, + NotifyResourcesDisconnectInactive = 0x20, + NotifyResourcesArmedForWake = 0x40, +}; + +enum FxPowerDownType { + FxPowerDownTypeExplicit = 0, + FxPowerDownTypeImplicit, +}; + +typedef +_Must_inspect_result_ +NTSTATUS +(*PFN_PNP_POWER_CALLBACK)( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + +// +// The naming of these values is very important. The following macros rely on +// it: +// +// (state related:) +// SET_PNP_DEVICE_STATE_BIT +// SET_TRI_STATE_FROM_STATE_BITS +// GET_PNP_STATE_BITS_FROM_STRUCT +// +// (caps related:) +// GET_PNP_CAP_BITS_FROM_STRUCT +// SET_PNP_CAP_IF_TRUE +// SET_PNP_CAP_IF_FALSE +// SET_PNP_CAP +// +// They using the naming convention to generically map the field name in +// WDF_DEVICE_PNP_CAPABILITIES and WDF_DEVICE_STATE to the appropriate bit +// values. +// +enum FxPnpStateAndCapValues { + FxPnpStateDisabledFalse = 0x00000000, + FxPnpStateDisabledTrue = 0x00000001, + FxPnpStateDisabledUseDefault = 0x00000002, + FxPnpStateDisabledMask = 0x00000003, + + FxPnpStateDontDisplayInUIFalse = 0x00000000, + FxPnpStateDontDisplayInUITrue = 0x00000004, + FxPnpStateDontDisplayInUIUseDefault = 0x00000008, + FxPnpStateDontDisplayInUIMask = 0x0000000C, + + FxPnpStateFailedFalse = 0x00000000, + FxPnpStateFailedTrue = 0x00000010, + FxPnpStateFailedUseDefault = 0x00000020, + FxPnpStateFailedMask = 0x00000030, + + FxPnpStateNotDisableableFalse = 0x00000000, + FxPnpStateNotDisableableTrue = 0x00000040, + FxPnpStateNotDisableableUseDefault = 0x00000080, + FxPnpStateNotDisableableMask = 0x000000C0, + + FxPnpStateRemovedFalse = 0x00000000, + FxPnpStateRemovedTrue = 0x00000100, + FxPnpStateRemovedUseDefault = 0x00000200, + FxPnpStateRemovedMask = 0x00000300, + + FxPnpStateResourcesChangedFalse = 0x00000000, + FxPnpStateResourcesChangedTrue = 0x00000400, + FxPnpStateResourcesChangedUseDefault= 0x00000800, + FxPnpStateResourcesChangedMask = 0x00000C00, + + FxPnpStateMask = 0x00000FFF, + + FxPnpCapLockSupportedFalse = 0x00000000, + FxPnpCapLockSupportedTrue = 0x00001000, + FxPnpCapLockSupportedUseDefault = 0x00002000, + FxPnpCapLockSupportedMask = 0x00003000, + + FxPnpCapEjectSupportedFalse = 0x00000000, + FxPnpCapEjectSupportedTrue = 0x00004000, + FxPnpCapEjectSupportedUseDefault = 0x00008000, + FxPnpCapEjectSupportedMask = 0x0000C000, + + FxPnpCapRemovableFalse = 0x00000000, + FxPnpCapRemovableTrue = 0x00010000, + FxPnpCapRemovableUseDefault = 0x00020000, + FxPnpCapRemovableMask = 0x00030000, + + FxPnpCapDockDeviceFalse = 0x00000000, + FxPnpCapDockDeviceTrue = 0x00040000, + FxPnpCapDockDeviceUseDefault = 0x00080000, + FxPnpCapDockDeviceMask = 0x000C0000, + + FxPnpCapUniqueIDFalse = 0x00000000, + FxPnpCapUniqueIDTrue = 0x00100000, + FxPnpCapUniqueIDUseDefault = 0x00200000, + FxPnpCapUniqueIDMask = 0x00300000, + + FxPnpCapSilentInstallFalse = 0x00000000, + FxPnpCapSilentInstallTrue = 0x00400000, + FxPnpCapSilentInstallUseDefault = 0x00800000, + FxPnpCapSilentInstallMask = 0x00C00000, + + FxPnpCapSurpriseRemovalOKFalse = 0x00000000, + FxPnpCapSurpriseRemovalOKTrue = 0x01000000, + FxPnpCapSurpriseRemovalOKUseDefault = 0x02000000, + FxPnpCapSurpriseRemovalOKMask = 0x03000000, + + FxPnpCapHardwareDisabledFalse = 0x00000000, + FxPnpCapHardwareDisabledTrue = 0x04000000, + FxPnpCapHardwareDisabledUseDefault = 0x08000000, + FxPnpCapHardwareDisabledMask = 0x0C000000, + + FxPnpCapNoDisplayInUIFalse = 0x00000000, + FxPnpCapNoDisplayInUITrue = 0x10000000, + FxPnpCapNoDisplayInUIUseDefault = 0x20000000, + FxPnpCapNoDisplayInUIMask = 0x30000000, + + FxPnpCapMask = 0x3FFFF000, +}; + +union FxPnpStateAndCaps { + struct { + // States + WDF_TRI_STATE Disabled : 2; + WDF_TRI_STATE DontDisplayInUI : 2; + WDF_TRI_STATE Failed : 2; + WDF_TRI_STATE NotDisableable : 2; + WDF_TRI_STATE Removed : 2; + WDF_TRI_STATE ResourcesChanged : 2; + + // Caps + WDF_TRI_STATE LockSupported : 2; + WDF_TRI_STATE EjectSupported : 2; + WDF_TRI_STATE Removable : 2; + WDF_TRI_STATE DockDevice : 2; + WDF_TRI_STATE UniqueID : 2; + WDF_TRI_STATE SilentInstall : 2; + WDF_TRI_STATE SurpriseRemovalOK : 2; + WDF_TRI_STATE HardwareDisabled : 2; + WDF_TRI_STATE NoDisplayInUI : 2; + } ByEnum; + + // + // The bottom 3 nibbles (0xFFF) are the pnp state tri state values encoded + // down to 2 bits each. + // + // The remaining portion (0x3FFFF000) are the pnp caps tri state values + // encoded down to 2 bits each as well. + // + LONG Value; +}; + +// +// The naming of these values is very important. The following macros rely on it: +// GET_POWER_CAP_BITS_FROM_STRUCT +// SET_POWER_CAP +// +// They using the naming convention to generically map the field name in +// WDF_DEVICE_POWER_CAPABILITIES to the appropriate bit values. +// +enum FxPowerCapValues { + FxPowerCapDeviceD1False = 0x0000, + FxPowerCapDeviceD1True = 0x0001, + FxPowerCapDeviceD1UseDefault = 0x0002, + FxPowerCapDeviceD1Mask = 0x0003, + + FxPowerCapDeviceD2False = 0x0000, + FxPowerCapDeviceD2True = 0x0004, + FxPowerCapDeviceD2UseDefault = 0x0008, + FxPowerCapDeviceD2Mask = 0x000C, + + FxPowerCapWakeFromD0False = 0x0000, + FxPowerCapWakeFromD0True = 0x0010, + FxPowerCapWakeFromD0UseDefault= 0x0020, + FxPowerCapWakeFromD0Mask = 0x0030, + + FxPowerCapWakeFromD1False = 0x0000, + FxPowerCapWakeFromD1True = 0x0040, + FxPowerCapWakeFromD1UseDefault= 0x0080, + FxPowerCapWakeFromD1Mask = 0x00C0, + + FxPowerCapWakeFromD2False = 0x0000, + FxPowerCapWakeFromD2True = 0x0100, + FxPowerCapWakeFromD2UseDefault= 0x0200, + FxPowerCapWakeFromD2Mask = 0x0300, + + FxPowerCapWakeFromD3False = 0x0000, + FxPowerCapWakeFromD3True = 0x0400, + FxPowerCapWakeFromD3UseDefault= 0x0800, + FxPowerCapWakeFromD3Mask = 0x0C00, +}; + +struct FxPowerCaps { + // + // Encoded with FxPowerCapValues, which encodes the WDF_TRI_STATE values + // + USHORT Caps; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + BYTE DeviceWake; // DEVICE_POWER_STATE + BYTE SystemWake; // SYSTEM_POWER_STATE + + // + // Each state is encoded in a nibble in a byte + // + ULONG States; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + ULONG D2Latency; + ULONG D3Latency; +}; + +struct FxEnumerationInfo : public FxStump { +public: + FxEnumerationInfo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : m_ChildListList(FxDriverGlobals) + { + } + + NTSTATUS + Initialize( + VOID + ) + { + NTSTATUS status; + + status = m_PowerStateLock.Initialize(); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_ChildListList.Initialize(); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; + } + + _Acquires_lock_(_Global_critical_region_) + VOID + AcquireParentPowerStateLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + (VOID) m_PowerStateLock.AcquireLock(FxDriverGlobals); + } + + _Releases_lock_(_Global_critical_region_) + VOID + ReleaseParentPowerStateLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + m_PowerStateLock.ReleaseLock(FxDriverGlobals); + } + +public: + FxWaitLockInternal m_PowerStateLock; + + // + // List of FxChildList objects which contain enumerated children + // + FxWaitLockTransactionedList m_ChildListList; +}; + +class FxPkgPnp : public FxPackage { + + friend FxPnpMachine; + friend FxPowerMachine; + friend FxPowerPolicyMachine; + friend FxPowerPolicyOwnerSettings; + friend FxInterrupt; + +protected: + FxPkgPnp( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice* Device, + __in WDFTYPE Type + ); + + ~FxPkgPnp(); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + virtual + NTSTATUS + Dispatch( + __in MdIrp Irp + ); + + virtual + const PFN_PNP_POWER_CALLBACK* + GetDispatchPnp( + VOID + ) =0; + + virtual + const PFN_PNP_POWER_CALLBACK* + GetDispatchPower( + VOID + ) =0; + + VOID + DeleteDevice( + VOID + ); + + VOID + SetInternalFailure( + VOID + ); + + NTSTATUS + CompletePowerRequest( + __inout FxIrp* Irp, + __in NTSTATUS Status + ); + + NTSTATUS + CompletePnpRequest( + __inout FxIrp* Irp, + __in NTSTATUS Status + ); + + PNP_DEVICE_STATE + HandleQueryPnpDeviceState( + __in PNP_DEVICE_STATE PnpDeviceState + ); + + _Must_inspect_result_ + NTSTATUS + HandleQueryBusRelations( + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + NTSTATUS + HandleQueryDeviceRelations( + __inout FxIrp* Irp, + __inout FxRelatedDeviceList* List + ); + + _Must_inspect_result_ + NTSTATUS + HandleQueryInterface( + __inout FxIrp* Irp, + __out PBOOLEAN CompleteRequest + ); + + _Must_inspect_result_ + NTSTATUS + QueryForCapabilities( + VOID + ); + + VOID + PnpAssignInterruptsSyncIrql( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PnpMatchResources( + VOID + ); + + __drv_when(!NT_SUCCESS(return), __drv_arg(ResourcesMatched, _Must_inspect_result_)) + NTSTATUS + PnpPrepareHardware( + __out PBOOLEAN ResourcesMatched + ); + + _Must_inspect_result_ + NTSTATUS + PnpPrepareHardwareInternal( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PnpReleaseHardware( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PnpEnableInterfacesAndRegisterWmi( + VOID + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpStartDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryStopDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpCancelStopDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpStopDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpQueryRemoveDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpCancelRemoveDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpRemoveDevice( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpSurpriseRemoval( + __inout FxIrp* Irp + ); + + NTSTATUS + FilterResourceRequirements( + __in IO_RESOURCE_REQUIREMENTS_LIST **IoList + ); + + virtual + VOID + PowerReleasePendingDeviceIrp( + BOOLEAN IrpMustBePresent = TRUE + ) =0; + + VOID + AddInterruptObject( + __in FxInterrupt* Interrupt + ); + + VOID + RemoveInterruptObject( + __in FxInterrupt* Interrupt + ); + + VOID + PnpProcessEventInner( + __inout FxPostProcessInfo* Info + ); + + VOID + PowerProcessEventInner( + __inout FxPostProcessInfo* Info + ); + + VOID + PowerPolicyProcessEventInner( + __inout FxPostProcessInfo* Info + ); + + static + VOID + _PnpProcessEventInner( + __inout FxPkgPnp* This, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ); + + static + VOID + _PowerProcessEventInner( + __in FxPkgPnp* This, + __in FxPostProcessInfo* Info, + __in PVOID WorkerContext + ); + + static + VOID + _PowerPolicyProcessEventInner( + __inout FxPkgPnp* This, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ); + + VOID + PnpEnterNewState( + __in WDF_DEVICE_PNP_STATE State + ); + + VOID + PowerEnterNewState( + __in WDF_DEVICE_POWER_STATE State + ); + + VOID + PowerPolicyEnterNewState( + __in WDF_DEVICE_POWER_POLICY_STATE State + ); + + VOID + NotPowerPolicyOwnerEnterNewState( + __in WDF_DEVICE_POWER_POLICY_STATE NewState + ); + + _Must_inspect_result_ + static + NTSTATUS + _DispatchWaitWake( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + NTSTATUS + DispatchWaitWake( + __inout FxIrp* Irp + ); + + VOID + SaveState( + __in BOOLEAN UseCanSaveState + ); + + _Must_inspect_result_ + static + NTSTATUS + _PnpDeviceUsageNotification( + __inout FxPkgPnp* This, + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + NTSTATUS + PnpDeviceUsageNotification( + __inout FxIrp* Irp + ); + + + LONG + GetPnpStateInternal( + VOID + ); + + LONG + GetPnpCapsInternal( + VOID + ); + + static + VOID + _SetPowerCapState( + __in ULONG Index, + __in DEVICE_POWER_STATE State, + __out PULONG Result + ); + + static + DEVICE_POWER_STATE + _GetPowerCapState( + __in ULONG Index, + __in ULONG State + ); + +// begin pnp state machine table based callbacks + static + WDF_DEVICE_PNP_STATE + PnpEventCheckForDevicePresence( + __inout FxPkgPnp* This + ); + + virtual + BOOLEAN + PnpSendStartDeviceDownTheStackOverload( + VOID + ) =0; + + virtual + WDF_DEVICE_PNP_STATE + PnpEventCheckForDevicePresenceOverload( + VOID + ) = 0; + + static + WDF_DEVICE_PNP_STATE + PnpEventEjectHardware( + __inout FxPkgPnp* This + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventEjectHardwareOverload( + VOID + ) = 0; + + static + WDF_DEVICE_PNP_STATE + PnpEventInitStarting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventInitSurpriseRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventHardwareAvailable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventEnableInterfaces( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventHardwareAvailablePowerPolicyFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryRemoveAskDriver( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryRemoveEnsureDeviceAwake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryRemovePending( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryRemoveStaticCheck( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueriedRemoving( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryStopAskDriver( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryStopEnsureDeviceAwake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryStopPending( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryStopStaticCheck( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueryCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRemoved( + __inout FxPkgPnp* This + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpGetPostRemoveState( + VOID + ) =0; + + static + WDF_DEVICE_PNP_STATE + PnpEventPdoRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRemovedPdoWait( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRemovedPdoSurpriseRemoved( + __inout FxPkgPnp* This + ); + + virtual + WDF_DEVICE_PNP_STATE + PnpEventPdoRemovedOverload( + VOID + ) =0; + + virtual + WDF_DEVICE_PNP_STATE + PnpEventFdoRemovedOverload( + VOID + ) =0; + + virtual + VOID + PnpEventSurpriseRemovePendingOverload( + VOID + ); + + VOID + PnpEventRemovedCommonCode( + VOID + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRemovingDisableInterfaces( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRestarting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStarted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStartedCancelStop( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStartedCancelRemove( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStartedRemoving( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStartingFromStopped( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStopped( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStoppedWaitForStartCompletion( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventStartedStopping( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventSurpriseRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventInitQueryRemove( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventInitQueryRemoveCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFdoRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventQueriedSurpriseRemove( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventSurpriseRemoveIoStarted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedPowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedIoStarting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedOwnHardware( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedPowerPolicyRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedSurpriseRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedStarted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFailedInit( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventPdoInitFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRestart( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRestartReleaseHardware( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRestartHardwareAvailable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventPdoRestart( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventRemovedChildrenRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_PNP_STATE + PnpEventFinal( + __inout FxPkgPnp* This + ); + // end pnp state machine table based callbacks + + VOID + PnpPowerPolicyStart( + VOID + ); + + VOID + PnpPowerPolicyStop( + VOID + ); + + VOID + PnpPowerPolicySurpriseRemove( + VOID + ); + + VOID + PnpPowerPolicyRemove( + VOID + ); + + VOID + PnpFinishProcessingIrp( + __in BOOLEAN IrpMustBePresent = TRUE + ); + + VOID + PnpDisableInterfaces( + VOID + ); + + virtual + NTSTATUS + SendIrpSynchronously( + FxIrp* Irp + ) =0; + + // begin power state machine table based callbacks + static + WDF_DEVICE_POWER_STATE + PowerCheckDeviceType( + __inout FxPkgPnp* This + ); + + virtual + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeOverload( + VOID + ) =0; + + static + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeNP( + __inout FxPkgPnp* This + ); + + virtual + WDF_DEVICE_POWER_STATE + PowerCheckDeviceTypeNPOverload( + VOID + ) =0; + + static + WDF_DEVICE_POWER_STATE + PowerEnablingWakeAtBus( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerEnablingWakeAtBusNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerCheckParentState( + __inout FxPkgPnp* This + ); + + virtual + NTSTATUS + PowerCheckParentOverload( + BOOLEAN* ParentOn + ) =0; + + static + WDF_DEVICE_POWER_STATE + PowerCheckParentStateNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDZero( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0NP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0BusWakeOwner( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0BusWakeOwnerNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0ArmedForWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0ArmedForWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoImplicitD3DisarmWakeAtBus( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0DisarmingWakeAtBus( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0DisarmingWakeAtBusNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0Starting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0StartingConnectInterrupt( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0StartingDmaEnable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0StartingStartSelfManagedIo( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDecideD0State( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoD3Stopped( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStartingCheckDeviceType( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStartingChild( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxDisablingWakeAtBus( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxDisablingWakeAtBusNP( + __inout FxPkgPnp* This + ); + + virtual + NTSTATUS + PowerEnableWakeAtBusOverload( + VOID + ) + { + return STATUS_SUCCESS; + } + + virtual + VOID + PowerDisableWakeAtBusOverload( + VOID + ) + { + } + + virtual + VOID + PowerParentPowerDereference( + VOID + ) =0; + + static + WDF_DEVICE_POWER_STATE + PowerGotoDNotZero( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDNotZeroNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDNotZeroIoStopped( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDNotZeroIoStoppedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxNPFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxArmedForWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxArmedForWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDNotZeroNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxIoStoppedArmedForWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxIoStoppedArmedForWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerCheckParentStateArmedForWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerCheckParentStateArmedForWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStartSelfManagedIo( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStartSelfManagedIoNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStartSelfManagedIoFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStartSelfManagedIoFailedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakePending( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakePendingNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWaking( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingConnectInterrupt( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingConnectInterruptNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingConnectInterruptFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingConnectInterruptFailedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingDmaEnable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingDmaEnableNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingDmaEnableFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerWakingDmaEnableFailedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerReportPowerUpFailedDerefParent( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerReportPowerUpFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerPowerFailedPowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerReportPowerDownFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerInitialConnectInterruptFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerInitialDmaEnableFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerInitialSelfManagedIoFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerInitialPowerUpFailedDerefParent( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerInitialPowerUpFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxSurpriseRemovedPowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxSurpriseRemovedPowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxStoppedDisarmWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxStoppedDisarmWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxStoppedDisableInterruptNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxStopped( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoStopped( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerStoppedCompleteDx( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxStoppedDecideDxState( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxStoppedArmForWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerDxStoppedArmForWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerFinalPowerDownFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerD0SurpriseRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerSurpriseRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerUpFailedDerefParent( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerUpFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + PowerGotoDxStoppedDisableInterrupt( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + FxPkgPnp::PowerUpFailedDerefParentNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + FxPkgPnp::PowerUpFailedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_STATE + FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP( + __inout FxPkgPnp* This + ); + + // end power state machine table based callbacks + + // begin power policy state machine table based callbacks + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStarting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartingPoweredUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartingPoweredUpFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartingSucceeded( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartingFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartingDecideS0Wake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartedIdleCapable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolIdleCapableDeviceIdle( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolDeviceIdleReturnToActive( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolDeviceIdleSleeping( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolDeviceIdleStopping( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredNoWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredNoWakeCompletePowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingUnarmedQueryIdle( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolS0NoWakePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolS0NoWakeCompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemSleepFromDeviceWaitingUnarmed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemSleepNeedWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemSleepNeedWakeCompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemSleepPowerRequestFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolCheckPowerPageable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakeWakeArrived( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakeRevertArmWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemAsleepWakeArmed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeEnabled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeEnabledWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeDisarm( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeTriggeredS0( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWokeDisarm( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakeWakeArrivedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakeRevertArmWakeNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakePowerDownFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakePowerDownFailedWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemAsleepWakeArmedNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeEnabledNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeDisarmNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeTriggeredS0NP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWokeDisarmNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeCompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleeping( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingNoWakePowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingNoWakeCompletePowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingNoWakeDxRequestFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingWakePowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingSendWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemAsleepNoWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeDisabled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceToD0( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceToD0CompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeQueryIdle( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartedWakeCapable( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWakeCapableDeviceIdle( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWakeCapableUsbSSCompleted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredDecideUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapablePowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableSendWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableWakeArrived( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableCancelWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableCleanup( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableDxAllocFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableUndoPowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCompletedPowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCompletedPowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCompletedHardwareStarted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedQueryIdle( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolIoPresentArmed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolIoPresentArmedWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolS0WakeDisarm( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolS0WakeCompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeSucceeded( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCompletedDisarm( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWakeFailedUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapablePowerDownFailedUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolCancelingWakeForSystemSleep( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolCancelingWakeForSystemSleepWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolDisarmingWakeForSystemSleepCompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolPowerUpForSystemSleepFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWokeFromS0UsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWokeFromS0( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWokeFromS0NotifyDriver( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingResetDevice( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingResetDeviceCompletePowerUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingResetDeviceFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingD0( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingD0Failed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingDisarmWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingDisarmWakeCancelWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingDisarmWakeWakeCanceled( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStopping( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingSucceeded( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingSendStatus( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppedRemoving( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolRemoved( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolRestarting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolRestartingFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingCancelTimer( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingCancelUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingCancelWake( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolCancelUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStarted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartedCancelTimer( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartedWakeCapableCancelTimerForSleep( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartedWakeCapableSleepingUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStartedIdleCapableCancelTimerForSleep( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolDeviceD0PowerRequestFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolDevicePowerRequestFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSleepingPowerDownNotProcessed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapablePowerDownNotProcessed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredNoWakePowerDownNotProcessed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredNoWakeUndoPowerDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredNoWakeReturnToActive( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredNoWakePoweredDownDisableIdleTimer( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolPowerUpForSystemSleepNotSeen( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedStoppingCancelUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedWakeFailedCancelUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedIoPresentCancelUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedWakeSucceededCancelUsbSS( + __inout FxPkgPnp* This + ); + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolCancelingUsbSSForSystemSleep( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolStoppingD0CancelUsbSS( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolWaitingArmedWakeInterruptFired( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeInterruptFired( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolSystemWakeDeviceWakeInterruptFiredNP( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + PowerPolTimerExpiredWakeCapableWakeInterruptArrived( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStarting( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStarted( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerGotoDx( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerGotoDxInDx( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerGotoD0( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerGotoD0InD0( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStopping( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStoppingSendStatus( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStartingFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStoppingFailed( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStoppingPoweringUp( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerStoppingPoweringDown( + __inout FxPkgPnp* This + ); + + static + WDF_DEVICE_POWER_POLICY_STATE + NotPowerPolOwnerRemoved( + __inout FxPkgPnp* This + ); + + // end power policy state machine table based callbacks + + VOID + PowerGotoDx( + VOID + ); + + BOOLEAN + PowerGotoDxIoStopped( + VOID + ); + + BOOLEAN + PowerGotoDxIoStoppedNP( + VOID + ); + + BOOLEAN + PowerDmaEnableAndScan( + __in BOOLEAN ImplicitPowerUp + ); + + VOID + PowerCompletePendedWakeIrp( + VOID + ); + + VOID + PowerCompleteWakeRequestFromWithinMachine( + __in NTSTATUS Status + ); + + BOOLEAN + PowerMakeWakeRequestNonCancelable( + __in NTSTATUS Status + ); + + BOOLEAN + PowerIsWakeRequestPresent( + VOID + ) + { + // + // We don't acquire the spinlock because when we transition to the state + // which will attempt the arming of the device (at bus level), we will + // gracefully handle the absence of the irp. + // + // On the other side if there is no irp and it is set immediately after + // our check, the event posted by the irp's arrival will transition us + // to the state which will attempt the arming. + // + return m_SharedPower.m_WaitWakeIrp != NULL ? TRUE : FALSE; + } + + VOID + PowerSendIdlePowerEvent( + __in FxPowerIdleEvents Event + ); + + VOID + PowerSendPowerDownEvents( + __in FxPowerDownType Type + ); + + VOID + PowerSendPowerUpEvents( + VOID + ); + + VOID + PowerSendPowerDownFailureEvent( + __in FxPowerDownType Type + ); + + VOID + PowerSendPowerUpFailureEvent( + VOID + ); + + VOID + PowerSetDevicePowerState( + __in WDF_POWER_DEVICE_STATE State + ); + + _Must_inspect_result_ + BOOLEAN + PowerDmaPowerUp( + VOID + ); + + BOOLEAN + PowerDmaPowerDown( + VOID + ); + + VOID + PowerConnectInterruptFailed( + VOID + ); + + static + MdCancelRoutineType + _PowerWaitWakeCancelRoutine; + + VOID + PowerPolicyUpdateSystemWakeSource( + __in FxIrp* Irp + ); + + static + VOID + _PowerSetSystemWakeSource( + __in FxIrp* Irp + ); + + static + MdRequestPowerCompleteType + _PowerPolDeviceWaitWakeComplete; + + static + MdRequestPowerCompleteType + _PowerPolDevicePowerDownComplete; + + static + MdRequestPowerCompleteType + _PowerPolDevicePowerUpComplete; + + _Must_inspect_result_ + NTSTATUS + PowerPolicySendDevicePowerRequest( + __in DEVICE_POWER_STATE DeviceState, + __in SendDeviceRequestAction Action + ); + + _Must_inspect_result_ + NTSTATUS + PowerPolicySendWaitWakeRequest( + __in SYSTEM_POWER_STATE SystemState + ); + + VOID + PowerPolicyCompleteSystemPowerIrp( + VOID + ); + + BOOLEAN + PowerPolicyCancelWaitWake( + VOID + ); + + VOID + PowerPolicySubmitUsbIdleNotification( + VOID + ); + + BOOLEAN + PowerPolicyCancelUsbSSIfCapable( + VOID + ); + + VOID + PowerPolicyCancelUsbSS( + VOID + ); + + static + MdCompletionRoutineType + _PowerPolicyWaitWakeCompletionRoutine; + + static + MdCompletionRoutineType + _PowerPolicyUsbSelectiveSuspendCompletionRoutine; + + SYSTEM_POWER_STATE + PowerPolicyGetPendingSystemState( + VOID + ) + { + FxIrp irp(m_PendingSystemPowerIrp); + + // + // In a FastS4 situation, Parameters.Power.State.SystemState will be + // PowerSystemHibernate, while TargetSystemState will indicate the + // true Sx state the machine is moving into. + // + return (SYSTEM_POWER_STATE) + (irp.GetParameterPowerSystemPowerStateContext()). + TargetSystemState; + } + + _Must_inspect_result_ + NTSTATUS + PowerPolicyHandleSystemQueryPower( + __in SYSTEM_POWER_STATE QueryState + ); + + BOOLEAN + PowerPolicyCanWakeFromSystemState( + __in SYSTEM_POWER_STATE SystemState + ) + { + return SystemState <= PowerPolicyGetDeviceDeepestSystemWakeState(); + } + + SYSTEM_POWER_STATE + PowerPolicyGetDeviceDeepestSystemWakeState( + VOID + ) + { + return (SYSTEM_POWER_STATE) m_SystemWake; + } + + DEVICE_POWER_STATE + PowerPolicyGetDeviceDeepestDeviceWakeState( + __in SYSTEM_POWER_STATE SystemState + ); + + static + CPPNP_STATE_TABLE + GetPnpTableEntry( + __in WDF_DEVICE_PNP_STATE State + ) + { + return &m_WdfPnpStates[WdfDevStateNormalize(State) - WdfDevStatePnpObjectCreated]; + } + + static + CPPOWER_STATE_TABLE + GetPowerTableEntry( + __in WDF_DEVICE_POWER_STATE State + ) + { + return &m_WdfPowerStates[WdfDevStateNormalize(State) - WdfDevStatePowerObjectCreated]; + } + + static + CPPOWER_POLICY_STATE_TABLE + GetPowerPolicyTableEntry( + __in WDF_DEVICE_POWER_POLICY_STATE State + ) + { + return &m_WdfPowerPolicyStates[WdfDevStateNormalize(State) - WdfDevStatePwrPolObjectCreated]; + } + +#if FX_STATE_MACHINE_VERIFY + static + CPPNP_STATE_ENTRY_FN_RETURN_STATE_TABLE + GetPnpStateEntryFunctionReturnStatesTableEntry( + __in WDF_DEVICE_PNP_STATE State + ) + { + return &m_WdfPnpStateEntryFunctionReturnStates[WdfDevStateNormalize(State) - WdfDevStatePnpObjectCreated]; + } + + static + CPPOWER_STATE_ENTRY_FN_RETURN_STATE_TABLE + GetPowerStateEntryFunctionReturnStatesTableEntry( + __in WDF_DEVICE_POWER_STATE State + ) + { + return &m_WdfPowerStateEntryFunctionReturnStates[WdfDevStateNormalize(State) - WdfDevStatePowerObjectCreated]; + } + + static + CPPWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE + GetPwrPolStateEntryFunctionReturnStatesTableEntry( + __in WDF_DEVICE_POWER_POLICY_STATE State + ) + { + return &m_WdfPwrPolStateEntryFunctionReturnStates[WdfDevStateNormalize(State) - WdfDevStatePwrPolObjectCreated]; + } + + VOID + ValidatePnpStateEntryFunctionReturnValue( + WDF_DEVICE_PNP_STATE CurrentState, + WDF_DEVICE_PNP_STATE NewState + ); + + VOID + ValidatePowerStateEntryFunctionReturnValue( + WDF_DEVICE_POWER_STATE CurrentState, + WDF_DEVICE_POWER_STATE NewState + ); + + VOID + ValidatePwrPolStateEntryFunctionReturnValue( + WDF_DEVICE_POWER_POLICY_STATE CurrentState, + WDF_DEVICE_POWER_POLICY_STATE NewState + ); +#endif //FX_STATE_MACHINE_VERIFY + + _Must_inspect_result_ + static + CPNOT_POWER_POLICY_OWNER_STATE_TABLE + GetNotPowerPolicyOwnerTableEntry( + __in WDF_DEVICE_POWER_POLICY_STATE State + ) + { + ULONG i; + + for (i = 0; + m_WdfNotPowerPolicyOwnerStates[i].CurrentTargetState != WdfDevStatePwrPolNull; + i++) { + if (m_WdfNotPowerPolicyOwnerStates[i].CurrentTargetState == State) { + return &m_WdfNotPowerPolicyOwnerStates[i]; + } + } + + return NULL; + } + + static + NTSTATUS + _S0IdleQueryInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG OutBufferSize, + __out PVOID OutBuffer, + __out PULONG BufferUsed + ); + + static + NTSTATUS + _S0IdleSetInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG InBufferSize, + __in PVOID InBuffer + ); + + static + NTSTATUS + _S0IdleSetItem( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in PVOID InBuffer + ); + + static + NTSTATUS + _SxWakeQueryInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instaace, + __in ULONG OutBufferSize, + __out PVOID OutBuffer, + __out PULONG BufferUsed + ); + + static + NTSTATUS + _SxWakeSetInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG InBufferSize, + __in PVOID InBuffer + ); + + static + NTSTATUS + _SxWakeSetItem( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in PVOID InBuffer + ); + + BOOLEAN + IsPresentPendingPnpIrp( + VOID + ) + { + return (m_PendingPnPIrp != NULL) ? TRUE : FALSE; + } + + VOID + SetPendingPnpIrp( + __inout FxIrp* Irp, + __in BOOLEAN MarkIrpPending = TRUE + ); + + VOID + SetPendingPnpIrpStatus( + __in NTSTATUS Status + ) + { + FxIrp irp(m_PendingPnPIrp); + + ASSERT(m_PendingPnPIrp != NULL); + irp.SetStatus(Status); + } + + MdIrp + ClearPendingPnpIrp( + VOID + ) + { + MdIrp irp; + + irp = m_PendingPnPIrp; + m_PendingPnPIrp = NULL; + + return irp; + } + + MdIrp + GetPendingPnpIrp( + VOID + ) + { + return m_PendingPnPIrp; + } + + VOID + SetPendingDevicePowerIrp( + __inout FxIrp* Irp + ) + { + ASSERT(m_PendingDevicePowerIrp == NULL); + + Irp->MarkIrpPending(); + m_PendingDevicePowerIrp = Irp->GetIrp(); + + if (Irp->GetParameterPowerStateDeviceState() > PowerDeviceD0) { + // + // We are powering down, capture the current power action. We will + // reset it to PowerActionNone once we have powered up. + // + m_SystemPowerAction = (UCHAR) Irp->GetParameterPowerShutdownType(); + } + } + + MdIrp + ClearPendingDevicePowerIrp( + VOID + ) + { + MdIrp irp; + + irp = m_PendingDevicePowerIrp; + m_PendingDevicePowerIrp = NULL; + + return irp; + } + + VOID + SetPendingSystemPowerIrp( + __inout FxIrp* Irp + ) + { + ASSERT(m_PendingSystemPowerIrp == NULL); + Irp->MarkIrpPending(); + m_PendingSystemPowerIrp = Irp->GetIrp(); + } + + MdIrp + ClearPendingSystemPowerIrp( + VOID + ) + { + MdIrp irp; + + irp = m_PendingSystemPowerIrp; + m_PendingSystemPowerIrp = NULL; + + return irp; + } + + MdIrp + GetPendingSystemPowerIrp( + VOID + ) + { + return m_PendingSystemPowerIrp; + } + + BOOLEAN + IsDevicePowerUpIrpPending( + VOID + ) + { + DEVICE_POWER_STATE state; + FxIrp irp(m_PendingDevicePowerIrp); + + if (irp.GetIrp() == NULL) { + return FALSE; + } + + state = irp.GetParameterPowerStateDeviceState(); + + return (state == PowerDeviceD0 ? TRUE : FALSE); + } + + BOOLEAN + IsUsageSupported( + __in DEVICE_USAGE_NOTIFICATION_TYPE Usage + ) + { + return m_SpecialSupport[((ULONG)Usage)-1]; + } + + VOID + SetUsageSupport( + __in DEVICE_USAGE_NOTIFICATION_TYPE Usage, + __in BOOLEAN Supported + ) + { + m_SpecialSupport[((ULONG) Usage)-1] = Supported; + } + + LONG + AdjustUsageCount( + __in DEVICE_USAGE_NOTIFICATION_TYPE Usage, + __in BOOLEAN Add + ) + { + if (Add) { + return InterlockedIncrement(&m_SpecialFileCount[((ULONG)Usage)-1]); + } + else { + return InterlockedDecrement(&m_SpecialFileCount[((ULONG)Usage)-1]); + } + } + + LONG + GetUsageCount( + // __range(WdfSpecialFilePaging, WdfSpecialFileBoot) + __in __range(1, 4) ULONG Usage + ) + { + return m_SpecialFileCount[Usage-1]; + } + + BOOLEAN + IsInSpecialUse( + VOID + ) + { + if (GetUsageCount(WdfSpecialFilePaging) == 0 && + GetUsageCount(WdfSpecialFileHibernation) == 0 && + GetUsageCount(WdfSpecialFileDump) == 0 && + GetUsageCount(WdfSpecialFileBoot) == 0) { + return FALSE; + } + else { + return TRUE; + } + } + + static + DEVICE_USAGE_NOTIFICATION_TYPE + _SpecialTypeToUsage( + __in WDF_SPECIAL_FILE_TYPE Type + ) + { + switch (Type) { + case WdfSpecialFilePaging: return DeviceUsageTypePaging; + case WdfSpecialFileHibernation: return DeviceUsageTypeHibernation; + case WdfSpecialFileDump: return DeviceUsageTypeDumpFile; + case WdfSpecialFileBoot: return DeviceUsageTypeBoot; + default: ASSERT(FALSE);return DeviceUsageTypePaging; + } + } + + static + WDF_SPECIAL_FILE_TYPE + _UsageToSpecialType( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type + ) + { + switch (Type) { + case DeviceUsageTypePaging: return WdfSpecialFilePaging; + case DeviceUsageTypeHibernation: return WdfSpecialFileHibernation; + case DeviceUsageTypeDumpFile: return WdfSpecialFileDump; + case DeviceUsageTypeBoot: return WdfSpecialFileBoot; + default: ASSERT(FALSE); return WdfSpecialFilePaging; + } + } + + ULONG + SetUsageNotificationFlags( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type, + __in BOOLEAN InPath + ); + + VOID + RevertUsageNotificationFlags( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type, + __in BOOLEAN InPath, + __in ULONG OldFlags + ); + + VOID + CommitUsageNotification( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type, + __in ULONG OldFlags + ); + + _Must_inspect_result_ + NTSTATUS + CreatePowerThread( + VOID + ); + +public: + VOID + PnpProcessEvent( + __in FxPnpEvent Event, + __in BOOLEAN ProcessEventOnDifferentThread = FALSE + ); + + VOID + PowerProcessEvent( + __in FxPowerEvent Event, + __in BOOLEAN ProcessEventOnDifferentThread = FALSE + ); + + VOID + PowerPolicyProcessEvent( + __in FxPowerPolicyEvent Event, + __in BOOLEAN ProcessEventOnDifferentThread = FALSE + ); + + BOOLEAN + ShouldProcessPnpEventOnDifferentThread( + __in KIRQL CurrentIrql, + __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread + ); + + BOOLEAN + ShouldProcessPowerPolicyEventOnDifferentThread( + __in KIRQL CurrentIrql, + __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread + ); + + VOID + CleanupStateMachines( + __in BOOLEAN ClenaupPnp + ); + + VOID + CleanupDeviceFromFailedCreate( + __in MxEvent * WaitEvent + ); + + _Must_inspect_result_ + virtual + NTSTATUS + Initialize( + __in PWDFDEVICE_INIT DeviceInit + ); + + _Must_inspect_result_ + NTSTATUS + PostCreateDeviceInitialize( + VOID + ); + + virtual + VOID + FinishInitialize( + __inout PWDFDEVICE_INIT DeviceInit + ); + + VOID + SetSpecialFileSupport( + __in WDF_SPECIAL_FILE_TYPE FileType, + __in BOOLEAN Supported + ); + + _Must_inspect_result_ + NTSTATUS + RegisterCallbacks( + __in PWDF_PNPPOWER_EVENT_CALLBACKS DispatchTable + ); + + VOID + RegisterPowerPolicyCallbacks( + __in PWDF_POWER_POLICY_EVENT_CALLBACKS Callbacks + ); + + NTSTATUS + RegisterPowerPolicyWmiInstance( + __in const GUID* Guid, + __in FxWmiInstanceInternalCallbacks* Callbacks, + __out FxWmiInstanceInternal** Instance + ); + + NTSTATUS + PowerPolicySetS0IdleSettings( + __in PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ); + + NTSTATUS + AssignPowerFrameworkSettings( + __in PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings + ); + + NTSTATUS + PowerPolicySetSxWakeSettings( + __in PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings, + __in BOOLEAN ArmForWakeIfChildrenAreArmedForWake, + __in BOOLEAN IndicateChildWakeOnParentWake + ); + +private: + + VOID + DisconnectInterruptNP( + VOID + ); + + NTSTATUS + UpdateWmiInstanceForS0Idle( + __in FxWmiInstanceAction Action + ); + + VOID + ReadRegistryS0Idle( + __in PCUNICODE_STRING ValueName, + __out BOOLEAN *Enabled + ); + + NTSTATUS + UpdateWmiInstanceForSxWake( + __in FxWmiInstanceAction Action + ); + + VOID + ReadRegistrySxWake( + __in PCUNICODE_STRING ValueName, + __out BOOLEAN *Enabled + ); + + VOID + WriteStateToRegistry( + __in HANDLE RegKey, + __in PUNICODE_STRING ValueName, + __in ULONG Value + ); + + NTSTATUS + ReadStateFromRegistry( + _In_ PCUNICODE_STRING ValueName, + _Out_ PULONG Value + ); + + NTSTATUS + UpdateWmiInstance( + _In_ FxWmiInstanceAction Action, + _In_ BOOLEAN ForS0Idle + ); + +public: + BOOLEAN + PowerIndicateWaitWakeStatus( + __in NTSTATUS WaitWakeStatus + ); + + BOOLEAN + PowerPolicyIsWakeEnabled( + VOID + ); + + ULONG + PowerPolicyGetCurrentWakeReason( + VOID + ); + + BOOLEAN + __inline + PowerPolicyShouldPropagateWakeStatusToChildren( + VOID + ) + { + return m_PowerPolicyMachine.m_Owner->m_WakeSettings.IndicateChildWakeOnParentWake; + } + + VOID + ChildRemoved( + VOID + ) + { + LONG c; + + // + // Called by a child that we are waiting on its removal + // + c = InterlockedDecrement(&m_PendingChildCount); + ASSERT(c >= 0); + + if (c == 0) { + PnpProcessEvent(PnpEventChildrenRemovalComplete); + } + } + + VOID + PowerPolicySetS0IdleState( + __in BOOLEAN State + ); + + VOID + PowerPolicySetSxWakeState( + __in BOOLEAN State + ); + + VOID + SetPowerCaps( + __in PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ); + + VOID + SetPnpCaps( + __in PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ); + + VOID + GetPnpState( + __out PWDF_DEVICE_STATE State + ); + + VOID + SetPnpState( + __in PWDF_DEVICE_STATE State + ); + + VOID + SetDeviceFailed( + __in WDF_DEVICE_FAILED_ACTION FailedAction + ); + + VOID + SetChildBusInformation( + __in PPNP_BUS_INFORMATION BusInformation + ) + { + RtlCopyMemory(&m_BusInformation, + BusInformation, + sizeof(PNP_BUS_INFORMATION)); + } + + _Must_inspect_result_ + NTSTATUS + HandleQueryBusInformation( + __inout FxIrp* Irp + ); + + _Must_inspect_result_ + NTSTATUS + __inline + PowerReference( + __in BOOLEAN WaitForD0, + __in_opt PVOID Tag = NULL, + __in_opt LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + return m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.PowerReference(WaitForD0, Tag, Line, File); + } + + VOID + __inline + PowerDereference( + __in_opt PVOID Tag = NULL, + __in_opt LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.IoDecrement(Tag, Line, File); + } + + BOOLEAN + HasPowerThread( + VOID + ) + { + return m_HasPowerThread; + } + + VOID + QueueToPowerThread( + __in PWORK_QUEUE_ITEM WorkItem + ) + { + m_PowerThreadInterface.PowerThreadEnqueue( + m_PowerThreadInterface.Interface.Context, + WorkItem + ); + } + + _Must_inspect_result_ + NTSTATUS + AddUsageDevice( + __in MdDeviceObject DependentDevice + ); + + VOID + RemoveUsageDevice( + __in MdDeviceObject DependentDevice + ); + + _Must_inspect_result_ + NTSTATUS + AddRemovalDevice( + __in MdDeviceObject DependentDevice + ); + + VOID + RemoveRemovalDevice( + __in MdDeviceObject DependentDevice + ); + + VOID + ClearRemovalDevicesList( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + AllocateEnumInfo( + VOID + ); + + VOID + AddChildList( + __in FxChildList* List + ); + + VOID + RemoveChildList( + __in FxChildList* List + ); + + VOID + ChildListNotifyRemove( + __inout PLONG PendingCount + ); + + _Must_inspect_result_ + NTSTATUS + AllocateDmaEnablerList( + VOID + ); + + VOID + AddDmaEnabler( + __in FxDmaEnabler* Enabler + ); + + VOID + RemoveDmaEnabler( + __in FxDmaEnabler* Enabler + ); + + VOID + RevokeDmaEnablerResources( + __in FxDmaEnabler* Enabler + ); + + VOID + AddQueryInterface( + __in FxQueryInterface* QI, + __in BOOLEAN Lock + ); + + VOID + QueryForD3ColdInterface( + VOID + ); + + VOID + DropD3ColdInterface( + VOID + ); + + BOOLEAN + IsPowerPolicyOwner( + VOID + ) + { + return m_PowerPolicyMachine.m_Owner != NULL ? TRUE : FALSE; + } + + BOOLEAN + SupportsWakeInterrupt( + VOID + ) + { + if (m_WakeInterruptCount > 0) { + return TRUE; + } else { + return FALSE; + } + } + + BOOLEAN + IsS0IdleWakeFromS0Enabled( + VOID + ) + { + if (IsPowerPolicyOwner()) { + return m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable; + } + else { + return FALSE; + } + } + + BOOLEAN + IsS0IdleSystemManaged( + VOID + ) + { + if (IsPowerPolicyOwner()) { + return m_PowerPolicyMachine.m_Owner->m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout(); + } + else { + return FALSE; + } + } + + BOOLEAN + IsS0IdleUsbSSEnabled( + VOID + ) + { + if (IsPowerPolicyOwner()) { + return (m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable && + m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable); + } + else { + return FALSE; + } + } + + BOOLEAN + IsSxWakeEnabled( + VOID + ) + { + if (IsPowerPolicyOwner()) { + return m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; + } + else { + return FALSE; + } + } + + _Must_inspect_result_ + NTSTATUS + PowerPolicyCanChildPowerUp( + __out PBOOLEAN PowerUp + ) + { + *PowerUp = FALSE; + + if (IsPowerPolicyOwner()) { + NTSTATUS status; + + // + // By referencing the parent (this device) we make sure that if the + // parent is in Dx, we force it back into D0 so that this child can + // be in D0. + // + status = PowerReference(FALSE); + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // m_EnumInfo is valid because the child device is calling into the + // parent device and if there is a child, there is a m_EnumInfo. + // + m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals()); + + // + // The caller has added a power reference to this device, so this device + // will remain in D0 until that power reference has been removed. This + // count is separate from the power ref count b/c the power ref count + // only controls when the idle timer will fire. This count handles the + // race that can occur after we decide that the parent is idle and act + // on it and the child powers up before this parent actually powers + // down. + // + m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount++; + *PowerUp = m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp; + + m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals()); + } + else { + // + // The parent (this device) is not the power policy owner. That + // means we cannot poke the parent to come back to D0 and rely on + // the parent being in D0. Our only recourse is to move into D0 and + // ignore the parent's device power state. + // + // We will only get into this situation if the parent is not the + // power policy owner of the stack. This usually means the parent + // is a filter driver in the parent stack and is creating a virtual + // child. Since the child is assumed virtual, it's D state is not + // tied to real hardware and doesn't really matter. + // + *PowerUp = TRUE; + } + + return STATUS_SUCCESS; + } + + VOID + PowerPolicyChildPoweredDown( + VOID + ) + { + // + // If this parent is the power policy owner of the child's stack, release + // the requirement this device to be in D0 while the child is in D0. + // + if (IsPowerPolicyOwner()) { + // + // Decrement the number of children who are powered on + // + m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals()); + ASSERT(m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount > 0); + m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount--; + m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals()); + + PowerDereference(); + } + } + + POWER_ACTION + GetSystemPowerAction( + VOID + ) + { + return (POWER_ACTION) m_SystemPowerAction; + } + + VOID + ProcessDelayedDeletion( + VOID + ); + + + VOID + SignalDeviceRemovedEvent( + VOID + ) + { + m_DeviceRemoveProcessed->Set(); + } + + virtual + NTSTATUS + FireAndForgetIrp( + FxIrp* Irp + ) =0; + + FxCmResList * + GetTranslatedResourceList( + VOID + ) + { + return m_Resources; + } + + FxCmResList * + GetRawResourceList( + VOID + ) + { + return m_ResourcesRaw; + } + + ULONG + GetInterruptObjectCount( + VOID + ) + { + return m_InterruptObjectCount; + } + + VOID + AckPendingWakeInterruptOperation( + __in BOOLEAN ProcessPowerEventOnDifferentThread + ); + + VOID + SendEventToAllWakeInterrupts( + __in enum FxWakeInterruptEvents WakeInterruptEvent + ); + +private: + VOID + PowerPolicyCheckAssumptions( + VOID + ); + + VOID + PowerCheckAssumptions( + VOID + ); + + VOID + PnpCheckAssumptions( + VOID + ); + + VOID + NotifyResourceobjectsToReleaseResources( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + NotifyResourceObjectsD0( + __in ULONG NotifyFlags + ); + + NTSTATUS + NotifyResourceObjectsDx( + __in ULONG NotifyFlags + ); + + BOOLEAN + PnpCheckAndIncrementRestartCount( + VOID + ); + + BOOLEAN + PnpIncrementRestartCountLogic( + _In_ HANDLE RestartKey, + _In_ BOOLEAN CreatedNewKey + ); + + VOID + PnpCleanupForRemove( + __in BOOLEAN GracefulRemove + ); + + virtual + NTSTATUS + ProcessRemoveDeviceOverload( + FxIrp* Irp + ) =0; + + virtual + VOID + DeleteSymbolicLinkOverload( + BOOLEAN GracefulRemove + ) =0; + + virtual + VOID + QueryForReenumerationInterface( + VOID + ) =0; + + virtual + VOID + ReleaseReenumerationInterface( + VOID + ) =0; + + virtual + NTSTATUS + AskParentToRemoveAndReenumerate( + VOID + ) =0; + + _Must_inspect_result_ + NTSTATUS + CreatePowerThreadIfNeeded( + VOID + ); + + virtual + NTSTATUS + QueryForPowerThread( + VOID + ) =0; + + VOID + ReleasePowerThread( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + HandleQueryInterfaceForPowerThread( + __inout FxIrp* Irp, + __out PBOOLEAN CompleteRequest + ); + + _Must_inspect_result_ + NTSTATUS + PnpPowerReferenceSelf( + VOID + ); + + VOID + PnpPowerDereferenceSelf( + VOID + ); + + static + VOID + _PowerThreadEnqueue( + __in PVOID Context, + __in PWORK_QUEUE_ITEM WorkItem + ) + { + BOOLEAN result; + + result = ((FxPkgPnp*) Context)->m_PowerThread->QueueWorkItem(WorkItem); +#if DBG + ASSERT(result); +#else + UNREFERENCED_PARAMETER(result); +#endif + } + + static + VOID + _PowerThreadInterfaceReference( + __inout PVOID Context + ); + + static + VOID + _PowerThreadInterfaceDereference( + __inout PVOID Context + ); + + BOOLEAN + PowerPolicyCanIdlePowerDown( + __in DEVICE_POWER_STATE DxState + ); + + VOID + PowerPolicyPostParentToD0ToChildren( + VOID + ); + + VOID + PowerPolicyChildrenCanPowerUp( + VOID + ); + + VOID + __inline + PowerPolicyDisarmWakeFromSx( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PowerPolicyPowerDownForSx( + __in DEVICE_POWER_STATE DxState, + __in SendDeviceRequestAction Action + ) + { + // + // The device is powering down because the system is moving into a lower + // power state. + // + // If we have child devices, setup the guard so that they do not power + // up while the parent is in low power. Note that in this case (an Sx + // transition) we do not look at the count of powered up children + // because the power policy owner for the child's stack should not be + // powering up the device once it has processed the Sx irp for its stack. + // + PowerPolicyBlockChildrenPowerUp(); + + return PowerPolicySendDevicePowerRequest(DxState, Action); + } + + VOID + PowerPolicyBlockChildrenPowerUp( + VOID + ) + { + if (m_EnumInfo != NULL) { + m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals()); + // + // Setup a guard so that no children power up until we return to S0. + // + m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp = FALSE; + m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals()); + } + } + + _Must_inspect_result_ + NTSTATUS + PnpPowerReferenceDuringQueryPnp( + VOID + ); + +public: + _Must_inspect_result_ + NTSTATUS + ValidateCmResource( + __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR* CmResourceRaw, + __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR* CmResource + ); + + _Must_inspect_result_ + NTSTATUS + ValidateInterruptResourceCm( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResource, + __in PWDF_INTERRUPT_CONFIG Configuration + ); + + BOOLEAN + IsDefaultReleaseHardwareOrder( + VOID + ) + { +#if FX_IS_KERNEL_MODE + return (m_ReleaseHardwareAfterDescendantsOnFailure == WdfReleaseHardwareOrderOnFailureEarly ? TRUE : FALSE); +#else + return FALSE; +#endif + } + + BOOLEAN + HasMultipleInterrupts( + VOID + ) + { + return (m_InterruptObjectCount > 1 ? TRUE : FALSE); + } + + VOID + WakeInterruptCreated( + VOID + ) + { + ASSERT(IsPowerPolicyOwner() != FALSE); + + ++m_WakeInterruptCount; + } + + // + // Start of members + // +public: + + FxPnpStateAndCaps m_PnpStateAndCaps; + + ULONG m_PnpCapsAddress; + ULONG m_PnpCapsUINumber; + + FxPowerCaps m_PowerCaps; + + BOOLEAN m_Failed; + + // + // Track the current device and system power states. + // + + // SYSTEM_POWER_STATE + BYTE m_SystemPowerState; + + // WDF_POWER_DEVICE_STATE + BYTE m_DevicePowerState; + + // WDF_POWER_DEVICE_STATE + BYTE m_DevicePowerStateOld; + + // + // List of dependent devices for usage notifications + // + FxRelatedDeviceList* m_UsageDependentDeviceList; + + FxRelatedDeviceList* m_RemovalDeviceList; + + // + // Collection of FxQueryInterface objects + // + FxWaitLockInternal m_QueryInterfaceLock; + + SINGLE_LIST_ENTRY m_QueryInterfaceHead; + + FxWaitLockInternal m_DeviceInterfaceLock; + + SINGLE_LIST_ENTRY m_DeviceInterfaceHead; + + BOOLEAN m_DeviceInterfacesCanBeEnabled; + + // + // Indicate the types of special files which are supported. + // + BOOLEAN m_SpecialSupport[WdfSpecialFileMax-1]; + + // + // Track the number of special file notifications + // (ie. paging file, crash dump file, and hibernate file). + // + LONG m_SpecialFileCount[WdfSpecialFileMax-1]; + + // + // ULONG and not a BOOLEAN so the driver can match nest calls to + // WdfDeviceSetStaticStopRemove without having to track the count on their + // own. + // + ULONG m_DeviceStopCount; + + // + // All 3 state machine engines + // + FxPnpMachine m_PnpMachine; + FxPowerMachine m_PowerMachine; + FxPowerPolicyMachine m_PowerPolicyMachine; + + FxSelfManagedIoMachine* m_SelfManagedIoMachine; + + // + // Data shared between the power and power policy machines determining how + // we handle wait wake irps. + // + SharedPowerData m_SharedPower; + + // + // Interface for managing the difference between D3hot and D3cold. + // + D3COLD_SUPPORT_INTERFACE m_D3ColdInterface; + +protected: + // + // Event that is set when processing a remove device is complete + // + MxEvent* m_DeviceRemoveProcessed; + + // + // Count of children we need to fully remove when the parent (this package) + // is being removed. + // + LONG m_PendingChildCount; + + // + // DEVICE_WAKE_DEPTH - Indicates the lowest D-state that can successfully + // generate a wake signal from a particular S-state. The array is tightly- + // packed, with index 0 corresponding to PowerSystemWorking. + // + BYTE m_DeviceWake[DeviceWakeStates]; + + // SYSTEM_POWER_STATE + BYTE m_SystemWake; + + // WDF_DEVICE_FAILED_ACTION + BYTE m_FailedAction; + + // + // Set the event which indicates that the pnp state machine is done outside + // of the state machine so that we can drain any remaining state machine + // events in the removing thread before signaling the event. + // + BYTE m_SetDeviceRemoveProcessed; + + // + // Interface to queue a work item to the devnode's power thread. Any device + // in the stack can export the power thread, but it must be the lowest + // device in the stack capable of doing so. This would always be a WDF + // enumerated PDO, but could theoretically be any PDO. If the PDO does + // support this interface, WDF will try to export the interface in a filter + // or FDO. + // + // This export is not publicly defined because this is an internal WDF + // implementation detail where we want to use as few threads as possible, + // but still guarantee that non power pagable devices can operate a passive + // level and not be blocked by paging I/O (which eliminates using work items). + // + POWER_THREAD_INTERFACE m_PowerThreadInterface; + + FxEnumerationInfo* m_EnumInfo; + + // + // Translated resources + // + FxCmResList* m_Resources; + + // + // Raw resources + // + FxCmResList* m_ResourcesRaw; + + FxSpinLockTransactionedList* m_DmaEnablerList; + + // + // Bus information for any enumerated children + // + PNP_BUS_INFORMATION m_BusInformation; + + // + // Number of times we have tried to enumerate children but failed + // + UCHAR m_BusEnumRetries; + + // + // The power action corresponding to the system power transition + // + UCHAR m_SystemPowerAction; + + // + // TRUE once the entire stack has been queried for the caps + // + BOOLEAN m_CapsQueried; + + BOOLEAN m_InternalFailure; + + // + // if FALSE, there is no power thread available on the devnode currently + // and a work item should be enqueued. if TRUE, there is a power thread + // and the callback should be enqueued to it. + // + BOOLEAN m_HasPowerThread; + + // + // If TRUE, we guarantee that in *all* cases that the ReleaseHardware + // callback for the current device is invoked only after all descendent + // devices have already been removed. We do this by ensuring that + // ReleaseHardware is only ever invoked when there is a PNP IRP such as + // remove, surprise-remove or stop is pending in the device. PNP already + // ensures that it sends us that IRP only after all child devices have + // processed the corresponding IRP in their stacks. + // + // Even if FALSE, in *most* cases, the ReleaseHardware callback of the + // current device should still be invoked only after all descendent devices + // have already been stopped/removed. However, in some failure paths we + // might invoke the ReleaseHardware callback of the current device before + // all descendent devices have been stopped. In these cases, we do not wait + // for the surprise-remove IRP sent as a result of the failure in order to + // invoke ReleaseHardware. Instead, we invoke it proactively. + // + // The default value is FALSE. + // + BOOLEAN m_ReleaseHardwareAfterDescendantsOnFailure; + + // + // GUID for querying for a power thread down the stack + // + static const GUID GUID_POWER_THREAD_INTERFACE; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // Interrupt APIs for Vista and forward + // + PFN_IO_CONNECT_INTERRUPT_EX m_IoConnectInterruptEx; + PFN_IO_DISCONNECT_INTERRUPT_EX m_IoDisconnectInterruptEx; + // + // Interrupt APIs for Windows 8 and forward + // + PFN_IO_REPORT_INTERRUPT_ACTIVE m_IoReportInterruptActive; + PFN_IO_REPORT_INTERRUPT_INACTIVE m_IoReportInterruptInactive; +#endif + +private: + + // + // For user mode we need to preallocate event since its initialization can + // fail + // +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + FxCREvent m_CleanupEventUm; + MxEvent m_RemoveEventUm; +#endif + + ULONG m_InterruptObjectCount; + + LIST_ENTRY m_InterruptListHead; + + // + // Number of interrupts that are declared to be capable + // of waking from low power + // + ULONG m_WakeInterruptCount; + + // + // Count that keeps track of the number of wake interrupt + // machines that have acknowledged back an event queued + // in to them by the device level PnP/Power code + // + ULONG m_WakeInterruptPendingAckCount; + + // + // Keeps track of whether the last system wake was due to + // a wake interrupt, so that we can report this device as + // the source of wake to the power manager + // + BOOLEAN m_SystemWokenByWakeInterrupt; + + // + // If TRUE, do not disconnect wake interrupts even if there is no + // pended IRP_MN_WAIT_WAKE. This works around a race condition between + // the wake interrupt firing (and the wake ISR running) and the device + // powering down. This flag is set when we are in a wake-enabled device + // powering down path and is cleared when the device is powered up again. + // + BOOLEAN m_WakeInterruptsKeepConnected; + + // + // If TRUE, the PNP State has reached PnpEventStarted at least once. + // + BOOLEAN m_AchievedStart; + + // + // Non NULL when this device is exporting the power thread interface. This + // would be the lowest device in the stack that supports this interface. + // + FxSystemThread* m_PowerThread; + + LONG m_PowerThreadInterfaceReferenceCount; + + FxCREvent* m_PowerThreadEvent; + + // + // The current pnp state changing irp in the stack that we have pended to + // process in the pnp state machine + // + MdIrp m_PendingPnPIrp; + + // + // The current system power irp in the stack that we have pended to process + // in the power state machine + // + MdIrp m_PendingSystemPowerIrp; + + // + // The current device power irp in the stack that we have pended to process + // in the power state machine + // + MdIrp m_PendingDevicePowerIrp; + + FxPnpStateCallback* m_PnpStateCallbacks; + + FxPowerStateCallback* m_PowerStateCallbacks; + + FxPowerPolicyStateCallback* m_PowerPolicyStateCallbacks; + + static const PNP_STATE_TABLE m_WdfPnpStates[]; + static const POWER_STATE_TABLE m_WdfPowerStates[]; + static const POWER_POLICY_STATE_TABLE m_WdfPowerPolicyStates[]; + static const NOT_POWER_POLICY_OWNER_STATE_TABLE m_WdfNotPowerPolicyOwnerStates[]; + + static const PNP_EVENT_TARGET_STATE m_PnpInitOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpInitStartingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpHardwareAvailableOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpQueryStopPendingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpRemovedPdoWaitOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpRestartingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpStartedOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpQueryRemovePendingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpQueriedRemovingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpInitQueryRemoveOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpStoppedOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpStoppedWaitForStartCompletionOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpStartedStoppingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpStartedStoppingFailedOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpEjectFailedOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpStartedRemovingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpFailedPowerDownOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpFailedIoStartingOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpFailedWaitForRemoveOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpRestartOtherStates[]; + static const PNP_EVENT_TARGET_STATE m_PnpRestartReleaseHardware[]; + static const PNP_EVENT_TARGET_STATE m_PnpRestartHardwareAvailableOtherStates[]; + + static const POWER_EVENT_TARGET_STATE m_PowerD0OtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerD0NPOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerD0BusWakeOwnerOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerD0BusWakeOwnerNPOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerD0ArmedForWakeOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerD0ArmedForWakeNPOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerDNotZeroOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerDNotZeroNPOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_DxArmedForWakeOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_DxArmedForWakeNPOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_WakePendingOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_WakePendingNPOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_DxSurpriseRemovedOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerStoppedOtherStates[]; + static const POWER_EVENT_TARGET_STATE m_PowerDxStoppedOtherStates[]; + + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolObjectCreatedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStartingOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStartedIdleCapableOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolIdleCapableDeviceIdleOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredNoWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredNoWakeCompletePowerDownOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolWaitingUnarmedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolS0NoWakePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolS0NoWakeCompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemSleepNeedWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemSleepNeedWakeCompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemAsleepWakeArmedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemAsleepWakeArmedNPOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceToD0OtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceToD0CompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStartedWakeCapableOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolWakeCapableDeviceIdleOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapablePowerDownOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableSendWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableUsbSSOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolWaitingArmedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolDisarmingWakeForSystemSleepCompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolCancelingWakeForSystemSleepWakeCanceledOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolWokeFromS0OtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingResetDeviceOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingResetDeviceCompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingD0OtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingDisarmWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingDisarmWakeCancelWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolIoPresentArmedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolIoPresentArmedWakeCanceledOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolS0WakeCompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableWakeSucceededOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableWakeFailedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolCancelingWakeForSystemSleepOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableWakeArrivedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableCancelWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCompletedPowerDownOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCompletedPowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeEnabledOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeEnabledNPOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNPOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingWakeWakeArrivedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeTriggeredS0OtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeTriggeredS0NPOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeCompletePowerUpOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingNoWakePowerDownOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingNoWakeCompletePowerDownOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingWakePowerDownOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingSendWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingWakeWakeArrivedNPOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingWakePowerDownFailedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStartedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStartedWaitForIdleTimeoutOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolDevicePowerRequestFailedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolRestartingOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolStoppingCancelWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolCancelUsbSSOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingWakeRevertArmWakeOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSleepingWakeRevertArmWakeNPOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolRemovedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapableWakeInterruptArrivedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrivedOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolWaitingArmedWakeInterruptFiredDuringPowerDownOtherStates[]; + + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerObjectCreatedStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStartingStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStartingSucceededStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStartingFailedStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerGotoDxStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerGotoDxInDxStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerDxStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerGotoD0States[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerGotoD0InD0States[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStoppedStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStoppingWaitForImplicitPowerDownStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStoppingPoweringUpStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerStoppingPoweringDownStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_NotPowerPolOwnerRemovedStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolWaitingArmedWakeInterruptFiredOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeInterruptFiredOtherStates[]; + static const POWER_POLICY_EVENT_TARGET_STATE m_PowerPolSystemWakeDeviceWakeInterruptFiredNPOtherStates[]; + +#if FX_STATE_MACHINE_VERIFY + // + // Array of possible states that can be returned by state entry functions + // + static const PNP_STATE_ENTRY_FN_RETURN_STATE_TABLE m_WdfPnpStateEntryFunctionReturnStates[]; + static const POWER_STATE_ENTRY_FN_RETURN_STATE_TABLE m_WdfPowerStateEntryFunctionReturnStates[]; + static const PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE m_WdfPwrPolStateEntryFunctionReturnStates[]; +#endif // FX_STATE_MACHINE_VERIFY + + // + // Names for registry values in which we will store the beginning of the + // restart time period, the number of restart attempts in that period, and + // if the device successfully started. + // + static const PWCHAR m_RestartStartAchievedName; + static const PWCHAR m_RestartStartTimeName; + static const PWCHAR m_RestartCountName; + + // + // Time between successive restarts in which we will attempt to restart a + // stack again. Expressed in seconds. + // + static const ULONG m_RestartTimePeriodMaximum; + + // + // Number of times in the restart time period in which we will attempt a + // restart. + // + static const ULONG m_RestartCountMaximum; + + // + // Shove the function pointers to the end of the structure so that when + // we dump the structure while debugging, the less pertinent info is at the + // bottom. + // +public: + FxPnpDeviceUsageNotification m_DeviceUsageNotification; + FxPnpDeviceUsageNotificationEx m_DeviceUsageNotificationEx; + FxPnpDeviceRelationsQuery m_DeviceRelationsQuery; + + FxPnpDeviceD0Entry m_DeviceD0Entry; + FxPnpDeviceD0EntryPostInterruptsEnabled m_DeviceD0EntryPostInterruptsEnabled; + FxPnpDeviceD0ExitPreInterruptsDisabled m_DeviceD0ExitPreInterruptsDisabled; + FxPnpDeviceD0Exit m_DeviceD0Exit; + + FxPnpDevicePrepareHardware m_DevicePrepareHardware; + FxPnpDeviceReleaseHardware m_DeviceReleaseHardware; + + FxPnpDeviceQueryStop m_DeviceQueryStop; + FxPnpDeviceQueryRemove m_DeviceQueryRemove; + FxPnpDeviceSurpriseRemoval m_DeviceSurpriseRemoval; +}; + +__inline +VOID +FxPostProcessInfo::Evaluate( + __inout FxPkgPnp* PkgPnp + ) +{ + if (m_SetRemovedEvent) { + ASSERT(m_DeleteObject == FALSE && m_Event == NULL && m_FireAndForgetIrp == NULL); + PkgPnp->SignalDeviceRemovedEvent(); + return; + } + + // + // Process any irp that should be sent down the stack/forgotten. + // + if (m_FireAndForgetIrp != NULL) { + FxIrp irp(m_FireAndForgetIrp); + + m_FireAndForgetIrp = NULL; + (void) PkgPnp->FireAndForgetIrp(&irp); + } + + if (m_DeleteObject) { + PkgPnp->ProcessDelayedDeletion(); + } + + if (m_Event != NULL) { + m_Event->Set(); + } +} + +#endif // _FXPKGPNP_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpnpcallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpnpcallbacks.hpp new file mode 100644 index 00000000000..83a517ef982 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpnpcallbacks.hpp @@ -0,0 +1,1127 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPnpCallbacks.hpp + +Abstract: + + This module implements the PnP/Power callback objects. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXPNPCALLBACKS_H_ +#define _FXPNPCALLBACKS_H_ + +class FxPnpDeviceFilterResourceRequirements : public FxCallback { + +public: + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS m_Method; + + FxPnpDeviceFilterResourceRequirements( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFIORESREQLIST Collection + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, Collection); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceD0Entry : public FxCallback { + +public: + PFN_WDF_DEVICE_D0_ENTRY m_Method; + + FxPnpDeviceD0Entry( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDF_POWER_DEVICE_STATE PreviousState + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, PreviousState); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceD0EntryPostInterruptsEnabled : public FxCallback { + +public: + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED m_Method; + + FxPnpDeviceD0EntryPostInterruptsEnabled( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDF_POWER_DEVICE_STATE PreviousState + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, PreviousState); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceD0Exit : public FxCallback { + +public: + PFN_WDF_DEVICE_D0_EXIT m_Method; + + FxPnpDeviceD0Exit( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDF_POWER_DEVICE_STATE TargetState + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, TargetState); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceD0ExitPreInterruptsDisabled : public FxCallback { + +public: + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED m_Method; + + FxPnpDeviceD0ExitPreInterruptsDisabled( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDF_POWER_DEVICE_STATE TargetState + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, TargetState); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDevicePrepareHardware : public FxCallback { + +public: + PFN_WDF_DEVICE_PREPARE_HARDWARE m_Method; + + FxPnpDevicePrepareHardware( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFCMRESLIST ResourcesRaw, + __in WDFCMRESLIST ResourcesTranslated + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, ResourcesRaw, ResourcesTranslated); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceReleaseHardware : public FxCallback { + +public: + PFN_WDF_DEVICE_RELEASE_HARDWARE m_Method; + + FxPnpDeviceReleaseHardware( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFCMRESLIST ResourcesTranslated + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, ResourcesTranslated); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceRemoveAddedResources : public FxCallback { +public: + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES m_Method; + +public: + FxPnpDeviceRemoveAddedResources( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFCMRESLIST ResourcesRaw, + __in WDFCMRESLIST ResourcesTranslated + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, ResourcesRaw, ResourcesTranslated); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceSelfManagedIoCleanup : public FxCallback { + +public: + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP m_Method; + + FxPnpDeviceSelfManagedIoCleanup( + VOID + ) : m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPnpDeviceSelfManagedIoFlush : public FxCallback { + +public: + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH m_Method; + + FxPnpDeviceSelfManagedIoFlush( + VOID + ) : m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPnpDeviceSelfManagedIoInit : public FxCallback { + +public: + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT m_Method; + + FxPnpDeviceSelfManagedIoInit( + VOID + ) : m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceSelfManagedIoSuspend : public FxCallback { + +public: + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND m_Method; + + FxPnpDeviceSelfManagedIoSuspend( + VOID + ) : m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceSelfManagedIoRestart : public FxCallback { + +public: + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART m_Method; + + FxPnpDeviceSelfManagedIoRestart( + VOID + ) : m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceQueryStop : public FxCallback { + +public: + PFN_WDF_DEVICE_QUERY_STOP m_Method; + + FxPnpDeviceQueryStop( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceQueryRemove : public FxCallback { + +public: + PFN_WDF_DEVICE_QUERY_REMOVE m_Method; + + FxPnpDeviceQueryRemove( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceResourcesQuery : public FxCallback { + +public: + PFN_WDF_DEVICE_RESOURCES_QUERY m_Method; + + FxPnpDeviceResourcesQuery( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFCMRESLIST Collection + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, Collection); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceResourceRequirementsQuery : public FxCallback { + +public: + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY m_Method; + + FxPnpDeviceResourceRequirementsQuery( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFIORESREQLIST Collection + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, Collection); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceEject : public FxCallback { + +public: + PFN_WDF_DEVICE_EJECT m_Method; + + FxPnpDeviceEject( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceSurpriseRemoval : public FxCallback { + +public: + PFN_WDF_DEVICE_SURPRISE_REMOVAL m_Method; + + FxPnpDeviceSurpriseRemoval( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPnpDeviceUsageNotification : public FxCallback { + +public: + PFN_WDF_DEVICE_USAGE_NOTIFICATION m_Method; + + FxPnpDeviceUsageNotification( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device, + __in WDF_SPECIAL_FILE_TYPE NotificationType, + __in BOOLEAN InPath + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device, NotificationType, InPath); + CallbackEnd(); + } + } +}; + +class FxPnpDeviceUsageNotificationEx : public FxCallback { + +public: + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX m_Method; + + FxPnpDeviceUsageNotificationEx( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDF_SPECIAL_FILE_TYPE NotificationType, + __in BOOLEAN InPath + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, NotificationType, InPath); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPnpDeviceRelationsQuery : public FxCallback { + +public: + PFN_WDF_DEVICE_RELATIONS_QUERY m_Method; + + FxPnpDeviceRelationsQuery( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device, + __in DEVICE_RELATION_TYPE RelationType + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device, RelationType); + CallbackEnd(); + } + } +}; + +class FxPnpDeviceSetLock : public FxCallback { + +public: + PFN_WDF_DEVICE_SET_LOCK m_Method; + + FxPnpDeviceSetLock( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in BOOLEAN Lock + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, Lock); + CallbackEnd(); + + return status; + } + else { + return STATUS_UNSUCCESSFUL; + } + } +}; + +class FxPnpDeviceReportedMissing : public FxCallback { + +public: + PFN_WDF_DEVICE_REPORTED_MISSING m_Method; + + FxPnpDeviceReportedMissing( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPowerDeviceEnableWakeAtBus : public FxCallback { + +public: + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS m_Method; + + FxPowerDeviceEnableWakeAtBus( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in SYSTEM_POWER_STATE PowerState + ) + { + NTSTATUS status; + + if (m_Method != NULL) { + CallbackStart(); + status = m_Method(Device, PowerState); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPowerDeviceDisableWakeAtBus : public FxCallback { + +public: + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS m_Method; + + FxPowerDeviceDisableWakeAtBus( + VOID + ) : FxCallback(), m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPowerDeviceArmWakeFromS0 : public FxCallback { + +public: + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 m_Method; + + FxPowerDeviceArmWakeFromS0( + VOID + ) : m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPowerDeviceArmWakeFromSx : public FxCallback { + +public: + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX m_Method; + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON m_MethodWithReason; + + FxPowerDeviceArmWakeFromSx( + VOID + ) : m_Method(NULL), + m_MethodWithReason(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in BOOLEAN DeviceWakeEnabled, + __in BOOLEAN ChildrenArmedForWake + ) + { + if (m_MethodWithReason != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_MethodWithReason(Device, + DeviceWakeEnabled, + ChildrenArmedForWake); + CallbackEnd(); + + return status; + } + else if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } +}; + +class FxPowerDeviceDisarmWakeFromS0 : public FxCallback { + +public: + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 m_Method; + + FxPowerDeviceDisarmWakeFromS0( + VOID + ) : m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPowerDeviceDisarmWakeFromSx : public FxCallback { + +public: + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX m_Method; + + FxPowerDeviceDisarmWakeFromSx( + VOID + ) : m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPowerDeviceWakeFromSxTriggered : public FxCallback { + +public: + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED m_Method; + + FxPowerDeviceWakeFromSxTriggered( + VOID + ) : m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +class FxPowerDeviceWakeFromS0Triggered : public FxCallback { + +public: + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED m_Method; + + FxPowerDeviceWakeFromS0Triggered( + VOID + ) : m_Method(NULL) + { + } + + VOID + Invoke( + __in WDFDEVICE Device + ) + { + if (m_Method != NULL) { + CallbackStart(); + m_Method(Device); + CallbackEnd(); + } + } +}; + +struct FxPnpStateCallbackInfo { + // + // Bit field of WDF_STATE_NOTIFICATION_TYPE defined values + // + ULONG Types; + + // + // Function to call + // + PFN_WDF_DEVICE_PNP_STATE_CHANGE_NOTIFICATION Callback; +}; + +struct FxPnpStateCallback : public FxCallback { + + FxPnpStateCallback( + VOID + ) : FxCallback() + { + RtlZeroMemory(&m_Methods[0], sizeof(m_Methods)); + } + + VOID + Invoke( + __in WDF_DEVICE_PNP_STATE State, + __in WDF_STATE_NOTIFICATION_TYPE Type, + __in WDFDEVICE Device, + __in PCWDF_DEVICE_PNP_NOTIFICATION_DATA NotificationData + ) + { + FxPnpStateCallbackInfo* pInfo; + + pInfo = &m_Methods[WdfDevStateNormalize(State)-WdfDevStatePnpObjectCreated]; + + if (pInfo->Callback != NULL && (pInfo->Types & Type)) { + CallbackStart(); + pInfo->Callback(Device, NotificationData); + CallbackEnd(); + } + } + + FxPnpStateCallbackInfo m_Methods[WdfDevStatePnpNull - WdfDevStatePnpObjectCreated]; +}; + +struct FxPowerStateCallbackInfo { + // + // Bit field of WDF_STATE_NOTIFICATION_TYPE defined values + // + ULONG Types; + + // + // Function to call + // + PFN_WDF_DEVICE_POWER_STATE_CHANGE_NOTIFICATION Callback; +}; + +struct FxPowerStateCallback : public FxCallback { + FxPowerStateCallback( + VOID + ) : FxCallback() + { + RtlZeroMemory(&m_Methods[0], sizeof(m_Methods)); + } + + VOID + Invoke( + __in WDF_DEVICE_POWER_STATE State, + __in WDF_STATE_NOTIFICATION_TYPE Type, + __in WDFDEVICE Device, + __in PCWDF_DEVICE_POWER_NOTIFICATION_DATA NotificationData + ) + { + FxPowerStateCallbackInfo *pInfo; + + pInfo = &m_Methods[WdfDevStateNormalize(State)-WdfDevStatePowerObjectCreated]; + + if (pInfo->Callback != NULL && (pInfo->Types & Type)) { + CallbackStart(); + pInfo->Callback(Device, NotificationData); + CallbackEnd(); + } + } + + FxPowerStateCallbackInfo m_Methods[WdfDevStatePowerNull-WdfDevStatePowerObjectCreated]; +}; + +struct FxPowerPolicyStateCallbackInfo { + // + // Bit field of WDF_STATE_NOTIFICATION_TYPE defined values + // + ULONG Types; + + // + // Function to call + // + PFN_WDF_DEVICE_POWER_POLICY_STATE_CHANGE_NOTIFICATION Callback; +}; + +struct FxPowerPolicyStateCallback : public FxCallback { + FxPowerPolicyStateCallback( + VOID + ) : FxCallback() + { + RtlZeroMemory(&m_Methods[0], sizeof(m_Methods)); + } + + VOID + Invoke( + __in WDF_DEVICE_POWER_POLICY_STATE State, + __in WDF_STATE_NOTIFICATION_TYPE Type, + __in WDFDEVICE Device, + __in PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA NotificationData + ) + { + FxPowerPolicyStateCallbackInfo *pInfo; + + pInfo = &m_Methods[WdfDevStateNormalize(State)-WdfDevStatePwrPolObjectCreated]; + + if (pInfo->Callback != NULL && (pInfo->Types & Type)) { + CallbackStart(); + pInfo->Callback(Device, NotificationData); + CallbackEnd(); + } + } + + FxPowerPolicyStateCallbackInfo m_Methods[WdfDevStatePwrPolNull-WdfDevStatePwrPolObjectCreated]; +}; + + + +#endif // _FXPNPCALLBACKS_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpnpstatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpnpstatemachine.hpp new file mode 100644 index 00000000000..64d8dca14e5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpnpstatemachine.hpp @@ -0,0 +1,225 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXPNPSTATEMACHINE_H_ +#define _FXPNPSTATEMACHINE_H_ + +// @@SMVERIFY_SPLIT_BEGIN + +typedef +WDF_DEVICE_PNP_STATE +(*PFN_PNP_STATE_ENTRY_FUNCTION)( + FxPkgPnp* This + ); + +// +// Treat these values as a bit field when comparing for known dropped events in +// the current state and treat them as values when they known transition events +// from state to the next. +// +enum FxPnpEvent { + PnpEventInvalid = 0x000000, + PnpEventAddDevice = 0x000001, + PnpEventStartDevice = 0x000002, + PnpEventStartDeviceComplete = 0x000004, + PnpEventStartDeviceFailed = 0x000008, + PnpEventQueryRemove = 0x000010, + PnpEventQueryStop = 0x000020, + PnpEventCancelRemove = 0x000040, + PnpEventCancelStop = 0x000080, + PnpEventStop = 0x000100, + PnpEventRemove = 0x000200, + PnpEventSurpriseRemove = 0x000400, + PnpEventEject = 0x000800, + PnpEventPwrPolStopped = 0x001000, + PnpEventPwrPolStopFailed = 0x002000, + PnpEventPowerUpFailed = 0x004000, + PnpEventPowerDownFailed = 0x008000, + PnpEventParentRemoved = 0x010000, + PnpEventChildrenRemovalComplete = 0x020000, + PnpEventPwrPolStarted = 0x040000, + PnpEventPwrPolStartFailed = 0x080000, + PnpEventDeviceInD0 = 0x100000, + PnpEventPwrPolRemoved = 0x200000, + + // + // Not a real event, just a value that shows all of the events which have + // queued the pnp irp. If we drop one of these events, we *must* complete + // the pended pnp irp. See PnpProcessEventInner. + // + PnpEventPending = PnpEventStartDeviceComplete | + PnpEventQueryRemove | + PnpEventQueryStop | + PnpEventCancelRemove | + PnpEventCancelStop | + PnpEventStop | + PnpEventSurpriseRemove | + PnpEventEject, + + // + // Not a real event, just a value that indicates all of the events which + // goto the head of the queue and are always processed, even if the state is + // locked. + // + PnpPriorityEventsMask = PnpEventPwrPolStarted | + PnpEventPwrPolStartFailed | + PnpEventPwrPolStopped | + PnpEventPwrPolStopFailed | + PnpEventDeviceInD0 | + PnpEventPwrPolRemoved, + + PnpEventNull = 0xFFFFFFFF, +}; + +// +// Bit packed ULONG. +// +union FxPnpStateInfo { + struct { + // + // Indicates whether the state is open to all events + // + ULONG QueueOpen : 1; + + // + // Bit of events we know we can drop in this state + // + ULONG KnownDroppedEvents : 31; + } Bits; + + struct { + // + // Maps to the same bit location as QueueOpen. Since we start + // KnownDroppedEvents at the next bit, start our bits by at the next + // bit as well. + // + ULONG Reserved : 1; + + // + // These are defined so that we can easily tell in the debugger what + // each set bit in KnownDroppedEvents maps to in the FxPnpEvent enum + // + ULONG PnpEventAddDeviceKnown : 1; + ULONG PnpEventStartDeviceKnown : 1; + ULONG PnpEventStartDeviceCompleteKnown : 1; + ULONG PnpEventStartDeviceFailedKnown : 1; + ULONG PnpEventQueryRemoveKnown : 1; + ULONG PnpEventQueryStopKnown : 1; + ULONG PnpEventCancelRemoveKnown : 1; + ULONG PnpEventCancelStopKnown : 1; + ULONG PnpEventStopKnown : 1; + ULONG PnpEventRemoveKnown : 1; + ULONG PnpEventSurpriseRemoveKnown : 1; + ULONG PnpEventEjectKnown : 1; + ULONG PnpEventPwrPolStopped : 1; + ULONG PnpEventPwrPolStopFailed : 1; + ULONG PnpEventPowerUpFailedKnown : 1; + ULONG PnpEventPowerDownFailedKnown : 1; + ULONG PnpEventParentRemovedKnown : 1; + ULONG PnpEventChildrenRemovalCompleteKnown : 1; + ULONG PnpEventPwrPolStarted : 1; + ULONG PnpEventPwrPolStartFailed : 1; + } BitsByName; +}; + +struct PNP_EVENT_TARGET_STATE { + FxPnpEvent PnpEvent; + + WDF_DEVICE_PNP_STATE TargetState; + + EVENT_TRAP_FIELD +}; + +typedef const PNP_EVENT_TARGET_STATE* CPPNP_EVENT_TARGET_STATE; + +struct PNP_STATE_TABLE { + // + // Framework internal function + // + PFN_PNP_STATE_ENTRY_FUNCTION StateFunc; + + PNP_EVENT_TARGET_STATE FirstTargetState; + + CPPNP_EVENT_TARGET_STATE OtherTargetStates; + + FxPnpStateInfo StateInfo; + +}; + +typedef const PNP_STATE_TABLE* CPPNP_STATE_TABLE; + +#if FX_STATE_MACHINE_VERIFY +#define MAX_PNP_STATE_ENTRY_FN_RETURN_STATES (5) + +struct PNP_STATE_ENTRY_FUNCTION_TARGET_STATE { + // + // Return value from state entry function + // + WDF_DEVICE_PNP_STATE State; + + // + // type of device the returning state applies to + // + FxStateMachineDeviceType DeviceType; + + // + // Info about the state transition + // + PSTR Comment; +}; + +typedef const PNP_STATE_ENTRY_FUNCTION_TARGET_STATE* CPPNP_STATE_ENTRY_FUNCTION_TARGET_STATE; + +struct PNP_STATE_ENTRY_FN_RETURN_STATE_TABLE { + // + // array of state transitions caused by state entry function + // + PNP_STATE_ENTRY_FUNCTION_TARGET_STATE TargetStates[MAX_PNP_STATE_ENTRY_FN_RETURN_STATES]; +}; + +typedef const PNP_STATE_ENTRY_FN_RETURN_STATE_TABLE* CPPNP_STATE_ENTRY_FN_RETURN_STATE_TABLE; +#endif //FX_STATE_MACHINE_VERIFY + +// @@SMVERIFY_SPLIT_END + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxPnpMachineStateHistory { + struct { + WDF_DEVICE_PNP_STATE State1 : 16; + WDF_DEVICE_PNP_STATE State2 : 16; + WDF_DEVICE_PNP_STATE State3 : 16; + WDF_DEVICE_PNP_STATE State4 : 16; + WDF_DEVICE_PNP_STATE State5 : 16; + WDF_DEVICE_PNP_STATE State6 : 16; + WDF_DEVICE_PNP_STATE State7 : 16; + WDF_DEVICE_PNP_STATE State8 : 16; + } S; + + USHORT History[PnpEventQueueDepth]; +}; + + +struct FxPnpMachine : public FxWorkItemEventQueue { + FxPnpMachine( + VOID + ) : FxWorkItemEventQueue(PnpEventQueueDepth) + { + RtlZeroMemory(&m_Queue[0], sizeof(m_Queue)); + RtlZeroMemory(&m_States, sizeof(m_States)); + + m_States.History[IncrementHistoryIndex()] = WdfDevStatePnpObjectCreated; + m_FireAndForget = FALSE; + } + + FxPnpEvent m_Queue[PnpEventQueueDepth]; + + FxPnpMachineStateHistory m_States; + + BOOLEAN m_FireAndForget; +}; + +#endif // _FXPNPSTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpool.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpool.h new file mode 100644 index 00000000000..906048036c8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpool.h @@ -0,0 +1,286 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPool.h + +Abstract: + + This module contains private Pool package definitions + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + Made it mode agnostic + + New failure paths: + Initialization failures of paged/non-paged lock - + + Upon failure we disable pool tracking, rest of the behavior + remains unchanged, and FxPoolInitialize not being bubbled up + doesn't become an issue. + +--*/ + +#ifndef _FXPOOL_H_ +#define _FXPOOL_H_ + +// +// Common pool header for small allocations (less than PAGE_SIZE) +// +struct FX_POOL_HEADER { + + PVOID Base; + + PFX_DRIVER_GLOBALS FxDriverGlobals; + + DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) ULONG AllocationStart[1]; +}; + +typedef FX_POOL_HEADER* PFX_POOL_HEADER; + +#define FX_POOL_HEADER_SIZE FIELD_OFFSET(FX_POOL_HEADER, AllocationStart) + + +// +// This structure described an indivdually tracked pool. +// +// The frameworks tracks pool on behalf of the frameworks (global), +// and per driver. +// + +struct FX_POOL { + MxLockNoDynam NonPagedLock; + LIST_ENTRY NonPagedHead; + + MxPagedLockNoDynam PagedLock; + LIST_ENTRY PagedHead; + + // Current Pool Usage Information + SIZE_T NonPagedBytes; + SIZE_T PagedBytes; + + ULONG NonPagedAllocations; + ULONG PagedAllocations; + + // Peak Pool Usage Information + SIZE_T PeakNonPagedBytes; + SIZE_T PeakPagedBytes; + + ULONG PeakNonPagedAllocations; + ULONG PeakPagedAllocations; +}; + +typedef FX_POOL *PFX_POOL; + +// +// This structure is allocated along with the pool item and +// is used to track it. +// +// Note: We would be messing up cache aligned if its greater +// than 16. +// +// Our struct is 7 DWORD's on an x86, and 11 DWORDS on 64 bit +// machines. +// +// This rounds up to 8 or 12 DWORDS. +// +// +struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) FX_POOL_TRACKER { + LIST_ENTRY Link; + PFX_POOL Pool; + ULONG Tag; + SIZE_T Size; + POOL_TYPE PoolType; + PVOID CallersAddress; +}; + +typedef FX_POOL_TRACKER *PFX_POOL_TRACKER; + +/*++ + +Routine Description: + + Initialize the FX_POOL tracking object + +Arguments: + + Pool - FX_POOL object for tracking allocations + +Returns: + + status + +--*/ +_Must_inspect_result_ +NTSTATUS +FxPoolInitialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool + ); + +/*++ + +Routine Description: + + Destory the FX_POOL tracking object + +Arguments: + + Pool - FX_POOL object for tracking allocations + +--*/ +VOID +FxPoolDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool + ); + + +extern "C" +_Must_inspect_result_ +PWDF_DRIVER_GLOBALS +FxAllocateDriverGlobals( + VOID + ); + +extern "C" +VOID +FxFreeDriverGlobals( + __in PWDF_DRIVER_GLOBALS DriverGlobals + ); + +BOOLEAN +FxIsPagedPoolType( + __in POOL_TYPE Type + ); + +/*++ + +Routine Description: + + Allocates system pool tracked in a FX_POOL tracking object. + +Arguments: + + Pool - FX_POOL object for tracking allocations + + Type - POOL_TYPE from ntddk.h + + Size - Size in bytes of the allocation + + Tag - Caller specified additional tag value for debugging/tracing + + PVOID - Caller's address, usefull for finding who allocated the memory + +Returns: + + NULL - Could not allocate pool + !NULL - Pointer to pool of minimum Size bytes + +--*/ +PVOID +FxPoolAllocator( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool, + __in POOL_TYPE Type, + __in SIZE_T Size, + __in ULONG Tag, + __in PVOID CallersAddress + ); + +/*++ + +Routine Description: + + Release tracked pool + +Arguments: + + Pool - FX_POOL object allocation is tracked in + + ptr - Pointer to pool to release + +Returns: + +--*/ +void +FxPoolFree( + __in_xcount(ptr is at an offset from AllocationStart) PVOID ptr + ); + +/*++ + +Routine Description: + + Dump the FX_POOL tracking object + +Arguments: + + Pool - FX_POOL object for tracking allocations + +Returns: + + STATUS_SUCCESS + +--*/ +NTSTATUS +FxPoolDump( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool + ); + +/*++ + +Routine Description: + + Initialize the pool support package at startup time. + + This must be called before the first allocation. + +Arguments: + +Returns: + + STATUS_SUCCESS + +--*/ +_Must_inspect_result_ +NTSTATUS +FxPoolPackageInitialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); +/*++ + +Routine Description: + + Destroy the pool support package at unload time + + This must be after the last free + +Arguments: + +Returns: + + status + +--*/ +VOID +FxPoolPackageDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + + +#endif // _FXPOOL_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoolinlines.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoolinlines.hpp new file mode 100644 index 00000000000..4e07b548d77 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoolinlines.hpp @@ -0,0 +1,258 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPoolInlines.h + +Abstract: + + This module contains inline functions for pool + +Environment: + + kernel/user mode + +Revision History: + + Made it mode agnostic + +--*/ + +#ifndef __FX_POOL_INLINES_HPP__ +#define __FX_POOL_INLINES_HPP__ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxPoolInlines.hpp.tmh" +#endif + +} + +_Must_inspect_result_ +NTSTATUS +__inline +FxPoolAddHeaderSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t AllocationSize, + __out size_t* NewSize + ) +{ + NTSTATUS status; + size_t total; + + total = AllocationSize; + + // + // sizeof(FX_POOL_HEADER) is too large since it will contain enough memory + // for AllocationStart which we compute on our own. + // + status = RtlSizeTAdd(total, FX_POOL_HEADER_SIZE, &total); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Size overflow, could not add pool header, %!STATUS!", status); + + return status; + } + + if (FxDriverGlobals->IsPoolTrackingOn()) { + status = RtlSizeTAdd(total, sizeof(FX_POOL_TRACKER), &total); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Size overflow, could not add pool tracker, %!STATUS!", status); + return status; + } + } + + *NewSize = total; + + return STATUS_SUCCESS; +} + +VOID +__inline +FxPoolInsertNonPagedAllocateTracker( + __in PFX_POOL Pool, + __in PFX_POOL_TRACKER Tracker, + __in SIZE_T Size, + __in ULONG Tag, + __in PVOID Caller + ) +/*++ + +Routine Description: + + Format and insert a Tracker for a NonPaged allocation. + +Arguments: + + Pool - Pointer to FX_POOL structure + + Tracker - Pointer to raw FX_POOL_TRACKER structure. + + Size - Size in bytes of the allocation + + Tag - Caller specified additional tag value for debugging/tracing + + Caller - Caller's address + +Returns: + + VOID + +--*/ +{ + KIRQL irql; + + Tracker->Tag = Tag; + Tracker->PoolType = NonPagedPool; + Tracker->Pool = Pool; + Tracker->Size = Size; + Tracker->CallersAddress = Caller; + + Pool->NonPagedLock.Acquire(&irql); + + InsertTailList(&Pool->NonPagedHead, &Tracker->Link); + + Pool->NonPagedBytes += Size; + Pool->NonPagedAllocations++; + + if( Pool->NonPagedBytes > Pool->PeakNonPagedBytes ) { + Pool->PeakNonPagedBytes = Pool->NonPagedBytes; + } + + if( Pool->NonPagedAllocations > Pool->PeakNonPagedAllocations ) { + Pool->PeakNonPagedAllocations = Pool->NonPagedAllocations; + } + + Pool->NonPagedLock.Release(irql); +} + +VOID +__inline +FxPoolRemoveNonPagedAllocateTracker( + __in PFX_POOL_TRACKER Tracker + ) +/*++ + +Routine Description: + + Decommission a Tracker for a NonPaged allocation. + +Arguments: + + Tracker - Pointer to the formatted FX_POOL_TRACKER structure. + +Returns: + + VOID + +--*/ +{ + KIRQL irql; + + Tracker->Pool->NonPagedLock.Acquire(&irql); + + RemoveEntryList(&Tracker->Link); + + Tracker->Pool->NonPagedBytes -= Tracker->Size; + Tracker->Pool->NonPagedAllocations--; + + Tracker->Pool->NonPagedLock.Release(irql); +} + +VOID +__inline +FxPoolInsertPagedAllocateTracker( + __in PFX_POOL Pool, + __in PFX_POOL_TRACKER Tracker, + __in SIZE_T Size, + __in ULONG Tag, + __in PVOID Caller + ) +/*++ + +Routine Description: + + Format and insert a Tracker for a Paged allocation. + +Arguments: + + Pool - Pointer to FX_POOL structure + + Tracker - Pointer to raw FX_POOL_TRACKER structure. + + Size - Size in bytes of the allocation + + Tag - Caller specified additional tag value for debugging/tracing + + Caller - Caller's address + +Returns: + + VOID + +--*/ +{ + Tracker->Tag = Tag; + Tracker->PoolType = PagedPool; + Tracker->Pool = Pool; + Tracker->Size = Size; + Tracker->CallersAddress = Caller; + + Pool->PagedLock.Acquire(); + + InsertTailList(&Pool->PagedHead, &Tracker->Link); + + Pool->PagedBytes += Size; + Pool->PagedAllocations++; + + if( Pool->PagedBytes > Pool->PeakPagedBytes ) { + Pool->PeakPagedBytes = Pool->PagedBytes; + } + + if( Pool->PagedAllocations > Pool->PeakPagedAllocations ) { + Pool->PeakPagedAllocations = Pool->PagedAllocations; + } + + Pool->PagedLock.Release(); +} + +VOID +__inline +FxPoolRemovePagedAllocateTracker( + __in PFX_POOL_TRACKER Tracker + ) +/*++ + +Routine Description: + + Decommission a Tracker for a Paged allocation. + +Arguments: + + Tracker - Pointer to the formatted FX_POOL_TRACKER structure. + +Returns: + + VOID + +--*/ +{ + Tracker->Pool->PagedLock.Acquire(); + + RemoveEntryList(&Tracker->Link); + + Tracker->Pool->PagedBytes -= Tracker->Size; + Tracker->Pool->PagedAllocations--; + + Tracker->Pool->PagedLock.Release(); +} + +#endif // __FX_POOL_INLINES_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoweridlestatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoweridlestatemachine.hpp new file mode 100644 index 00000000000..28e6594ad17 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoweridlestatemachine.hpp @@ -0,0 +1,550 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXPOWERIDLESTATEMACHINE_H_ +#define _FXPOWERIDLESTATEMACHINE_H_ + +// +// This is a magical number based on inspection. If the queue overflows, +// it is OK to increase these numbers without fear of either dependencies or +// weird side affects. +// +const UCHAR FxPowerIdleEventQueueDepth = 8; + +enum FxPowerIdleEvents { + // CAN BE REUSED = 0x0001, + PowerIdleEventPowerUpFailed = 0x0002, + PowerIdleEventPowerUpComplete = 0x0004, + PowerIdleEventPowerDown = 0x0008, + PowerIdleEventPowerDownFailed = 0x0010, + PowerIdleEventTimerExpired = 0x0020, + PowerIdleEventEnabled = 0x0040, + PowerIdleEventDisabled = 0x0080, + PowerIdleEventIoDecrement = 0x0100, + PowerIdleEventIoIncrement = 0x0200, + PowerIdleEventStart = 0x0400, + PowerIdleEventStop = 0x0800, + PowerIdleNull = 0x0000, +}; + +// begin_wpp config +// CUSTOM_TYPE(FxPowerIdleEvents, ItemEnum(FxPowerIdleEvents)); +// end_wpp + +enum FxPowerIdleStates { + FxIdleStopped = 1, + FxIdleStarted, + FxIdleStartedPowerUp, + FxIdleStartedPowerFailed, + FxIdleDisabled, + FxIdleCheckIoCount, + FxIdleBusy, + FxIdleDecrementIo, + FxIdleStartTimer, + FxIdleTimerRunning, + FxIdleTimingOut, + FxIdleTimedOut, + FxIdleTimedOutIoIncrement, + FxIdleTimedOutPowerDown, + FxIdleTimedOutPowerDownFailed, + FxIdleGoingToDx, + FxIdleInDx, + FxIdleInDxIoIncrement, + FxIdleInDxPowerUpFailure, + FxIdleInDxStopped, + FxIdleInDxDisabled, + FxIdleInDxEnabled, + FxIdlePowerUp, + FxIdlePowerUpComplete, + FxIdleTimedOutDisabled, + FxIdleTimedOutEnabled, + FxIdleCancelTimer, + FxIdleWaitForTimeout, + FxIdleTimerExpired, + FxIdleDisabling, + FxIdleDisablingWaitForTimeout, + FxIdleDisablingTimerExpired, + FxIdlePowerFailedWaitForTimeout, + FxIdlePowerFailed, + FxIdleMax, +}; + +// +// NOTE: if you change these flags (order, values, etc), you must also modify +// m_FlagsByName to match your changes. +// +enum FxPowerIdleFlags { + FxPowerIdleTimerEnabled = 0x01, + FxPowerIdleInDx = 0x02, + FxPowerIdleTimerCanceled = 0x04, + FxPowerIdleTimerStarted = 0x08, + FxPowerIdlePowerFailed = 0x10, + FxPowerIdleIsStarted = 0x20, + FxPowerIdleIoPresentSent = 0x40, + FxPowerIdleSendPnpPowerUpEvent = 0x80, +}; + +enum FxPowerReferenceFlags { + FxPowerReferenceDefault = 0x0, + FxPowerReferenceSendPnpPowerUpEvent = 0x1 +}; + +typedef +FxPowerIdleStates +(*PFN_POWER_IDLE_STATE_ENTRY_FUNCTION)( + FxPowerIdleMachine* + ); + +struct FxPowerIdleTargetState { + FxPowerIdleEvents PowerIdleEvent; + + FxPowerIdleStates PowerIdleState; + +#if FX_SUPER_DBG + BOOLEAN EventDebugged; +#endif +}; + +struct FxIdleStateTable { + PFN_POWER_IDLE_STATE_ENTRY_FUNCTION StateFunc; + + const FxPowerIdleTargetState* TargetStates; + + ULONG TargetStatesCount; +}; + +class FxPowerIdleMachine : public FxStump { + +public: + FxPowerIdleMachine( + VOID + ); + + ~FxPowerIdleMachine( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Init( + VOID + ); + + VOID + EnableTimer( + VOID + ); + + BOOLEAN + DisableTimer( + VOID + ); + + VOID + Start( + VOID + ); + + VOID + Stop( + VOID + ); + + VOID + Reset( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + IoIncrement( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + IoIncrementWithFlags( + __in FxPowerReferenceFlags Flags, + __out_opt PULONG Count = NULL + ); + + VOID + IoDecrement( + __in_opt PVOID Tag = NULL, + __in_opt LONG Line = 0, + __in_opt PSTR File = NULL + ); + + BOOLEAN + QueryReturnToIdle( + VOID + ); + + VOID + WaitForD0( + VOID + ) + { + m_D0NotificationEvent.EnterCRAndWaitAndLeave(); + } + + _Must_inspect_result_ + NTSTATUS + PowerReference( + __in BOOLEAN WaitForD0, + __in_opt PVOID Tag = NULL, + __in_opt LONG Line = 0, + __in_opt PSTR File = NULL + ) + { + return PowerReferenceWorker(WaitForD0, FxPowerReferenceDefault, Tag, Line, File); + } + + _Must_inspect_result_ + NTSTATUS + PowerReferenceWithFlags( + __in FxPowerReferenceFlags Flags + ) + { + return PowerReferenceWorker(FALSE, // WaitForD0 + Flags); + } + + VOID + ProcessPowerEvent( + __in FxPowerIdleEvents Event + ); + +protected: + + VOID + ProcessEventLocked( + __in FxPowerIdleEvents Event + ); + + BOOLEAN + IsTransitioning( + VOID + ) + { + return m_D0NotificationEvent.ReadState() ? FALSE : TRUE; + } + + BOOLEAN + CancelIdleTimer( + VOID + ) + { + // + // If we are canceling the timer, be well sure it is started + // + ASSERT(m_Flags & FxPowerIdleTimerStarted); + + if (m_PowerTimeoutTimer.Stop()) { + m_Flags &= ~FxPowerIdleTimerStarted; + return TRUE; + } + else { + return FALSE; + } + } + + BOOLEAN + InD0Locked( + VOID + ) + { + return m_D0NotificationEvent.ReadState() ? TRUE : FALSE; + } + + VOID + SendD0Notification( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PowerReferenceWorker( + __in BOOLEAN WaitForD0, + __in FxPowerReferenceFlags Flags, + __in_opt PVOID Tag = NULL, + __in_opt LONG Line = 0, + __in_opt PSTR File = NULL + ); + + static + MdDeferredRoutineType + _PowerTimeoutDpcRoutine; + + static + FxPowerIdleStates + Stopped( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + Started( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + StartedPowerUp( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + StartedPowerFailed( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + Disabled( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + CheckIoCount( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + DecrementIo( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + StartTimer( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimingOut( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimedOutIoIncrement( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimedOutPowerDown( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimedOutPowerDownFailed( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + GoingToDx( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + InDx( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + InDxIoIncrement( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + InDxPowerUpFailure( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + InDxStopped( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + InDxDisabled( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + InDxEnabled( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + PowerUp( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + PowerUpComplete( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimedOutDisabled( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimedOutEnabled( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + CancelTimer( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + TimerExpired( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + Disabling( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + DisablingTimerExpired( + __inout FxPowerIdleMachine* This + ); + + static + FxPowerIdleStates + PowerFailed( + __inout FxPowerIdleMachine* This + ); + +private: + VOID + CheckAssumptions( + VOID + ); + +public: + LARGE_INTEGER m_PowerTimeout; + +protected: + // + // Lock which guards state + // + MxLock m_Lock; + + // + // Number of pending requests which require being in D0 + // + ULONG m_IoCount; + + // + // Tracks power references and releases. + // + FxTagTracker* m_TagTracker; + + // + // Timer which will be set when the I/O count goes to zero + // + MxTimer m_PowerTimeoutTimer; + + // + // Event to wait on when transitioning from Dx to D0 + // + FxCREvent m_D0NotificationEvent; + + union { + // + // Combintaion of FxPowerIdleFlags enum values + // + UCHAR m_Flags; + + // + // Not used in the code. Here so that you can easily decode m_Flags in + // the debugger without needing the enum definition. + // + struct { + UCHAR TimerEnabled : 1; + UCHAR InDx : 1; + UCHAR TimerCanceled : 1; + UCHAR TimerStarted : 1; + UCHAR TimerPowerFailed : 1; + UCHAR IsStarted : 1; + UCHAR IoPresentSent : 1; + UCHAR SendPnpPowerUpEvent : 1; + } m_FlagsByName; + }; + + // + // Index into m_EventHistory where to place the next value + // + UCHAR m_EventHistoryIndex; + + // + // Index into m_StateHistory where to place the next value + UCHAR m_StateHistoryIndex; + + // + // our current state + // + FxPowerIdleStates m_CurrentIdleState; + + // + // Circular history of events fed into this state machine + // + FxPowerIdleEvents m_EventHistory[FxPowerIdleEventQueueDepth]; + + // + // Circular history of states the state machine was in + // + FxPowerIdleStates m_StateHistory[FxPowerIdleEventQueueDepth]; + + static const FxPowerIdleTargetState m_StoppedStates[]; + static const FxPowerIdleTargetState m_StartedStates[]; + static const FxPowerIdleTargetState m_DisabledStates[]; + static const FxPowerIdleTargetState m_BusyStates[]; + static const FxPowerIdleTargetState m_TimerRunningStates[]; + static const FxPowerIdleTargetState m_TimedOutStates[]; + static const FxPowerIdleTargetState m_InDxStates[]; + static const FxPowerIdleTargetState m_WaitForTimeoutStates[]; + static const FxPowerIdleTargetState m_DisablingWaitForTimeoutStates[]; + static const FxPowerIdleTargetState m_PowerFailedWaitForTimeoutStates[]; + + static const FxIdleStateTable m_StateTable[]; + + // + // We use a coalescable timer for idle timeout. The tolerable delay for the + // idle timer is defined below. The value below is an arbitrary choice and + // can be changed if necessary. MSDN documentation suggests 100 ms as being + // a reasonable choice. + // + static const ULONG m_IdleTimerTolerableDelayMS = 100; +}; + +#endif // _FXPOWERIDLESTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpowerpolicystatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpowerpolicystatemachine.hpp new file mode 100644 index 00000000000..2574dee0005 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpowerpolicystatemachine.hpp @@ -0,0 +1,811 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXPOWERPOLICYSTATEMACHINE_H_ +#define _FXPOWERPOLICYSTATEMACHINE_H_ + +#include "FxPowerIdleStateMachine.hpp" +#include "FxPoxInterface.hpp" + +// @@SMVERIFY_SPLIT_BEGIN +// +// Treat these values as a bit field when comparing for known dropped events in +// the current state and treat them as values when they known transition events +// from state to the next. +// +enum FxPowerPolicyEvent { + PwrPolInvalid = 0x00000000, + PwrPolStart = 0x00000001, + PwrPolStop = 0x00000002, + PwrPolSx = 0x00000004, + PwrPolS0 = 0x00000008, + PwrPolPowerDown = 0x00000010, + PwrPolPowerUp = 0x00000020, + PwrPolPowerDownIoStopped = 0x00000040, + PwrPolPowerUpHwStarted = 0x00000080, + PwrPolWakeArrived = 0x00000100, + PwrPolWakeSuccess = 0x00000200, + PwrPolWakeFailed = 0x00000400, + PwrPolIoPresent = 0x00000800, + PwrPolPowerTimeoutExpired = 0x00001000, + PwrPolS0IdlePolicyChanged = 0x00002000, + PwrPolSurpriseRemove = 0x00004000, + PwrPolUsbSelectiveSuspendCallback = 0x00008000, + PwrPolUsbSelectiveSuspendCompleted = 0x00010000, + PwrPolPowerDownFailed = 0x00020000, + PwrPolPowerUpFailed = 0x00040000, + PwrPolImplicitPowerDown = 0x00080000, + PwrPolImplicitPowerDownFailed = 0x00100000, + PwrPolPowerUpNotSeen = 0x00200000, + PwrPolDevicePowerNotRequired = 0x00400000, + PwrPolDevicePowerRequired = 0x00800000, + PwrPolRemove = 0x01000000, + PwrPolWakeInterruptFired = 0x02000000, + + // + // Not a real event, just a value that indicates all of the events which + // goto the head of the queue and are always processed, even if the state is + // locked. This applies to the power policy owner state machine. + // + PwrPolPriorityEventsMask = PwrPolPowerUp | + PwrPolPowerDown | + PwrPolPowerUpFailed | + PwrPolPowerDownFailed | + PwrPolPowerDownIoStopped | + PwrPolPowerUpHwStarted | + PwrPolImplicitPowerDown | + PwrPolImplicitPowerDownFailed | + PwrPolWakeArrived | + PwrPolWakeSuccess | + PwrPolWakeFailed | + PwrPolPowerUpNotSeen | + PwrPolUsbSelectiveSuspendCompleted | + PwrPolWakeInterruptFired, + + // + // Not a real event, just a value that indicates all of the events which + // goto the head of the queue and are always processed, even if the state is + // locked. This applies to the not power policy owner state machine. + // + PwrPolNotOwnerPriorityEventsMask = PwrPolPowerUp | + PwrPolPowerUpFailed | + PwrPolPowerDown | + PwrPolPowerDownFailed, + + // + // Not a real event, just a value that indicate all of the events which + // should not be in the queue, if a similar event is already enqueued. + // + PowerPolSingularEventMask = PwrPolS0IdlePolicyChanged | + // + // A device could have multiple wake interrupts that could each fire + // this event. + // + PwrPolWakeInterruptFired, + + + PwrPolNull = 0xFFFFFFFF, +}; + +// +// Bit packed ULONG. +// +union FxPwrPolStateInfo { + struct { + // + // Indicates whether the state is open to all events + // + ULONG QueueOpen : 1; + + // + // Bit of events we know we can drop in this state + // + ULONG KnownDroppedEvents : 31; + } Bits; + + struct { + // + // Maps to the same bit location as QueueOpen. Since we start + // KnownDroppedEvents at the next bit, start our bits by at the next + // bit as well. + // + ULONG Reserved : 1; + + // + // These are defined so that we can easily tell in the debugger what + // each set bit in KnownDroppedEvents maps to in the FxPowerPolicyEvent + // enum + // + ULONG PwrPolStartKnown : 1; + ULONG PwrPolStopKnown : 1; + ULONG PwrPolSxKnown : 1; + ULONG PwrPolS0Known : 1; + ULONG PwrPolPowerDownKnown : 1; + ULONG PwrPolPowerUpKnown : 1; + ULONG PwrPolPowerDownIoStoppedKnown : 1; + ULONG PwrPolPowerUpHwStartedKnown : 1; + ULONG PwrPolWakeArrivedKnown : 1; + ULONG PwrPolWakeSuccessKnown : 1; + ULONG PwrPolWakeFailedKnown : 1; + ULONG PwrPolIoPresentKnown : 1; + ULONG PwrPolPowerTimeoutExpiredKnown : 1; + ULONG PwrPolS0IdlePolicyChangedKnown : 1; + ULONG PwrPolSurpriseRemoveKnown : 1; + ULONG PwrPolUsbSelectiveSuspendCallbackKnown : 1; + ULONG PwrPolUsbSelectiveSuspendCompletedKnown : 1; + ULONG PwrPolPowerDownFailedKnown : 1; + ULONG PwrPolPowerUpFailedKnown : 1; + } BitsByName; +}; + +struct POWER_POLICY_EVENT_TARGET_STATE { + FxPowerPolicyEvent PowerPolicyEvent; + + WDF_DEVICE_POWER_POLICY_STATE TargetState; + + EVENT_TRAP_FIELD +}; + +typedef const POWER_POLICY_EVENT_TARGET_STATE* CPPOWER_POLICY_EVENT_TARGET_STATE; + +typedef +WDF_DEVICE_POWER_POLICY_STATE +(*PFN_POWER_POLICY_STATE_ENTRY_FUNCTION)( + FxPkgPnp* This + ); + +typedef struct POWER_POLICY_STATE_TABLE { + // + // Framework internal function to handle the transition into this state + // + PFN_POWER_POLICY_STATE_ENTRY_FUNCTION StateFunc; + + // + // First state transition out of this state + // + POWER_POLICY_EVENT_TARGET_STATE FirstTargetState; + + // + // Other state transitions out of this state if FirstTargetState is not + // matched. This is an array where we expect the final element to be + // { PwrPolNull, WdfDevStatePwrPolNull } + // + CPPOWER_POLICY_EVENT_TARGET_STATE OtherTargetStates; + + // + // Whether we allow transitions out of this state that are not D state + // related events, ie if this is a green dot state, TRUE, if this is a red + // dot state, FALSE. D state events (PwrPolPowerUp, PwrPolPowerDown) + // are never affected by the queue state and are always processed. + // + FxPwrPolStateInfo StateInfo; + +} *PPOWER_POLICY_STATE_TABLE; + +typedef const POWER_POLICY_STATE_TABLE* CPPOWER_POLICY_STATE_TABLE; + +typedef +WDF_DEVICE_POWER_POLICY_STATE +(*PFN_NOT_POWER_POLICY_OWNER_STATE_ENTRY_FUNCTION)( + FxPkgPnp* This + ); + +typedef struct NOT_POWER_POLICY_OWNER_STATE_TABLE { + // + // The current power policy state that this entry applies to + // + WDF_DEVICE_POWER_POLICY_STATE CurrentTargetState; + + // + // Framework internal function to handle the transition into this state + // + PFN_NOT_POWER_POLICY_OWNER_STATE_ENTRY_FUNCTION StateFunc; + + // + // Only state transition out of this state + // + CPPOWER_POLICY_EVENT_TARGET_STATE TargetStates; + + UCHAR TargetStatesCount; + + BOOLEAN QueueOpen; + +} *PNOT_POWER_POLICY_OWNER_STATE_TABLE; + +typedef const NOT_POWER_POLICY_OWNER_STATE_TABLE* CPNOT_POWER_POLICY_OWNER_STATE_TABLE; + +#if FX_STATE_MACHINE_VERIFY +#define MAX_PWR_POL_STATE_ENTRY_FN_RETURN_STATES (5) + +struct PWR_POL_STATE_ENTRY_FUNCTION_TARGET_STATE { + // + // Return value from state entry function + // + WDF_DEVICE_POWER_POLICY_STATE State; + + // + // type of device the returning state applies to + // + FxStateMachineDeviceType DeviceType; + + // + // Info about the state transition + // + PSTR Comment; +}; + +struct PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE { + // + // array of state transitions caused by state entry function + // + PWR_POL_STATE_ENTRY_FUNCTION_TARGET_STATE TargetStates[MAX_PWR_POL_STATE_ENTRY_FN_RETURN_STATES]; +}; + +typedef const PWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE* CPPWR_POL_STATE_ENTRY_FN_RETURN_STATE_TABLE; +#endif // FX_STATE_MACHINE_VERIFY + + +// @@SMVERIFY_SPLIT_END + +enum FxPowerPolicyConstants { + FxPowerPolicyNoTimeout = 0, + + FxPowerPolicyDefaultTimeout = 5000, // Timeout in milliseconds +}; + +enum CancelIrpCompletionOwnership { + CancelOwnershipUnclaimed = 0, + CancelOwnershipClaimed = 1, +}; + +enum FxPowerPolicySxWakeSettingsFlags { + FxPowerPolicySxWakeDeviceEnabledFlag = 0x1, + FxPowerPolicySxWakeChildrenArmedFlag = 0x2, +}; + +struct PolicySettings { + PolicySettings() + { + WmiInstance = NULL; + DxState = PowerDeviceD3; + + Enabled = Overridable = Set = Dirty = FALSE; + } + + ~PolicySettings(); + + // + // Dx state to put the device in when the policy is applied + // + DEVICE_POWER_STATE DxState; + + FxWmiInstanceInternal* WmiInstance; + + BOOLEAN Enabled; + + BOOLEAN Overridable; + + BOOLEAN Set; + + BOOLEAN Dirty; +}; + +typedef struct _POX_SETTINGS { + PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE + EvtDeviceWdmPostPoFxRegisterDevice; + PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE + EvtDeviceWdmPrePoFxUnregisterDevice; + PPO_FX_COMPONENT Component; + PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback; + PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback; + PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback; + PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + PVOID PoFxDeviceContext; +} POX_SETTINGS, *PPOX_SETTINGS; + +class IdleTimeoutManagement { + +private: + // + // This member is used to control whether or not the idle timeout is + // determined by the power manager when running on Windows 8 and above. + // The value of this member is some combination of the flags defined below. + // + LONG volatile m_IdleTimeoutStatus; + + // + // Flags for the m_IdleTimeoutStatus member + // + // IdleTimeoutStatusFrozen - This flag implies that the decision on + // whether the power manager determines the idle timeout is "frozen" + // and can no longer be changed. The decision is frozen during start + // IRP completion processing, just before WDF registers with the + // power manager. + // + // IdleTimeoutSystemManaged - This flag implies that the power manager + // determines the idle timeout on Windows 8 and above. If this flag + // is not set, the idle timeout specified by the client driver is + // used. + // + // IdleTimeoutPoxSettingsSpecified - This flag implies that the client + // driver has already specified the settings that need to be used + // when registering with the power framework. This flag is used to + // track that the settings are not specified more than once. + // + enum IdleTimeoutStatusFlag { + IdleTimeoutStatusFrozen = 0x00000001, + IdleTimeoutSystemManaged = 0x00000002, + IdleTimeoutPoxSettingsSpecified = 0x00000004, + }; + + // + // Result returned by the UpdateIdleTimeoutStatus() method + // + enum IdleTimeoutStatusUpdateResult { + // + // Flags were sucessfully updated + // + IdleTimeoutStatusFlagsUpdated, + + // + // The flag we were trying to set was already set + // + IdleTimeoutStatusFlagAlreadySet, + + // + // It is too late to set the flag. The flags have already been frozen. + // Flags are frozen the first time a device is started. + // + IdleTimeoutStatusFlagsAlreadyFrozen, + + // + // Flags are being set by multiple threads in parallel. This is not + // supported. + // + IdleTimeoutStatusFlagsUnexpected + }; + + // + // This member contains the client driver's settings that will be used when + // we register with the power manager on Windows 8 and above. + // + PPOX_SETTINGS m_PoxSettings; + +private: + IdleTimeoutStatusUpdateResult + UpdateIdleTimeoutStatus( + __in IdleTimeoutStatusFlag Flag + ); + + CfxDevice * + GetDevice( + VOID + ); + +public: + IdleTimeoutManagement( + VOID + ) : m_IdleTimeoutStatus(0), + m_PoxSettings(NULL) + { + } + + ~IdleTimeoutManagement( + VOID + ) + { + BYTE * buffer = NULL; + ULONG poxSettingsOffset; + + if (NULL != m_PoxSettings) { + + buffer = (BYTE*) m_PoxSettings; + + // + // In the function FxPkgPnp::AssignPowerFrameworkSettings, we had + // allocated a buffer which we need to free now. Note that + // m_PoxSettings does not necessarily point to the beginning of the + // buffer. It points to the POX_SETTINGS structure in the buffer, + // which may or may not be in the beginning. If it is not in the + // beginning, figure out where the beginning of the buffer is. + // + if (m_PoxSettings->Component != NULL) { + // + // The computation below won't overflow because we already + // performed this computation successfully using safeint + // functions in FxPkgPnp::AssignPowerFrameworkSettings. + // + poxSettingsOffset = + (sizeof(*(m_PoxSettings->Component->IdleStates)) * + (m_PoxSettings->Component->IdleStateCount)) + + (sizeof(*(m_PoxSettings->Component))); + } + else { + poxSettingsOffset = 0; + } + + // + // Move to the beginning of the buffer + // + buffer = buffer - poxSettingsOffset; + + // + // Free the buffer + // + MxMemory::MxFreePool(buffer); + } + } + + static + BOOLEAN + _SystemManagedIdleTimeoutAvailable( + VOID + ); + + NTSTATUS + UseSystemManagedIdleTimeout( + __in PFX_DRIVER_GLOBALS DriverGlobals + ); + + VOID + FreezeIdleTimeoutManagementStatus( + __in PFX_DRIVER_GLOBALS DriverGlobals + ); + + BOOLEAN + UsingSystemManagedIdleTimeout( + VOID + ); + + NTSTATUS + CommitPowerFrameworkSettings( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in PPOX_SETTINGS PoxSettings + ); + + BOOLEAN + DriverSpecifiedPowerFrameworkSettings( + VOID + ); + + PPOX_SETTINGS + GetPowerFrameworkSettings( + VOID + ) + { + return m_PoxSettings; + } +}; + +struct IdlePolicySettings : PolicySettings { + IdlePolicySettings( + VOID + ) : PolicySettings() + { + WakeFromS0Capable = FALSE; + UsbSSCapable = FALSE; + PowerUpIdleDeviceOnSystemWake = FALSE; + UsbSSCapabilityKnown = FALSE; + } + + // + // TRUE if the device capable of waking from S0 + // + BOOLEAN WakeFromS0Capable; + + // + // This member is meaningful only if the WakeFromS0Capable member (above) is + // TRUE. The WakeFromS0Capable member indicates whether or not wake-from-S0 + // is currently enabled. If wake-from-S0 is currently enabled, the + // UsbSSCapable member indicates whether the wake-from-S0 support is generic + // or USB SS specific. If wake-from-S0 is not enabled, the UsbSSCapable + // member is ignored. + // + BOOLEAN UsbSSCapable; + + // + // TRUE if we know whether the device supports generic wake or USB SS wake. + // This value is initialized to FALSE and remains FALSE until the first time + // that the driver specifies S0-idle settings with an idle capability value + // of IdleCanWakeFromS0 or IdleUsbSelectiveSuspend. When the driver + // specifies one of these idle capabilities, this value is set to TRUE and + // remains TRUE for the lifetime of the device. + // + BOOLEAN UsbSSCapabilityKnown; + + // + // TRUE if idle enabled device should be powered up even when idle, + // when resuming from Sx + // + BOOLEAN PowerUpIdleDeviceOnSystemWake; + + // + // Member to manage interactions with the power manager for S0-idle support + // on Win8 and above + // + IdleTimeoutManagement m_TimeoutMgmt; +}; + +struct WakePolicySettings : PolicySettings { + WakePolicySettings( + VOID + ) : PolicySettings() + { + ArmForWakeIfChildrenAreArmedForWake = FALSE; + IndicateChildWakeOnParentWake = FALSE; + } + + // + // TRUE if the device should arm for wake when one or more children are + // armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // TRUE if the device should propagate the wake status to its children. + // + BOOLEAN IndicateChildWakeOnParentWake; +}; + +struct FxPowerPolicyOwnerSettings : public FxStump { + +friend FxPowerPolicyMachine; + +public: + FxPowerPolicyOwnerSettings( + __in FxPkgPnp* PkgPnp + ); + + ~FxPowerPolicyOwnerSettings( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Init( + VOID + ); + + VOID + CleanupPowerCallback( + VOID + ); + + VOID + IncrementChildrenArmedForWakeCount( + VOID + ) + { + InterlockedIncrement(&m_ChildrenArmedCount); + } + + VOID + DecrementChildrenArmedForWakeCount( + VOID + ) + { + InterlockedDecrement(&m_ChildrenArmedCount); + } + +protected: + static + MdCallbackFunctionType + _PowerStateCallback; + +public: + FxPowerIdleMachine m_PowerIdleMachine; + FxPoxInterface m_PoxInterface; + + + + + + + FxPowerDeviceArmWakeFromS0 m_DeviceArmWakeFromS0; + FxPowerDeviceArmWakeFromSx m_DeviceArmWakeFromSx; + + FxPowerDeviceDisarmWakeFromS0 m_DeviceDisarmWakeFromS0; + FxPowerDeviceDisarmWakeFromSx m_DeviceDisarmWakeFromSx; + + FxPowerDeviceWakeFromS0Triggered m_DeviceWakeFromS0Triggered; + FxPowerDeviceWakeFromSxTriggered m_DeviceWakeFromSxTriggered; + + FxUsbIdleInfo* m_UsbIdle; + + FxPkgPnp* m_PkgPnp; + + WakePolicySettings m_WakeSettings; + + IdlePolicySettings m_IdleSettings; + + // + // Nibble packed structure. Each D state is encoded 4 bits. The S state is + // used as the "index" within the ULONG. PowerSystemUnspecified is the + // first 4 bits of the first byte, etc. etc. ... + // + ULONG m_SystemToDeviceStateMap; + + // + // The number of children who are in the D0 state. If this count is > 0, + // then this parent cannot idle out while in S0. Note that each child also + // has an explicit call to PowerReference against this device which is used + // to control the idle timer for this device. + // + ULONG m_ChildrenPoweredOnCount; + + // + // The number of children who are currently armed for wake. This count + // can be used by the the wake owner to determine whether wake should be + // enabled or not for a parent stack if arming for wake depends on + // children being armed for wake. + // + LONG m_ChildrenArmedCount; + + // + // The status of the last wait wake IRP to complete in the stack + // + NTSTATUS m_WaitWakeStatus; + + // + // Dx state to put the device into when an Sx irp arrives and the device is + // not armed for wake from Sx. DEVICE_POWER_STATE values are used. + // + BYTE m_IdealDxStateForSx; + + // + // Track power requests to assert if someone other than this driver sent it + // and to determine if this driver has received the requested irp (to catch + // someone above completing irp w/o sending to this driver) + // + BOOLEAN m_RequestedPowerUpIrp; + BOOLEAN m_RequestedPowerDownIrp; + BOOLEAN m_RequestedWaitWakeIrp; + + // + // Tracks wake event being dropped + // + BOOLEAN m_WakeCompletionEventDropped; + + BOOLEAN m_PowerFailed; + + // + // Indicates whether we can cause paging I/O by writing to the registry + // + BOOLEAN m_CanSaveState; + + // + // Guard to stop children from powering up while the parent is in Dx or + // about to transition into Dx. + // + BOOLEAN m_ChildrenCanPowerUp; + + // + // TRUE if our device caused the machine to wake up. Access to this value + // is not synchronized between the parent and PDO. The parent sets it to + // TRUE upon successful completion of the WW irp and cleared after + // EvtDeviceDisarmWakeFromSx. If a PDO's WW IRP is completed within this + // window, the PDO's WW IRP will have PoSetSystemWake called on it. It is + // acceptable if the PDO's WW IRP completion races with the clearing of the + // value and is not set as a source of wake. + // + BOOLEAN m_SystemWakeSource; + +protected: + PCALLBACK_OBJECT m_PowerCallbackObject; + + PVOID m_PowerCallbackRegistration; + + LONG m_WaitWakeCancelCompletionOwnership; + +}; + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxPowerPolicyMachineStateHistory { + struct { + WDF_DEVICE_POWER_POLICY_STATE State1 : 16; + WDF_DEVICE_POWER_POLICY_STATE State2 : 16; + WDF_DEVICE_POWER_POLICY_STATE State3 : 16; + WDF_DEVICE_POWER_POLICY_STATE State4 : 16; + WDF_DEVICE_POWER_POLICY_STATE State5 : 16; + WDF_DEVICE_POWER_POLICY_STATE State6 : 16; + WDF_DEVICE_POWER_POLICY_STATE State7 : 16; + WDF_DEVICE_POWER_POLICY_STATE State8 : 16; + } S; + + USHORT History[FxPowerPolicyEventQueueDepth]; +}; + +struct FxPowerPolicyMachine : public FxThreadedEventQueue { + FxPowerPolicyMachine( + VOID + ); + + ~FxPowerPolicyMachine( + VOID + ); + + VOID + UsbSSCallbackProcessingComplete( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + InitUsbSS( + VOID + ); + + VOID + SetWaitWakeUnclaimed( + VOID + ) + { + m_Owner->m_WaitWakeCancelCompletionOwnership = CancelOwnershipUnclaimed; + } + + BOOLEAN + CanCompleteWaitWakeIrp( + VOID + ) + { + // + // We have 2 potential call sites racing on trying to complete the wait + // wake irp. The first is the cancelling call site. The other is the + // irp's completion routine. What we want is for the *2nd* (and last) + // call site to actually complete the irp. This is why we check to see + // if the result of the exchange is that the ownership is already claimed + // (and not unclaimed as one might first be led to think). + // + if (InterlockedExchange(&m_Owner->m_WaitWakeCancelCompletionOwnership, + CancelOwnershipClaimed) == CancelOwnershipClaimed) { + return TRUE; + } + else { + return FALSE; + } + } + +public: + FxPowerPolicyEvent m_Queue[FxPowerPolicyEventQueueDepth]; + + FxPowerPolicyMachineStateHistory m_States; + + FxPowerPolicyOwnerSettings* m_Owner; + + union { + ULONG m_SingularEventsPresent; + + union { + // + // These are defined so that we can easily tell in the debugger what + // each set bit in m_SingularEventsPresent maps to in the + // FxPowerPolicyEvent enum. + // + ULONG PwrPolStartKnown : 1; + ULONG PwrPolStopKnown : 1; + ULONG PwrPolSxKnown : 1; + ULONG PwrPolS0Known : 1; + ULONG PwrPolPowerDownKnown : 1; + ULONG PwrPolPowerUpKnown : 1; + ULONG PwrPolPowerDownIoStoppedKnown : 1; + ULONG PwrPolPowerUpHwStartedKnown : 1; + ULONG PwrPolWakeArrivedKnown : 1; + ULONG PwrPolWakeSuccessKnown : 1; + ULONG PwrPolWakeFailedKnown : 1; + ULONG PwrPolIoPresentKnown : 1; + ULONG PwrPolPowerTimeoutExpiredKnown : 1; + ULONG PwrPolS0IdlePolicyChangedKnown : 1; + ULONG PwrPolSurpriseRemoveKnown : 1; + ULONG PwrPolUsbSelectiveSuspendCallbackKnown : 1; + ULONG PwrPolUsbSelectiveSuspendCompletedKnown : 1; + ULONG PwrPolPowerDownFailedKnown : 1; + ULONG PwrPolPowerUpFailedKnown : 1; + } m_SingularEventsPresentByName; + }; +}; + +#endif // _FXPOWERPOLICYSTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpowerstatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpowerstatemachine.hpp new file mode 100644 index 00000000000..23d7332af0a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpowerstatemachine.hpp @@ -0,0 +1,285 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXPOWERSTATEMACHINE_H_ +#define _FXPOWERSTATEMACHINE_H_ + +// @@SMVERIFY_SPLIT_BEGIN +// +// Treat these values as a bit field when comparing for known dropped events in +// the current state and treat them as values when they known transition events +// from state to the next. +// +enum FxPowerEvent { + PowerEventInvalid = 0x0000, + PowerD0 = 0x0001, + PowerDx = 0x0002, + PowerWakeArrival = 0x0004, + PowerWakeSucceeded = 0x0008, + PowerWakeFailed = 0x0010, + PowerWakeCanceled = 0x0020, + PowerImplicitD0 = 0x0040, + PowerImplicitD3 = 0x0080, + PowerParentToD0 = 0x0100, + PowerMarkPageable = 0x0200, + PowerMarkNonpageable = 0x0400, + PowerCompleteD0 = 0x0800, + PowerCompleteDx = 0x1000, + PowerWakeInterruptCompleteTransition + = 0x2000, + + // + // Not a real event, just a value that indicates all of the events which + // goto the head of the queue and are always processed, even if the state is + // locked. + // + PowerPriorityEventsMask = PowerParentToD0 | + PowerCompleteD0 | + PowerCompleteDx | + PowerWakeInterruptCompleteTransition, + + // + // Not a real event, just a value that indicate all of the events which + // should not be in the queue, if a similar event is already enqueued. + // + PowerSingularEventMask = PowerParentToD0, + + PowerEventMaximum = 0xFFFFFFFF, +}; + +union FxPowerStateInfo { + struct { + // + // Is this a state where we rest and wait for events to bring us out + // of that state. + // + // NOTE: this value is purely notational, we don't use it anywhere in + // the state machine. If need be, reuse this slot for something + // else without worry. + // + ULONG QueueOpen : 1; + + // + // Bit of events we know we can drop in this state + // + ULONG KnownDroppedEvents : 31; + } Bits; + + struct { + // + // Maps to the same bit location as QueueOpen. Since we start + // KnownDroppedEvents at the next bit, start our bits by at the next + // bit as well. + // + ULONG Reserved : 1; + + // + // These are defined so that we can easily tell in the debugger what + // each set bit in KnownDroppedEvents maps to in the FxPowerEvent enum + // + ULONG PowerD0Known : 1; + ULONG PowerDxKnown : 1; + ULONG PowerWakeArrivalKnown : 1; + ULONG PowerWakeSucceededKnown : 1; + ULONG PowerWakeFailedKnown : 1; + ULONG PowerWakeCanceledKnown : 1; + ULONG PowerImplicitD0Known : 1; + ULONG PowerImplicitD3Known : 1; + ULONG PowerParentToD0Known : 1; + ULONG PowerMarkPageableKnown : 1; + ULONG PowerMarkNonpageableKnown : 1; + ULONG PowerCompleteD0Known : 1; + ULONG PowerCompleteDxKnown : 1; + } BitsByName; +}; + + +struct POWER_EVENT_TARGET_STATE { + FxPowerEvent PowerEvent; + + WDF_DEVICE_POWER_STATE TargetState; + + EVENT_TRAP_FIELD +}; + +typedef const POWER_EVENT_TARGET_STATE* CPPPOWER_EVENT_TARGET_STATE; + +typedef +WDF_DEVICE_POWER_STATE +(*PFN_POWER_STATE_ENTRY_FUNCTION)( + FxPkgPnp* + ); + +typedef struct POWER_STATE_TABLE { + // + // Function called when the state is entered + // + PFN_POWER_STATE_ENTRY_FUNCTION StateFunc; + + // + // First state transition out of this state + // + POWER_EVENT_TARGET_STATE FirstTargetState; + + // + // Other state transitions out of this state if FirstTargetState is not + // matched. This is an array where we expect the final element to be + // { PowerEventMaximum, WdfDevStatePowerNull } + // + CPPPOWER_EVENT_TARGET_STATE OtherTargetStates; + + FxPowerStateInfo StateInfo; + +} *PPOWER_STATE_TABLE; + +typedef const POWER_STATE_TABLE* CPPOWER_STATE_TABLE; + +#if FX_STATE_MACHINE_VERIFY +#define MAX_POWER_STATE_ENTRY_FN_RETURN_STATES (5) + +struct POWER_STATE_ENTRY_FUNCTION_TARGET_STATE { + // + // Return value from state entry function + // + WDF_DEVICE_POWER_STATE State; + + // + // type of device the returning state applies to + // + FxStateMachineDeviceType DeviceType; + + // + // Info about the state transition + // + PSTR Comment; +}; + +struct POWER_STATE_ENTRY_FN_RETURN_STATE_TABLE { + // + // array of state transitions caused by state entry function + // + POWER_STATE_ENTRY_FUNCTION_TARGET_STATE TargetStates[MAX_POWER_STATE_ENTRY_FN_RETURN_STATES]; +}; + +typedef const POWER_STATE_ENTRY_FN_RETURN_STATE_TABLE* CPPOWER_STATE_ENTRY_FN_RETURN_STATE_TABLE; +#endif // FX_STATE_MACHINE_VERIFY + +// @@SMVERIFY_SPLIT_END + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxPowerMachineEventQueue { + struct { + FxPowerEvent Event1 : 16; + FxPowerEvent Event2 : 16; + FxPowerEvent Event3 : 16; + FxPowerEvent Event4 : 16; + FxPowerEvent Event5 : 16; + FxPowerEvent Event6 : 16; + FxPowerEvent Event7 : 16; + FxPowerEvent Event8 : 16; + } E; + + USHORT Events[PowerEventQueueDepth]; +}; + +// +// Same as FxPowerMachineEventQueue +// +union FxPowerMachineStateHistory { + struct { + WDF_DEVICE_POWER_STATE State1 : 16; + WDF_DEVICE_POWER_STATE State2 : 16; + WDF_DEVICE_POWER_STATE State3 : 16; + WDF_DEVICE_POWER_STATE State4 : 16; + WDF_DEVICE_POWER_STATE State5 : 16; + WDF_DEVICE_POWER_STATE State6 : 16; + WDF_DEVICE_POWER_STATE State7 : 16; + WDF_DEVICE_POWER_STATE State8 : 16; + } S; + + USHORT History[PowerEventQueueDepth]; +}; + +struct FxPowerMachine : public FxThreadedEventQueue { + FxPowerMachine( + VOID + ) : FxThreadedEventQueue(PowerEventQueueDepth) + { + // + // m_WaitWakeLock can not be initialized here since Initiliaze can + // return failure for UM. It's now being initialized in Init() function. + // + + InitializeListHead(&m_WaitWakeIrpToBeProcessedList); + + RtlZeroMemory(&m_Queue, sizeof(m_Queue)); + RtlZeroMemory(&m_States, sizeof(m_States)); + + m_States.History[IncrementHistoryIndex()] = WdfDevStatePowerObjectCreated; + m_IoCallbackFailure = FALSE; + m_PowerDownFailure = FALSE; + m_SingularEventsPresent = 0x0; + } + + _Must_inspect_result_ + NTSTATUS + Init( + __inout FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine + ); + + FxPowerMachineEventQueue m_Queue; + + FxPowerMachineStateHistory m_States; + + // + // Lock to guard wait wake irp + // + MxLock m_WaitWakeLock; + + // + // List of wait wake requests which have either been completed or cancelled + // and we are waiting for the state machine to process and complete the irp. + // + // We require a list of irps (instead of just storage for one irp) because + // the power policy owner might be misbehaving and sending wake requests + // successively down the stack and we want the state machine to be able + // to keep track of all the requests. + // + LIST_ENTRY m_WaitWakeIrpToBeProcessedList; + + union { + USHORT m_SingularEventsPresent; + + union { + // + // These are defined so that we can easily tell in the debugger what + // each set bit in m_SingularEventsPresent maps to in the + // FxPowerEvent enum. + // + USHORT PowerD0Known : 1; + USHORT PowerDxKnown : 1; + USHORT PowerWakeArrivalKnown : 1; + USHORT PowerWakeSucceededKnown : 1; + USHORT PowerWakeFailedKnown : 1; + USHORT PowerWakeCanceledKnown : 1; + USHORT PowerImplicitD0Known : 1; + USHORT PowerImplicitD3Known : 1; + USHORT PowerParentToD0Known : 1; + USHORT PowerMarkPageableKnown : 1; + USHORT PowerMarkNonpageableKnown : 1; + USHORT PowerCompleteD0Known : 1; + USHORT PowerCompleteDxKnown : 1; + } m_SingularEventsPresentByName; + }; + + BOOLEAN m_IoCallbackFailure; + + BOOLEAN m_PowerDownFailure; +}; + +#endif // _FXPOWERSTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoxinterface.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoxinterface.hpp new file mode 100644 index 00000000000..6da5496779e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxpoxinterface.hpp @@ -0,0 +1,197 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXPOXINTERFACE_H_ +#define _FXPOXINTERFACE_H_ + +#include "FxDevicePwrReqStateMachine.hpp" + +class FxPoxInterface { + +friend class FxDevicePwrRequirementMachine; + +public: + FxPoxInterface( + __in FxPkgPnp* PkgPnp + ); + + ~FxPoxInterface( + VOID + ); + + NTSTATUS + CreateDevicePowerRequirementMachine( + VOID + ); + + NTSTATUS + NotifyDevicePowerDown( + VOID + ); + + + VOID + DeviceIsPoweredOn( + VOID + ); + + FxPkgPnp* + PkgPnp( + VOID + ) + { + return m_PkgPnp; + } + + POHANDLE + GetPoHandle( + VOID + ) + { + return m_PoHandle; + } + + NTSTATUS + InitializeComponents( + VOID + ); + + VOID + UninitializeComponents( + VOID + ); + + VOID + RequestComponentActive( + VOID + ); + + BOOLEAN + DeclareComponentIdle( + VOID + ); + + VOID + UpdateIdleTimeoutHint( + VOID + ); + + VOID + SimulateDevicePowerRequired( + VOID + ); + + VOID + SimulateDevicePowerNotRequired( + VOID + ); + + VOID + PoxReportDevicePoweredOn( + VOID + ); + + VOID + PowerRequiredCallbackInvoked( + VOID + ); + + VOID + PowerNotRequiredCallbackInvoked( + VOID + ); + +private: + + NTSTATUS + PoxRegisterDevice( + VOID + ); + + VOID + DprProcessEventFromPoxCallback( + __in FxDevicePwrRequirementEvents Event + ); + + struct _POX_SETTINGS * + GetPowerFrameworkSettings( + VOID + ); + + VOID + PowerRequiredCallbackWorker( + __in BOOLEAN InvokedFromPoxCallback + ); + + VOID + PowerNotRequiredCallbackWorker( + __in BOOLEAN InvokedFromPoxCallback + ); + + VOID + PoxStartDevicePowerManagement( + VOID + ); + + + VOID + PoxUnregisterDevice( + VOID + ); + + VOID + PoxActivateComponent( + VOID + ); + + VOID + PoxIdleComponent( + VOID + ); + + VOID + PoxSetDeviceIdleTimeout( + __in ULONGLONG IdleTimeout + ); + + static PO_FX_COMPONENT_IDLE_STATE_CALLBACK StateCallback; + static PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveCallback; + static PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleCallback; + static PO_FX_DEVICE_POWER_REQUIRED_CALLBACK PowerRequiredCallback; + static PO_FX_DEVICE_POWER_NOT_REQUIRED_CALLBACK PowerNotRequiredCallback; + static PO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + +public: + // + // Device power requirement state machine + // + FxDevicePwrRequirementMachine * m_DevicePowerRequirementMachine; + + // + // Idle timeout hint to be provided to power framework at the next + // opportunity, i.e. a pending update to the idle timeout hint. + // + ULONG m_NextIdleTimeoutHint; + +private: + FxPkgPnp* m_PkgPnp; + + // + // Handle obtained upon registration with power manager + // + POHANDLE m_PoHandle; + + // + // Variable that tracks whether device power is required and the lock that + // protects this variable + // + BOOLEAN m_DevicePowerRequired; + MxLock m_DevicePowerRequiredLock; + + // + // Idle timeout hint currently provided to power framework. + // + ULONG m_CurrentIdleTimeoutHint; +}; + +#endif // _FXPOXINTERFACE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxqueryinterface.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxqueryinterface.hpp new file mode 100644 index 00000000000..fce92940fce --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxqueryinterface.hpp @@ -0,0 +1,137 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxQueryInterface.hpp + +Abstract: + + This module implements the "query" interface object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXQUERYINTERFACE_H_ +#define _FXQUERYINTERFACE_H_ + +class FxDeviceProcessQueryInterfaceRequest : public FxCallback { + +public: + + FxDeviceProcessQueryInterfaceRequest( + VOID + ) : + m_Method(NULL) + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in LPGUID InterfacType, + __out PINTERFACE ExposedInterface, + __in_opt PVOID ExposedInterfaceSpecificData + ) + { + if (m_Method != NULL) { + NTSTATUS status; + + CallbackStart(); + status = m_Method(Device, + InterfacType, + ExposedInterface, + ExposedInterfaceSpecificData); + CallbackEnd(); + + return status; + } + else { + return STATUS_SUCCESS; + } + } + +public: + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST m_Method; +}; + +struct FxQueryInterface : public FxStump { + +public: + FxQueryInterface( + __in CfxDevice* Device, + __in PWDF_QUERY_INTERFACE_CONFIG Config + ); + + ~FxQueryInterface( + VOID + ); + + VOID + SetEmbedded( + __in PWDF_QUERY_INTERFACE_CONFIG Config, + __in PINTERFACE Interface + ); + + static + FxQueryInterface* + _FromEntry( + __in PSINGLE_LIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxQueryInterface, m_Entry); + } + + static + VOID + _FormatIrp( + __in PIRP Irp, + __in const GUID* InterfaceGuid, + __out PINTERFACE Interface, + __in USHORT InterfaceSize, + __in USHORT InterfaceVersion, + __in_opt PVOID InterfaceSpecificData = NULL + ); + + _Must_inspect_result_ + static + NTSTATUS + _QueryForInterface( + __in PDEVICE_OBJECT TopOfStack, + __in const GUID* InterfaceType, + __out PINTERFACE Interface, + __in USHORT Size, + __in USHORT Version, + __in_opt PVOID InterfaceSpecificData + ); + +public: + GUID m_InterfaceType; + + PINTERFACE m_Interface; + + CfxDevice *m_Device; + + FxDeviceProcessQueryInterfaceRequest m_ProcessRequest; + + SINGLE_LIST_ENTRY m_Entry; + + BOOLEAN m_ImportInterface; + + BOOLEAN m_SendQueryToParentStack; + + BOOLEAN m_EmbeddedInterface; +}; + +#endif // _FXQUERYINTERFACE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxregkey.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxregkey.hpp new file mode 100644 index 00000000000..e6b647e81f4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxregkey.hpp @@ -0,0 +1,286 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRegKey.hpp + +Abstract: + + This is the C++ header for FxRegKey which represents a key into the registry + +Author: + + + + +Revision History: + +--*/ + +#ifndef _FXREGKEY_H_ +#define _FXREGKEY_H_ + +class FxRegKey : public FxPagedObject { + +public: + FxRegKey( + PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + ~FxRegKey( + VOID + ); + + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Create( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __in ACCESS_MASK DesiredAccess = KEY_ALL_ACCESS, + __in ULONG CreateOptions = REG_OPTION_NON_VOLATILE, + __out_opt PULONG CreateDisposition = NULL + ) + { + return _Create(ParentKey, + KeyName, + &m_Key, + DesiredAccess, + CreateOptions, + CreateDisposition); + } + + static + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _Create( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __out HANDLE* NewKey, + __in ACCESS_MASK DesiredAccess = KEY_ALL_ACCESS, + __in ULONG CreateOptions = REG_OPTION_NON_VOLATILE, + __out_opt PULONG CreateDisposition = NULL + ); + + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Open( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __in ACCESS_MASK DesiredAccess = KEY_ALL_ACCESS + ) + { + return _OpenKey(ParentKey, KeyName, &m_Key, DesiredAccess); + } + + static + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _OpenKey( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __out HANDLE* Key, + __in ACCESS_MASK DesiredAccess = KEY_ALL_ACCESS + ); + + __inline + VOID + SetHandle( + __in HANDLE Key + ) + { + m_Key = Key; + } + + __inline + HANDLE + GetHandle( + VOID + ) + { + return m_Key; + } + + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Close( + VOID + ) + { + HANDLE key; + + key = m_Key; + m_Key = NULL; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // For special cases where, due to user-mode restrictions, + // we cannot open a specific handle for write access, + // so we reuse a pre-opened one multiple times. + // + // In this case we do not want to close it when we close + // the FxRegKey object. + // + if (m_CanCloseHandle == FALSE) { + return STATUS_SUCCESS; + } +#endif + return _Close(key); + } + + static + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _Close( + __in HANDLE Key + ); + + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetValue( + __in PCUNICODE_STRING ValueName, + __in ULONG ValueType, + __in_bcount(ValueLength) PVOID Value, + __in ULONG ValueLength + ) + { + return _SetValue(m_Key, + ValueName, + ValueType, + Value, + ValueLength); + } + + static + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _SetValue( + _In_ HANDLE Key, + _In_ PCUNICODE_STRING ValueName, + _In_ ULONG ValueType, + _In_reads_bytes_(ValueLength) PVOID Value, + _In_ ULONG ValueLength + ); + + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + QueryValue( + __in PCUNICODE_STRING ValueName, + __in ULONG ValueLength, + __out_bcount_opt(ValueLength) PVOID Value, + __out_opt PULONG ValueLengthQueried, + __out_opt PULONG ValueType + ) + { + return _QueryValue(m_Globals, + m_Key, + ValueName, + ValueLength, + Value, + ValueLengthQueried, + ValueType); + } + + static + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _QueryValue( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __in ULONG ValueLength, + __out_bcount_opt(ValueLength) PVOID Value, + __out_opt PULONG ValueLengthQueried, + __out_opt PULONG ValueType + ); + + static + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _QueryULong( + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __out PULONG Value + ); + + static + _Must_inspect_result_ + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + _QueryQuadWord( + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __out PLARGE_INTEGER Value + ); + + static + BOOLEAN + __inline + _IsValidSzType( + __in ULONG RegValueType + ) + { + return (RegValueType == REG_SZ) || (RegValueType == REG_EXPAND_SZ); + } + + static + _Must_inspect_result_ + NTSTATUS + _VerifyMultiSzString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegValueName, + __in_bcount(DataLength) PWCHAR DataString, + __in ULONG DataLength + ); + +private: + + static + __out_range(Length, (Length+sizeof(KEY_VALUE_PARTIAL_INFORMATION)-1)) + ULONG + _ComputePartialSize( + __in_bound ULONG Length + ) + { + return FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + Length; + } + +protected: + + HANDLE m_Key; + PFX_DRIVER_GLOBALS m_Globals; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +private: + + // + // If FALSE, then closing or destroying the FxRegKey + // will have no effect on the HKEY m_Key. + // + BOOLEAN m_CanCloseHandle; + +public: + + VOID + __inline + SetCanCloseHandle( + BOOLEAN CanCloseHandle + ) + { + m_CanCloseHandle = CanCloseHandle; + } +#endif +}; + +#endif // _FXREGKEY_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrelateddevice.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrelateddevice.hpp new file mode 100644 index 00000000000..e7a03492c8a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrelateddevice.hpp @@ -0,0 +1,81 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRelatedDevice.hpp + +Abstract: + + This module defines the "related device" class. These objects are used + to handle device relations queries. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXRELATEDDEVICE_H_ +#define _FXRELATEDDEVICE_H_ + +enum FxRelatedDeviceState { + RelatedDeviceStateUnspecified = 0, + RelatedDeviceStateNeedsReportPresent, + RelatedDeviceStateReportedPresent, + RelatedDeviceStateNeedsReportMissing, +}; + +class FxRelatedDevice : public FxObject { + friend FxRelatedDeviceList; + +protected: + FxTransactionedEntry m_TransactionedEntry; + + MdDeviceObject m_DeviceObject; + +public: + FxRelatedDeviceState m_State; + +public: + FxRelatedDevice( + __in MdDeviceObject DeviceObject, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxRelatedDevice( + VOID + ); + + MdDeviceObject + GetDevice( + VOID + ) + { + return m_DeviceObject; + } + + DECLARE_INTERNAL_NEW_OPERATOR(); + +#ifdef INLINE_WRAPPER_ALLOCATION +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + FORCEINLINE + PVOID + GetCOMWrapper( + ) + { + PBYTE ptr = (PBYTE) this; + return (ptr + (USHORT) WDF_ALIGN_SIZE_UP(sizeof(*this), MEMORY_ALLOCATION_ALIGNMENT)); + } +#endif +#endif +}; + +#endif // _FXRELATEDDEVICE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrelateddevicelist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrelateddevicelist.hpp new file mode 100644 index 00000000000..77ac388f5c3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrelateddevicelist.hpp @@ -0,0 +1,112 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXRELATEDDEVICELIST_H_ +#define _FXRELATEDDEVICELIST_H_ + +class FxRelatedDeviceList : protected FxSpinLockTransactionedList { +public: + FxRelatedDeviceList( + VOID + ) + { + m_DeleteOnRemove = TRUE; + m_NeedReportMissing = 0; + } + + VOID + LockForEnum( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + __super::LockForEnum(FxDriverGlobals); + } + + VOID + UnlockFromEnum( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + __super::UnlockFromEnum(FxDriverGlobals); + } + + _Must_inspect_result_ + NTSTATUS + Add( + __in PFX_DRIVER_GLOBALS Globals, + __inout FxRelatedDevice* Entry + ); + + VOID + Remove( + __in PFX_DRIVER_GLOBALS Globals, + __in MdDeviceObject Device + ); + + _Must_inspect_result_ + FxRelatedDevice* + GetNextEntry( + __in_opt FxRelatedDevice* Entry + ); + + UCHAR + IncrementRetries( + VOID + ) + { + m_Retries++; + return m_Retries; + } + + VOID + ZeroRetries( + VOID + ) + { + m_Retries = 0; + } + + _Must_inspect_result_ + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + return FxPoolAllocate(FxDriverGlobals, NonPagedPool, Size); + } + + VOID + operator delete( + __in PVOID pointer + ) + { + FxPoolFree(pointer); + } + +protected: + virtual + _Must_inspect_result_ + NTSTATUS + ProcessAdd( + __in FxTransactionedEntry *Entry + ); + + virtual + BOOLEAN + Compare( + __in FxTransactionedEntry* Entry, + __in PVOID Data + ); + + virtual + VOID + EntryRemoved( + __in FxTransactionedEntry* Entry + ); + +public: + ULONG m_NeedReportMissing; +}; + +#endif _FXRELATEDDEVICELIST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequest.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequest.hpp new file mode 100644 index 00000000000..76d2a92545e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequest.hpp @@ -0,0 +1,1530 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequest.hpp + +Abstract: + + This is the request object for the driver frameworks. + + The request object wraps the IRP, containing persistent + information required by the driver frameworks. + +Author: + + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXREQUEST_H_ +#define _FXREQUEST_H_ + +// +// Magic number to differentiate between default value and caller provided one +// +#define USE_DEFAULT_PRIORITY_BOOST ((CHAR) 0x7F) + +// +// This tag is used to set and clear the completion callback state as the +// ownership of the request transfers from I/O pkg-to-queue or queue-to-queue. +// +#define FXREQUEST_STATE_TAG (PVOID) 'tatS' + +// +// This tag is used when the request is added and removed from FxIrpQueue. +// +#define FXREQUEST_QUEUE_TAG (PVOID) 'ueuQ' + +// +// This tag is used to take a reference in the completion path. +// +#define FXREQUEST_COMPLETE_TAG (PVOID) 'pmoC' + +// +// Use this tag when you want to temporarily hold the object from +// disappearing between unlock and lock operation. +// +#define FXREQUEST_HOLD_TAG (PVOID) 'dloH' + +// +// This tag is used to take a reference in the completion path. +// +#define FXREQUEST_FWDPRG_TAG (PVOID) 'PdwF' + +// +// This tag is used to take a reference in the completion path for driver created +// requests that support completion operations. +// +#define FXREQUEST_DCRC_TAG (PVOID) 'CRCD' + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxRequest.hpp.tmh" +#endif +} + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#define WDF_REQUEST_SEND_OPTION_IMPERSONATION_FLAGS \ + (WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT | \ + WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE) + +#define FxIrpStackFlagsFromSendFlags(sendFlags) \ + ((WUDFX_IRP_STACK_FLAGS) \ + ((sendFlags) & WDF_REQUEST_SEND_OPTION_IMPERSONATION_FLAGS)) +#endif + +typedef +NTSTATUS +(*PFN_FX_QUEUE_REQUEST_COMPLETE) ( + __in FxRequest* Request, + __in FxIoQueue* Queue, + __in_opt WDFCONTEXT Context + ); + +struct FxRequestSystemBuffer : public IFxMemory { + friend FxRequest; + +public: + FxRequestSystemBuffer( + VOID + ) + { + m_Buffer = NULL; + } + + _Must_inspect_result_ + virtual + PVOID + GetBuffer( + VOID + ); + + virtual + size_t + GetBufferSize( + VOID + ); + + _Must_inspect_result_ + virtual + PMDL + GetMdl( + VOID + ); + + virtual + WDFMEMORY + GetHandle( + VOID + ); + + virtual + USHORT + GetFlags( + VOID + ); + + virtual + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ); + + virtual + ULONG + AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ); + + virtual + ULONG + Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ); + + virtual + VOID + Delete( + VOID + ); + + __inline + BOOLEAN + IsBufferSet( + VOID + ) + { + return m_Buffer != NULL ? TRUE : FALSE; + } + + __inline + VOID + ClearBufferMdl( + VOID + ) + { + m_Buffer = NULL; + m_Mdl = NULL; + } + +protected: + __inline + VOID + SetBuffer( + PVOID Buffer + ) + { + ASSERT(m_Buffer == NULL); + m_Buffer = Buffer; + } + + __inline + VOID + SetMdl( + PMDL Mdl + ) + { + ASSERT(m_Mdl == NULL); + m_Mdl = Mdl; + } + + FxRequest* + GetRequest( + VOID + ); + +protected: + // + // The current irp stack location indicates which type to use + // + // The buffer / MDL is cached away as a copy instead of using the PIRP values + // directly because we want to capture the current state of the irp when + // returning the WDFMEMORY. For instance, if used the PIRP value directly + // when implementing GetBuffer(), we are subject to the PIRP being formatted + // for the next stack location and changing the buffer pointer, or worse, + // changing the MDL value and have the resulting MDL not be mapped, and then + // a call to MmGetSystemAddressForMdlSafe can return NULL, and thus GetBuffer(), + // return NULL, which would violate the contract for GetBuffer(). + // + // As an example, let's + // 1) the WDFREQUEST/PIRP comes in as a read on a direct io device object, + // so Irp->MdlAddress = + // 2) This WDFMEMORY will return in GetBuffer() + // 3) the WDFREQUEST is formatted for an IOCTL which is METHOD_OUT_DIRECT + // with a new output buffer. Irp->MdlAddres = now. + // 4) This same WDFMEMORY will now return in GetBuffer() + // + // Essentialy, formatting the WDFREQUEST causes unintended side affects for + // the WDFMEMORYs it returns. To eliminate those side affects, we capture + // the original buffer. + // + union { + PVOID m_Buffer; + PMDL m_Mdl; + }; +}; + +struct FxRequestOutputBuffer : public IFxMemory { + friend FxRequest; + +public: + FxRequestOutputBuffer( + VOID + ) + { + m_Buffer = NULL; + } + + virtual + PVOID + GetBuffer( + VOID + ); + + virtual + size_t + GetBufferSize( + VOID + ); + + _Must_inspect_result_ + virtual + PMDL + GetMdl( + VOID + ); + + virtual + WDFMEMORY + GetHandle( + VOID + ); + + virtual + USHORT + GetFlags( + VOID + ); + + virtual + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ); + + virtual + ULONG + AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ); + + virtual + ULONG + Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ); + + virtual + VOID + Delete( + VOID + ); + + __inline + BOOLEAN + IsBufferSet( + VOID + ) + { + return m_Buffer != NULL ? TRUE : FALSE; + } + + __inline + VOID + ClearBufferMdl( + VOID + ) + { + m_Buffer = NULL; + m_Mdl = NULL; + } + +protected: + __inline + VOID + SetBuffer( + __in PVOID Buffer + ) + { + ASSERT(m_Buffer == NULL); + m_Buffer = Buffer; + } + + __inline + VOID + SetMdl( + __in PMDL Mdl + ) + { + ASSERT(m_Mdl == NULL); + m_Mdl = Mdl; + } + + FxRequest* + GetRequest( + VOID + ); + +protected: + // + // The current irp stack location indicates which type to use + // + // See comments in FxRequestSystemBuffer's union for why we capture the + // values vs using them directly from the PIRP. + // + union { + PVOID m_Buffer; + PMDL m_Mdl; + }; +}; + +// begin_wpp enum +enum FxListEntryNames { + FxListEntryNameCleanup = 0, + + // this entry is used when the request is owned by the framework + FxListEntryQueueOwned, + + // this entry is used when the request is presented to the driver + FxListEntryDriverOwned, + + // this entry is used for forward progress + FxListEntryForwardProgress +}; + +enum FxRequestPowerStopState { + FxRequestPowerStopUnknown = 0, // Initial state + + // Set when the driver calls WdfRequestStopAcknowledge + FxRequestPowerStopAcknowledged = 0x1, + + // Set when the driver WdfRequestStopAcknowledge with requeue option + FxRequestPowerStopAcknowledgedWithRequeue = 0x2, +}; + +// end_wpp + +class FxRequest : public FxRequestBase { + + friend FxIoTarget; + friend FxIoQueue; + + friend FxRequestMemory; + friend FxRequestOutputBuffer; + friend FxRequestSystemBuffer; + friend VOID GetTriageInfo(VOID); + +protected: + // + // This field points to the queue that the request is currently + // associated with. + // + FxIoQueue* m_IoQueue; + + FxRequestSystemBuffer m_SystemBuffer; + + FxRequestOutputBuffer m_OutputBuffer; + + // + // This is for use by the owner of the FxRequest which is FxIoQueue OR FxIoTarget + // + LIST_ENTRY m_OwnerListEntry; + + LIST_ENTRY m_OwnerListEntry2; + + // + // This is used by the queue to keep track of all forward progress requests + // + LIST_ENTRY m_ForwardProgressList; + + // + // Used when the request is a reserved request to track the queue it was + // originally allocated for, so that it can be returned to the forward + // progress queue for reuse when the request is completed. + // + FxIoQueue *m_ForwardProgressQueue; + + // + // Generic context exposed to other modules. + // + PVOID m_InternalContext; + + // + // If TRUE, the client driver has been presented with this WDFREQUEST at + // least once. + // + BOOLEAN m_Presented; + + // + // For tracking whether the driver has acknowledged power stop/purge notifications. + // + BYTE m_PowerStopState; + + // + // If TRUE, this is a reserved request + // + BOOLEAN m_Reserved; + + // + // If TRUE, this is used to determine how to free the request - + // either to the lookaside list or using ExFreePool + // + BOOLEAN m_ForwardRequestToParent; + +public: + + // + // Normally, this is available by the object implementing + // IFxListEntry, but currently all callers of this know they + // are dealing with an FxRequest*. + // + // If FxRequests must go on a general typeless list, then + // the IFxListEntry interface should be added to FxRequest. + // + __inline + PLIST_ENTRY + GetListEntry( + __in FxListEntryNames Index + ) + { + switch (Index) { + case FxListEntryQueueOwned: return &m_OwnerListEntry; + case FxListEntryDriverOwned: return &m_OwnerListEntry2; + case FxListEntryForwardProgress: return &m_ForwardProgressList; + default: ASSERT(FALSE); return NULL; + } + } + + static + FxRequest* + _FromOwnerListEntry( + __in FxListEntryNames Index, + __in PLIST_ENTRY OwnerListEntry + ) + { + switch (Index) { + case FxListEntryQueueOwned: + return CONTAINING_RECORD(OwnerListEntry, FxRequest, m_OwnerListEntry); + case FxListEntryDriverOwned: + return CONTAINING_RECORD(OwnerListEntry, FxRequest, m_OwnerListEntry2); + case FxListEntryForwardProgress: + return CONTAINING_RECORD(OwnerListEntry, FxRequest, m_ForwardProgressList); + default: + ASSERT(FALSE); + return NULL; + } + } + + __inline + VOID + CopyCurrentIrpStackLocationToNext( + VOID + ) + { + FxIrp* irp = GetSubmitFxIrp(); + irp->CopyCurrentIrpStackLocationToNext(); + } + + _Must_inspect_result_ + NTSTATUS + Reuse( + __in PWDF_REQUEST_REUSE_PARAMS ReuseParams + ); + + __inline + BOOLEAN + IsCancelled( + VOID + ) + { + return m_Irp.IsCanceled() || m_Canceled; + } + + __inline + VOID + CopyCompletionParams( + __in PWDF_REQUEST_COMPLETION_PARAMS Params + ) + { + if (m_RequestContext != NULL) { + RtlCopyMemory(Params, + &m_RequestContext->m_CompletionParams, + sizeof(WDF_REQUEST_COMPLETION_PARAMS)); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGREQUEST, + "WdfRequestGetCompletionParams will not return valid information if the" + " request is not formatted using WdfIoTargetFormatxxx DDIs" + ); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + WDF_REQUEST_COMPLETION_PARAMS_INIT(Params); + } + } + + VOID + __inline + SetPresented( + VOID + ) + { + // + // No need to synchronize setting this value with checking it because + // we check it in the complete path. We will not be about to present + // and completing the request in 2 simultaneous contexts. + // + m_Presented = TRUE; + } + + VOID + AddIrpReference( + VOID + ); + + VOID + ReleaseIrpReference( + VOID + ); + + virtual + ULONG + AddRefOverride( + __in WDFOBJECT_OFFSET Offset, + __in PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ); + + virtual + ULONG + ReleaseOverride( + __in WDFOBJECT_OFFSET Offset, + __in PVOID Tag = NULL, + __in LONG Line = 0, + __in_opt PSTR File = NULL + ); + + __inline + CfxDevice* + GetDevice( + VOID + ) + { + return m_Device; + } + + __inline + BOOLEAN + IsReserved( + ) + { + return m_Reserved; + } + + __inline + VOID + SetReserved( + ) + { + m_Reserved = TRUE; + } + + __inline + VOID + SetForwardProgressQueue( + __in FxIoQueue *Queue + ) + { + m_ForwardProgressQueue = Queue; + } + +protected: + FxRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in MdIrp Irp, + __in FxRequestIrpOwnership Ownership, + __in FxRequestConstructorCaller Caller, + __in USHORT ObjectSize + ); + + #if DBG + FxRequest::~FxRequest( + VOID + ); + #endif // DBG + + __inline + VOID + SetCurrentQueue( + __in FxIoQueue *Queue + ) + { + m_IoQueue = Queue; + } + + + WDFMEMORY + GetMemoryHandle( + __in USHORT Offset + ) + { + ULONG_PTR handle; + + // + // The offset into this object must be self relative. + // + ASSERT(*((PUSHORT) WDF_PTR_ADD_OFFSET(this, Offset)) == Offset); + + handle = (ULONG_PTR) WDF_PTR_ADD_OFFSET(this, Offset); + + // + // Make sure initial value has the flag bits cleared. + // + ASSERT((handle & FxHandleFlagMask) == 0); + + // + // We always apply the mask. + // + handle = handle ^ FxHandleValueMask; + + // + // Make sure final value (before we set the flag) has the flag bits + // cleared. + // + ASSERT((handle & FxHandleFlagMask) == 0); + + // + // This handle is an offset + handle |= FxHandleFlagIsOffset; + + return (WDFMEMORY) handle; + } + + _Must_inspect_result_ + virtual + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ); + +public: + // Factory functions to create FxRequest* objects + _Must_inspect_result_ + static + NTSTATUS + _CreateForPackage( + __in CfxDevice* Device, + __in PWDF_OBJECT_ATTRIBUTES RequestAttributes, + __in MdIrp Irp, + __deref_out FxRequest** Request + ); + + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES RequestAttributes, + __in_opt MdIrp Irp, + __in_opt FxIoTarget* Target, + __in FxRequestIrpOwnership Ownership, + __in FxRequestConstructorCaller Caller, + __deref_out FxRequest** Request + ); + + _Must_inspect_result_ + FxIoQueue* + GetCurrentQueue( + VOID + ) + { + if(m_Completed) { + return NULL; + } + + return m_IoQueue; + } + + FxRequestCompletionState + SetCompletionState( + __in FxRequestCompletionState NewState + ); + + VOID + __inline + SetStatus( + __in NTSTATUS Status + ) + { + m_Irp.SetStatus(Status); + } + + NTSTATUS + SetInformation( + __in ULONG_PTR Information + ); + + ULONG_PTR + GetInformation( + VOID + ); + + KPROCESSOR_MODE + GetRequestorMode( + VOID + ); + + __inline + NTSTATUS + Complete( + __in NTSTATUS Status + ) + { + CfxDevice* const fxDevice = GetDevice(); + + // + // Complete the current request object. Can be called directly + // by the FxIoQueue to complete a request. + // + // When an FxRequest is completed, it is marked as completed, + // removed from any CSQ it may be a member of, and any registered + // callback functions are called. Then the NT IRP is completed, + // and the reference count on the object due to the callback routine + // is released if a callback routine was specified. + // + // Completing a request object can cause its reference + // count to go to zero, thus deleting it. So the caller + // must either reference it explicitly, or not touch it + // any more after calling complete. + // + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Completing WDFREQUEST 0x%p for IRP 0x%p with " + "Information 0x%I64x, %!STATUS!", + GetHandle(), m_Irp.GetIrp(), m_Irp.GetInformation(), Status); + + if (fxDevice != NULL) { + SetPriorityBoost(fxDevice->GetDefaultPriorityBoost()); + } + else { + SetPriorityBoost(0); + } + + return CompleteInternal(Status); + } + + __inline + NTSTATUS + CompleteWithInformation( + __in NTSTATUS Status, + __in ULONG_PTR Information + ) + { + // + // Complete the request object. If the status is success, get the + // priority boost for the owning device type, and complete the request. + // + m_Irp.SetInformation(Information); + return Complete(Status); + } + + __inline + NTSTATUS + CompleteWithPriority( + __in NTSTATUS Status, + __in CCHAR PriorityBoost + ) + { + // + // Complete the current request object. Can be called directly + // by the FxIoQueue to complete a request. + // + // When an FxRequest is completed, it is marked as completed, + // removed from any CSQ it may be a member of, and any registered + // callback functions are called. Then the NT IRP is completed, + // and the reference count on the object due to the callback routine + // is released if a callback routine was specified. + // + // Completing a request object can cause its reference + // count to go to zero, thus deleting it. So the caller + // must either reference it explicitly, or not touch it + // any more after calling complete. + // + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGREQUEST, + "Completing WDFREQUEST 0x%p for IRP 0x%p with " + "Information 0x%I64x, %!STATUS!", + GetHandle(), m_Irp.GetIrp(), m_Irp.GetInformation(), Status); + + SetPriorityBoost(PriorityBoost); + return CompleteInternal(Status); + } + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + VOID, + VerifyPreProcessSendAndForget + ); + + VOID + PreProcessSendAndForget( + VOID + ); + + VOID + PostProcessSendAndForget( + VOID + ); + + NTSTATUS + GetStatus( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + GetParameters( + __out PWDF_REQUEST_PARAMETERS Parameters + ); + + _Must_inspect_result_ + NTSTATUS + GetMemoryObject( + __deref_out IFxMemory** Memory, + __out PVOID* Buffer, + __out size_t* Length + ); + + _Must_inspect_result_ + NTSTATUS + GetMdl( + __out PMDL *pMdl + ); + + _Must_inspect_result_ + NTSTATUS + GetDeviceControlOutputMemoryObject( + __deref_out IFxMemory** MemoryObject, + __out PVOID* Buffer, + __out size_t* Length + ); + + _Must_inspect_result_ + NTSTATUS + GetDeviceControlOutputMdl( + __out PMDL *pMdl + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyProbeAndLock + ); + + _Must_inspect_result_ + NTSTATUS + ProbeAndLockForRead( + __in PVOID Buffer, + __in ULONG Length, + __deref_out FxRequestMemory** pMemoryObject + ); + + _Must_inspect_result_ + NTSTATUS + ProbeAndLockForWrite( + __in PVOID Buffer, + __in ULONG Length, + __deref_out FxRequestMemory** pMemoryObject + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + _Must_inspect_result_ + NTSTATUS + Impersonate( + _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_ PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate, + _In_opt_ PVOID Context + ); +#endif + + VOID + SetImpersonationFlags( + _In_ ULONG Flags + ) + { +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + GetSubmitFxIrp()->GetIoIrp()->SetFlagsForNextStackLocation( + FxIrpStackFlagsFromSendFlags(Flags)); +#else + UNREFERENCED_PARAMETER(Flags); +#endif + } + + FxIrp* + GetFxIrp( + VOID + ) + { + return &m_Irp; + } + + __inline + FxIoQueue* + GetIoQueue( + VOID + ) + { + return m_IoQueue; + } + + _Must_inspect_result_ + NTSTATUS + GetIrp( + __deref_out MdIrp* ppIrp + ) + { + if (GetDriverGlobals()->FxVerifierIO) { + NTSTATUS status; + KIRQL irql; + + Lock(&irql); + + status = VerifyRequestIsNotCompleted(GetDriverGlobals()); + if (!NT_SUCCESS(status)) { + *ppIrp = NULL; + status = STATUS_INVALID_DEVICE_REQUEST; + } + else { + *ppIrp = m_Irp.GetIrp(); + } + + Unlock(irql); + + return status; + } + else { + *ppIrp = m_Irp.GetIrp(); + return STATUS_SUCCESS; + } + } + + // + // Return the FxFileObject if associated with this request + // + _Must_inspect_result_ + NTSTATUS + GetFileObject( + __deref_out_opt FxFileObject** pFileObject + ); + + // + // Get the IoStack location of the request. + // + // Since this returns the pointer to the underlying IRP + // IO_STACK_LOCATION, it can not be called in a situation + // which the request is completed out from underneath us. + // + // Note: Must implemention a version for the drivers use. + // Must interact with completion events from the + // driver due to cancel as well. + // + // + PIO_STACK_LOCATION + GetCurrentIrpStackLocation( + VOID + ) + { + if (GetDriverGlobals()->FxVerifierIO) { + PIO_STACK_LOCATION ios; + KIRQL irql; + NTSTATUS status; + + Lock(&irql); + status = VerifyRequestIsNotCompleted(GetDriverGlobals()); + if (!NT_SUCCESS(status)) { + ios = NULL; + } + else { + ios = m_Irp.GetCurrentIrpStackLocation(); + } + Unlock(irql); + + return ios; + } + else { + return m_Irp.GetCurrentIrpStackLocation(); + } + } + + // + // The following functions are to support use of + // the Cancel Safe FxIrpQueue. + // + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifyInsertIrpQueue, + _In_ FxIrpQueue* + ); + + // + // Insert the request in the supplied FxIrpQueue + // and associated it with it. + // + _Must_inspect_result_ + NTSTATUS + InsertTailIrpQueue( + __in FxIrpQueue* IrpQueue, + __out_opt ULONG* pRequestCount + ); + + _Must_inspect_result_ + NTSTATUS + InsertHeadIrpQueue( + __in FxIrpQueue* IrpQueue, + __out_opt ULONG* pRequestCount + ); + + // + // Remove it from the FxIrpQueue it is associated with. + // + // Returns STATUS_CANCELLED if the cancel routine has + // fired and removed it from the queue first. + // + // + _Must_inspect_result_ + NTSTATUS + RemoveFromIrpQueue( + __in FxIrpQueue* IrpQueue + ); + + // + // Mark that this request is no longer on the IrpQueue + // + __inline + VOID + MarkRemovedFromIrpQueue( + VOID + ) + { + m_IrpQueue = NULL; + return; + } + + // + // Return the FxRequest's CsqContext address + // + __inline + PMdIoCsqIrpContext + GetCsqContext( + VOID + ) + { + return &m_CsqContext; + } + + + // + // Function to return an FxRequest from an FxIrpQueue + // + _Must_inspect_result_ + static + FxRequest* + GetNextRequest( + __in FxIrpQueue* IrpQueue + ); + + _Must_inspect_result_ + static + NTSTATUS + GetNextRequest( + __in FxIrpQueue* IrpQueue, + __in_opt MdFileObject FileObject, + __in_opt FxRequest* TagRequest, + __deref_out FxRequest** ppOutRequest + ); + + // + // Allow peeking at requests in the IrpQueue + // + _Must_inspect_result_ + static + NTSTATUS + PeekRequest( + __in FxIrpQueue* IrpQueue, + __in_opt FxRequest* TagRequest, + __in_opt MdFileObject FileObject, + __out_opt PWDF_REQUEST_PARAMETERS Parameters, + __deref_out FxRequest** ppOutRequest + ); + + // + // Internal function to retrieve the FxRequest + // structure from a pointer to its CsqContext + // member. + // + __inline + static + FxRequest* + RetrieveFromCsqContext( + __in PMdIoCsqIrpContext pCsqContext + ) + { + return CONTAINING_RECORD(pCsqContext, FxRequest, m_CsqContext); + } + + + __inline + BOOLEAN + IsInIrpQueue( + __in FxIrpQueue* pIrpQueue + ) + { + return pIrpQueue->IsIrpInQueue(GetCsqContext()); + } + + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION_P1( + NTSTATUS, + VerifyStopAcknowledge, + _In_ BOOLEAN + ); + + VOID + StopAcknowledge( + __in BOOLEAN Requeue + ); + + __inline + BOOLEAN + IsPowerStopAcknowledged( + VOID + ) + { + return ((m_PowerStopState == FxRequestPowerStopAcknowledged) + || + (m_PowerStopState == FxRequestPowerStopAcknowledgedWithRequeue))? TRUE : FALSE; + } + + __inline + BOOLEAN + IsPowerStopAcknowledgedWithRequeue( + VOID + ) + { + return (m_PowerStopState == FxRequestPowerStopAcknowledgedWithRequeue) ? TRUE : FALSE; + } + + VOID + ClearPowerStopState( + VOID + ) + { + m_PowerStopState = FxRequestPowerStopUnknown; + } + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + VOID, + VerifierBreakpoint_RequestEarlyDisposeDeferred + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsDriverOwned + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsCancelable + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsNotCancelable + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsInCallerContext + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsInEvtIoStopContext + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsNotCompleted + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsTagRequest + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsAllocatedFromIo + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestIsCurrentStackValid + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + NTSTATUS, + VerifyRequestCanBeCompleted + ); + + VOID + FreeRequest( + VOID + ); + + __inline + VOID + ClearFieldsForReuse( + VOID + ) + { + m_SystemBuffer.ClearBufferMdl(); + m_OutputBuffer.ClearBufferMdl(); + + ASSERT(m_ForwardRequestToParent == FALSE); + + __super::ClearFieldsForReuse(); + } + + virtual + ULONG + Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ); + + __inline + BOOLEAN + IsRequestForwardedToParent( + VOID + ) + { + return m_ForwardRequestToParent; + } + +private: + FX_DECLARE_VF_FUNCTION_P1( + VOID, + VerifyCompleteInternal, + _In_ NTSTATUS + ); + + NTSTATUS + CompleteInternalReserved( + __in NTSTATUS Status, + __in CCHAR PriorityBoost + ); + + NTSTATUS + CompleteInternal( + __in NTSTATUS Status + ); + + VOID + PostProcessCompletion( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ); + + VOID + PostProcessCompletionForReserved( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ); + + VOID + PreProcessCompletionForDriverRequest( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ); + + VOID + PostProcessCompletionForDriverRequest( + __in FxRequestCompletionState State, + __in FxIoQueue* Queue + ); + + static + VOID + CheckAssumptions( + VOID + ); + + VOID + AssignMemoryBuffers( + __in WDF_DEVICE_IO_TYPE IoType + ) +{ + + switch (m_Irp.GetMajorFunction()) { + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + + + + + + + + + + switch (m_Irp.GetParameterIoctlCodeBufferMethod()) { + case METHOD_BUFFERED: + // + // Set the buffer in the memory interface. For kernel mode, + // GetOutputBuffer is same as GetSystemBuffer, but for user-mode, + // host provides separate buffers, so that input buffer can only be + // read, and output buffer can only be written to. + // + m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer()); + m_OutputBuffer.SetBuffer(m_Irp.GetOutputBuffer()); + break; + + case METHOD_IN_DIRECT: + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with read access + // + KMDF_ONLY_CODE_PATH_ASSERT(); + m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer()); + break; + + case METHOD_OUT_DIRECT: + // + // InputBuffer is in SystemBuffer + // OutputBuffer is in MdlAddress with write access + // + KMDF_ONLY_CODE_PATH_ASSERT(); + m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer()); + break; + + case METHOD_NEITHER: + // + // Internal device controls are kernel mode to kernel mode, and deal + // with direct unmapped pointers. + // + // In addition, a normal device control with + // RequestorMode == KernelMode is also treated as kernel mode + // to kernel mode since the I/O Manager will not generate requests + // with this setting from a user mode request. + // + KMDF_ONLY_CODE_PATH_ASSERT(); + if (m_Irp.GetMajorFunction() == IRP_MJ_INTERNAL_DEVICE_CONTROL || + (m_Irp.GetRequestorMode() == KernelMode)) { + m_SystemBuffer.SetBuffer( + m_Irp.GetParameterIoctlType3InputBuffer() + ); + m_OutputBuffer.SetBuffer(m_Irp.GetUserBuffer()); + } + else { + return; + } + break; + } + break; + + case IRP_MJ_READ: + case IRP_MJ_WRITE: + switch (IoType) { + case WdfDeviceIoBuffered: + m_SystemBuffer.SetBuffer(m_Irp.GetSystemBuffer()); + break; + + case WdfDeviceIoNeither: + KMDF_ONLY_CODE_PATH_ASSERT(); + if (m_Irp.GetRequestorMode() == KernelMode) { + m_SystemBuffer.SetBuffer(m_Irp.GetUserBuffer()); + } + else { + return; + } + break; + + default: + return; + } + break; + + default: + return; + } + + if (m_SystemBuffer.IsBufferSet()) { + m_RequestBaseStaticFlags |= FxRequestBaseStaticSystemBufferValid; + } + if (m_OutputBuffer.IsBufferSet()) { + m_RequestBaseStaticFlags |= FxRequestBaseStaticOutputBufferValid; + } +} + + +public: + __inline + VOID + SetInternalContext( + PVOID Context + ) + { + ASSERT(NULL == m_InternalContext); + m_InternalContext = Context; + } + + __inline + PVOID + GetInternalContext( + VOID + ) + { + PVOID context; + + context = m_InternalContext; + m_InternalContext = NULL; + + return context; + } +}; + +class FxRequestFromLookaside : public FxRequest { + +public: + FxRequestFromLookaside( + __in CfxDevice* Device, + __in MdIrp Irp + ); + + PVOID + operator new( + __in size_t Size, + __in CfxDevice* Device, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ); + +protected: + // + // FxObject override + // + VOID + SelfDestruct( + VOID + ); +}; + +#endif // _FXREQUEST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbase.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbase.hpp new file mode 100644 index 00000000000..fdcd510150f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbase.hpp @@ -0,0 +1,959 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRequestBase.hpp + +Abstract: + + This is the base class which request objects derive from for the driver + frameworks. + + The request base object wraps the IRP, containing persistent + information required by the driver frameworks. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXREQUESTBASE_H_ +#define _FXREQUESTBASE_H_ + +#include "FxRequestCallbacks.hpp" + + +// +// COMPLETED - set when the request's i/o completion routine has executed +// +// PENDED - set when the request has been put onto the target's CSQ +// +// TIMER_SET - set when a timer has been queued along with sending the request +// down to the target +// +// CANCELLED_FROM_TIME - set by the timer to indicate that the request was +// cancelled by the timer DPC +// +// IGNORE_STATE - set when the request is going to be sent ignoring the +// state of the target. +// +enum FxRequestTargetFlags { + FX_REQUEST_COMPLETED = 0x01, + FX_REQUEST_PENDED = 0x02, + FX_REQUEST_TIMER_SET = 0x04, + FX_REQUEST_CANCELLED_FROM_TIMER = 0x08, + FX_REQUEST_IGNORE_STATE = 0x10, +}; + +// +// internal private constraints +// +#define WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND (0x80000000) + +#define WDF_REQUEST_INTERNAL_CONSTRAINTS_VALID_FLAGS \ + (WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND) + + +// +// Completion event callback prototype +// +typedef +VOID +(*PFN_COMPLETE_COPY_ROUTINE)( + __in FxIoTarget* This, + __in FxRequest* Request, + __in_opt FxRequestContext* Context + ); + + +struct FxRequestTimer : public FxStump { + MxTimer Timer; +}; + +enum FxRequestAllocationSource { + REQUEST_ALLOCATED_FROM_IO = 0, // Irp came from the I/O package + REQUEST_ALLOCATED_INTERNAL = 1, // Irp was allocated internally and should be freed by the request + REQUEST_ALLOCATED_DRIVER = 2, // Irp was given to the request by the driver writer +}; + +enum FxRequestIrpOwnership { + FxRequestOwnsIrp = 1, + FxRequestDoesNotOwnIrp, +}; + +// begin_wpp config +// CUSTOM_TYPE(FxRequestIrpOwnership, ItemEnum(FxRequestIrpOwnership)); +// end_wpp + +enum FxRequestConstructorCaller { + FxRequestConstructorCallerIsFx = 1, + FxRequestConstructorCallerIsDriver, +}; + +// +// These defines are for VerifierFlags +// +enum FxRequestVerifierFlags { + // Request has been passed to the Driver + FXREQUEST_FLAG_DRIVER_OWNED = 0x0001, + + // Request was returned as a "Tag" request to WdfIoQueuePeekNextRequest. + FXREQUEST_FLAG_TAG_REQUEST = 0x0002, + + // Request has been forwarded from one queue to another + FXREQUEST_FLAG_FORWARDED = 0x0004, + + // Request is being EvtIoDefault to the driver + FXREQUEST_FLAG_DRIVER_DISPATCH = 0x0008, + + // The driver has specified the request as cancelable + FXREQUEST_FLAG_DRIVER_CANCELABLE = 0x0010, + + FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT = 0x0020, + + // The request has been cancelled + FXREQUEST_FLAG_CANCELLED = 0x0040, + + // the next stack location has been formatted + FXREQUEST_FLAG_FORMATTED = 0x0080, + + // the request has been sent on an I/O target and is in the target's sent list + FXREQUEST_FLAG_SENT_TO_TARGET = 0x0100, + + // used to make sure the driver stop acknowledges in the context of EvtIoStop + FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT = 0x0200, + + // used to indicate whether the Reserved Request is in use or on Free list + FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP = 0x0400, +}; + +enum FxRequestBaseFlags { + FxRequestBaseSystemMdlMapped = 0x1, + FxRequestBaseOutputMdlMapped = 0x2, + FxRequestBaseSyncCleanupContext = 0x10, +}; + +enum FxRequestBaseStaticFlags { + FxRequestBaseStaticSystemBufferValid = 0x1, + FxRequestBaseStaticOutputBufferValid = 0x2, +}; + +// +// Designed to fit into a byte. FxRequestCompletionPkgFlag is a bit value +// used to distinguish between calling back into the io package or the current +// queue. When calling back into the current queue, we assume m_IoQueue is valid +// +enum FxRequestCompletionState { + FxRequestCompletionStateIoPkgFlag = 0x80, + + FxRequestCompletionStateNone = 0x00, + FxRequestCompletionStateQueue = 0x01, + FxRequestCompletionStateIoPkg = 0x02 | FxRequestCompletionStateIoPkgFlag, +}; + +class FxRequestBase : public FxNonPagedObject { + + friend FxIoTarget; + friend FxSyncRequest; + +public: + + __inline + VOID + SetCompletionRoutine( + __in_opt PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine = NULL, + __in_opt WDFCONTEXT CompletionContext = NULL + ) + { + m_CompletionRoutine.m_Completion = CompletionRoutine; + m_TargetCompletionContext = CompletionContext; + } + + PFN_WDF_REQUEST_COMPLETION_ROUTINE + ClearCompletionRoutine( + VOID + ) + { + PFN_WDF_REQUEST_COMPLETION_ROUTINE pRoutine; + + pRoutine = m_CompletionRoutine.m_Completion; + m_CompletionRoutine.m_Completion = NULL; + + return pRoutine; + } + + WDFCONTEXT + ClearCompletionContext( + VOID + ) + { + WDFCONTEXT pContext; + + pContext = m_TargetCompletionContext; + m_TargetCompletionContext = NULL; + + return pContext; + } + + __inline + BOOLEAN + IsCompletionRoutineSet( + VOID + ) + { + return (m_CompletionRoutine.m_Completion != NULL) ? + TRUE : FALSE; + } + + __inline + BOOLEAN + IsCancelRoutineSet( + VOID + ) + { + return (m_CancelRoutine.m_Cancel != NULL) ? + TRUE : FALSE; + } + + __inline + FxRequestContext* + GetContext( + VOID + ) + { + return m_RequestContext; + } + + __inline + VOID + SetContext( + __in FxRequestContext* RequestContext = NULL + ) + { + // + // If we are setting to the same value, just return + // + if (m_RequestContext == RequestContext) { + return; + } + + // + // If we are changing the context to another unique pointer, free the + // old context. + // + if (m_RequestContext != NULL) { + delete m_RequestContext; + } + + m_RequestContext = RequestContext; + } + + VOID + ContextReleaseAndRestore( + VOID + ) + { + // + // This does not free the context, rather it tells the context to release + // any references it is holding and restore fields back into the PIRP + // + if (m_RequestContext != NULL && m_Irp.GetIrp() != NULL) { + m_RequestContext->ReleaseAndRestore(this); + VerifierClearFormatted(); + } + } + + __inline + VOID + EnableContextDisposeNotification( + VOID + ) + { + MarkDisposeOverride(); + } + + __inline + BOOLEAN + HasContextType( + __in FX_REQUEST_CONTEXT_TYPE Type + ) + { + return (m_RequestContext != NULL && + m_RequestContext->m_RequestType == Type) ? TRUE : FALSE; + } + + __inline + HasContext( + VOID + ) + { + return (m_RequestContext != NULL && + m_RequestContext->m_RequestType != + FX_REQUEST_CONTEXT_TYPE_NONE) ? TRUE : FALSE; + } + + __inline + MdIrp + GetSubmitIrp( + VOID + ) + { + return m_Irp.GetIrp(); + } + + __inline + FxIrp* + GetSubmitFxIrp( + VOID + ) + { + return &m_Irp; + } + + MdIrp + SetSubmitIrp( + __in_opt MdIrp NewIrp, + __in BOOLEAN FreeIrp = TRUE + ); + + __inline + BOOLEAN + CanComplete( + VOID + ) + { + LONG count; + count = InterlockedDecrement(&m_IrpCompletionReferenceCount); + ASSERT(count >= 0); + return count == 0 ? TRUE : FALSE; + } + + VOID + CompleteSubmitted( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + ValidateTarget( + __in FxIoTarget* Target + ); + + __inline + FxIoTarget* + GetTarget( + VOID + ) + { + return m_Target; + } + + VOID + __inline + SetTarget( + __in FxIoTarget* Target + ) + { + m_Target = Target; + } + + __inline + UCHAR + GetTargetFlags( + VOID + ) + { + // Assumes caller is holding appropriate lock + return m_TargetFlags; + } + + __inline + VOID + SetTargetFlags( + __in UCHAR Flags + ) + { + // Assumes caller is holding appropriate lock + m_TargetFlags |= Flags; + } + + __inline + ULONG + ClearTargetFlags( + __in UCHAR Flags + ) + { + ULONG oldFlags; + + oldFlags = m_TargetFlags; + + // Assumes caller is holding appropriate lock + m_TargetFlags &= ~Flags; + + return oldFlags; + } + + __inline + VOID + SetRequestBaseFlags( + __in UCHAR Flags + ) + { + // Assumes caller is holding appropriate lock + m_RequestBaseFlags|= Flags; + } + + SHORT + GetVerifierFlagsLocked( + VOID + ) + { + ASSERT(GetDriverGlobals()->FxVerifierOn); + return m_VerifierFlags; + } + + __inline + SHORT + GetVerifierFlags( + VOID + ) + { + SHORT flags; + KIRQL irql; + + Lock(&irql); + flags = GetVerifierFlagsLocked(); + Unlock(irql); + + return flags; + } + + __inline + VOID + SetVerifierFlagsLocked( + __in SHORT Flags + ) + { + m_VerifierFlags |= Flags; + } + + __inline + VOID + SetVerifierFlags( + __in SHORT Flags + ) + { + KIRQL irql; + + ASSERT(GetDriverGlobals()->FxVerifierOn); + + Lock(&irql); + SetVerifierFlagsLocked(Flags); + Unlock(irql); + } + + __inline + VOID + ClearVerifierFlagsLocked( + __in SHORT Flags + ) + { + m_VerifierFlags &= ~Flags; + } + + __inline + VOID + ClearVerifierFlags( + __in SHORT Flags + ) + { + KIRQL irql; + + ASSERT(GetDriverGlobals()->FxVerifierOn); + + Lock(&irql); + ClearVerifierFlagsLocked(Flags); + Unlock(irql); + } + + __inline + VOID + VerifierSetFormatted( + VOID + ) + { + if (GetDriverGlobals()->FxVerifierOn && + GetDriverGlobals()->FxVerifierIO) { + SetVerifierFlags(FXREQUEST_FLAG_FORMATTED); + } + } + + __inline + VOID + VerifierClearFormatted( + VOID + ) + { + if (GetDriverGlobals()->FxVerifierOn && + GetDriverGlobals()->FxVerifierIO) { + ClearVerifierFlags(FXREQUEST_FLAG_FORMATTED); + } + } + + __inline + BOOLEAN + VerifierIsFormatted( + VOID + ) + { + if (GetDriverGlobals()->FxVerifierOn && + GetDriverGlobals()->FxVerifierIO) { + return (GetVerifierFlags() & FXREQUEST_FLAG_FORMATTED) ? TRUE : FALSE; + } + else { + // + // we are not tracking the state + // + return TRUE; + } + } + + __inline + BOOLEAN + ShouldClearContext( + VOID + ) + { + return (m_RequestBaseFlags & FxRequestBaseSyncCleanupContext) ? TRUE + : FALSE; + } + + _Must_inspect_result_ + NTSTATUS + CreateTimer( + VOID + ); + + VOID + StartTimer( + __in LONGLONG Timeout + ); + + _Must_inspect_result_ + BOOLEAN + CancelTimer( + VOID + ); + + BOOLEAN + Cancel( + VOID + ); + + BOOLEAN + __inline + IsAllocatedFromIo( + VOID + ) + { + return m_IrpAllocation == REQUEST_ALLOCATED_FROM_IO ? TRUE : FALSE; + } + + BOOLEAN + __inline + IsAllocatedDriver( + VOID + ) + { + return m_IrpAllocation == REQUEST_ALLOCATED_DRIVER ? TRUE : FALSE; + } + + BOOLEAN + __inline + IsCanComplete( + VOID + ) + { + return m_CanComplete; + } + + __inline + VOID + SetCompleted( + __in BOOLEAN Value + ) + { + m_Completed = Value; + } + + VOID + __inline + SetPriorityBoost( + CCHAR PriorityBoost + ) + { + m_PriorityBoost = PriorityBoost; + } + + CCHAR + __inline + GetPriorityBoost( + VOID + ) + { + return m_PriorityBoost; + } + + + + + + + + + + + + + + + __inline + WDFREQUEST + GetHandle( + VOID + ) + { + return (WDFREQUEST) GetObjectHandle(); + } + + __inline + static + FxRequestBase* + _FromListEntry( + __in PLIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxRequestBase, m_ListEntry); + } + + __inline + static + FxRequestBase* + _FromDrainEntry( + __in PSINGLE_LIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxRequestBase, m_DrainSingleEntry); + } + + + __inline + static + FxRequestBase* + _FromCsqContext( + __in PMdIoCsqIrpContext Context + ) + { + return CONTAINING_RECORD(Context, FxRequestBase, m_CsqContext); + } + + __inline + PVOID + GetTraceObjectHandle( + VOID + ) + { + PVOID handle; + + handle = GetObjectHandle(); + + if (handle != NULL) { + return handle; + } + else { + return (PVOID) this; + } + } + + VOID + FreeMdls( + VOID + ); + + __declspec(noreturn) + VOID + FatalError( + __in NTSTATUS Status + ); + + VOID + ClearFieldsForReuse( + VOID + ); + +protected: + FxRequestBase( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in_opt MdIrp Irp, + __in FxRequestIrpOwnership Ownership, + __in FxRequestConstructorCaller Caller, + __in FxObjectType ObjectType = FxObjectTypeExternal + ); + + virtual + ~FxRequestBase( + VOID + ); + + // Do not specify argument names + FX_DECLARE_VF_FUNCTION( + VOID, + VerifyDispose + ); + + // FxObject overrides + virtual + BOOLEAN + Dispose( + VOID + ); + + static + MdDeferredRoutineType _TimerDPC; + + VOID + CompleteSubmittedNoContext( + VOID + ); + + VOID + ZeroOutDriverContext( + VOID + ) + { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + RtlZeroMemory(GetSubmitFxIrp()->GetDriverContext(), + GetSubmitFxIrp()->GetDriverContextSize()); +#else + // + // UMDF host doesn't expose any easier way to zero out the contexts so + // set context to NULL one by one. + // + GetSubmitFxIrp()->SetContext(0, NULL); + GetSubmitFxIrp()->SetContext(1, NULL); + GetSubmitFxIrp()->SetContext(2, NULL); + GetSubmitFxIrp()->SetContext(3, NULL); +#endif + } + +public: + + union { + // + // The cancel safe queues use this context to identify + // the request in a race free manner. + // + MdIoCsqIrpContext m_CsqContext; + + // + // IoTargets uses this to track the request when it is sent to the target. + // Since the request cannot be on an CSQ and sent to a target at the + // same time, we can unionize this with the CSQ context. + // + LIST_ENTRY m_ListEntry; + }; + + union { + // + // IoTargest uses this when it needs to create a list of requests to cancel + // when making a state transition + // + SINGLE_LIST_ENTRY m_DrainSingleEntry; + + // + // If TRUE, the driver formatted the request by copying the current stack + // location to next or by manually passing in an IO_STACK_LOCATION. This + // is union'ed with m_DrainSingleEntry b/c it is only relevant during + // send and forget and the request is never enqueued on the target in + // this case and m_DrainSingleEntry is used when tracking requests sent + // on a target for cancelation due to a target state change. + // + BOOLEAN m_NextStackLocationFormatted; + }; + +protected: + // + // The NT IRP is wrapped by a frameworks FxIrp + // + // Note: If m_Irp is NULL after initialization, this means + // the IRP was cancelled by a FxIrpQueue cancellation + // callback, or completed. + // + FxIrp m_Irp; + + // + // Target of the request. Access to this field is unguarded. The following + // have access to this field + // o The owning target itself + // o _TimerDPC() + // o Cancel() IFF it has successfully incremented the irp completion ref count + // + FxIoTarget* m_Target; + + FxRequestContext* m_RequestContext; + + + + + FxRequestTimer* m_Timer; + + // + // Client driver completion routine to call when the request has come back + // from the target device. + // + FxRequestCancelCallback m_CancelRoutine; + + FxRequestCompletionCallback m_CompletionRoutine; + + // + // Context to pass to CompletionRoutine when called + // + WDFCONTEXT m_TargetCompletionContext; + + // + // Synchronization for this field is through Interlocked operations + // + LONG m_IrpCompletionReferenceCount; + + // + // Access to flags guarded by FxIoTarget::Lock + // + // Values defined in the enum FxRequestTargetFlags + // + union { + UCHAR m_TargetFlags; + + // + // These are used purely for debugging, not in live code anywhere! + // NOTE: if FxRequestTargetFlagschanges, so this this union + // + struct { + UCHAR Completed : 1; + UCHAR FlagsPended : 1; + UCHAR TimerSet : 1; + UCHAR CancelledFromTimer : 1; + UCHAR IgnoreState : 1; + } m_TargetFlagsByName; + }; + + // + // Contains a value from the enum type FxRequestAllocationSource describing + // how the irp was allocated + // + UCHAR m_IrpAllocation; + + BOOLEAN m_Completed; + + BOOLEAN m_Canceled; + + WDFOBJECT_OFFSET_ALIGNED m_SystemBufferOffset; + + union { + // + // These are flags used by verifier. Set with values from the enum + // FxRequestVerifierFlags + // + SHORT m_VerifierFlags; + + struct { + SHORT DriverOwned : 1; + SHORT TagRequest : 1; + SHORT Forwarded : 1; + SHORT DriverDispatch : 1; + SHORT DriverCancelable : 1; + SHORT DriverInprocessContext : 1; + SHORT Cancelled : 1; + SHORT Formatted : 1; + SHORT SentToTarget : 1; + SHORT DriverInEvtIoStopContext : 1; + } m_VeriferFlagsByName; + }; + + // + // If this is !=0, its an indication of outstanding references + // on WDM IRP fields such as any system buffers. + // + LONG m_IrpReferenceCount; + + // This field !=NULL if the request is on an IrpQueue. + FxIrpQueue* m_IrpQueue; + + WDFOBJECT_OFFSET_ALIGNED m_OutputBufferOffset; + + union { + // + // Bit field. Set with values from the enum FxRequestBaseFlags + // + UCHAR m_RequestBaseFlags; + + struct { + UCHAR SystemMdlMapped : 1; + UCHAR OutputMdlMapped : 1; + UCHAR SyncCleanupContext : 1; + } m_RequestBaseFlagsByName; + }; + + union { + // + // Bit field. Set with values from the enum FxRequestBaseStaticFlags + // + + // + UCHAR m_RequestBaseStaticFlags; + + struct { + UCHAR SystemBufferValid : 1; + UCHAR OutputBufferValid : 1; + } m_RequestBaseStaticFlagsByName; + }; + + // + // Priority boost. + // + CCHAR m_PriorityBoost; + + // + // Contains values from FxRequestCompletionState + // + BYTE m_CompletionState; + + // + // TRUE, request can be completed by the driver. + // + BOOLEAN m_CanComplete; + + // + // If !=NULL, MDL allocated and assocated with the request + // + PMDL m_AllocatedMdl; +}; + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#include "FxRequestBaseKm.hpp" +#else if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#include "FxRequestBaseUm.hpp" +#endif + + +#endif // _FXREQUESTBASE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbuffer.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbuffer.hpp new file mode 100644 index 00000000000..15cd88f0e39 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestbuffer.hpp @@ -0,0 +1,157 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRequestBuffer.hpp + +Abstract: + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXREQUESTBUFFER_H_ +#define _FXREQUESTBUFFER_H_ + +enum FxRequestBufferType { + FxRequestBufferUnspecified, + FxRequestBufferMemory, // framework managed memory + FxRequestBufferMdl, // raw MDL + FxRequestBufferBuffer, // raw PVOID + FxRequestBufferReferencedMdl, // MDL belonging to a FxMemoryObject +}; + +enum FxValidateMemoryDescriptorFlags { + MemoryDescriptorNullAllowed = 0x1, + MemoryDescriptorNoBufferAllowed = 0x2, +}; + +struct FxRequestBuffer { +public: + FxRequestBuffer(VOID); + + NTSTATUS + ValidateMemoryDescriptor( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_MEMORY_DESCRIPTOR Descriptor, + __in ULONG Flags = 0x0 + ); + + VOID + SetMemory( + __in IFxMemory* Memory, + __in PWDFMEMORY_OFFSET Offsets + ); + + VOID + SetMdl( + __in PMDL Mdl, + __in ULONG Length + ); + + __inline + VOID + SetBuffer( + __in PVOID Buffer, + __in ULONG Length + ) + { + DataType = FxRequestBufferBuffer; + u.Buffer.Buffer = Buffer; + u.Buffer.Length = Length; + } + + __inline + BOOLEAN + HasMdl( + VOID + ) + { + return (DataType == FxRequestBufferMdl || + DataType == FxRequestBufferReferencedMdl) ? TRUE : FALSE; + } + + ULONG + GetBufferLength( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + GetBuffer( + __deref_out PVOID* Buffer + ); + + _Must_inspect_result_ + NTSTATUS + GetOrAllocateMdl( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __deref_out_opt PMDL* Mdl, + __inout PMDL* MdlToFree, + __inout PBOOLEAN UnlockWhenFreed, + __in LOCK_OPERATION Operation, + __in BOOLEAN ReuseMdl = FALSE, + __inout_opt size_t* SizeOfMdl = NULL + ); + + NTSTATUS + GetOrAllocateMdlWorker( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __deref_out PMDL* Mdl, + __in BOOLEAN * ReuseMdl, + __in LONG Length, + __in PVOID Buffer, + __inout size_t* SizeOfMdl, + __in BOOLEAN UnlockWhenFreed, + __deref_out_opt PMDL* MdlToFree + ); + + VOID + AssignValues( + __deref_out_opt PVOID* PPBuffer, + __deref_out_opt PMDL* PPMdl, + __out PULONG BufferLength + ); + +public: + FxRequestBufferType DataType; + + union { + struct { + IFxMemory* Memory; + PWDFMEMORY_OFFSET Offsets; + } Memory; + struct { + PMDL Mdl; + ULONG Length; + } Mdl; + struct { + PVOID Buffer; + ULONG Length; + } Buffer; + struct { + IFxMemory* Memory; + PWDFMEMORY_OFFSET Offsets; + PMDL Mdl; + } RefMdl; + } u; +}; + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#include "FxRequestBufferKm.hpp" +#else if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#include "FxRequestBufferUm.hpp" +#endif + + +#endif // _FXREQUESTBUFFER_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcallbacks.hpp new file mode 100644 index 00000000000..a7fa37c1f16 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcallbacks.hpp @@ -0,0 +1,99 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoQueueCallbacks.h + +Abstract: + + This module implements the I/O package queue object callbacks + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXREQUESTCALLBACKS_H_ +#define _FXREQUESTCALLBACKS_H_ + + +// +// Delegate which contains EvtRequestCancel +// +class FxRequestCancelCallback : public FxCallback { + +public: + PFN_WDF_REQUEST_CANCEL m_Cancel; + + FxRequestCancelCallback( + VOID + ) + { + m_Cancel = NULL; + } + + void + InvokeCancel( + __in FxCallbackLock* Lock, + __in WDFREQUEST Request + ) + { + if (m_Cancel != NULL) { + PFN_WDF_REQUEST_CANCEL pMethod; + KIRQL irql; + + // + // Satisfy W4 warning, even though it is technically not necessary to + // assign an initial value. + // + irql = PASSIVE_LEVEL; + + if (Lock != NULL) { + Lock->Lock(&irql); + } + + // + // Clear the value before invoking the routine since the assignment + // is invalidated when the routine is run. + // + pMethod = m_Cancel; + m_Cancel = NULL; + + pMethod(Request); + + if (Lock != NULL) { + Lock->Unlock(irql); + } + } + } +}; + +// +// Delegate which contains EvtRequestCompletion +// +class FxRequestCompletionCallback : public FxCallback { + +public: + PFN_WDF_REQUEST_COMPLETION_ROUTINE m_Completion; + + FxRequestCompletionCallback( + VOID + ) + { + m_Completion = NULL; + } +}; + + +#endif // _FXREQUESTCALLBACKS_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcontext.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcontext.hpp new file mode 100644 index 00000000000..43e2949a9ad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcontext.hpp @@ -0,0 +1,156 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxRequestContext.hpp + +Abstract: + + Defines the base structure for contexts associated with FxRequest + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXREQUESTCONTEXT_H_ +#define _FXREQUESTCONTEXT_H_ + +typedef UCHAR FX_REQUEST_CONTEXT_TYPE; + +// +// IO_STACK_LOCATION::Parameters.Others.Argument3 is taken up by the IOCTL +// value, so there are only 3 +// +#define FX_REQUEST_NUM_OTHER_PARAMS (3) + +// +// Here are all the derivations off of FxRequestContext +// +// FxIoContext +// FxInternalIoctlOthersContext +// FxUsbRequestContext +// +FxUsbDeviceVendorContext +// +FxUsbDeviceStatusContext +// +FxUsbDeviceFeatureContext +// +FxUsbPipeTransferContext +// +FxUsbUrbContext +// +FxUsbPipeRequestContext +// +FxUsbPipeControlTransferContext +// + +typedef struct _FxInternalIoctlParams{ + WDFMEMORY Argument1; + WDFMEMORY Argument2; + WDFMEMORY Argument4; +}FxInternalIoctlParams,*pFxInternalIoctlParams; + +struct FxRequestContext : public FxStump { + + FxRequestContext( + __in FX_REQUEST_CONTEXT_TYPE Type + ); + + virtual + ~FxRequestContext( + VOID + ); + + virtual + VOID + Dispose( + VOID + ) + {} + + virtual + VOID + StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ); + + virtual + VOID + ReleaseAndRestore( + __in FxRequestBase* Request + ); + + __inline + BOOLEAN + IsType( + __in FX_REQUEST_CONTEXT_TYPE Type + ) + { + return m_RequestType == Type; + } + + virtual + VOID + CopyParameters( + __in FxRequestBase* Request + ) + { + UNREFERENCED_PARAMETER(Request); + } + + VOID + FormatWriteParams( + __in_opt IFxMemory* WriteMemory, + __in_opt PWDFMEMORY_OFFSET WriteOffsets + ); + + VOID + FormatReadParams( + __in_opt IFxMemory* ReadMemory, + __in_opt PWDFMEMORY_OFFSET ReadOffsets + ); + + VOID + FormatOtherParams( + __in FxInternalIoctlParams *InternalIoctlParams + ); + +protected: + static + VOID + _StoreAndReferenceMemoryWorker( + __in PVOID Tag, + __deref_out_opt IFxMemory** PPMemory, + __in FxRequestBuffer* Buffer + ); + + VOID + __inline + InitCompletionParams( + VOID + ) + { + WDF_REQUEST_COMPLETION_PARAMS_INIT(&m_CompletionParams); + m_CompletionParams.Type = WdfRequestTypeNoFormat; + } + +public: + WDF_REQUEST_COMPLETION_PARAMS m_CompletionParams; + + // + // Memory associated with the context that will be released when the + // FxRequestBase has been completed by the target. + // + IFxMemory* m_RequestMemory; + + // + // RTTI replacement + // + FX_REQUEST_CONTEXT_TYPE m_RequestType; +}; + +#endif // _FXREQUESTCONTEXT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcontexttypes.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcontexttypes.h new file mode 100644 index 00000000000..5c9a2bcf5a8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestcontexttypes.h @@ -0,0 +1,27 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXREQUESTCONTEXTTYPES_H_ +#define _FXREQUESTCONTEXTTYPES_H_ + +// +// Current typedef for a FX_REQUEST_CONTEXT_TYPE is a byte big +// +#define USB_BASE (0x10) + +// +// FX_REQUEST_CONTEXT_TYPE_Xxx is very long. Just use FX_RCT_Xxx instead. +// +enum FxRequestContextTypes { + FX_REQUEST_CONTEXT_TYPE_NONE = 0x00, + FX_RCT_IO = 0x01, + FX_RCT_INTERNAL_IOCTL_OTHERS = 0x02, + FX_RCT_USB_PIPE_XFER = USB_BASE+0x00, + FX_RCT_USB_URB_REQUEST = USB_BASE+0x01, + FX_RCT_USB_PIPE_REQUEST = USB_BASE+0x02, + FX_RCT_USB_CONTROL_REQUEST = USB_BASE+0x03, + FX_RCT_USB_STRING_REQUEST = USB_BASE+0x04, +}; + + +#endif // _FXREQUESTCONTEXTTYPES_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestmemory.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestmemory.hpp new file mode 100644 index 00000000000..1b51cfbf69b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestmemory.hpp @@ -0,0 +1,124 @@ + +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRequestMemory.hpp + +Abstract: + + This is the memory object for FxRequest that is sized, and + allows checking for read/write access. + + It's reference lifetime is tied with IRP completion in + FxRequest. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXREQUESTMEMORY_H_ +#define _FXREQUESTMEMORY_H_ + +class FxRequestMemory : public FxMemoryBufferPreallocated { +public: + + // Factory function + static + NTSTATUS + Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out FxRequestMemory** Object + ); + + FxRequestMemory( + __in PFX_DRIVER_GLOBALS Globals + ); + + // begin end FxMemoryObject + virtual + PVOID + GetBuffer( + VOID + ); + + _Must_inspect_result_ + virtual + PMDL + GetMdl( + VOID + ); + + virtual + USHORT + GetFlags( + VOID + ) + { + return m_Flags; + } + // end FxMemoryObject overrides + + VOID + SetBuffer( + _In_ FxRequest* Request, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) PVOID Buffer, + _In_ PMDL BackingMdl, + _In_ size_t BufferSize, + _In_ BOOLEAN ReadOnly + ); + + VOID + SetMdl( + __in FxRequest* Request, + __in PMDL Mdl, + __in PVOID MdlBuffer, + __in size_t BufferSize, + __in BOOLEAN ReadOnly + ); + + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ); + + ~FxRequestMemory( + VOID + ); + +protected: + VOID + SetFlags( + __in USHORT Flags + ) + { + m_Flags = Flags; + } + +protected: + + FxRequest* m_Request; + + // + // The m_Mdl is owned by this object and it must be freed by the this object. + // + PMDL m_Mdl; + + USHORT m_Flags; +}; + +#endif // _FXREQUESTMEMORY_H_ + + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestvalidatefunctions.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestvalidatefunctions.hpp new file mode 100644 index 00000000000..4f562ee0cf2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxrequestvalidatefunctions.hpp @@ -0,0 +1,163 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxValidateFunctions.h + +Abstract: + + Split from FxValidateFunctions.hpp + (FxValidateFunctions.hpp has moved to shared\inc) + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ +#ifndef _FXREQUESTVALIDATEFUNCTIONS_HPP_ +#define _FXREQUESTVALIDATEFUNCTIONS_HPP_ + +#if defined(EVENT_TRACING) +extern "C" { +#include "FxRequestValidateFunctions.hpp.tmh" +} +#endif + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#define WDF_REQUEST_SEND_OPTIONS_VALID_FLAGS \ + (WDF_REQUEST_SEND_OPTION_TIMEOUT | \ + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | \ + WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE | \ + WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET) + +#else // (FX_CORE_MODE == FX_CORE_USER_MODE) +#define WDF_REQUEST_SEND_OPTIONS_VALID_FLAGS \ + (WDF_REQUEST_SEND_OPTION_TIMEOUT | \ + WDF_REQUEST_SEND_OPTION_SYNCHRONOUS | \ + WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE | \ + WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET | \ + WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT | \ + WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE) +#endif + +NTSTATUS +__inline +FxValidateRequestOptions( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ PWDF_REQUEST_SEND_OPTIONS Options, + _In_opt_ FxRequestBase* Request = NULL + ) +{ + if (Options == NULL) { + return STATUS_SUCCESS; + } + + if (Options->Size != sizeof(WDF_REQUEST_SEND_OPTIONS)) { + // + // Size is wrong, bale out + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Options %p Size incorrect, expected %d, got %d", + Options, sizeof(WDF_REQUEST_SEND_OPTIONS), + Options->Size); + + return STATUS_INFO_LENGTH_MISMATCH; + } + + if ((Options->Flags & ~WDF_REQUEST_SEND_OPTIONS_VALID_FLAGS) != 0) { + // + // Invalid flags + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Options %p Flags 0x%x invalid, valid mask is 0x%x", + Options, Options->Flags, + WDF_REQUEST_SEND_OPTIONS_VALID_FLAGS); + + return STATUS_INVALID_PARAMETER; + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + UNREFERENCED_PARAMETER(Request); + + if ((Options->Flags & WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET) && + (Options->Flags & ~WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET)) { + // + // If WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET is set, no other bits + // can be set. + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Options %p, if WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET (0x%x) is " + "set, no other Flags 0x%x can be set", + Options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET, Options->Flags); + + return STATUS_INVALID_PARAMETER; + } + +#else // FX_CORE_USER_MODE + + if ((Options->Flags & WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET) && + (Options->Flags & ~(WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET | + WDF_REQUEST_SEND_OPTION_IMPERSONATION_FLAGS))) { + // + // If WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET is set, no other bits + // can be set except impersonation flags. + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Options %p, if WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET (0x%x) is " + "set, no other Flags 0x%x can be set except impersonation flags " + "%!status!", + Options, WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET, Options->Flags, + STATUS_INVALID_PARAMETER); + + return STATUS_INVALID_PARAMETER; + } + + // + // Verify the send option flags. + // + if ((Options->Flags & WDF_REQUEST_SEND_OPTION_IMPERSONATION_FLAGS) != 0) { + // + // The request must be a create request (which also means it can never + // be a driver-created request). + // + if (Request == NULL || + Request->IsAllocatedFromIo() == FALSE || + Request->GetSubmitFxIrp()->GetMajorFunction() != IRP_MJ_CREATE) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "WDF_REQUEST_SEND_OPTION impersonation flags may only " + "be set on Create requests. %!status!", + STATUS_INVALID_PARAMETER); + + return STATUS_INVALID_PARAMETER; + } + + if ((Options->Flags & WDF_REQUEST_SEND_OPTION_IMPERSONATION_IGNORE_FAILURE) != 0 && + (Options->Flags & WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT) == 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Driver must set WDF_REQUEST_SEND_OPTION_IMPERSONATION_" + "IGNORE_FAILURE with WDF_REQUEST_SEND_OPTION_IMPERSONATE_CLIENT." + " %!status!", STATUS_INVALID_PARAMETER); + + return STATUS_INVALID_PARAMETER; + } + } + +#endif // FX_CORE_MODE + + return STATUS_SUCCESS; +} + +#endif // _FXREQUESTVALIDATEFUNCTIONS_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxresource.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxresource.hpp new file mode 100644 index 00000000000..05d81554e18 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxresource.hpp @@ -0,0 +1,749 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxResource.hpp + +Abstract: + + This module implements the resource object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXRESOURCE_H_ +#define _FXRESOURCE_H_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxResource.hpp.tmh" +#endif + +} + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + +struct FxRegisterResourceInfo : FxStump { + // + // start physical address of resource range assigned by pnp + // + PHYSICAL_ADDRESS m_StartPa; + + // + // start of mapped system base address + // + PVOID m_StartSystemVa; + + // + // end of mapped system base address + // + PVOID m_EndSystemVa; + + // + // user-mode mapped address + // + PVOID m_StartUsermodeVa; + + // + // Length of resource range assigned by pnp + // + SIZE_T m_Length; + + // + // Length of mapped resource range + // + SIZE_T m_MappedLength; + + static + NTSTATUS + _CreateAndInit( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_ ULONG Count, + _Out_ FxRegisterResourceInfo** RegisterTable + ) + { + NTSTATUS status; + FxRegisterResourceInfo* table; + + ASSERT(RegisterTable != NULL); + *RegisterTable = NULL; + + table = new (DriverGlobals) FxRegisterResourceInfo[Count]; + if (table == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to allocate Resource table %!STATUS!", status); + return status; + } + + *RegisterTable = table; + status = STATUS_SUCCESS; + + return status; + } + + FxRegisterResourceInfo( + VOID + ): + m_StartSystemVa(NULL), + m_EndSystemVa(NULL), + m_StartUsermodeVa(NULL), + m_Length(0), + m_MappedLength(0) + { + m_StartPa.QuadPart = 0; + }; + + ~FxRegisterResourceInfo(){;}; + + VOID + SetPhysicalAddress( + __in PHYSICAL_ADDRESS StartPa, + __in SIZE_T Length + ) + { + m_StartPa = StartPa; + m_Length = Length; + } + + VOID + SetMappedAddress( + __in PVOID SystemBaseAddress, + __in SIZE_T MappedLength, + __in PVOID UsermodeBaseAddress + ) + { + m_StartSystemVa = SystemBaseAddress; + m_MappedLength = MappedLength; + m_EndSystemVa = ((PUCHAR) m_StartSystemVa) + MappedLength - 1; + m_StartUsermodeVa = UsermodeBaseAddress; + }; + + VOID + ClearMappedAddress( + VOID + ) + { + m_StartSystemVa = NULL; + m_EndSystemVa = NULL; + m_StartUsermodeVa = NULL; + m_MappedLength = 0; + }; + +}; + +struct FxPortResourceInfo : FxStump { + // + // start physical address + // + PHYSICAL_ADDRESS m_StartPa; + + // + // end physical address + // + PHYSICAL_ADDRESS m_EndPa; + + // + // Length of resource + // + SIZE_T m_Length; + + static + NTSTATUS + _CreateAndInit( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_ ULONG Count, + _Out_ FxPortResourceInfo** PortTable + ) + { + NTSTATUS status; + FxPortResourceInfo* table; + + ASSERT(PortTable != NULL); + *PortTable = NULL; + + table = new (DriverGlobals) FxPortResourceInfo[Count]; + if (table == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to allocate Resource table %!STATUS!", status); + return status; + } + + *PortTable = table; + status = STATUS_SUCCESS; + + return status; + } + + FxPortResourceInfo( + VOID + ): + m_Length(0) + { + m_StartPa.QuadPart = 0; + m_EndPa.QuadPart = 0; + }; + + ~FxPortResourceInfo(){;}; + + VOID + SetPhysicalAddress( + __in PHYSICAL_ADDRESS StartPa, + __in SIZE_T Length + ) + { + m_StartPa = StartPa; + m_EndPa.QuadPart = StartPa.QuadPart + Length - 1; + m_Length = Length; + } +}; + +#endif + +// +// Used in FilterResourceRequirements, and QueryResourceRequirements +// + +class FxResourceIo : public FxObject { +public: + IO_RESOURCE_DESCRIPTOR m_Descriptor; + + // + // Clone of m_Descriptor which is returned to the driver writer when it + // requests a descriptor pointer. We clone the descriptor so that if the + // driver writer attempts to modify the pointer in place, they modify the + // clone and not the real descriptor. + // + IO_RESOURCE_DESCRIPTOR m_DescriptorClone; + +public: + FxResourceIo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PIO_RESOURCE_DESCRIPTOR Resource + ) : FxObject(FX_TYPE_RESOURCE_IO, 0, FxDriverGlobals) + { + RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor)); + } + + DECLARE_INTERNAL_NEW_OPERATOR(); +}; + +// +// Used in StartDevice +// +class FxResourceCm : public FxObject { +public: + CM_PARTIAL_RESOURCE_DESCRIPTOR m_Descriptor; + + // + // Clone of m_Descriptor which is returned to the driver writer when it + // requests a descriptor pointer. We clone the descriptor so that if the + // driver writer attempts to modify the pointer in place, they modify the + // clone and not the real descriptor. + // + CM_PARTIAL_RESOURCE_DESCRIPTOR m_DescriptorClone; + +public: + FxResourceCm( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Resource + ) : FxObject(FX_TYPE_RESOURCE_CM, 0, FxDriverGlobals) + { + RtlCopyMemory(&m_Descriptor, Resource, sizeof(m_Descriptor)); + } + + DECLARE_INTERNAL_NEW_OPERATOR(); +}; + +enum FxResourceAccessFlags { + FxResourceNoAccess = 0x0000, + FxResourceAddAllowed = 0x0001, + FxResourceRemoveAllowed = 0x0002, + FxResourceAllAccessAllowed = FxResourceAddAllowed | FxResourceRemoveAllowed, +}; + +class FxResourceCollection : public FxCollection { +protected: + FxResourceCollection( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFTYPE Type, + __in USHORT Size, + __in UCHAR AccessFlags = FxResourceNoAccess + ) : FxCollection(FxDriverGlobals, Type, Size), + m_AccessFlags(AccessFlags), m_Changed(FALSE) + { + // + // Driver cannot delete this or any of its derivations + // + MarkNoDeleteDDI(); + } + +public: + + BOOLEAN + RemoveAndDelete( + __in ULONG Index + ); + + _Must_inspect_result_ + NTSTATUS + AddAt( + __in ULONG Index, + __in FxObject* Object + ); + + BOOLEAN + IsRemoveAllowed( + VOID + ) + { + return FLAG_TO_BOOL(m_AccessFlags, FxResourceRemoveAllowed); + } + + BOOLEAN + IsAddAllowed( + VOID + ) + { + return FLAG_TO_BOOL(m_AccessFlags, FxResourceAddAllowed); + } + + VOID + MarkChanged( + VOID + ) + { + m_Changed = TRUE; + } + + BOOLEAN + IsChanged( + VOID + ) + { + return m_Changed; + } + +public: + UCHAR m_AccessFlags; + + BOOLEAN m_Changed; +}; + +class FxCmResList : public FxResourceCollection { + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) +protected: + // + // Table of mapped register resources + // + FxRegisterResourceInfo* m_RegisterResourceTable; + ULONG m_RegisterResourceTableSizeCe; + + // + // Table of port resources + // + FxPortResourceInfo* m_PortResourceTable; + ULONG m_PortResourceTableSizeCe; + + // + // TRUE if we have at least one CmResourceTypeConnection resource. + // + BOOLEAN m_HasConnectionResources; + + // + // Lock to serialize access to port/register resource table + // + MxLock m_ResourceTableLock; + +#endif // FX_CORE_USER_MODE + +protected: + FxCmResList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in UCHAR AccessFlags + ) : FxResourceCollection(FxDriverGlobals, + FX_TYPE_CM_RES_LIST, + sizeof(FxCmResList), + AccessFlags) + { +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + m_RegisterResourceTable = NULL; + m_PortResourceTable = NULL; + m_RegisterResourceTableSizeCe = 0; + m_PortResourceTableSizeCe = 0; + m_HasConnectionResources = FALSE; +#endif // FX_CORE_USER_MODE + } + + ~FxCmResList(); + +public: + static + _Must_inspect_result_ + NTSTATUS + _CreateAndInit( + __in FxCmResList** ResourceList, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice * Device, + __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes, + __in UCHAR AccessFlags + ) + { + NTSTATUS ntStatus; + FxCmResList *resList = NULL; + + UNREFERENCED_PARAMETER(Device); + + // + // Initialize + // + *ResourceList = NULL; + + // + // Allocate a new resource list object + // + resList = new(FxDriverGlobals, ListAttributes) + FxCmResList(FxDriverGlobals, AccessFlags); + + if (resList == NULL) { + + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, + TRACINGDEVICE, + "Failed to allocate FxCmResList, " + "returning %!STATUS!", + ntStatus); + goto exit; + } + + *ResourceList = resList; + ntStatus = STATUS_SUCCESS; + + exit: + if (!NT_SUCCESS(ntStatus)) { + if (NULL != resList) { + resList->DeleteFromFailedCreate(); + } + } + return ntStatus; + } + + WDFCMRESLIST + GetHandle( + VOID + ) + { + return (WDFCMRESLIST) GetObjectHandle(); + } + + _Must_inspect_result_ + NTSTATUS + BuildFromWdmList( + __in PCM_RESOURCE_LIST ResourceList, + __in UCHAR AccessFlags + ); + + _Must_inspect_result_ + PCM_RESOURCE_LIST + CreateWdmList( + __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType = PagedPool + ); + + ULONG + GetCount( + VOID + ); + + PCM_PARTIAL_RESOURCE_DESCRIPTOR + GetDescriptor( + __in ULONG Index + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + // + // Lock functions used internally + // + __inline + void +#pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL") + LockResourceTable( + ) + { + KIRQL oldIrql; + + m_ResourceTableLock.Acquire(&oldIrql); + + UNREFERENCED_PARAMETER(oldIrql); + } + + __inline + void +#pragma prefast(suppress:__WARNING_UNEXPECTED_IRQL_CHANGE, "UM has no IRQL") + UnlockResourceTable( + ) + { + m_ResourceTableLock.Release(PASSIVE_LEVEL); + } + + NTSTATUS + BuildRegisterResourceTable( + VOID + ); + + NTSTATUS + BuildPortResourceTable( + VOID + ); + + VOID + UpdateRegisterResourceEntryLocked( + __in FxRegisterResourceInfo* Entry, + __in PVOID SystemMappedAddress, + __in SIZE_T NumberOfBytes, + __in PVOID UsermodeMappedAddress + ); + + VOID + ClearRegisterResourceEntryLocked( + __in FxRegisterResourceInfo* Entry + ); + + HRESULT + ValidateRegisterPhysicalAddressRange ( + __in PHYSICAL_ADDRESS PhysicalAddress, + __in SIZE_T Size, + __out FxRegisterResourceInfo** TableEntry + ); + + HRESULT + ValidateRegisterSystemBaseAddress ( + __in PVOID Address, + __out PVOID* UsermodeBaseAddress + ); + + HRESULT + ValidateRegisterSystemAddressRange ( + __in PVOID SystemAddress, + __in SIZE_T Length, + __out_opt PVOID* UsermodeAddress + ); + + HRESULT + ValidateAndClearMapping( + __in PVOID Address, + __in SIZE_T Length + ); + + HRESULT + ValidatePortAddressRange( + __in PVOID Address, + __in SIZE_T Length + ); + + SIZE_T + GetResourceLength( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + __out_opt PHYSICAL_ADDRESS* Start + ); + + HRESULT + MapIoSpaceWorker( + __in PHYSICAL_ADDRESS PhysicalAddress, + __in SIZE_T NumberOfBytes, + __in MEMORY_CACHING_TYPE CacheType, + __deref_out VOID** PseudoBaseAddress + ); + + VOID + ValidateResourceUnmap( + VOID + ); + + VOID + DeleteRegisterResourceTable( + VOID + ) + { + LockResourceTable(); + if (m_RegisterResourceTable != NULL) { + delete [] m_RegisterResourceTable; + m_RegisterResourceTable = NULL; + m_RegisterResourceTableSizeCe = 0; + } + UnlockResourceTable(); + } + + VOID + DeletePortResourceTable( + VOID + ) + { + LockResourceTable(); + if (m_PortResourceTable != NULL) { + delete [] m_PortResourceTable; + m_PortResourceTable = NULL; + m_PortResourceTableSizeCe = 0; + } + UnlockResourceTable(); + } + + _Must_inspect_result_ + NTSTATUS + CheckForConnectionResources( + VOID + ); + + BOOLEAN + HasConnectionResources( + VOID + ) + { + return m_HasConnectionResources; + } + +#endif // FX_CORE_USER_MODE + +}; + +class FxIoResReqList : public FxResourceCollection { +protected: + FxIoResReqList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in UCHAR AccessFlags = FxResourceNoAccess + ) : + FxResourceCollection(FxDriverGlobals, + FX_TYPE_IO_RES_REQ_LIST, + sizeof(FxIoResReqList), + AccessFlags), + m_SlotNumber(0), m_InterfaceType(Internal) + { + m_AccessFlags = AccessFlags; + } + +public: + + static + _Must_inspect_result_ + NTSTATUS + _CreateAndInit( + __in FxIoResReqList** ResourceReqList, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES ListAttributes, + __in UCHAR AccessFlags + ) + { + NTSTATUS ntStatus; + FxIoResReqList *resReqList = NULL; + + // + // Initialize + // + *ResourceReqList = NULL; + + // + // Allocate a new resource list object + // + resReqList = new(FxDriverGlobals, ListAttributes) + FxIoResReqList(FxDriverGlobals, AccessFlags); + if (resReqList == NULL) { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, + TRACINGDEVICE, + "Failed to allocate FxIoResReqList, " + "returning %!STATUS!", + ntStatus); + + goto exit; + } + + *ResourceReqList = resReqList; + ntStatus = STATUS_SUCCESS; + + exit: + if (!NT_SUCCESS(ntStatus)) { + if (NULL != resReqList) { + resReqList->DeleteFromFailedCreate(); + } + } + return ntStatus; + } + + WDFIORESREQLIST + GetHandle( + VOID + ) + { + return (WDFIORESREQLIST) GetObjectHandle(); + } + + static + _Must_inspect_result_ + FxIoResReqList* + _CreateFromWdmList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList, + __in UCHAR AccessFlags + ); + + _Must_inspect_result_ + PIO_RESOURCE_REQUIREMENTS_LIST + CreateWdmList( + VOID + ); + +public: + ULONG m_SlotNumber; + + INTERFACE_TYPE m_InterfaceType; +}; + +class FxIoResList : public FxResourceCollection { +public: + FxIoResList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxIoResReqList* RequirementsList + ) : + FxResourceCollection(FxDriverGlobals, FX_TYPE_IO_RES_LIST, sizeof(FxIoResList)), + m_OwningList(RequirementsList) + { + m_AccessFlags = RequirementsList->m_AccessFlags; + } + + WDFIORESLIST + GetHandle( + VOID + ) + { + return (WDFIORESLIST) GetObjectHandle(); + } + + _Must_inspect_result_ + NTSTATUS + BuildFromWdmList( + __deref_in PIO_RESOURCE_LIST* WdmResourceList + ); + +public: + FxIoResReqList* m_OwningList; +}; + +#endif // _FXRESOURCE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxselfmanagediostatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxselfmanagediostatemachine.hpp new file mode 100644 index 00000000000..0cc56e73399 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxselfmanagediostatemachine.hpp @@ -0,0 +1,245 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXSELFMANAGEDIOSTATEMACHINE_H_ +#define _FXSELFMANAGEDIOSTATEMACHINE_H_ + +// +// This is a magical number based on inspection. If the queue overflows, +// it is OK to increase these numbers without fear of either dependencies or +// weird side affects. +// +const UCHAR FxSelfManagedIoEventQueueDepth = 8; + +enum FxSelfManagedIoEvents { + SelfManagedIoEventInvalid = 0x00, + SelfManagedIoEventStart = 0x01, + SelfManagedIoEventCleanup = 0x02, + SelfManagedIoEventSuspend = 0x04, + SelfManagedIoEventFlush = 0x08, + SelfManagedIoEventNull = 0xFF, +}; + +enum FxSelfManagedIoStates { + FxSelfManagedIoInvalid = 0, + FxSelfManagedIoCreated, + FxSelfManagedIoInit, + FxSelfManagedIoInitFailed, + FxSelfManagedIoStarted, + FxSelfManagedIoSuspending, + FxSelfManagedIoStopped, + FxSelfManagedIoRestarting, + FxSelfManagedIoFailed, + FxSelfManagedIoFlushing, + FxSelfManagedIoFlushed, + FxSelfManagedIoCleanup, + FxSelfManagedIoFinal, + FxSelfManagedIoMax, +}; + +typedef +_Must_inspect_result_ +FxSelfManagedIoStates +(*PFN_SELF_MANAGED_IO_STATE_ENTRY_FUNCTION)( + __in FxSelfManagedIoMachine*, + __out PNTSTATUS Status + ); + +struct FxSelfManagedIoTargetState { + FxSelfManagedIoEvents SelfManagedIoEvent; + + FxSelfManagedIoStates SelfManagedIoState; + +#if FX_SUPER_DBG + BOOLEAN EventDebugged; +#endif +}; + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxSelfManagedIoMachineEventHistory { + struct { + FxSelfManagedIoEvents Event1 : 8; + FxSelfManagedIoEvents Event2 : 8; + FxSelfManagedIoEvents Event3 : 8; + FxSelfManagedIoEvents Event4 : 8; + FxSelfManagedIoEvents Event5 : 8; + FxSelfManagedIoEvents Event6 : 8; + FxSelfManagedIoEvents Event7 : 8; + FxSelfManagedIoEvents Event8 : 8; + } E; + + UCHAR History[FxSelfManagedIoEventQueueDepth]; +}; + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxSelfManagedIoMachineStateHistory { + struct { + FxSelfManagedIoStates State1 : 8; + FxSelfManagedIoStates State2 : 8; + FxSelfManagedIoStates State3 : 8; + FxSelfManagedIoStates State4 : 8; + FxSelfManagedIoStates State5 : 8; + FxSelfManagedIoStates State6 : 8; + FxSelfManagedIoStates State7 : 8; + FxSelfManagedIoStates State8 : 8; + } S; + + UCHAR History[FxSelfManagedIoEventQueueDepth]; +}; + +struct FxSelfManagedIoStateTable { + PFN_SELF_MANAGED_IO_STATE_ENTRY_FUNCTION StateFunc; + + const FxSelfManagedIoTargetState* TargetStates; + + ULONG TargetStatesCount; +}; + +class FxSelfManagedIoMachine : public FxStump { + +public: + FxSelfManagedIoMachine( + __in FxPkgPnp* PkgPnp + ); + + static + NTSTATUS + _CreateAndInit( + __deref_out FxSelfManagedIoMachine** SelfManagedIoMachine, + __in FxPkgPnp* PkgPnp + ); + + + // + // Sets event callbacks + // + VOID + InitializeMachine( + __in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks + ); + + _Must_inspect_result_ + NTSTATUS + Start( + VOID + ) + { + return ProcessEvent(SelfManagedIoEventStart); + } + + _Must_inspect_result_ + NTSTATUS + Suspend( + VOID + ) + { + return ProcessEvent(SelfManagedIoEventSuspend); + } + + VOID + Flush( + VOID + ) + { + (void) ProcessEvent(SelfManagedIoEventFlush); + } + + VOID + Cleanup( + VOID + ) + { + (void) ProcessEvent(SelfManagedIoEventCleanup); + } + +protected: + _Must_inspect_result_ + NTSTATUS + ProcessEvent( + __in FxSelfManagedIoEvents Event + ); + + static + FxSelfManagedIoStates + Init( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ); + + static + FxSelfManagedIoStates + Suspending( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ); + + static + FxSelfManagedIoStates + Restarting( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ); + + static + FxSelfManagedIoStates + Flushing( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ); + + static + FxSelfManagedIoStates + Cleanup( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ); + + WDFDEVICE + GetDeviceHandle( + VOID + ); + +public: + FxPnpDeviceSelfManagedIoCleanup m_DeviceSelfManagedIoCleanup; + FxPnpDeviceSelfManagedIoFlush m_DeviceSelfManagedIoFlush; + FxPnpDeviceSelfManagedIoInit m_DeviceSelfManagedIoInit; + FxPnpDeviceSelfManagedIoSuspend m_DeviceSelfManagedIoSuspend; + FxPnpDeviceSelfManagedIoRestart m_DeviceSelfManagedIoRestart; + +protected: + FxWaitLockInternal m_StateMachineLock; + + FxPkgPnp* m_PkgPnp; + + // uses FxSelfManagedIoStates values + BYTE m_CurrentState; + + UCHAR m_EventHistoryIndex; + + UCHAR m_StateHistoryIndex; + + // extra padded byte is put in here by the compiler + + FxSelfManagedIoMachineEventHistory m_Events; + + FxSelfManagedIoMachineStateHistory m_States; + + static const FxSelfManagedIoStateTable m_StateTable[]; + + static const FxSelfManagedIoTargetState m_CreatedStates[]; + static const FxSelfManagedIoTargetState m_InitFailedStates[]; + static const FxSelfManagedIoTargetState m_StartedStates[]; + static const FxSelfManagedIoTargetState m_StoppedStates[]; + static const FxSelfManagedIoTargetState m_FailedStates[]; + static const FxSelfManagedIoTargetState m_FlushedStates[]; +}; + +#endif // _FXSELFMANAGEDIOSTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxspinlock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxspinlock.hpp new file mode 100644 index 00000000000..89edaf61501 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxspinlock.hpp @@ -0,0 +1,121 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSpinLock.hpp + +Abstract: + +Author: + + +Revision History: + +--*/ + +#ifndef _FXSPINLOCK_H_ +#define _FXSPINLOCK_H_ + +#define FX_SPIN_LOCK_NUM_HISTORY_ENTRIES (10) + +struct FX_SPIN_LOCK_HISTORY_ENTRY { + PVOID CallersAddress; + LARGE_INTEGER AcquiredAtTime; + LONGLONG LockedDuraction; +}; + +typedef struct FX_SPIN_LOCK_HISTORY_ENTRY *PFX_SPIN_LOCK_HISTORY_ENTRY; + +struct FX_SPIN_LOCK_HISTORY { + MxThread OwningThread; + + PFX_SPIN_LOCK_HISTORY_ENTRY CurrentHistory; + + FX_SPIN_LOCK_HISTORY_ENTRY History[FX_SPIN_LOCK_NUM_HISTORY_ENTRIES]; +}; + +typedef struct FX_SPIN_LOCK_HISTORY *PFX_SPIN_LOCK_HISTORY; + +class FxSpinLock : public FxObject { + +public: + FxSpinLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ExtraSize + ); + + + __drv_raisesIRQL(DISPATCH_LEVEL) + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + AcquireLock( + __in PVOID CallersAddress + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + VOID + ReleaseLock( + VOID + ); + + + MdLock* + GetLock( + VOID + ) + { + return &m_SpinLock.Get(); + } + + VOID + SetInterruptSpinLock( + VOID + ) + { + m_InterruptLock = TRUE; + } + + BOOLEAN + IsInterruptLock( + VOID + ) + { + return m_InterruptLock; + } + +protected: + PFX_SPIN_LOCK_HISTORY + GetHistory( + VOID + ) + { + if (GetObjectSize() == WDF_ALIGN_SIZE_UP(sizeof(FxSpinLock), + MEMORY_ALLOCATION_ALIGNMENT)) { + return NULL; + } + else { + return WDF_PTR_ADD_OFFSET_TYPE( + this, + COMPUTE_RAW_OBJECT_SIZE(sizeof(FxSpinLock)), + PFX_SPIN_LOCK_HISTORY); + } + } + +protected: + MxLock m_SpinLock; + + KIRQL m_Irql; + + // + // TRUE, this lock is being used to synchronize FxInterrupts. As such, the + // caller is not allowed to actually call WDFSPINLOCK APIs on the handle + // because it would then be acquiring a spinlock at DISPATCH_LEVEL and the + // interrupt could be attempting to acquire the same lock at a higher IRQL + // on the same processor. + // + BOOLEAN m_InterruptLock; +}; + +#endif // _FXSPINLOCK_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxstring.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxstring.hpp new file mode 100644 index 00000000000..4f6ad1cf403 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxstring.hpp @@ -0,0 +1,152 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxString.hpp + +Abstract: + + This module implements a simple string class to operate on + unicode strings. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ +#ifndef _FXSTRING_H_ +#define _FXSTRING_H_ + +class FxString : public FxObject { +public: + // + // Length describes the length of the string in bytes (not WCHARs) + // MaximumLength describes the size of the buffer in bytes + // + UNICODE_STRING m_UnicodeString; + +public: + FxString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxString(); + + VOID + __inline + ReleaseString( + __out PUNICODE_STRING ReleaseTo + ) + { + RtlCopyMemory(ReleaseTo, &m_UnicodeString, sizeof(UNICODE_STRING)); + RtlZeroMemory(&m_UnicodeString, sizeof(m_UnicodeString)); + } + + __inline + operator PUNICODE_STRING( + ) + { + return &m_UnicodeString; + } + + PUNICODE_STRING + __inline + GetUnicodeString( + VOID + ) + { + return &m_UnicodeString; + } + + _Must_inspect_result_ + NTSTATUS + Assign( + __in PCWSTR SourceString + ); + + _Must_inspect_result_ + NTSTATUS + Assign( + __in const UNICODE_STRING* UnicodeString + ); + + __inline + USHORT + Length( + VOID + ) + { + return m_UnicodeString.Length; + } + + __inline + USHORT + ByteLength( + __in BOOLEAN IncludeNull + ) + { + if (IncludeNull) { + return m_UnicodeString.Length + sizeof(UNICODE_NULL); + } + else { + return m_UnicodeString.Length; + } + } + + __inline + USHORT + CharacterLength( + VOID + ) + { + return m_UnicodeString.Length / sizeof(WCHAR); + } + + __inline + USHORT + MaximumLength( + VOID + ) + { + return m_UnicodeString.MaximumLength; + } + + __inline + USHORT + MaximumByteLength( + VOID + ) + { + return m_UnicodeString.MaximumLength; + } + + __inline + USHORT + MaximumCharacterLength( + VOID + ) + { + return m_UnicodeString.MaximumLength / sizeof(WCHAR); + } + + __inline + PWCHAR + Buffer( + VOID + ) + { + return m_UnicodeString.Buffer; + } +}; + +#endif // _FXSTRING_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxstump.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxstump.hpp new file mode 100644 index 00000000000..68282729343 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxstump.hpp @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxStump.hpp + +Abstract: + +Author: + +Revision History: + +--*/ + +#ifndef _FXSTUMP_HPP_ +#define _FXSTUMP_HPP_ + +struct FxStump { + +protected: + FxStump( + VOID + ) + { + } + +public: + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + return FxPoolAllocate(FxDriverGlobals, NonPagedPool, Size); + } + + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in POOL_TYPE PoolType + ) + { + return FxPoolAllocate(FxDriverGlobals, PoolType, Size); + } + + VOID + operator delete( + __in PVOID pointer + ) + { + if (pointer) { + FxPoolFree(pointer); + } + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + PVOID + operator new[]( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + return FxPoolAllocate(FxDriverGlobals, NonPagedPool, Size); + } + + VOID + operator delete[]( + __in PVOID pointer + ) + { + if (pointer) { + FxPoolFree(pointer); + } + } + +#endif + +}; + +struct FxGlobalsStump : public FxStump { + +private: + PFX_DRIVER_GLOBALS m_Globals; + +public: + FxGlobalsStump( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + m_Globals = FxDriverGlobals; + } + + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ) + { + return m_Globals; + } +}; + +#endif // _FXSTUMP_HPP_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxsyncrequest.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxsyncrequest.hpp new file mode 100644 index 00000000000..ed40730c44e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxsyncrequest.hpp @@ -0,0 +1,121 @@ + +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSyncRequest.hpp + +Abstract: + + FxSyncRequest is meant to be a completely stack based structure. This + allows synchronous functions to not have to allocate an FxRequest for + something that only lives for the lifetime of the function call. + Additionally, this object can substitute a WDFREQUEST for itself when making + synchronous calls. This allows the driver writer to pass a WDFREQUEST to a + synchronous DDI and be able to cancel it on another thread later. + + To overcome the initial reference count that is associated upon request, the + destructor releases the initial reference and SelfDestruct does nothing + because there is no memory to free. + + FxSyncRequest derives from FxRequestBase as protected so that it cannot be + used as a FxRequestBase directly. Instead, m_TrueRequest should be used. + m_TrueRequest is either this object itself or the WDFREQUEST, as set by + SetRequestHandle. + +Author: + + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXSYNCREQUEST_H_ +#define _FXSYNCREQUEST_H_ + +class DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) FxSyncRequest : protected FxRequestBase { + +public: + // Create a sync request that allocates its own PIRP + FxSyncRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt FxRequestContext* Context, + __in_opt WDFREQUEST Request = NULL + ); + + ~FxSyncRequest(); + + // + // FxObject overrides + // + VOID + SelfDestruct( + VOID + ); + +protected: + PVOID + operator new( + __in size_t Size + ) + { + UNREFERENCED_PARAMETER(Size); + + ASSERTMSG("FxSyncRequest::operator new called, should only be" + " declared on the stack\n", FALSE); + + return NULL; + } + +public: + + NTSTATUS + Initialize( + VOID + ) + { + NTSTATUS status; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // FxCrEvent initialization can fail in UMDF so check for status. + // + status = m_DestroyedEvent.Initialize(); + if (!NT_SUCCESS(status)) { + return status; + } +#else + UNREFERENCED_PARAMETER(status); + DO_NOTHING(); +#endif + return STATUS_SUCCESS; + } + + // + // Since this object can be sitting on a list which is access by another + // thread and that thread will expect lifetime semantics from AddRef and + // Release, we need to hold up destruction of the object until all + // references are released. This event will be set when the last reference + // is dropped. + // + FxCREvent m_DestroyedEvent; + + // + // By default, this will point to this object. If AssignRequestHandle is + // called, it will point to the underlying object for that handle. Since + // this object derives from FxRequestBase as protected, this field is how + // the object is used as an FxRequestBase* pointer. + // + FxRequestBase* m_TrueRequest; + + BOOLEAN m_ClearContextOnDestroy; +}; + +#endif _FXSYNCREQUEST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemthread.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemthread.hpp new file mode 100644 index 00000000000..a0237181929 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemthread.hpp @@ -0,0 +1,289 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSystemThread.hpp + +Abstract: + + This class provides the safe handling for system threads + in the driver frameworks. + + +Author: + + + + +Revision History: + +--*/ + +#ifndef _FXSYSTEMTHREAD_H_ +#define _FXSYSTEMTHREAD_H_ + +class FxSystemThread : public FxNonPagedObject { + +private: + + MxEvent m_InitEvent; + MxEvent m_WorkEvent; + + LIST_ENTRY m_WorkList; + + PVOID m_ThreadPtr; + + MdEThread m_PEThread; + + // Used for Async thread spinup and reaping + //WORK_QUEUE_ITEM m_Spinup; // Async-Thread-Spinup + WORK_QUEUE_ITEM m_Reaper; + + BOOLEAN m_Exit; + BOOLEAN m_Initialized; + + FxSystemThread( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + // + // Create the system thread in order to be able to service work items + // + // It is recommended this is done from the system process context + // since the thread's handle is available to the user mode process + // for a temporary window. XP and later supports OBJ_KERNELHANDLE, but + // DriverFrameworks must support W2K with the same binary. + // + // It is safe to call this at DriverEntry which is in the system process + // to create an initial driver thread, and this driver thread should be + // used for creating any child driver threads on demand by using + // Initialize(FxSystemThread* SpinupThread). + // + BOOLEAN + Initialize( + VOID + ); + +public: + + _Must_inspect_result_ + static + NTSTATUS + _CreateAndInit( + __deref_out FxSystemThread** SystemThread, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFDEVICE Device, + __in MdDeviceObject DeviceObject + ); + + virtual + ~FxSystemThread( + VOID + ); + + + + + + + + + + + + + + + + + + + + + + // + // This is called to tell the thread to exit. + // + // It must be called from thread context such as + // the driver unload routine since it will wait for the + // thread to exit. + // + // A worker thread will not exit unless it has processed + // all of its queued work items. If processing of queued + // workitems is no longer desired, then use CancelWorkItem + // to remove the items before calling this method. + // + BOOLEAN + ExitThread( + VOID + ); + + // + // This is called to tell the thread to exit. + // + // This may be called from any context since it + // only signals the thread to exit, and does not + // wait for it. It is safe to release the object + // reference when this routine returns. + // + // This routine requires an FxSystemThread* to perform + // final thread reaping. This allows a driver to ensure that + // child threads have exited by waiting on their object pointer, + // before exiting a top level driver thread. + // + // This is required since a frameworks object that contains a + // system thread can be dereferenced, and thus destroyed + // in any context, so waiting may not be available. But unless + // a wait is done on the thread object pointer, no guarantee can be + // made that the thread has actually run and exited before + // the drivers code get unloaded, resulting in a system crash. + // + // Top level threads, such as the reaper, are exited using the + // ExitThread() synchronous call that waits for it to exit. This + // can be done in synchronous thread context such as DriverUnload + // time. + // + // If Synchronous threading is configured in the frameworks, the + // FxDriver object always contains a top level worker thread that + // may be used as the reaper, and DriverUnload synchronously waits + // for this thread to finish processing its work queue before + // exiting. + // + // A worker thread will not exit unless it has processed + // all of its queued work items. If processing of queued + // workitems is no longer desired, then use CancelWorkItem + // to remove the items before calling this method. + // + BOOLEAN + ExitThreadAsync( + __inout FxSystemThread* Reaper + ); + + // + // Queue a work item to the thread + // + // It is valid to queue work items before thread + // Initialize()/Initialize(FxSystemThread*) is called. The items + // remain queued until the system thread is started. + // + BOOLEAN + QueueWorkItem( + __inout PWORK_QUEUE_ITEM WorkItem + ); + + // + // Attempt to cancel the work item. + // + // Returns TRUE if success. + // + // If returns FALSE, the work item + // routine either has been called, is running, + // or is about to be called. + // + BOOLEAN + CancelWorkItem( + __inout PWORK_QUEUE_ITEM WorkItem + ); + + // + // Determine if current thread is this + // worker thread + // + __inline + BOOLEAN + IsCurrentThread() + { + return (Mx::GetCurrentEThread() == m_PEThread) ? TRUE : FALSE; + } + + DECLARE_INTERNAL_NEW_OPERATOR(); + +#ifdef INLINE_WRAPPER_ALLOCATION +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + FORCEINLINE + PVOID + GetCOMWrapper( + ) + { + PBYTE ptr = (PBYTE) this; + return (ptr + (USHORT) WDF_ALIGN_SIZE_UP(sizeof(*this), MEMORY_ALLOCATION_ALIGNMENT)); + } +#endif +#endif + +private: + + // + // This is the thread's main processing function + // + VOID + Thread( + VOID + ); + + + + + + + + + + + + + + + // + // This is the reaper method + // + VOID + Reaper( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + CreateThread( + VOID + ); + + // + // This is the thunk used to get from the system + // thread start callback into this class + // + static + VOID + StaticThreadThunk( + __inout PVOID Context + ); + + + + + + + + + + + + + + + + + // + // This thunk is called from the workitem in another + // thread that is reaping this thread + // + static + VOID + StaticReaperThunk( + __inout PVOID Context + ); +}; + +#endif // _FXSYSTEMTHREAD_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemworkitem.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemworkitem.hpp new file mode 100644 index 00000000000..b1a428b2676 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxsystemworkitem.hpp @@ -0,0 +1,254 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSystemWorkItem.hpp + +Abstract: + + This implements an internal framework workitem that manages + cleanup. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXSYSTEMWORKITEM_H +#define _FXSYSTEMWORKITEM_H + +// +// This class provides a common place for code to deal with +// cleanup and synchronization issues of workitems utilized +// internally by the framework +// + +_Function_class_(EVT_SYSTEMWORKITEM) +__drv_maxIRQL(PASSIVE_LEVEL) +__drv_maxFunctionIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +typedef +VOID +EVT_SYSTEMWORKITEM( + __in PVOID Parameter + ); + +typedef EVT_SYSTEMWORKITEM FN_WDF_SYSTEMWORKITEM,*PFN_WDF_SYSTEMWORKITEM; + +class FxSystemWorkItem : public FxNonPagedObject { + +private: + + // Ensures only one of either Delete or Cleanup runs down the object + BOOLEAN m_RunningDown; + + // + // If this is set, a WorkItem has been enqueued + // + BOOLEAN m_Enqueued; + + // + // The workitem we use + // + MxWorkItem m_WorkItem; + + // + // The callback function + // + PFN_WDF_SYSTEMWORKITEM m_Callback; + + PVOID m_CallbackArg; + + // + // This event is signaled when the workitem is done processing + // an Enqueue request. + // + FxCREvent m_WorkItemCompleted; + + // + // This count is used to prevent the object from being deleted if + // one worker thread is preempted right after we drop the lock to call + // the client callback and another workitem gets queued and runs + // to completion and signals the event. + // + ULONG m_WorkItemRunningCount; + + // + // We will keep a count of workitems queued and wait for + // all the workitems to run to completion before allowing the + // dispose to complete. Since this object is also used in running + // down the dispose list during driver unload, this run-down + // protection is required to make sure that the unload after deleting + // this object doesn't run ahead of the dispose worker thread. + // + LONG m_OutStandingWorkItem; + + // + // This event will be signed when the above count drops to zero. + // The initial value of the count is biased to zero to provide + // remlock semantics. This event is configured to be a synchronziation + // event because we know for sure the only thread that's going to + // wait on this event is the one that's going to call Dispose and + // after that the object will be destroyed. + // + FxCREvent m_RemoveEvent; + +public: + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID WdmObject, + __out FxSystemWorkItem** pObject + ); + + virtual + ~FxSystemWorkItem( + ); + + virtual + _Must_inspect_result_ + NTSTATUS + QueryInterface( + __inout FxQueryInterfaceParams* Params + ) + { + switch (Params->Type) { + case FX_TYPE_SYSTEMWORKITEM: + *Params->Object = (FxSystemWorkItem*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; + } + + __inline + MdWorkItem + GetWorkItemPtr( + VOID + ) + { + return m_WorkItem.GetWorkItem(); + } + + __inline + BOOLEAN + Enqueue( + __in PFN_WDF_SYSTEMWORKITEM CallbackFunc, + __in PVOID Parameter + ) + { + return EnqueueWorker(CallbackFunc, Parameter, TRUE); + } + + __inline + BOOLEAN + TryToEnqueue( + __in PFN_WDF_SYSTEMWORKITEM CallbackFunc, + __in PVOID Parameter + ) + { + return EnqueueWorker(CallbackFunc, Parameter, FALSE); + } + + VOID + WaitForExit( + VOID + ); + + __inline + VOID + IncrementWorkItemQueued( + ) + { + ASSERT(m_OutStandingWorkItem >= 1); + + InterlockedIncrement(&m_OutStandingWorkItem); + } + + __inline + VOID + DecrementWorkItemQueued( + ) + { + LONG result; + + ASSERT(m_OutStandingWorkItem >= 1); + + result = InterlockedDecrement(&m_OutStandingWorkItem); + + if (result == 0) { + m_RemoveEvent.Set(); + } + } + + __inline + VOID + ReleaseWorkItemQueuedCountAndWait( + ) + { + NTSTATUS status; + + // + // Drop the bias count to indicate the object is being removed. + // + DecrementWorkItemQueued(); + + status = m_RemoveEvent.EnterCRAndWaitAndLeave(); + ASSERT(NT_SUCCESS(status)); + UNREFERENCED_PARAMETER(status); + + ASSERT(m_OutStandingWorkItem == 0); + } + + DECLARE_INTERNAL_NEW_OPERATOR(); + +private: + FxSystemWorkItem( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PVOID WdmObject + ); + + VOID + WorkItemHandler( + ); + + static + MX_WORKITEM_ROUTINE + _WorkItemThunk; + + BOOLEAN + EnqueueWorker( + __in PFN_WDF_SYSTEMWORKITEM Func, + __in PVOID Parameter, + __in BOOLEAN AssertIfAlreadyQueued + ); +}; + +#endif // _FXSYSTEMWORKITEM_H + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtagtracker.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtagtracker.hpp new file mode 100644 index 00000000000..a55894db68a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtagtracker.hpp @@ -0,0 +1,317 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTagTracker.hpp + +Abstract: + + This is the C++ header for the FxTagTracker + +Author: + + + + +Revision History: + + + + + + + + + + + +--*/ + +#ifndef _FXTAGTRACKER_HPP_ +#define _FXTAGTRACKER_HPP_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxTagTracker.hpp.tmh" +#endif + +} + +enum FxTagTrackerType : UCHAR { + FxTagTrackerTypeHandle = 0, + FxTagTrackerTypePower +}; + +enum FxTagRefType { + TagAddRef = 0, + TagRelease +}; + +#define FRAMES_TO_CAPTURE 16 +#define FRAMES_TO_SKIP 3 + +struct FxTagTrackingStackFrames : public FxStump { + USHORT NumFrames; + ULONG64 Frames[FRAMES_TO_CAPTURE]; +}; + +// +// Tracks outstanding references +// + +struct FxTagTrackingBlock : public FxStump { + + FxTagTrackingBlock( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File, + __in_opt BOOLEAN Initial = FALSE + ) : + Tag(Tag), + Line(Line), + File(File), + StackFrames(NULL), + Next(NULL) + { + Mx::MxQueryTickCount(&TimeLocked); + + if (Initial == FALSE) { + // + // !wdftagtracker identifies a reference with Line == 0 + // as the initial reference. However, references taken + // in framework code may leave the File/Line empty yet + // not be the initial references. They could still + // capture stack frames, so they are useful to track. + // + // Leaving File == NULL but setting Line = 1 unless this + // was explicitly labeled an Initial Ref works around this. + // + if (File == NULL && Line == 0) { + this->Line = 1; + } + } + } + + ~FxTagTrackingBlock( + ) + { + if (StackFrames != NULL) { + delete StackFrames; + StackFrames = NULL; + } + } + + struct FxTagTrackingBlock* Next; + PVOID Tag; + PCHAR File; + LONG Line; + LARGE_INTEGER TimeLocked; + FxTagTrackingStackFrames* StackFrames; +}; + +// +// Tracks reference and release history +// +struct FxTagHistory { + FxTagRefType RefType; + // + // Note: RefCount may be inaccurate when multiple FxObject::Release + // calls execute concurrently. This value should be considered + // an approximation and is for wdfkd consumption only. + // + ULONG RefCount; + PCHAR File; + LONG Line; + PVOID Tag; + LARGE_INTEGER Time; + FxTagTrackingStackFrames* StackFrames; + + FxTagHistory( + ) + { + StackFrames = NULL; + } + + ~FxTagHistory( + ) + { + if (StackFrames != NULL) { + delete StackFrames; + StackFrames = NULL; + } + } +}; + + +#define TAG_HISTORY_DEPTH (25) + +class FxTagTracker : public FxGlobalsStump { + +private: + + // + // Making constructor private to enforce usage + // of CreateAndInitialize + // + + FxTagTracker( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxTagTrackerType Type, + __in BOOLEAN CaptureStack, + __in FxObject* Owner, + __in_opt PVOID CreateTag = NULL + ) : + FxGlobalsStump(FxDriverGlobals), + m_TrackerType(Type), + m_CaptureStack(CaptureStack), + m_Next(NULL), + m_FailedCount(0), + m_CurRefHistory(0), + m_OwningObject(Owner) + { + RtlZeroMemory(m_TagHistory, sizeof(m_TagHistory)); + + // + // We keep handle reference trackers in a list, + // which wdfkd uses to identify potential handle leaks. + // + if (m_TrackerType == FxTagTrackerTypeHandle) { + FxDriverGlobalsDebugExtension* pExtension; + KIRQL irql; + + pExtension = GetDriverGlobals()->DebugExtension; + ASSERT(pExtension != NULL); + + // + // Insert the tag tracker into the list of allocated trackers + // + pExtension->AllocatedTagTrackersLock.Acquire(&irql); + InsertTailList(&pExtension->AllocatedTagTrackersListHead, + &m_TrackerEntry); + pExtension->AllocatedTagTrackersLock.Release(irql); + + // + // Handle references default to 1 outstanding ref (the object creation ref) + // + m_Next = new(FxDriverGlobals) FxTagTrackingBlock(CreateTag, 0, NULL, TRUE); + if (m_Next == NULL) { + m_FailedCount = 1; + } + } + else { + ASSERT(m_TrackerType == FxTagTrackerTypePower); + } + } + + VOID + CopyStackFrames( + _Inout_ FxTagTrackingStackFrames** StackFrames, + _In_ USHORT NumFrames, + _In_reads_(NumFrames) PVOID* Frames + ); + +public: + + _Must_inspect_result_ + static + NTSTATUS + __inline + CreateAndInitialize( + __out FxTagTracker ** TagTracker, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxTagTrackerType Type, + __in BOOLEAN CaptureStack, + __in FxObject* Owner, + __in_opt PVOID CreateTag = NULL + ) + { + NTSTATUS status; + + FxTagTracker * tagTracker = new(FxDriverGlobals) + FxTagTracker(FxDriverGlobals, Type, CaptureStack, Owner, CreateTag); + + if (NULL == tagTracker) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Failed to allocate tag tracker, returning %!STATUS!", status); + + goto exit; + } + + *TagTracker = tagTracker; + status = STATUS_SUCCESS; + + exit: + return status; + } + + ~FxTagTracker(); + + VOID + CheckForAbandondedTags( + VOID + ); + + VOID + UpdateTagHistory( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File, + __in FxTagRefType RefType, + __in ULONG RefCount + ); + +protected: + // + // Whether this tracks handle references or power references. + // + FxTagTrackerType m_TrackerType; + + // + // Whether to capture stack frames for each ref/release. + // + BOOLEAN m_CaptureStack; + + // + // Owner object for this FxTagTracker. An FxDevice if this tracks power refs. + // + FxObject* m_OwningObject; + + // + // Link into list of allocated tag trackers kept in the driver's globals + // + LIST_ENTRY m_TrackerEntry; + + // + // Number of times we failed to alloc a tracking block + // + LONG m_FailedCount; + + // + // Lock to guard the insertion/removal of tracking blocks + // + MxLock m_SpinLock; + + // + // List head for tracking blocks + // + FxTagTrackingBlock* m_Next; + + // + // Last TAG_HISTORY_DEPTH addrefs and releases on the object + // + FxTagHistory m_TagHistory[TAG_HISTORY_DEPTH]; + + // + // Current index into RefHistory + // + LONG m_CurRefHistory; +}; + +#endif // _FXTAGTRACKER_HPP_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtelemetry.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtelemetry.hpp new file mode 100644 index 00000000000..7759bd8d663 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtelemetry.hpp @@ -0,0 +1,197 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetry.hpp + +Abstract: + + This is the header file for core framework (Wdf0100 and Wudfx02000) + related telemetry. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +Notes: + +--*/ + +#pragma once + +#include +#include "FxTelemetryCommon.hpp" + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#include "FxTelemetryKm.hpp" +#else +#include "FxTelemetryUm.hpp" +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +TRACELOGGING_DECLARE_PROVIDER(g_TelemetryProvider); + +#define FX_TELEMETRY_ENABLED(TraceHandle, Globals) \ + (TraceHandle && IsDriverTelemetryContextInitialized(Globals)) \ + +#define WDF_CENSUS_EVT_DATA_COMMON(FxGlobals) \ + TraceLoggingStruct(1, "CensusCommonV1"), \ + TraceLoggingGuid((FxGlobals)->TelemetryContext->DriverSessionGUID, "SessionGUID") + +// +// For events that want to fire once per +// session define a bit for use in DoOnceFlagsBitmap +// +typedef enum _FX_TELEMETRY_DO_ONCE_BITS { + DeviceStartEventBit = 0 +} FX_TELEMETRY_DO_ONCE_BITS; + +// +// Event name: WdfCensusEvtDrvLoad +// +// Source: Mode agnostic (UMDF and KMDF) +// +// Description: Written when a WDF client or cx calls WdfDriverCreate. +// The event contains information about the driver version, +// verifier options, service name and driver configuration +// to track non-pnp drivers or WDF miniports. +// +// Frequency: If FX_TELEMETRY_ENABLED then everytime a driver calls WdfDriverCreate. +// +#define WDF_CENSUS_EVT_WRITE_DRIVER_LOAD(TraceHandle, Globals, DrvImage, WdfVersion) \ + TraceLoggingWrite(TraceHandle, \ + "WdfCensusEvtDrvLoad", \ + WDF_TELEMETRY_EVT_KEYWORDS, \ + WDF_CENSUS_EVT_DATA_COMMON(Globals), \ + TraceLoggingStruct(9, "DriverInfo" ), \ + TraceLoggingString((Globals)->Public.DriverName, "DriverService" ), \ + TraceLoggingWideString(DrvImage, "DriverImage" ), \ + TraceLoggingWideString(WdfVersion, "WdfVersion" ), \ + TraceLoggingUInt32((Globals)->WdfBindInfo->Version.Major, "DriverVersionMajor" ), \ + TraceLoggingUInt32((Globals)->WdfBindInfo->Version.Minor, "DriverVersionMinor" ), \ + TraceLoggingBoolean((Globals)->FxVerifierOn, "FxVerifierOn" ), \ + TraceLoggingBoolean(!!((Globals)->Public.DriverFlags & WdfDriverInitNonPnpDriver), "DriverNonPnP" ), \ + TraceLoggingBoolean(!!((Globals)->Public.DriverFlags & WdfDriverInitNoDispatchOverride), "DriverNoDispatchOverride" ), \ + TraceLoggingUInt32((Globals)->FxEnhancedVerifierOptions, "FxEnhancedVeriferOptions" ) \ + ); + +#define MIN_HOURS_BEFORE_NEXT_LOG 24 +#define BASE_10 (10) + +#define WDF_LAST_TELEMETRY_LOG_TIME_VALUE L"TimeOfLastTelemetryLog" +#define WDF_DRIVER_IMAGE_NAME_VALUE L"ImagePath" + +// +// bit-flags for tracking hardware info for device start telemetry event +// +enum FxDeviceInfoFlags : USHORT { + DeviceInfoLineBasedLevelTriggeredInterrupt = 0x1, + DeviceInfoLineBasedEdgeTriggeredInterrupt = 0x2, + DeviceInfoMsiXOrSingleMsi22Interrupt = 0x4, + DeviceInfoMsi22MultiMessageInterrupt = 0x8, + DeviceInfoPassiveLevelInterrupt = 0x10, + DeviceInfoDmaBusMaster = 0x20, + DeviceInfoDmaSystem = 0x40, + DeviceInfoDmaSystemDuplex = 0x80, + DeviceInfoHasStaticChildren = 0x100, + DeviceInfoHasDynamicChildren = 0x200, + DeviceInfoIsUsingDriverWppRecorder = 0x400 +}; + +// +// wdf version strig example "01.011" +// +#define WDF_VERSION_STRING_SIZE_INCLUDING_SEPARATOR_CCH 10 + +BOOLEAN +__inline +IsDeviceInfoFlagSet( + _In_ USHORT DeviceInfo, + _In_ FxDeviceInfoFlags Flag + ) +{ + return FLAG_TO_BOOL(DeviceInfo, Flag); +} + +VOID +AllocAndInitializeTelemetryContext( + _In_ PFX_TELEMETRY_CONTEXT* TelemetryContext + ); + +__inline +BOOLEAN +IsDriverTelemetryContextInitialized( +_In_ PFX_DRIVER_GLOBALS FxDrvGlobals +) +{ + ASSERT(FxDrvGlobals); + return (NULL != FxDrvGlobals->TelemetryContext); +} + +VOID +RegisterTelemetryProvider( + VOID + ); + +VOID +UnregisterTelemetryProvider( + VOID + ); + +VOID +LogDeviceStartTelemetryEvent( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ FxDevice* Fdo + ); + +VOID +LogDriverInfoStream( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ FxDevice* Fdo + ); + +_Must_inspect_result_ +NTSTATUS +GetImageName( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _Out_ PUNICODE_STRING ImageName + ); + +VOID +__inline +BuildStringFromPartialInfo( + _In_ PKEY_VALUE_PARTIAL_INFORMATION Info, + _Out_ PUNICODE_STRING String + ) +{ + String->Buffer = (PWCHAR) &Info->Data[0]; + String->MaximumLength = (USHORT) Info->DataLength; + String->Length = String->MaximumLength - sizeof(UNICODE_NULL); + + // + // ensure string is null terminated + // + String->Buffer[String->Length/sizeof(WCHAR)] = UNICODE_NULL; +} + +VOID +GetNameFromPath( + _In_ PCUNICODE_STRING Path, + _Out_ PUNICODE_STRING Name + ); + +#if defined(__cplusplus) +} +#endif + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtelemetrycommon.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtelemetrycommon.hpp new file mode 100644 index 00000000000..7fa35e5f1b7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtelemetrycommon.hpp @@ -0,0 +1,55 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetryCommon.hpp + +Abstract: + + This is header file for telemetry methods common to all WDF components + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +Notes: + +--*/ + +#pragma once + +// +// The TraceLogging infrastructure calls EtwSetInformation API that is not available on Win7. +// Setting TLG_HAVE_EVENT_SET_INFORMATION, modifies the behavior of TraceLoggingProvider.h. +// The value 2 indicates that the trace logging infra would find "EtwSetInformation" via +// MmGetSystemRoutineAddress. This allows our code to be backwards compatible to Win7 +// +#define TLG_HAVE_EVENT_SET_INFORMATION 2 +#include +#include + +// WDF01000.sys +#define KMDF_FX_TRACE_LOGGING_PROVIDER_NAME "Microsoft.Wdf.KMDF.Fx" + +// WUDFX0200.dll +#define UMDF_FX_TRACE_LOGGING_PROVIDER_NAME "Microsoft.Wdf.UMDF.Fx" + +// WudfHost.exe +#define UMDF_HOST_TRACE_LOGGING_PROVIDER_NAME "Microsoft.Wdf.UMDF.Host" + +// WdfLdr.sys +#define KMDF_LDR_TRACE_LOGGING_PROVIDER_NAME "Microsoft.Wdf.KMDF.Ldr" + +// WudfSvc.dll +#define UMDF_DM_TRACE_LOGGING_PROVIDER_NAME "Microsoft.Wdf.UMDF.Dm" + +// Common telemetry related keyword used across all telemetry events +#define WDF_TELEMETRY_EVT_KEYWORDS TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY) diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtimer.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtimer.hpp new file mode 100644 index 00000000000..af6f05ea788 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtimer.hpp @@ -0,0 +1,221 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTimer.hpp + +Abstract: + + This module implements a frameworks managed TIMER that + can synchrononize with driver frameworks object locks. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXTIMER_H_ +#define _FXTIMER_H_ + +// +// Driver Frameworks TIMER Design: +// +// The driver frameworks provides an optional TIMER wrapper object that allows +// a reference counted TIMER object to be created that can synchronize +// automatically with certain frameworks objects. +// +// This provides automatic synchronization between the TIMER's execution, and the +// frameworks objects event callbacks into the device driver. +// + +class FxTimer : public FxNonPagedObject { + +private: + + // + // Kernel Timer Object + // + MxTimer m_Timer; + + // + // This is the Framework object who is associated with the TIMER + // if supplied + // + FxObject* m_Object; + + // + // This is the supplied Period to WdfTimerCreate + // + ULONG m_Period; + + // + // Optional tolerance for the timer in milliseconds + // + ULONG m_TolerableDelay; + + // + // This indicates whether a high resolution attribute is set + // for the timer + // + BOOLEAN m_UseHighResolutionTimer; + + // + // This is the callback lock for the object this TIMER will + // synchronize with + // + FxCallbackLock* m_CallbackLock; + + // + // This is the object whose reference count actually controls + // the lifetime of the m_CallbackLock + // + FxObject* m_CallbackLockObject; + + // + // This is the user supplied callback function + // + PFN_WDF_TIMER m_Callback; + + // + // This workitem object will be used to queue workitem from the timer + // dpc callback if the caller requests passive callback. + // + FxSystemWorkItem* m_SystemWorkItem; + + // + // This is a pointer to thread object that invoked our dpc callback + // callback. This value will be used to avoid deadlock when we try + // to stop or delete the timer. + // + volatile POINTER_ALIGNMENT MxThread m_CallbackThread; + + // + // This is a pointer to the Stop thread object when driver invokes the + // timer's WdfTimerStop function. + // + MxThread m_StopThread; + + // + // TRUE if the timer was restarted while stopping. + // + BOOLEAN m_StopAgain; + + // + // TRUE if a start operation was aborted b/c stop was in progress. + // + BOOLEAN m_StartAborted; + + // + // Ensures only one of either Delete or Cleanup runsdown the object + // + BOOLEAN m_RunningDown; + +public: + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_TIMER_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObject* ParentObject, + __out WDFTIMER* Timer + ); + + FxTimer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + ~FxTimer( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_TIMER_CONFIG Config, + __in FxObject* ParentObject, + __out WDFTIMER* Timer + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + BOOLEAN + Start( + __in LARGE_INTEGER DueTime + ); + + BOOLEAN + Stop( + __in BOOLEAN Wait + ); + + VOID + TimerHandler( + VOID + ); + + WDFOBJECT + GetObject( + VOID + ) + { + if( m_Object != NULL ) { + return m_Object->GetObjectHandle(); + } + else { + return NULL; + } + } + + WDFTIMER + GetHandle( + VOID + ) + { + return (WDFTIMER) GetObjectHandle(); + } + +private: + + // + // Called from Dispose, or cleanup list to perform final flushing of any + // outstanding DPC's and dereferencing of objects. + // + VOID + FlushAndRundown( + VOID + ); + + static + FN_WDF_SYSTEMWORKITEM + _FxTimerWorkItemCallback; + + static + MdDeferredRoutineType + _FxTimerDpcThunk; + + static + MdExtCallbackType + _FxTimerExtCallbackThunk; +}; + +#endif // _FXTIMER_H + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtoobjectitf.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtoobjectitf.hpp new file mode 100644 index 00000000000..7a37886ef7e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtoobjectitf.hpp @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxToObjectItf.hpp + +Abstract: + + This file contains the funcionality exposed by framework to object + (Framework to Object Interface) + +Author: + +Revision History: + +--*/ + +#ifndef _FXTOOBJECTITF_H +#define _FXTOOBJECTITF_H + +extern "C" { +//////////////////////////////////////////////// +//To be implemented by respective frameworks +//////////////////////////////////////////////// + +class FxToObjectItf +{ +public: + static + VOID + FxAddToDisposeList( + __in CfxDeviceBase* DeviceBase, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject * ObjectToAdd + ); + + static + VOID + FxAddToDriverDisposeList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject * ObjectToAdd + ); + + + + + + static + FxObject * + FxGetDriverAsDefaultParent( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject * Object + ); +}; +//////////////////////////////////////////////// +} //extern "C" + +#endif //_FXTOOBJECTITF_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtrace.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtrace.h new file mode 100644 index 00000000000..3c44459fb7e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtrace.h @@ -0,0 +1,119 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTrace.h + +Abstract: + + This module contains the private tracing definitions + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXTRACE_H_ +#define _FXTRACE_H_ + +typedef struct _WDF_DRIVER_CONFIG *PWDF_DRIVER_CONFIG; + +/** + * Tracing Definitions: + */ + +#if FX_CORE_MODE == FX_CORE_KERNEL_MODE +#define WDF_FX_TRACE_WPPGUID (544d4c9d,942c,46d5,bf50,df5cd9524a50) +#elif FX_CORE_MODE == FX_CORE_USER_MODE +#define WDF_FX_TRACE_WPPGUID (485e7de9,0a80,11d8,ad15,505054503030) +#endif + +#define WDF_FRAMEWORKS_TRACE_FLAGS \ + WPP_DEFINE_WDF_CONTROL_GUID( \ + KmdfTraceGuid, \ + WDF_FX_TRACE_WPPGUID, \ + WPP_DEFINE_BIT(TRACINGFULL) \ + WPP_DEFINE_BIT(TRACINGERROR) \ + WPP_DEFINE_BIT(TRACINGDBGPRINT) \ + WPP_DEFINE_BIT(TRACINGFRAMEWORKS) \ + WPP_DEFINE_BIT(TRACINGAPI) \ + WPP_DEFINE_BIT(TRACINGAPIERROR) \ + WPP_DEFINE_BIT(TRACINGRESOURCES) \ + WPP_DEFINE_BIT(TRACINGLOCKING) \ + WPP_DEFINE_BIT(TRACINGCONTEXT) \ + WPP_DEFINE_BIT(TRACINGPOOL) \ + WPP_DEFINE_BIT(TRACINGHANDLE) \ + WPP_DEFINE_BIT(TRACINGPNP) \ + WPP_DEFINE_BIT(TRACINGIO) \ + WPP_DEFINE_BIT(TRACINGIOTARGET) \ + WPP_DEFINE_BIT(TRACINGDMA) \ + WPP_DEFINE_BIT(TRACINGREQUEST) \ + WPP_DEFINE_BIT(TRACINGDRIVER) \ + WPP_DEFINE_BIT(TRACINGDEVICE) \ + WPP_DEFINE_BIT(TRACINGUSEROBJECT) \ + WPP_DEFINE_BIT(TRACINGOBJECT) \ + WPP_DEFINE_BIT(TRACINGPNPPOWERSTATES) \ + ) + +#define WPP_CONTROL_GUIDS \ + WDF_FRAMEWORKS_TRACE_FLAGS + + + + + + + + + +//#define WPP_DEBUG(args) DbgPrint args , DbgPrint("\n") + +#define WPP_GLOBALS_LEVEL_FLAGS_LOGGER(globals,lvl,flags) WPP_LEVEL_LOGGER(flags) +#define WPP_GLOBALS_LEVEL_FLAGS_ENABLED(globals,lvl,flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +#define IFR_GLOBALS_LEVEL_FLAGS_FILTER(globals,lvl,flags) (lvl < TRACE_LEVEL_VERBOSE || globals->FxVerboseOn) + +// +// These are pure enums (one and only one value) +// +// begin_wpp config +// CUSTOM_TYPE(WdfDmaEnablerCallback, ItemListLong(FxEvtDmaEnablerInvalid,FxEvtDmaEnablerFill,FxEvtDmaEnablerFlush,FxEvtDmaEnablerEnable,FxEvtDmaEnablerDisable,FxEvtDmaEnablerSelfManagedIoStart,FxEvtDmaEnablerSelfManagedIoStop),"s"); +// CUSTOM_TYPE(IRPMJ, ItemListByte(IRP_MJ_CREATE,IRP_MJ_CREATE_NAMED_PIPE,IRP_MJ_CLOSE,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_QUERY_INFORMATION,IRP_MJ_SET_INFORMATION,IRP_MJ_QUERY_EA,IRP_MJ_SET_EA,IRP_MJ_FLUSH_BUFFERS,IRP_MJ_QUERY_VOLUME_INFORMATION,IRP_MJ_SET_VOLUME_INFORMATION,IRP_MJ_DIRECTORY_CONTROL,IRP_MJ_FILE_SYSTEM_CONTROL,IRP_MJ_DEVICE_CONTROL,IRP_MJ_INTERNAL_DEVICE_CONTROL,IRP_MJ_SHUTDOWN,IRP_MJ_LOCK_CONTROL,IRP_MJ_CLEANUP,IRP_MJ_CREATE_MAILSLOT,IRP_MJ_QUERY_SECURITY,IRP_MJ_SET_SECURITY,IRP_MJ_POWER,IRP_MJ_SYSTEM_CONTROL,IRP_MJ_DEVICE_CHANGE,IRP_MJ_QUERY_QUOTA,IRP_MJ_SET_QUOTA,IRP_MJ_PNP)); +// end_wpp + + +_Must_inspect_result_ +NTSTATUS +FxTraceInitialize( + VOID + ); + +VOID +TraceUninitialize( + VOID + ); + +VOID +FxIFRStart( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath, + __in MdDriverObject DriverObject + ); + +VOID +FxIFRStop( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +#endif // _FXTRACE_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtransactionedlist.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtransactionedlist.hpp new file mode 100644 index 00000000000..7c096c58124 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtransactionedlist.hpp @@ -0,0 +1,305 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTransactionedList.hpp + +Abstract: + + This module defines the abstract FxTransactionedList class. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _FXTRANSACTIONEDLIST_H_ +#define _FXTRANSACTIONEDLIST_H_ + +enum FxListTransactionAction { + FxTransactionActionNothing = 1, + FxTransactionActionAdd, + FxTransactionActionRemove, +}; + +struct FxTransactionedEntry { + friend FxTransactionedList; + + FxTransactionedEntry( + __in_opt FxObject* Object = NULL + ) + { + m_Transaction = FxTransactionActionNothing; + m_TransactionedObject = Object; + InitializeListHead(&m_ListLink); + InitializeListHead(&m_TransactionLink); + } + + VOID + SetTransactionedObject( + __in FxObject* Object + ) + { + m_TransactionedObject = Object; + } + + FxObject* + GetTransactionedObject( + VOID + ) + { + return m_TransactionedObject; + } + + static + FxTransactionedEntry* + _FromEntry( + __in PLIST_ENTRY Entry + ) + { + return CONTAINING_RECORD(Entry, FxTransactionedEntry, m_ListLink); + } + + FxListTransactionAction + GetTransactionAction( + VOID + ) + { + return m_Transaction; + } + +private: + LIST_ENTRY m_ListLink; + + LIST_ENTRY m_TransactionLink; + + FxListTransactionAction m_Transaction; + + FxObject* m_TransactionedObject; +}; + +class FxTransactionedList : public FxStump { +public: + FxTransactionedList(); + + ~FxTransactionedList(); + + VOID + LockForEnum( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + VOID + UnlockFromEnum( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + NTSTATUS + Add( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxTransactionedEntry* Entry + ); + + VOID + Remove( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxTransactionedEntry* Entry + ); + + _Must_inspect_result_ + FxTransactionedEntry* + GetNextEntry( + __in_opt FxTransactionedEntry* Entry + ); + + BOOLEAN + Deleting( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt MxEvent* DeleteDoneEvent + ); + +protected: + virtual + VOID + AcquireLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __out PKIRQL Irql + ) =0; + + virtual + VOID + ReleaseLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in KIRQL Irql + ) =0; + + virtual + _Must_inspect_result_ + NTSTATUS + ProcessAdd( + __in FxTransactionedEntry* Entry + ) + { + UNREFERENCED_PARAMETER(Entry); + + return STATUS_SUCCESS; + } + + virtual + VOID + EntryAdded( + __in FxTransactionedEntry* Entry + ) + { + UNREFERENCED_PARAMETER(Entry); + } + + virtual + VOID + EntryRemoved( + __in FxTransactionedEntry* Entry + ) + { + UNREFERENCED_PARAMETER(Entry); + } + + virtual + BOOLEAN + Compare( + __in FxTransactionedEntry* Entry, + __in PVOID Data + ) + { + UNREFERENCED_PARAMETER(Entry); + UNREFERENCED_PARAMETER(Data); + + return TRUE; + } + + VOID + SearchForAndRemove( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID EntryData + ); + + _Must_inspect_result_ + FxTransactionedEntry* + GetNextEntryLocked( + __in_opt FxTransactionedEntry* Entry + ); + + BOOLEAN + RemoveLocked( + __in FxTransactionedEntry* Entry + ); + + VOID + ProcessTransactionList( + __in PLIST_ENTRY ReleaseHead + ); + + VOID + ProcessObjectsToRelease( + __in PLIST_ENTRY ReleaseHead + ); + +protected: + LIST_ENTRY m_ListHead; + + LIST_ENTRY m_TransactionHead; + + MxEvent* m_DeletingDoneEvent; + + ULONG m_ListLockedRecursionCount; + + BOOLEAN m_DeleteOnRemove; + + BOOLEAN m_Deleting; + + // + // The base class does not use this field, but to save space in the size of + // the derived structures, we place it here after the BOOLEANs and there is + // minimal structure byte packing. + // + UCHAR m_Retries; +}; + + +class FxSpinLockTransactionedList : public FxTransactionedList { + +public: + FxSpinLockTransactionedList(); + +protected: + + __drv_raisesIRQL(DISPATCH_LEVEL) + __drv_maxIRQL(DISPATCH_LEVEL) + virtual + VOID + AcquireLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __out PKIRQL Irql + ); + + __drv_requiresIRQL(DISPATCH_LEVEL) + virtual + VOID + ReleaseLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in __drv_restoresIRQL KIRQL Irql + ); + + MxLock m_ListLock; +}; + +class FxWaitLockTransactionedList : public FxTransactionedList { + +public: + + FxWaitLockTransactionedList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + UNREFERENCED_PARAMETER(FxDriverGlobals); + } + + __inline + NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DEFN, "_Must_inspect_result_ not needed in kernel mode as the function always succeeds"); + Initialize( + VOID + ) + { + return m_StateChangeListLock.Initialize(); + } + +protected: + virtual + _Acquires_lock_(_Global_critical_region_) + VOID + AcquireLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __out PKIRQL Irql + ); + + virtual + _Releases_lock_(_Global_critical_region_) + VOID + ReleaseLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in KIRQL Irql + ); + + FxWaitLockInternal m_StateChangeListLock; +}; + +#endif // _FXTRANSACTIONEDLIST_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtypedefs.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtypedefs.hpp new file mode 100644 index 00000000000..42eddecd320 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtypedefs.hpp @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxtypedefs.hpp + +Abstract: + + Contains defines for types that are different in KMDF and UMDF + Respective defines are in km\fxtypedefsKm.hpp and um\fxtypedefsUm.hpp + + For example CfxDevice is defined as + FxDevice in km + AWDFDevice in um + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#pragma once + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + +#include "fxtypedefsKm.hpp" + +#else + +#include "fxtypedefsUm.hpp" + +#endif + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxtypes.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtypes.h new file mode 100644 index 00000000000..1a658b7fb26 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxtypes.h @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxTypes.h + +Abstract: + + This defines the memory tags for the frameworks objects + +Author: + + + + +Revision History: + + +--*/ + +#ifndef _FXTYPES_H +#define _FXTYPES_H + +// +// Might be expanded to a ULONG if we need the storage +// +typedef USHORT WDFTYPE; + + +enum FX_OBJECT_TYPES_BASE { + + FX_TYPES_BASE = 0x1000, + FX_TYPES_PACKAGES_BASE = 0x1100, + FX_TYPES_IO_TARGET_BASE = 0x1200, + FX_ABSTRACT_TYPES_BASE = 0x1300, + FX_TYPES_DMA_BASE = 0x1400, + FX_TYPES_INTERFACES_BASE = 0x1500, +}; + +enum FX_OBJECT_TYPES { + // Use Hex numbers since this the kd default dump value + + FX_TYPE_OBJECT = FX_TYPES_BASE+0x0, + FX_TYPE_DRIVER = FX_TYPES_BASE+0x1, + FX_TYPE_DEVICE = FX_TYPES_BASE+0x2, + FX_TYPE_QUEUE = FX_TYPES_BASE+0x3, + FX_TYPE_WMI_PROVIDER = FX_TYPES_BASE+0x4, + // can be reused = FX_TYPES_BASE+0x5, + FX_TYPE_REG_KEY = FX_TYPES_BASE+0x6, + FX_TYPE_STRING = FX_TYPES_BASE+0x7, + FX_TYPE_REQUEST = FX_TYPES_BASE+0x8, + FX_TYPE_LOOKASIDE = FX_TYPES_BASE+0x9, + IFX_TYPE_MEMORY = FX_TYPES_BASE+0xA, + FX_TYPE_IRPQUEUE = FX_TYPES_BASE+0xB, + FX_TYPE_USEROBJECT = FX_TYPES_BASE+0xC, + // can be reused FX_TYPES_BASE+0xD, + FX_TYPE_COLLECTION = FX_TYPES_BASE+0xE, + + + + + // can be reused = FX_TYPES_BASE+0x11, + FX_TYPE_VERIFIERLOCK = FX_TYPES_BASE+0x12, + FX_TYPE_SYSTEMTHREAD = FX_TYPES_BASE+0x13, + FX_TYPE_MP_DEVICE = FX_TYPES_BASE+0x14, + FX_TYPE_DPC = FX_TYPES_BASE+0x15, + FX_TYPE_RESOURCE_IO = FX_TYPES_BASE+0x16, + FX_TYPE_RESOURCE_CM = FX_TYPES_BASE+0x17, + FX_TYPE_FILEOBJECT = FX_TYPES_BASE+0x18, + // can be reused = FX_TYPES_BASE+0x19, + // can be reused = FX_TYPES_BASE+0x20, + FX_TYPE_RELATED_DEVICE = FX_TYPES_BASE+0x21, + FX_TYPE_MEMORY_PREALLOCATED = FX_TYPES_BASE+0x22, + FX_TYPE_WAIT_LOCK = FX_TYPES_BASE+0x23, + FX_TYPE_SPIN_LOCK = FX_TYPES_BASE+0x24, + FX_TYPE_WORKITEM = FX_TYPES_BASE+0x25, + FX_TYPE_CLEANUPLIST = FX_TYPES_BASE+0x26, + FX_TYPE_INTERRUPT = FX_TYPES_BASE+0x27, + FX_TYPE_TIMER = FX_TYPES_BASE+0x28, + FX_TYPE_CHILD_LIST = FX_TYPES_BASE+0x29, + FX_TYPE_DEVICE_BASE = FX_TYPES_BASE+0x30, + FX_TYPE_SYSTEMWORKITEM = FX_TYPES_BASE+0x31, + FX_TYPE_REQUEST_MEMORY = FX_TYPES_BASE+0x32, + FX_TYPE_DISPOSELIST = FX_TYPES_BASE+0x33, + FX_TYPE_WMI_INSTANCE = FX_TYPES_BASE+0x34, + FX_TYPE_IO_RES_LIST = FX_TYPES_BASE+0x35, + FX_TYPE_CM_RES_LIST = FX_TYPES_BASE+0x36, + FX_TYPE_IO_RES_REQ_LIST = FX_TYPES_BASE+0x37, + + FX_TYPE_PACKAGE_IO = FX_TYPES_PACKAGES_BASE+0x0, + FX_TYPE_PACKAGE_FDO = FX_TYPES_PACKAGES_BASE+0x1, + FX_TYPE_PACKAGE_PDO = FX_TYPES_PACKAGES_BASE+0x2, + FX_TYPE_WMI_IRP_HANDLER = FX_TYPES_PACKAGES_BASE+0x3, + FX_TYPE_PACKAGE_GENERAL = FX_TYPES_PACKAGES_BASE+0x4, + FX_TYPE_DEFAULT_IRP_HANDLER = FX_TYPES_PACKAGES_BASE+0x5, + FX_TYPE_WMI_TRACING_IRP_HANDLER = FX_TYPES_PACKAGES_BASE+0x6, + + FX_TYPE_IO_TARGET = FX_TYPES_IO_TARGET_BASE+0x0, + FX_TYPE_IO_TARGET_REMOTE = FX_TYPES_IO_TARGET_BASE+0x1, + FX_TYPE_IO_TARGET_USB_DEVICE = FX_TYPES_IO_TARGET_BASE+0x2, + FX_TYPE_IO_TARGET_USB_PIPE = FX_TYPES_IO_TARGET_BASE+0x3, + FX_TYPE_USB_INTERFACE = FX_TYPES_IO_TARGET_BASE+0x4, + FX_TYPE_IO_TARGET_SELF = FX_TYPES_IO_TARGET_BASE+0x5, + + FX_TYPE_DMA_ENABLER = FX_TYPES_DMA_BASE+0x0, + FX_TYPE_DMA_TRANSACTION = FX_TYPES_DMA_BASE+0x1, + FX_TYPE_COMMON_BUFFER = FX_TYPES_DMA_BASE+0x2, + + // Interfaces + FX_TYPE_IASSOCIATE = FX_TYPES_INTERFACES_BASE+0x01, + // unused + FX_TYPE_IHASCALLBACKS = FX_TYPES_INTERFACES_BASE+0x03, + // unused = FX_TYPES_INTERFACES_BASE+0x04, + + FX_TYPE_NONE = 0xFFFF, +}; + +// begin_wpp config +// CUSTOM_TYPE(FX_OBJECT_TYPES, ItemEnum(FX_OBJECT_TYPES)); +// end_wpp + +#endif // _FXTYPES_H diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbdevice.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbdevice.hpp new file mode 100644 index 00000000000..5890cbfae16 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbdevice.hpp @@ -0,0 +1,664 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbDevice.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXUSBDEVICE_H_ +#define _FXUSBDEVICE_H_ + +#include "FxUsbRequestContext.hpp" + +typedef enum _FX_URB_TYPE : UCHAR { + FxUrbTypeLegacy, + FxUrbTypeUsbdAllocated +} FX_URB_TYPE; + +struct FxUsbDeviceControlContext : public FxUsbRequestContext { + FxUsbDeviceControlContext( + __in FX_URB_TYPE FxUrbType + ); + + ~FxUsbDeviceControlContext( + VOID + ); + + __checkReturn + NTSTATUS + AllocateUrb( + __in USBD_HANDLE USBDHandle + ); + + virtual + VOID + Dispose( + VOID + ); + + virtual + VOID + CopyParameters( + __in FxRequestBase* Request + ); + + VOID + StoreAndReferenceMemory( + __in FxUsbDevice* Device, + __in FxRequestBuffer* Buffer, + __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket + ); + + virtual + VOID + ReleaseAndRestore( + __in FxRequestBase* Request + ); + + USBD_STATUS + GetUsbdStatus( + VOID + ); + +private: + USBD_HANDLE m_USBDHandle; + +public: + + _URB_CONTROL_TRANSFER m_UrbLegacy; + + // + // m_Urb will either point to m_UrbLegacy or one allocated by USBD_UrbAllocate + // + _URB_CONTROL_TRANSFER* m_Urb; + + PMDL m_PartialMdl; + + BOOLEAN m_UnlockPages; +}; + +struct FxUsbDeviceStringContext : public FxUsbRequestContext { + FxUsbDeviceStringContext( + __in FX_URB_TYPE FxUrbType + ); + + ~FxUsbDeviceStringContext( + VOID + ); + + __checkReturn + NTSTATUS + AllocateUrb( + __in USBD_HANDLE USBDHandle + ); + + virtual + VOID + Dispose( + VOID + ); + + virtual + VOID + CopyParameters( + __in FxRequestBase* Request + ); + + VOID + SetUrbInfo( + __in UCHAR StringIndex, + __in USHORT LangID + ); + + USBD_STATUS + GetUsbdStatus( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + AllocateDescriptor( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize + ); + +private: + USBD_HANDLE m_USBDHandle; + +public: + + _URB_CONTROL_DESCRIPTOR_REQUEST m_UrbLegacy; + + // + // m_Urb will either point to m_UrbLegacy or one allocated by USBD_UrbAllocate + // + _URB_CONTROL_DESCRIPTOR_REQUEST* m_Urb; + + PUSB_STRING_DESCRIPTOR m_StringDescriptor; + + ULONG m_StringDescriptorLength; +}; + +class FxUsbUrb : public FxMemoryBufferPreallocated { +public: + + FxUsbUrb( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USBD_HANDLE USBDHandle, + __in_bcount(BufferSize) PVOID Buffer, + __in size_t BufferSize + ); + +protected: + + virtual + BOOLEAN + Dispose( + VOID + ); + + ~FxUsbUrb(); + +private: + + USBD_HANDLE m_USBDHandle; +}; + + +#define FX_USB_DEVICE_TAG 'sUfD' + +class FxUsbDevice : public FxIoTarget { +public: + friend FxUsbPipe; + friend FxUsbInterface; + + FxUsbDevice( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + _Must_inspect_result_ + NTSTATUS + InitDevice( + __in ULONG USBDClientContractVersionForWdfClient + ); + + _Must_inspect_result_ + NTSTATUS + GetConfigDescriptor( + __out PVOID ConfigDescriptor, + __inout PUSHORT ConfigDescriptorLength + ); + + _Must_inspect_result_ + NTSTATUS + GetString( + __in_ecount(*NumCharacters) PUSHORT String, + __in PUSHORT NumCharacters, + __in UCHAR StringIndex, + __in_opt USHORT LangID, + __in_opt WDFREQUEST Request = NULL, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options = NULL + ); + + __inline + CopyDeviceDescriptor( + __out PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ) + { + RtlCopyMemory(UsbDeviceDescriptor, + &m_DeviceDescriptor, + sizeof(m_DeviceDescriptor)); + } + + VOID + GetInformation( + __out PWDF_USB_DEVICE_INFORMATION Information + ); + + __inline + USBD_CONFIGURATION_HANDLE + GetConfigHandle( + VOID + ) + { + return m_ConfigHandle; + } + + _Must_inspect_result_ + __inline + NTSTATUS + GetCurrentFrameNumber( + __in PULONG Current + ) + { + if (m_QueryBusTime != NULL) { + return m_QueryBusTime(m_BusInterfaceContext, Current); + } + else { + return STATUS_UNSUCCESSFUL; + } + } + + _Must_inspect_result_ + NTSTATUS + SelectConfigAuto( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes + ); + + _Must_inspect_result_ + NTSTATUS + SelectConfigInterfaces( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + __in_ecount(NumInterfaces)PUSB_INTERFACE_DESCRIPTOR* InterfaceDescriptors, + __in ULONG NumInterfaces + ); + + _Must_inspect_result_ + NTSTATUS + SelectConfig( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PURB Urb, + __in FX_URB_TYPE FxUrbType, + __out_opt PUCHAR NumConfiguredInterfaces + ); + + _Must_inspect_result_ + NTSTATUS + Deconfig( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + SelectInterfaceByInterface( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + + _Must_inspect_result_ + NTSTATUS + SelectInterface( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PURB Urb + ); + + UCHAR + GetNumInterfaces( + VOID + ) + { + return m_NumInterfaces; + } + + UCHAR + GetInterfaceNumEndpoints( + __in UCHAR InterfaceNumber + ); + + WDFUSBPIPE + GetInterfacePipeReferenced( + __in UCHAR InterfaceNumber, + __in UCHAR EndpointNumber + ); + + _Must_inspect_result_ + NTSTATUS + FormatStringRequest( + __in FxRequestBase* Request, + __in FxRequestBuffer *RequestBuffer, + __in UCHAR StringIndex, + __in USHORT LangID + ); + + _Must_inspect_result_ + NTSTATUS + FormatControlRequest( + __in FxRequestBase* Request, + __in PWDF_USB_CONTROL_SETUP_PACKET Packet, + __in FxRequestBuffer *RequestBuffer + ); + + _Must_inspect_result_ + NTSTATUS + IsConnected( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Reset( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + CyclePort( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + FormatCycleRequest( + __in FxRequestBase* Request + ); + + BOOLEAN + OnUSBD( + VOID + ) + { + return m_OnUSBD; + } + + USBD_PIPE_HANDLE + GetControlPipeHandle( + VOID + ) + { + return m_ControlPipe; + } + + _Must_inspect_result_ + NTSTATUS + CreateInterfaces( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + SelectConfigSingle( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + + _Must_inspect_result_ + NTSTATUS + SelectConfigMulti( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + + _Must_inspect_result_ + NTSTATUS + SelectConfigDescriptor( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + + FxUsbInterface * + GetInterfaceFromIndex( + __in UCHAR InterfaceIndex + ); + + BOOLEAN + HasMismatchedInterfacesInConfigDescriptor( + VOID + ) + { + return m_MismatchedInterfacesInConfigDescriptor; + } + + VOID + CancelSentIo( + VOID + ); + + BOOLEAN + IsEnabled( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + QueryUsbCapability( + __in + CONST GUID* CapabilityType, + __in + ULONG CapabilityBufferLength, + __drv_when(CapabilityBufferLength == 0, __out_opt) + __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength)) + __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + __out_opt + __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength)) + PULONG ResultLength + ); + + __checkReturn + NTSTATUS + CreateUrb( + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFMEMORY* UrbMemory, + __deref_opt_out_bcount(sizeof(URB)) + PURB* Urb + ); + +#pragma warning(disable:28285) + __checkReturn + NTSTATUS + CreateIsochUrb( + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __in + ULONG NumberOfIsochPackets, + __out + WDFMEMORY* UrbMemory, + __deref_opt_out_bcount(GET_ISOCH_URB_SIZE(NumberOfIsochPackets)) + PURB* Urb + ); + + USBD_HANDLE + GetUSBDHandle( + VOID + ) + { + return m_USBDHandle; + } + + FX_URB_TYPE + GetUrbType( + VOID + ) + { + return m_UrbType; + } + + FX_URB_TYPE + GetFxUrbTypeForRequest( + __in FxRequestBase* Request + ); + + BOOLEAN + IsObjectDisposedOnRemove( + __in FxObject* Object + ); + +protected: + ~FxUsbDevice( + VOID + ); + + VOID + RemoveDeletedInterface( + __in FxUsbInterface* Interface + ); + + // + // FxIoTarget overrides + // + virtual + _Must_inspect_result_ + NTSTATUS + Start( + VOID + ); + + virtual + VOID + Stop( + __in WDF_IO_TARGET_SENT_IO_ACTION Action + ); + + virtual + VOID + Purge( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action + ); + // end FxIoTarget overrides + + VOID + PipesGotoRemoveState( + __in BOOLEAN ForceRemovePipes + ); + + static + VOID + _CleanupPipesRequests( + __in PLIST_ENTRY PendHead, + __in PSINGLE_LIST_ENTRY SentHead + ); + + FxUsbInterface * + GetInterfaceFromNumber( + __in UCHAR InterfaceNumber + ); + + _Must_inspect_result_ + NTSTATUS + GetInterfaceNumberFromInterface( + __in WDFUSBINTERFACE UsbInterface, + __out PUCHAR InterfaceNumber + ); + + VOID + CleanupInterfacePipesAndDelete( + __in FxUsbInterface * UsbInterface + ); + + _Acquires_lock_(_Global_critical_region_) + VOID + AcquireInterfaceIterationLock( + VOID + ) + { + m_InterfaceIterationLock.AcquireLock(GetDriverGlobals()); + } + + _Releases_lock_(_Global_critical_region_) + VOID + ReleaseInterfaceIterationLock( + VOID + ) + { + m_InterfaceIterationLock.ReleaseLock(GetDriverGlobals()); + } + + ULONG + GetDefaultMaxTransferSize( + VOID + ); + + VOID + FormatInterfaceSelectSettingUrb( + __in PURB Urb, + __in USHORT NumEndpoints, + __in UCHAR InterfaceNumber, + __in UCHAR SettingNumber + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + GetPortStatus( + __out PULONG PortStatus + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + _Must_inspect_result_ + NTSTATUS + FxUsbDevice::SendSyncRequest( + __in FxSyncRequest* Request, + __in ULONGLONG Time + ); + + _Must_inspect_result_ + NTSTATUS + SendSyncUmUrb( + __inout PUMURB Urb, + __in ULONGLONG Time, + __in_opt WDFREQUEST Request = NULL, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options = NULL + ); +#endif + +protected: + USBD_HANDLE m_USBDHandle; + + USBD_PIPE_HANDLE m_ControlPipe; + + FxUsbInterface ** m_Interfaces; + + USBD_CONFIGURATION_HANDLE m_ConfigHandle; + + USB_DEVICE_DESCRIPTOR m_DeviceDescriptor; + + PUSB_CONFIGURATION_DESCRIPTOR m_ConfigDescriptor; + + USBD_VERSION_INFORMATION m_UsbdVersionInformation; + + PUSB_BUSIFFN_QUERY_BUS_TIME m_QueryBusTime; + + PVOID m_BusInterfaceContext; + + PINTERFACE_DEREFERENCE m_BusInterfaceDereference; + + FxWaitLockInternal m_InterfaceIterationLock; + + ULONG m_HcdPortCapabilities; + + ULONG m_Traits; + + BOOLEAN m_OnUSBD; + + UCHAR m_NumInterfaces; + + BOOLEAN m_MismatchedInterfacesInConfigDescriptor; + + FX_URB_TYPE m_UrbType; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +private: + // + // Used to format the IWudfIrp for user-mode requests + // + IWudfFile* m_pHostTargetFile; + + // + // Handle to the default USB interface exposed by WinUsb + // + WINUSB_INTERFACE_HANDLE m_WinUsbHandle; +#endif +}; + +#endif // _FXUSBDEVICE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbidleinfo.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbidleinfo.hpp new file mode 100644 index 00000000000..55554915a52 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbidleinfo.hpp @@ -0,0 +1,45 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXUSBIDLEINFO_H_ +#define _FXUSBIDLEINFO_H_ + +struct FxUsbIdleInfo : public FxStump { +public: + FxUsbIdleInfo( + __in FxPkgPnp* PkgPnp + ) : m_IdleCallbackEvent(NULL), m_IdleIrp(NULL) + { + m_CallbackInfo.IdleCallback = _UsbIdleCallback; + m_CallbackInfo.IdleContext = PkgPnp; + m_EventDropped = FALSE; + } + + _Must_inspect_result_ + NTSTATUS + Initialize( + VOID + ); + + FxCREvent* m_IdleCallbackEvent; + + FxAutoIrp m_IdleIrp; + + USB_IDLE_CALLBACK_INFO m_CallbackInfo; + + // + // used to check if UsbSelectiveSuspendCompleted event was dropped. + // + BOOLEAN m_EventDropped; + +private: + + __drv_maxIRQL(PASSIVE_LEVEL) + static + VOID + _UsbIdleCallback( + __in PVOID Context + ); +}; + +#endif // _FXUSBIDLEINFO_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbinterface.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbinterface.hpp new file mode 100644 index 00000000000..b9596a8ba1e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbinterface.hpp @@ -0,0 +1,270 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXUSBINTERFACE_H_ +#define _FXUSBINTERFACE_H_ + +extern "C" { +#include +#include +} + +#include "FxUsbRequestContext.hpp" + +#define FX_USB_INTERFACE_TAG 'uItG' //using a random uniqure value + + + +struct FxUsbInterfaceSetting{ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + + + + + + + USB_INTERFACE_DESCRIPTOR InterfaceDescriptorAlloc; +#endif +}; + +class FxUsbInterface : public FxNonPagedObject { //any base class +public: + friend FxUsbDevice; + friend FxUsbPipe; + //friend FxUsbTarget; + + FxUsbInterface( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxUsbDevice* UsbDevice, + _In_ PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + + VOID + SetInfo( + __in PUSBD_INTERFACE_INFORMATION Interface + ); + + VOID + CleanUpAndDelete( + __in BOOLEAN ClearDestroyCallback + ); + + _Must_inspect_result_ + NTSTATUS + SelectSetting( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PURB Urb + ); + + UCHAR + GetNumConfiguredPipes( + VOID + ) + { + return m_NumberOfConfiguredPipes; + } + + UCHAR + GetInterfaceNumber( + VOID + ) + { + return m_InterfaceNumber; + } + + UCHAR + GetNumSettings( + VOID + ) + { + return m_NumSettings; + } + + UCHAR + GetNumEndpoints( + __in UCHAR SettingIndex + ); + + VOID + GetEndpointInformation( + __in UCHAR SettingIndex, + __in UCHAR PipeIndex, + __in PWDF_USB_PIPE_INFORMATION PipeInfo + ); + + VOID + GetDescriptor( + __in PUSB_INTERFACE_DESCRIPTOR UsbInterfaceDescriptor, + __in UCHAR SettingIndex + ); + + //post config + + UCHAR + GetConfiguredSettingIndex( + VOID + ) ; + + WDFUSBPIPE + GetConfiguredPipe( + __in UCHAR PipeIndex, + __out_opt PWDF_USB_PIPE_INFORMATION PipeInfo + ); + + _Must_inspect_result_ + NTSTATUS + CreateSettings( + VOID + ); + + VOID + SetNumConfiguredPipes( + __in UCHAR NumberOfPipes + ) + { + m_NumberOfConfiguredPipes = NumberOfPipes; + } + + VOID + SetConfiguredPipes( + __in FxUsbPipe **ppPipes + ) + { + m_ConfiguredPipes = ppPipes; + } + + BOOLEAN + IsInterfaceConfigured( + VOID + ) + { + return m_ConfiguredPipes != NULL ? TRUE : FALSE; + } + + _Must_inspect_result_ + NTSTATUS + SelectSettingByDescriptor( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + + _Must_inspect_result_ + NTSTATUS + SelectSettingByIndex( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in UCHAR SettingIndex + ); + + VOID + CopyEndpointFieldsFromDescriptor( + __in PWDF_USB_PIPE_INFORMATION PipeInfo, + __in PUSB_ENDPOINT_DESCRIPTOR EndpointDesc, + __in UCHAR SettingIndex + ); + + ULONG + DetermineDefaultMaxTransferSize( + VOID + ); + + WDFUSBINTERFACE + GetHandle(VOID) + { + return (WDFUSBINTERFACE) GetObjectHandle(); + } + + PUSB_INTERFACE_DESCRIPTOR + GetSettingDescriptor( + __in UCHAR Setting + ); + + NTSTATUS + CheckAndSelectSettingByIndex( + __in UCHAR SettingIndex + ); + + NTSTATUS + UpdatePipeAttributes( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes + ); + +protected: + ~FxUsbInterface( + VOID + ); + + VOID + RemoveDeletedPipe( + __in FxUsbPipe* Pipe + ); + + VOID + FormatSelectSettingUrb( + __in_bcount(GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints)) PURB Urb, + __in USHORT NumEndpoints, + __in UCHAR SettingNumber + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +public: + NTSTATUS + SetWinUsbHandle( + _In_ UCHAR FrameworkInterfaceIndex + ); + + NTSTATUS + MakeAndConfigurePipes( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in UCHAR NumPipes + ); +#endif + +protected: + // + // Backpointer to the owning device + // + FxUsbDevice* m_UsbDevice; + + // + // Array of pipe pointers + // + FxUsbPipe** m_ConfiguredPipes; + + // + // Array of alternative settings for the interface + // + __field_ecount(m_NumSettings) FxUsbInterfaceSetting* m_Settings; + + // + // Number of elements in m_Settings + // + UCHAR m_NumSettings; + + // + // Number of elements in m_ConfiguredPipes + // + UCHAR m_NumberOfConfiguredPipes; + + // + // Information out of the interface descriptor + // + UCHAR m_InterfaceNumber; + UCHAR m_CurAlternateSetting; + UCHAR m_Class; + UCHAR m_SubClass; + UCHAR m_Protocol; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +private: + // + // Handle to USB interface exposed by WinUsb + // + WINUSB_INTERFACE_HANDLE m_WinUsbHandle; +#endif +}; + + +#endif // _FXUSBINTERFACE_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbpipe.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbpipe.hpp new file mode 100644 index 00000000000..6ddf6e81289 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbpipe.hpp @@ -0,0 +1,747 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXUSBPIPE_H_ +#define _FXUSBPIPE_H_ + +#include "FxUsbRequestContext.hpp" +#include "FxUsbInterface.hpp" + +// +// Technically, EHCI can support 4MB, but the usb driver stack doesn't +// allocate enough TDs for such a transfer, here I arbitrarily chose 2MB +// +enum FxUsbPipeMaxTransferSize { + FxUsbPipeHighSpeedMaxTransferSize = 2*1024*1024 , + FxUsbPipeLowSpeedMaxTransferSize = 256 * 1024, + FxUsbPipeControlMaxTransferSize = 4*1024 +}; + +struct FxUsbPipeTransferContext : public FxUsbRequestContext { + FxUsbPipeTransferContext( + __in FX_URB_TYPE UrbType + ); + + ~FxUsbPipeTransferContext( + VOID + ); + + __checkReturn + NTSTATUS + AllocateUrb( + __in USBD_HANDLE USBDHandle + ); + + virtual + VOID + Dispose( + VOID + ); + + virtual + VOID + CopyParameters( + __in FxRequestBase* Request + ); + + virtual + VOID + StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ); + + virtual + VOID + ReleaseAndRestore( + __in FxRequestBase* Request + ); + + VOID + SetUrbInfo( + __in USBD_PIPE_HANDLE PipeHandle, + __in ULONG TransferFlags + ); + + USBD_STATUS + GetUsbdStatus( + VOID + ); + + ULONG + GetUrbTransferLength( + VOID + ) + { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return m_Urb->TransferBufferLength; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + return m_UmUrb.UmUrbBulkOrInterruptTransfer.TransferBufferLength; +#endif + } + +private: + USBD_HANDLE m_USBDHandle; + +public: + _URB_BULK_OR_INTERRUPT_TRANSFER m_UrbLegacy; + + // + // m_Urb will either point to m_UrbLegacy or one allocated by USBD_UrbAllocate + // + _URB_BULK_OR_INTERRUPT_TRANSFER* m_Urb; + + PMDL m_PartialMdl; + + BOOLEAN m_UnlockPages; +}; + +struct FxUsbUrbContext : public FxUsbRequestContext { + FxUsbUrbContext( + VOID + ); + + USBD_STATUS + GetUsbdStatus( + VOID + ); + + virtual + VOID + StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ); + + virtual + VOID + ReleaseAndRestore( + __in FxRequestBase* Request + ); + + PURB m_pUrb; +}; + +struct FxUsbPipeRequestContext : public FxUsbRequestContext { + FxUsbPipeRequestContext( + __in FX_URB_TYPE FxUrbType + ); + + ~FxUsbPipeRequestContext( + VOID + ); + + __checkReturn + NTSTATUS + AllocateUrb( + __in USBD_HANDLE USBDHandle + ); + + virtual + VOID + Dispose( + VOID + ); + + VOID + SetInfo( + __in WDF_USB_REQUEST_TYPE Type, + __in USBD_PIPE_HANDLE PipeHandle, + __in USHORT Function + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + VOID + SetInfo( + __in WDF_USB_REQUEST_TYPE Type, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in UCHAR PipeId, + __in USHORT Function + ); +#endif + + USBD_STATUS + GetUsbdStatus( + VOID + ); + +private: + USBD_HANDLE m_USBDHandle; + +public: + _URB_PIPE_REQUEST m_UrbLegacy; + + // + // m_Urb will either point to m_UrbLegacy or one allocated by USBD_UrbAllocate + // + _URB_PIPE_REQUEST* m_Urb; + +}; + +struct FxUsbPipeRepeatReader { + // + // Request used to send IRPs + // + FxRequest* Request; + + // + // IRP out of Request. Store it off so we don't have to call + // Request->GetSubmitIrp() everytime. + // + MdIrp RequestIrp; + + // + // The containing parent + // + FxUsbPipeContinuousReader* Parent; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // DPC to queue ourselves to when a read completes so that we don't spin in + // the same thread repeatedly. + // + KDPC Dpc; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // Workitem to queue ourselves to when a read completes so that we don't recurse in + // the same thread repeatedly. + // + MxWorkItem m_ReadWorkItem; + + // + // Check if the CR got called on a recursive call + // + LONG ThreadOwnerId; +#endif + + // + // Event that is set when the reader has completed and is not + // + MxEvent ReadCompletedEvent; +}; + +#define NUM_PENDING_READS_DEFAULT (2) +#define NUM_PENDING_READS_MAX (10) + +// +// Work-item callback flags +// +#define FX_USB_WORKITEM_IN_PROGRESS (0x00000001) +#define FX_USB_WORKITEM_RERUN (0x00000002) + +// +// In theory this can be a base class independent of bus type, but this is +// easier for now and there is no need on another bus type yet. +// +struct FxUsbPipeContinuousReader : public FxStump { +public: + FxUsbPipeContinuousReader( + __in FxUsbPipe* Pipe, + __in UCHAR NumReaders + ); + + ~FxUsbPipeContinuousReader(); + + _Must_inspect_result_ + NTSTATUS + Config( + __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, + __in size_t TotalBufferLength + ); + + PVOID + operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __range(1, NUM_PENDING_READS_MAX) ULONG NumReaders + ); + + _Must_inspect_result_ + NTSTATUS + FormatRepeater( + __in FxUsbPipeRepeatReader* Repeater + ); + + VOID + CancelRepeaters( + VOID + ); + + ULONG + ResubmitRepeater( + __in FxUsbPipeRepeatReader* Repeater, + __out NTSTATUS* Status + ); + +protected: + VOID + DeleteMemory( + __in FxRequestBase* Request + ) + { + FxRequestContext* pContext; + + pContext = Request->GetContext(); + if (pContext != NULL && pContext->m_RequestMemory != NULL) { + pContext->m_RequestMemory->Delete(); + // + // NOTE: Don't NULL out the m_RequestMemory member as this will + // prevent Reuse from releasing a reference on the m_RequestMemory object + // and hence these memory objects will not be freed. + // + } + } + + BOOLEAN + QueueWorkItemLocked( + __in FxUsbPipeRepeatReader* Repeater + ); + + __inline + VOID + FxUsbPipeRequestWorkItemHandler( + __in FxUsbPipeRepeatReader* FailedRepeater + ); + + static + MdDeferredRoutineType + _FxUsbPipeContinuousReadDpc; + + static + MX_WORKITEM_ROUTINE + _ReadWorkItem; + + + static + EVT_WDF_REQUEST_COMPLETION_ROUTINE + _FxUsbPipeRequestComplete; + + static + EVT_SYSTEMWORKITEM + _FxUsbPipeRequestWorkItemThunk; + +public: + // + // Completion routine for the client + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE m_ReadCompleteCallback; + + // + // Context for completion routine + // + WDFCONTEXT m_ReadCompleteContext; + + // + // Callback to invoke when a reader fails + // + PFN_WDF_USB_READERS_FAILED m_ReadersFailedCallback; + + // + // The owning pipe + // + FxUsbPipe* m_Pipe; + + // + // Lookaside list from which we will allocate buffers for each new read + // + FxLookasideList* m_Lookaside; + + // + // The devobj we are sending requests to + // + MdDeviceObject m_TargetDevice; + + // + // Offsets and length into the memory buffers created by the lookaside list + // + WDFMEMORY_OFFSET m_Offsets; + + // + // Work item to queue when we hit various errors + // + FxSystemWorkItem* m_WorkItem; + + // + // Work item re-run context. + // + PVOID m_WorkItemRerunContext; + + // + // This is a pointer to the work-item's thread object. This value is + // used for not deadlocking when misbehaved drivers (< v1.9) call + // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback. + // + volatile POINTER_ALIGNMENT MxThread m_WorkItemThread; + + // + // Work item flags (see FX_USB_WORKITEM_Xxx defines). + // + ULONG m_WorkItemFlags; + + // + // Number of readers who have failed due to internal allocation errors + // + UCHAR m_NumFailedReaders; + + // + // Number of readers + // + UCHAR m_NumReaders; + + // + // Value to use with InterlockedXxx to test to see if a work item has been + // queued or not + // + BOOLEAN m_WorkItemQueued; + + // + // Track whether the readers should be submitted when moving into the start + // state. We cannot just track a start -> start transition and not send + // the readers on that particular state transition because the first time + // we need to send the readers, the target is already in the started state + // + BOOLEAN m_ReadersSubmitted; + + // + // Open ended array of readers. MUST be the last element in this structure. + // + FxUsbPipeRepeatReader m_Readers[1]; +}; + +class FxUsbPipe : public FxIoTarget { +public: + friend FxUsbDevice; + friend FxUsbInterface; + friend FxUsbPipeContinuousReader; + + FxUsbPipe( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxUsbDevice* UsbDevice + ); + + VOID + InitPipe( + __in PUSBD_PIPE_INFORMATION PipeInfo, + __in UCHAR InterfaceNumber, + __in FxUsbInterface* UsbInterface + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + VOID + InitPipe( + __in PWINUSB_PIPE_INFORMATION PipeInfo, + __in UCHAR InterfaceNumber, + __in FxUsbInterface* UsbInterface + ); +#endif + + _Must_inspect_result_ + virtual + NTSTATUS + GotoStartState( + __in PLIST_ENTRY RequestListHead, + __in BOOLEAN Lock = TRUE + ); + + virtual + VOID + GotoStopState( + __in WDF_IO_TARGET_SENT_IO_ACTION Action, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ); + + VOID + GotoPurgeState( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ); + + virtual + VOID + GotoRemoveState( + __in WDF_IO_TARGET_STATE NewState, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __in BOOLEAN Lock, + __out PBOOLEAN Wait + ); + + virtual + VOID + WaitForSentIoToComplete( + VOID + ); + + __inline + VOID + SetNoCheckPacketSize( + VOID + ) + { + m_CheckPacketSize = FALSE; + } + + VOID + GetInformation( + __out PWDF_USB_PIPE_INFORMATION PipeInformation + ); + + BOOLEAN + IsType( + __in WDF_USB_PIPE_TYPE Type + ); + + + WDF_USB_PIPE_TYPE + GetType( + VOID + ); + + WDFUSBPIPE + GetHandle( + VOID + ) + { + return (WDFUSBPIPE) GetObjectHandle(); + } + + __inline + BOOLEAN + IsInEndpoint( + VOID + ) + { + // + // USB_ENDPOINT_DIRECTION_IN just does a bitwise compre so it could + // return 0 or some non zero value. Make sure the non zero value is + // TRUE + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return USB_ENDPOINT_DIRECTION_IN(m_PipeInformation.EndpointAddress) ? TRUE : FALSE; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + return USB_ENDPOINT_DIRECTION_IN(m_PipeInformationUm.PipeId) ? TRUE : FALSE; +#endif + } + + __inline + BOOLEAN + IsOutEndpoint( + VOID + ) + { + // + // USB_ENDPOINT_DIRECTION_OUT just does a bitwise compre so it could + // return 0 or some non zero value. Make sure the non zero value is + // TRUE + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return USB_ENDPOINT_DIRECTION_OUT(m_PipeInformation.EndpointAddress) ? TRUE : FALSE; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + return USB_ENDPOINT_DIRECTION_OUT(m_PipeInformationUm.PipeId) ? TRUE : FALSE; +#endif + } + + _Must_inspect_result_ + NTSTATUS + InitContinuousReader( + __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, + __in size_t TotalBufferLength + ); + + ULONG + GetMaxPacketSize( + VOID + ) + { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + return m_PipeInformation.MaximumPacketSize; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + return m_PipeInformationUm.MaximumPacketSize; +#endif + } + + _Must_inspect_result_ + NTSTATUS + ValidateTransferLength( + __in size_t Length + ) + { + // + // Assumes this is not a control pipe + // + if (m_CheckPacketSize && +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + (Length % m_PipeInformation.MaximumPacketSize) != 0) { +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + (Length % m_PipeInformationUm.MaximumPacketSize) != 0) { +#endif + return STATUS_INVALID_BUFFER_SIZE; + } + else { + return STATUS_SUCCESS; + } + } + + _Must_inspect_result_ + NTSTATUS + FormatTransferRequest( + __in FxRequestBase* Request, + __in FxRequestBuffer* Buffer, + __in ULONG TransferFlags = 0 + ); + + _Must_inspect_result_ + NTSTATUS + FormatAbortRequest( + __in FxRequestBase* Request + ); + + _Must_inspect_result_ + NTSTATUS + FormatResetRequest( + __in FxRequestBase* Request + ); + + static + _Must_inspect_result_ + NTSTATUS + _FormatTransfer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFUSBPIPE Pipe, + __in WDFREQUEST Request, + __in_opt WDFMEMORY TransferMemory, + __in_opt PWDFMEMORY_OFFSET TransferOffsets, + __in ULONG Flags + ); + + static + _Must_inspect_result_ + NTSTATUS + _SendTransfer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFUSBPIPE Pipe, + __in_opt WDFREQUEST Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in_opt PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + __out_opt PULONG BytesTransferred, + __in ULONG Flags + ); + + USBD_PIPE_HANDLE + WdmGetPipeHandle( + VOID + ) + { + return m_PipeInformation.PipeHandle; + } + + static + WDF_USB_PIPE_TYPE + _UsbdPipeTypeToWdf( + __in USBD_PIPE_TYPE UsbdPipeType + ) + { + const static WDF_USB_PIPE_TYPE types[] = { + WdfUsbPipeTypeControl, // UsbdPipeTypeControl + WdfUsbPipeTypeIsochronous, // UsbdPipeTypeIsochronous + WdfUsbPipeTypeBulk, // UsbdPipeTypeBulk + WdfUsbPipeTypeInterrupt, // UsbdPipeTypeInterrupt + }; + + if (UsbdPipeType < sizeof(types)/sizeof(types[0])) { + return types[UsbdPipeType]; + } + else { + return WdfUsbPipeTypeInvalid; + } + } + + NTSTATUS + Reset( + VOID + ); + + USBD_HANDLE + GetUSBDHandle( + VOID + ) + { + return m_USBDHandle; + } + + FX_URB_TYPE + GetUrbType( + VOID + ) + { + return m_UrbType; + } + +public: + // + // Link for FxUsbDevice to use to hold a list of Pipes + // + LIST_ENTRY m_ListEntry; + +protected: + ~FxUsbPipe(); + + virtual + BOOLEAN + Dispose( + VOID + ); + + FxUsbDevice* m_UsbDevice; + + FxUsbInterface* m_UsbInterface; + + // + // If the pipe does not have a continuous reader, this field is NULL. + // It is also cleared within the pipe's Dispose function after deleting + // the continuous reader to prevent misbehaved drivers from + // crashing the system when they call WdfIoTargetStop from their usb pipe's + // destroy callback. + // + FxUsbPipeContinuousReader* m_Reader; + + // + // Information about this pipe + // + USBD_PIPE_INFORMATION m_PipeInformation; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + + + WINUSB_PIPE_INFORMATION m_PipeInformationUm; +#endif + + // + // Interface associated with this pipe + // + UCHAR m_InterfaceNumber; + + // + // Indicates if we should check that the buffer being trasnfered is of a + // multiple of max packet size. + // + BOOLEAN m_CheckPacketSize; + + // + // The USBD_HANDLE exchanged by FxUsbDevice + // + USBD_HANDLE m_USBDHandle; + + // + // If the client driver submits an URB to do a USB transfer, this field indicates + // the type of that Urb + // + FX_URB_TYPE m_UrbType; + +}; + +#endif // _FXUSBPIPE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbrequestcontext.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbrequestcontext.hpp new file mode 100644 index 00000000000..8c560b5313c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxusbrequestcontext.hpp @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbRequestContext.hpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXUSBREQUESTCONTEXT_H_ +#define _FXUSBREQUESTCONTEXT_H_ + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include +#endif + +struct FxUsbRequestContext : public FxRequestContext { + FxUsbRequestContext( + __in FX_REQUEST_CONTEXT_TYPE Type + ) : + FxRequestContext(Type) + { + InitUsbParameters(); + SetUsbType(WdfUsbRequestTypeNoFormat); + } + + virtual + USBD_STATUS + GetUsbdStatus( + VOID + ) = 0; + + virtual + VOID + CopyParameters( + __in FxRequestBase* Request + ) + { + m_UsbParameters.UsbdStatus = GetUsbdStatus(); + __super::CopyParameters(Request); + } + + VOID + SetUsbType( + __in WDF_USB_REQUEST_TYPE Type + ) + { + // + // The completion params are set every time we set the type + // + m_CompletionParams.Type = WdfRequestTypeUsb; + m_CompletionParams.Parameters.Usb.Completion = &m_UsbParameters; + + m_UsbParameters.Type = Type; + } + + VOID + __inline + InitUsbParameters( + VOID + ) + { + RtlZeroMemory(&m_UsbParameters, sizeof(m_UsbParameters)); + } + +public: + WDF_USB_REQUEST_COMPLETION_PARAMS m_UsbParameters; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // UMURB we send to the WUDF USB Dispatcher. The dispatcher + // extracts the encoded data and passes it to WinUsb APIs. + // + UMURB m_UmUrb; +#endif +}; + +#endif // _FXUSBREQUESTCONTEXT_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxuserobject.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxuserobject.hpp new file mode 100644 index 00000000000..43372110423 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxuserobject.hpp @@ -0,0 +1,106 @@ + +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxUserObject.hpp + +Abstract: + + This module implements the user object that device + driver writers can use to take advantage of the + driver frameworks infrastructure. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + Made mode agnostic + +--*/ + +#ifndef _FXUSEROBJECT_H_ +#define _FXUSEROBJECT_H_ + +class FxUserObject : public FxNonPagedObject { + +private: + +public: + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out FxUserObject** Object + ); + + FxUserObject( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + NTSTATUS + QueryInterface( + __in FxQueryInterfaceParams* Params + ) + { + switch (Params->Type) { + case FX_TYPE_USEROBJECT: + *Params->Object = (FxUserObject*) this; + break; + + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; + } + + __inline + WDFOBJECT + GetHandle( + VOID + ) + { + return (WDFOBJECT) GetObjectHandle(); + } + +private: + +#ifdef INLINE_WRAPPER_ALLOCATION +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + static + USHORT + GetWrapperSize( + VOID + ); + +public: + FORCEINLINE + PVOID + GetCOMWrapper( + VOID + ) + { + PBYTE ptr = (PBYTE) this; + return (ptr + (USHORT) WDF_ALIGN_SIZE_UP(sizeof(*this), MEMORY_ALLOCATION_ALIGNMENT)); + } +#endif +#endif +}; + +#endif // _FXUSEROBJECT_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxvalidatefunctions.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxvalidatefunctions.hpp new file mode 100644 index 00000000000..0b2855febe6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxvalidatefunctions.hpp @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxValidateFunctions.h + +Abstract: + + Inline functions which validate external WDF data structures + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + Made it mode agnostic + + Moved request options validation to FxRequestValidateFunctions.hpp + in kmdf\inc\private + + When request is merged FxRequestValidateFunctions.hpp can be moved to + shared directory + +--*/ + +#ifndef _FXVALIDATEFUNCTIONS_H_ +#define _FXVALIDATEFUNCTIONS_H_ + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxValidateFunctions.hpp.tmh" +#endif + +} + +enum FX_VALIDATE_FUNCTIONS_FLAGS { + FX_VALIDATE_OPTION_NONE_SPECIFIED = 0x00000000, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED = 0x00000001, + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED = 0x00000002, + FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED = 0x00000004, + FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED = 0x00000008, + + // not used directly, use FX_VALIDATE_OPTION_PARENT_REQUIRED instead + FX_VALIDATE_OPTION_PARENT_REQUIRED_FLAG = 0x00000010, + + // if a parent is required, the attributes themselves are requried + FX_VALIDATE_OPTION_PARENT_REQUIRED = FX_VALIDATE_OPTION_PARENT_REQUIRED_FLAG | + FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED, +}; + +_Must_inspect_result_ +NTSTATUS +FxValidateObjectAttributes( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in ULONG Flags = FX_VALIDATE_OPTION_NONE_SPECIFIED + ); + +_Must_inspect_result_ +NTSTATUS +__inline +FxValidateObjectAttributesForParentHandle( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in ULONG Flags = FX_VALIDATE_OPTION_NONE_SPECIFIED + ) +{ + if (Attributes == NULL) { + if (Flags & FX_VALIDATE_OPTION_PARENT_REQUIRED) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDF_OBJECT_ATTRIBUTES required, %!STATUS!", + (ULONG) STATUS_WDF_PARENT_NOT_SPECIFIED); + } + return STATUS_WDF_PARENT_NOT_SPECIFIED; + } + + if (Attributes->Size != sizeof(WDF_OBJECT_ATTRIBUTES)) { + // + // Size is wrong, bail out + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p Size incorrect, expected %d, got %d, %!STATUS!", + Attributes, sizeof(WDF_OBJECT_ATTRIBUTES), + Attributes->Size, STATUS_INFO_LENGTH_MISMATCH); + + return STATUS_INFO_LENGTH_MISMATCH; + } + + if (Attributes->ParentObject == NULL) { + if (Flags & FX_VALIDATE_OPTION_PARENT_REQUIRED) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "ParentObject required in WDF_OBJECT_ATTRIBUTES %p, %!STATUS!", + Attributes, STATUS_WDF_PARENT_NOT_SPECIFIED); + } + return STATUS_WDF_PARENT_NOT_SPECIFIED; + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +__inline +FxValidateUnicodeString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING String + ) +{ + NTSTATUS status; + + status = STATUS_INVALID_PARAMETER; + + if (String->Length & 1) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "UNICODE_STRING %p, Length %d is odd, %!STATUS!", + String, String->Length, status); + + return status; + } + + if (String->MaximumLength & 1) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "UNICODE_STRING %p, MaximumLength %d is odd, %!STATUS!", + String, String->MaximumLength, status); + + return status; + } + + if (String->MaximumLength > 0 && String->Buffer == NULL) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "UNICODE_STRING %p, MaximumLength %d > 0, Buffer is NULL, %!STATUS!", + String, String->MaximumLength, status); + + return status; + } + + if (String->Length > String->MaximumLength) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "UNICODE_STRING %p, Length %d > MaximumLength %d, %!STATUS!", + String, String->Length, String->MaximumLength, status); + + return status; + } + + return STATUS_SUCCESS; +} + +#endif // _FXVALIDATEFUNCTIONS_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxverifier.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxverifier.h new file mode 100644 index 00000000000..5cfd5916714 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxverifier.h @@ -0,0 +1,263 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxVerifier.cpp + +Abstract: + + This is the main driver framework verifier + +Environment: + + kernel/user mode + +Revision History: + + + Made it mode agnostic + +--*/ + +#ifndef _FXVERIFIER_H_ +#define _FXVERIFIER_H_ + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxVerifier.h.tmh" +#endif +} + + +enum FxEnhancedVerifierBitFlags { + // + // low 2 bytes are used for function table Hooking + // + FxEnhancedVerifierCallbackIrqlAndCRCheck = 0x00000001, + // + // Lower nibble of 3rd byte for forward progress + // + FxEnhancedVerifierForwardProgressFailAll = 0x00010000, + FxEnhancedVerifierForwardProgressFailRandom = 0x00020000, + + // + // bit masks + // + FxEnhancedVerifierFunctionTableHookMask = 0x0000ffff, + FxEnhancedVerifierForwardProgressMask = 0x000f0000, + + // + // higher nibble of 3rd byte for performance analysis + // + FxEnhancedVerifierPerformanceAnalysisMask = 0x00f00000, +}; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#define FxVerifierBugCheck(FxDriverGlobals, Error, ...) \ + FX_VERIFY_WITH_NAME(DRIVER(BadAction, Error), \ + TRAPMSG("WDF Violation: Please check" \ + "tracelog for a description of this error"), \ + FxDriverGlobals->Public.DriverName) +#else +#define FxVerifierBugCheck(FxDriverGlobals, ...) \ + FxVerifierBugCheckWorker(FxDriverGlobals, __VA_ARGS__); +#endif + +// +// FxVerifierDbgBreakPoint and FxVerifierBreakOnDeviceStateError are mapped +// to FX_VERIFY in UMDF and break regardless of any flags +// +__inline +VOID +FxVerifierDbgBreakPoint( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ +#if FX_CORE_MODE == FX_CORE_KERNEL_MODE + CHAR ext[] = "sys"; +#else + CHAR ext[] = "dll"; +#endif + + Mx::MxDbgPrint("WDF detected potentially invalid operation by %s.%s " + "Dump the driver log (!wdflogdump %s.%s) for more information.\n", + FxDriverGlobals->Public.DriverName, ext, + FxDriverGlobals->Public.DriverName, ext + ); + + if (FxDriverGlobals->FxVerifierDbgBreakOnError) { + Mx::MxDbgBreakPoint(); + } else { + Mx::MxDbgPrint("Turn on framework verifier for %s.%s to automatically " + "break into the debugger next time it happens.\n", + FxDriverGlobals->Public.DriverName, ext); + } +} + +__inline +VOID +FxVerifierBreakOnDeviceStateError( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ +#if FX_CORE_MODE == FX_CORE_KERNEL_MODE + CHAR ext[] = "sys"; +#else + CHAR ext[] = "dll"; +#endif + + Mx::MxDbgPrint("WDF detected potentially invalid device state in %s.%s. " + "Dump the driver log (!wdflogdump %s.$s) for more information.\n", + FxDriverGlobals->Public.DriverName, ext, + FxDriverGlobals->Public.DriverName, ext); + + if (FxDriverGlobals->FxVerifierDbgBreakOnDeviceStateError) { + Mx::MxDbgBreakPoint(); + } else { + Mx::MxDbgPrint("Turn on framework verifier for %s.%s to automatically " + "break into the debugger next time it happens.\n", + FxDriverGlobals->Public.DriverName, ext); + } +} + +__inline +BOOLEAN +IsFxVerifierFunctionTableHooking( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if (FxDriverGlobals->FxEnhancedVerifierOptions & + FxEnhancedVerifierFunctionTableHookMask) { + return TRUE; + } + else { + return FALSE; + } +} + +VOID +__declspec(noreturn) +FxVerifierBugCheckWorker( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDF_BUGCHECK_CODES WdfBugCheckCode, + __in_opt ULONG_PTR BugCheckParameter2 = 0, + __in_opt ULONG_PTR BugCheckParameter3 = 0 + ); + +VOID +__declspec(noreturn) +FxVerifierNullBugCheck( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID ReturnAddress + ); + +__inline +NTSTATUS +FxVerifierCheckIrqlLevel( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in KIRQL Irql + ) +/*++ + +Routine Description: + Check that current IRQL matches expected IRQL. + +Arguments: + Irql - The expected IRQL + +Return Value: + STATUS_SUCCESS if expected IRQL matches current IRQL. + STATUS_INVALID_DEVICE_REQUEST if expected IRQL does not match current IRQL. + + --*/ +{ + // + // Full treatment only if VerifierOn is set. + // + if (FxDriverGlobals->FxVerifierOn) { + + KIRQL currentIrql = Mx::MxGetCurrentIrql(); + + if (currentIrql <= Irql) { + return STATUS_SUCCESS; + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Called at wrong IRQL; at level %d, should be " + "at level %d", currentIrql, Irql); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // If Verifier is turned off, always return success. + // + return STATUS_SUCCESS; +} + + +__inline +BOOLEAN +IsFxVerifierTestForwardProgressFailAll( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if (FxDriverGlobals->FxEnhancedVerifierOptions & + FxEnhancedVerifierForwardProgressFailAll) { + return TRUE; + } + else { + return FALSE; + } +} + +__inline +BOOLEAN +IsFxVerifierTestForwardProgressFailRandom( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if (FxDriverGlobals->FxEnhancedVerifierOptions & + FxEnhancedVerifierForwardProgressFailRandom) { + return TRUE; + } + else { + return FALSE; + } +} + +__inline +BOOLEAN +IsFxVerifierTestForwardProgress( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if (FxDriverGlobals->FxEnhancedVerifierOptions & + FxEnhancedVerifierForwardProgressMask) { + return TRUE; + } + else { + return FALSE; + } +} + +__inline +BOOLEAN +IsFxPerformanceAnalysis( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if (FxDriverGlobals->FxEnhancedVerifierOptions & + FxEnhancedVerifierPerformanceAnalysisMask) { + return TRUE; + } + else { + return FALSE; + } +} + +#endif // _FXVERIFIER_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxverifierlock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxverifierlock.hpp new file mode 100644 index 00000000000..2ed37f863fe --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxverifierlock.hpp @@ -0,0 +1,562 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxVerifierLock.hpp + +Abstract: + + This is the C++ header for the verifier FxLock + + This separate object allows the verifier overhead + to only be allocated when WdfVerifierLock is on. + +Author: + + + +Revision History: + + + Made it mode agnostic + + New failure paths: + m_Mutex/m_Lock initialize + To enforce initialization hidden constructors + Callers are forced to use CreateAndInitialize methods + +--*/ + +#ifndef _FXVERIFIERLOCK_HPP_ +#define _FXVERIFIERLOCK_HPP_ + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxVerifierLock.hpp.tmh" +#endif +} + +/** + * These define the lock order used by verifier + * for basic objects internal to the driver frameworks. + * + * Higher numbers are "lower" locks in the hierachy, which means + * a lock can be acquired if its number greater than or equal + * to the current one. + * + * Correct Order: + * + * FX_LOCK_ORDER_DRIVER -> FX_LOCK_ORDER_QUEUE -> FX_LOCK_ORDER_REQUEST + * + * Incorrect Order: + * + * FX_LOCK_ORDER_DRIVER -> FX_LOCK_ORDER_QUEUE -> FX_LOCK_ORDER_DEVICE + * + * FX_LOCK_ORDER_UNKNOWN represents an object who has not (yet) + * defined a lock order. It has the highest number, meaning it + * can be acquired holding any other locks, including itself. + * At some point in time, this will cause a verifier break point, + * otherwise we can not fully test the frameworks. + * + * FX_LOCK_ORDER_NONE is a statement by the object that it will + * not use its Lock/Unlock routines. Use of locks on this object + * under verifier will cause a verifier breakpoint. + * + * There is a table mapping these from FX_TYPE_* to the lock orders + * define here in fx\core\FxVerifierLock.cpp + * + */ + +// +// These locks are driver frameworks "internal" object +// locks and are not intended to be held across callbacks +// to the driver. +// +// They are acquired and released as the result of driver +// calls into the frameworks, which may be holding a driver +// callback lock. +// +#define FX_LOCK_ORDER_NONE 0x0000 +#define FX_LOCK_ORDER_UNKNOWN 0xFFFF + +#define FX_LOCK_ORDER_PACKAGE_PDO 0x1000 +#define FX_LOCK_ORDER_PACKAGE_FDO 0x1000 +#define FX_LOCK_ORDER_WMI_IRP_HANDLER 0x1000 +#define FX_LOCK_ORDER_PACKAGE_GENERAL 0x1000 + +#define FX_LOCK_ORDER_IO_TARGET 0x1000 + +#define FX_LOCK_ORDER_WMI_PROVIDER 0x1001 +#define FX_LOCK_ORDER_WMI_INSTANCE 0x1002 + +#define FX_LOCK_ORDER_DMA_ENABLER 0x1000 +#define FX_LOCK_ORDER_DMA_TRANSACTION 0x1001 +#define FX_LOCK_ORDER_COMMON_BUFFER 0x1001 + +// +// A USB device owns a bunch of pipes, so make sure that device can acquire a +// pipe lock while locked, but not vice versa +// +#define FX_LOCK_ORDER_USB_DEVICE_IO_TARGET 0x1000 +#define FX_LOCK_ORDER_USB_PIPE_IO_TARGET 0x1001 + + +#define FX_LOCK_ORDER_DRIVER 0x1010 +#define FX_LOCK_ORDER_DEVICE 0x1020 +#define FX_LOCK_ORDER_MP_DEVICE 0x1020 +#define FX_LOCK_ORDER_DEFAULT_IRP_HANDLER 0x1030 +#define FX_LOCK_ORDER_QUEUE 0x1030 +#define FX_LOCK_ORDER_PACKAGE_IO 0x1031 +#define FX_LOCK_ORDER_REQUEST 0x1040 +#define FX_LOCK_ORDER_IRPQUEUE 0x1051 +#define FX_LOCK_ORDER_TIMER 0x1059 +#define FX_LOCK_ORDER_DPC 0x1060 +#define FX_LOCK_ORDER_WORKITEM 0x1060 +#define FX_LOCK_ORDER_CLEANUPLIST 0x1060 +#define FX_LOCK_ORDER_INTERRUPT 0x1060 +#define FX_LOCK_ORDER_FILEOBJECT 0x1060 +#define FX_LOCK_ORDER_DEVICE_LIST 0x1061 +#define FX_LOCK_ORDER_COLLECTION 0x1070 // collection can be used in any + // of the above object's callbacks +#define FX_LOCK_ORDER_USEROBJECT 0x2000 + +// dispose list is very far down in the list because pretty much any item can +// be added to the dispose list while that object's lock is being held +#define FX_LOCK_ORDER_DISPOSELIST 0x8000 + +#define FX_LOCK_ORDER_SYSTEMWORKITEM FX_LOCK_ORDER_UNKNOWN +#define FX_LOCK_ORDER_SYSTEMTHREAD FX_LOCK_ORDER_UNKNOWN // No lock level + +// +// These are the device driver callback locks +// used to synchronize callback to the device +// driver. They are "higher" than the internal +// frameworks locks since an internal frameworks lock +// should not be held when these are acquired. +// +// (which should only be due to FxCallback.Invoke to a driver +// event handler) +// +// This means they must have a lower number than the internal frameworks +// locks. +// +// They may be held when a device driver is calling into a frameworks +// DDI while in an event callback handler. +// +// These levels enforce not only the level of locks acquired +// and released by and for the driver, but also the rules +// about holding internal frameworks locks when calling into +// a driver. If a frameworks bug is holding a frameworks lock +// when it goes to do a callback, the attempt to acquire the +// lower numbered lock will raise the error. +// +#define FX_CALLBACKLOCK_ORDER_DRIVER 0x10 +#define FX_CALLBACKLOCK_ORDER_DEVICE 0x20 +#define FX_CALLBACKLOCK_ORDER_PACKAGE 0x30 +#define FX_CALLBACKLOCK_ORDER_QUEUE 0x31 + +#define FX_VERIFIER_LOCK_ENTRY(FX_OBJECT_TYPE, FX_LOCK_ORDER) { ##FX_OBJECT_TYPE, ##FX_LOCK_ORDER } + +// Internal FxLock spinlock entries +#define FX_VERIFIER_LOCK_ENTRIES() \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DRIVER, FX_LOCK_ORDER_DRIVER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEVICE, FX_LOCK_ORDER_DEVICE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_MP_DEVICE, FX_LOCK_ORDER_MP_DEVICE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_IO, FX_LOCK_ORDER_PACKAGE_IO), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_INSTANCE, FX_LOCK_ORDER_WMI_INSTANCE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_PROVIDER, FX_LOCK_ORDER_WMI_PROVIDER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_QUEUE, FX_LOCK_ORDER_QUEUE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_REQUEST, FX_LOCK_ORDER_REQUEST), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IRPQUEUE, FX_LOCK_ORDER_IRPQUEUE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_PDO, FX_LOCK_ORDER_PACKAGE_PDO), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_FDO, FX_LOCK_ORDER_PACKAGE_FDO), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WMI_IRP_HANDLER, FX_LOCK_ORDER_WMI_IRP_HANDLER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_GENERAL, FX_LOCK_ORDER_PACKAGE_GENERAL), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DMA_ENABLER, FX_LOCK_ORDER_DMA_ENABLER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DMA_TRANSACTION, FX_LOCK_ORDER_DMA_TRANSACTION), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_COMMON_BUFFER, FX_LOCK_ORDER_COMMON_BUFFER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET, FX_LOCK_ORDER_IO_TARGET), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_SELF, FX_LOCK_ORDER_IO_TARGET), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_USB_DEVICE,FX_LOCK_ORDER_USB_DEVICE_IO_TARGET),\ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_IO_TARGET_USB_PIPE, FX_LOCK_ORDER_USB_PIPE_IO_TARGET), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DPC, FX_LOCK_ORDER_DPC), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_WORKITEM, FX_LOCK_ORDER_WORKITEM), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_SYSTEMTHREAD, FX_LOCK_ORDER_SYSTEMTHREAD), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_CLEANUPLIST, FX_LOCK_ORDER_CLEANUPLIST), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_INTERRUPT, FX_LOCK_ORDER_INTERRUPT), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_TIMER, FX_LOCK_ORDER_TIMER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_FILEOBJECT, FX_LOCK_ORDER_FILEOBJECT), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_CHILD_LIST, FX_LOCK_ORDER_DEVICE_LIST), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_SYSTEMWORKITEM, FX_LOCK_ORDER_SYSTEMWORKITEM), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEFAULT_IRP_HANDLER, FX_LOCK_ORDER_DEFAULT_IRP_HANDLER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_COLLECTION, FX_LOCK_ORDER_COLLECTION), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DISPOSELIST, FX_LOCK_ORDER_DISPOSELIST), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_USEROBJECT, FX_LOCK_ORDER_USEROBJECT), \ + FX_VERIFIER_LOCK_ENTRY(0, 0) + +// Device Driver Callback lock entries +#define FX_VERIFIER_CALLBACKLOCK_ENTRIES() \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DRIVER, FX_CALLBACKLOCK_ORDER_DRIVER), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_DEVICE, FX_CALLBACKLOCK_ORDER_DEVICE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_PACKAGE_IO, FX_CALLBACKLOCK_ORDER_PACKAGE), \ + FX_VERIFIER_LOCK_ENTRY(FX_TYPE_QUEUE, FX_CALLBACKLOCK_ORDER_QUEUE), \ + FX_VERIFIER_LOCK_ENTRY(0, 0) + +// +// Mapping table structure between Fx object types and lock orders +// +struct FxVerifierOrderMapping { + USHORT ObjectType; + USHORT ObjectLockOrder; +}; + +typedef struct FxVerifierOrderMapping *pFxVerifierOrderMapping; +// +// This must be a power of two for hash algorithm +// +// Table size is dependent on the number of active threads +// in the frameworks at a given time. This can not execeed +// the number of (virtual due to hyperthreading) CPU's in the system. +// +// Setting this number lower just increases collisions, but does +// not impede correct function. +// +#define VERIFIER_THREAD_HASHTABLE_SIZE 64 + + +// +// This structure is used by verifier hash table implementation +// for linking records per thread +// +struct FxVerifierThreadTableEntry { + MxThread Thread; + FxVerifierLock* PerThreadPassiveLockList; + FxVerifierLock* PerThreadDispatchLockList; + LIST_ENTRY HashChain; +}; + +typedef struct FxVerifierThreadTableEntry *pFxVerifierThreadTableEntry; +/* + * This lock performs the same actions as the base + * FxLock, but provides additional tracking of lock + * order to help detect and debug + * deadlock and recursive lock situations. + * + * It does not inherit from FxLock since this would + * cause a recursion chain. + * + * Since lock verification is already more costly than + * basic lock use, this verifier lock supports both the + * FAST_MUTEX and SpinLock modes in order to utilize common + * code to support verification of FxCallback locks. + * + * FxVerifierLocks are only allocated when WdfVerifierLock + * is turned on. + */ + +class FxVerifierLock : public FxGlobalsStump { + +private: + // Standard NT pool object identification + USHORT m_Type; + USHORT m_Size; + + // Spinlock to perform our lock functionality + MxLock m_Lock; + KIRQL m_OldIrql; + + // Fast Mutex for thread level verifier locks + MxPagedLock m_Mutex; + + // + // Verifier per lock working values, protected + // by our m_Lock + // + FxObject* m_ParentObject; + MxThread m_OwningThread; + USHORT m_Order; + + // True if its a Mutex based (thread context) lock + BOOLEAN m_UseMutex; + + // True if its used as a Callback lock + BOOLEAN m_CallbackLock; + + // + // This is the link for the per thread lock chain. + // + FxVerifierLock* m_OwnedLink; + +private: + FxVerifierLock( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxGlobalsStump(FxDriverGlobals) + { + } + + void + InitializeLockOrder( + VOID + ); + + void + FxVerifierLock::FxVerifierLockDumpDetails( + __in FxVerifierLock* Lock, + __in PVOID curThread, + __in FxVerifierLock* PerThreadList + ); + +private: + // + // This constructor is used by internal object + // locks, which always use a spinlock. + // + FxVerifierLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* ParentObject + ) : + FxGlobalsStump(FxDriverGlobals) + { + m_Type = FX_TYPE_VERIFIERLOCK; + m_Size = sizeof(FxVerifierLock); + + m_ParentObject = ParentObject; + + m_OwningThread = NULL; + m_OwnedLink = NULL; + m_Order = FX_LOCK_ORDER_UNKNOWN; + + m_ThreadTableEntry.Thread = NULL; + m_ThreadTableEntry.PerThreadPassiveLockList = NULL; + m_ThreadTableEntry.PerThreadDispatchLockList = NULL; + + m_UseMutex = FALSE; + m_CallbackLock = FALSE; + + InitializeLockOrder(); + } + + _Must_inspect_result_ + __inline + NTSTATUS + Initialize( + ) + { + NTSTATUS status; + + if (m_UseMutex) { + status = m_Mutex.Initialize(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Unable to initialize paged lock for VerifierLock 0x%p " + "status %!STATUS!", + this, status); + return status; + } + } + + return STATUS_SUCCESS; + } + + // + // This constructor is used by the Callback lock + // functions when verifer is on. + // + // The lock utlizes the callback lock order table entries to + // set its level. + // + FxVerifierLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* ParentObject, + __in BOOLEAN UseMutex + ) : + FxGlobalsStump(FxDriverGlobals) + { + + m_Type = FX_TYPE_VERIFIERLOCK; + m_Size = sizeof(FxVerifierLock); + + m_ParentObject = ParentObject; + + m_OwningThread = NULL; + m_OwnedLink = NULL; + m_Order = FX_LOCK_ORDER_UNKNOWN; + + m_ThreadTableEntry.Thread = NULL; + m_ThreadTableEntry.PerThreadPassiveLockList = NULL; + m_ThreadTableEntry.PerThreadDispatchLockList = NULL; + + // Different verifier table + m_CallbackLock = TRUE; + + if (UseMutex) { + m_UseMutex = TRUE; + } + else { + m_UseMutex = FALSE; + } + + InitializeLockOrder(); + } + +public: + + _Must_inspect_result_ + __inline + static + NTSTATUS + CreateAndInitialize( + __out FxVerifierLock ** VerifierLock, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* ParentObject, + __in BOOLEAN UseMutex + ) + { + NTSTATUS status; + FxVerifierLock * verifierLock; + + verifierLock = new (FxDriverGlobals) FxVerifierLock(FxDriverGlobals, + ParentObject, + UseMutex); + if (NULL == verifierLock) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Failed to allocate verifier lock, returning %!STATUS!", + status); + goto exit; + } + + status = verifierLock->Initialize(); + if (!NT_SUCCESS(status)) { + delete verifierLock; + goto exit; + } + + *VerifierLock = verifierLock; + + exit: + return status; + } + + _Must_inspect_result_ + __inline + static + NTSTATUS + CreateAndInitialize( + __out FxVerifierLock ** VerifierLock, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* ParentObject + ) + { + NTSTATUS status; + FxVerifierLock * verifierLock; + + verifierLock = new (FxDriverGlobals) FxVerifierLock(FxDriverGlobals, + ParentObject); + if (NULL == verifierLock) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Failed to allocate verifier lock, returning %!STATUS!", + status); + goto exit; + } + + status = verifierLock->Initialize(); + if (!NT_SUCCESS(status)) { + delete verifierLock; + goto exit; + } + + *VerifierLock = verifierLock; + + exit: + return status; + } + + ~FxVerifierLock( + VOID + ) + { + if (m_OwningThread != NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Lock 0x%p is being destroyed while owned by " + "thread 0x%p, Owning Object 0x%p", + this, m_OwningThread, m_ParentObject); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + + VOID + Lock( + __out PKIRQL PreviousIrql, + __in BOOLEAN AtDpc + ); + + VOID + Unlock( + __in KIRQL PreviousIrql, + __in BOOLEAN AtDpc + ); + + KIRQL + GetLockPreviousIrql( + VOID + ); + + // + // Instance data needed for the hash table chaining + // + FxVerifierThreadTableEntry m_ThreadTableEntry; + + // + // Static data and methods for hash table chaining + // + static ULONG ThreadTableSize; + + static KSPIN_LOCK ThreadTableLock; + + static PLIST_ENTRY ThreadTable; + + static + void + AllocateThreadTable( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + static + void + FreeThreadTable( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + static + void + DumpDetails( + __in FxVerifierLock* Lock, + __in MxThread curThread, + __in FxVerifierLock* PerThreadList + ); + + static + pFxVerifierThreadTableEntry + GetThreadTableEntry( + __in MxThread curThread, + __in FxVerifierLock* pLock, + __in BOOLEAN LookupOnly + ); + + static + void + ReleaseOrReplaceThreadTableEntry( + __in MxThread curThread, + __in FxVerifierLock* pLock + ); +}; + +#endif // _FXVERIFIERLOCK_HPP_ + + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwaitlock.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwaitlock.hpp new file mode 100644 index 00000000000..2d854fbf1da --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwaitlock.hpp @@ -0,0 +1,351 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWaitLock.hpp + +Abstract: + +--*/ + +#ifndef _FXWAITLOCK_HPP_ +#define _FXWAITLOCK_HPP_ + +struct FxCREvent { + FxCREvent( + __in BOOLEAN InitialState = FALSE + ) + { + // + // For kernel mode letting c'tor do the initialization to not churn the + // non-shared code + // +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + m_Event.Initialize(SynchronizationEvent, InitialState); +#else + UNREFERENCED_PARAMETER(InitialState); +#endif + } + + + + + + FxCREvent( + __in EVENT_TYPE Type, + __in BOOLEAN InitialState + ) + { +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + m_Event.Initialize(Type, InitialState); +#else + UNREFERENCED_PARAMETER(Type); + UNREFERENCED_PARAMETER(InitialState); +#endif + } + + CHECK_RETURN_IF_USER_MODE + NTSTATUS + Initialize( + __in BOOLEAN InitialState = FALSE + ) + { + return m_Event.Initialize(SynchronizationEvent, InitialState); + } + + CHECK_RETURN_IF_USER_MODE + NTSTATUS + Initialize( + __in EVENT_TYPE Type, + __in BOOLEAN InitialState + ) + { + return m_Event.Initialize(Type, InitialState); + } + + __drv_valueIs(==0;==258) + _Acquires_lock_(_Global_critical_region_) + NTSTATUS + EnterCRAndWait( + VOID + ) + { + NTSTATUS status; + + Mx::MxEnterCriticalRegion(); + + status = m_Event.WaitFor(Executive, + KernelMode, + FALSE, + NULL); + return status; + } + + NTSTATUS + EnterCRAndWaitAndLeave( + VOID + ) + { + NTSTATUS status; + + status = EnterCRAndWait(); + LeaveCR(); + + return status; + } + + __drv_when(Timeout == NULL, __drv_valueIs(==0)) + __drv_when(Timeout != NULL, __drv_valueIs(==0;==258)) + __drv_when(Timeout != NULL, _Must_inspect_result_) + _Acquires_lock_(_Global_critical_region_) + NTSTATUS + EnterCRAndWait( + __in PLONGLONG Timeout + ) + { + NTSTATUS status; + + Mx::MxEnterCriticalRegion(); + + status = m_Event.WaitFor(Executive, + KernelMode, + FALSE, + (PLARGE_INTEGER) Timeout); + + return status; + } + + _Must_inspect_result_ + NTSTATUS + EnterCRAndWaitAndLeave( + __in PLONGLONG Timeout + ) + { + NTSTATUS status; + + status = EnterCRAndWait(Timeout); + LeaveCR(); + + return status; + } + + _Releases_lock_(_Global_critical_region_) + VOID + LeaveCR( + VOID + ) + { + Mx::MxLeaveCriticalRegion(); + } + + VOID + Set( + VOID + ) + { + m_Event.Set(); + } + + VOID + Clear( + VOID + ) + { + m_Event.Clear(); + } + + LONG + ReadState( + VOID + ) + { + return m_Event.ReadState(); + } + + // + // Return the underlying event + // PKEVENT in kernel mode and event HANDLE in user-mode + // + PVOID + GetEvent( + VOID + ) + { + return m_Event.GetEvent(); + } + + FxCREvent* + GetSelfPointer( + VOID + ) + { + // + // Since operator& is hidden, we still need to be able to get a pointer + // to this object, so we must make it an explicit method. + // + return this; + } +private: + FxCREvent* operator&( + VOID + ) + { + // + // By making the address of operator private, we make it harder (hopefully + // impossible) to accidentally use this object in an improper fashion, ie + // something like this is prevented: + // + // FxCREvent event; + // KeWaitForSingleObject(&event, ...); + // + ASSERT(FALSE); + return NULL; + } + +private: + MxEvent m_Event; +}; + +// +// Non referencable object, just pure implementation +// +class FxWaitLockInternal { + +public: + + FxWaitLockInternal( + VOID + ) + { + // + // For kernel mode letting c'tor do the initialization to not churn the + // non-shared code + // +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + m_Event.Initialize(SynchronizationEvent, TRUE); +#endif + + m_OwningThread = NULL; + } + + CHECK_RETURN_IF_USER_MODE + NTSTATUS + Initialize( + ) + { + return m_Event.Initialize(SynchronizationEvent, TRUE); + } + + // + + // + __drv_when(Timeout == NULL, __drv_valueIs(==0)) + __drv_when(Timeout != NULL, __drv_valueIs(==0;==258)) + __drv_when(Timeout != NULL, _Must_inspect_result_) + _When_(return!=0x00000102L, _Acquires_lock_(_Global_critical_region_)) + NTSTATUS + AcquireLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PLONGLONG Timeout = NULL + ) + { + LARGE_INTEGER li; + NTSTATUS status; + + UNREFERENCED_PARAMETER(FxDriverGlobals); + + ASSERT(m_OwningThread != Mx::MxGetCurrentThread() || (Timeout != NULL)); + + if (Timeout != NULL) { + li.QuadPart = *Timeout; + } + + Mx::MxEnterCriticalRegion(); + status = m_Event.WaitFor(Executive, + KernelMode, + FALSE, + Timeout == NULL ? NULL : &li); + + if (status == STATUS_TIMEOUT) { + Mx::MxLeaveCriticalRegion(); + } + else { + m_OwningThread = Mx::MxGetCurrentThread(); + } + + return status; + } + + static + BOOLEAN + IsLockAcquired( + __in NTSTATUS Status + ) + { + // + // STATUS_TIMEOUT will return TRUE for NT_SUCCESS so check explicitly + // + return (NT_SUCCESS(Status) && Status != STATUS_TIMEOUT) ? TRUE : FALSE; + } + + _Releases_lock_(_Global_critical_region_) + VOID + ReleaseLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + UNREFERENCED_PARAMETER(FxDriverGlobals); + + ASSERT(m_OwningThread == Mx::MxGetCurrentThread()); + m_OwningThread = NULL; + + m_Event.Set(); + Mx::MxLeaveCriticalRegion(); + } + +protected: + MxEvent m_Event; + + MxThread m_OwningThread; +}; + + +// +// Order is important here, FxObject *must* be the first class in the +// list so that &FxWaitWaitLock == &FxNonPagedObject. +// +class FxWaitLock : public FxObject, public FxWaitLockInternal { + +public: + // Factory function + _Must_inspect_result_ + static + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in_opt FxObject* ParentObject, + __in BOOLEAN AssignDriverAsDefaultParent, + __out WDFWAITLOCK* LockHandle + ); + + + CHECK_RETURN_IF_USER_MODE + NTSTATUS + Initialize( + ) + { + return __super::Initialize(); + } + + FxWaitLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxObject(FX_TYPE_WAIT_LOCK, sizeof(FxWaitLock), FxDriverGlobals) + { + } +}; + +#endif // _FXWAITLOCK_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwakeinterruptstatemachine.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwakeinterruptstatemachine.hpp new file mode 100644 index 00000000000..13f2711bc54 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwakeinterruptstatemachine.hpp @@ -0,0 +1,196 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXWAKEINTERRUPTSTATEMACHINE_H_ +#define _FXWAKEINTERRUPTSTATEMACHINE_H_ + +// +// This is a magical number based on inspection. If the queue overflows, +// it is OK to increase these numbers without fear of either dependencies or +// weird side affects. +// +const UCHAR FxWakeInterruptEventQueueDepth = 8; + +enum FxWakeInterruptEvents { + WakeInterruptEventInvalid = 0x00, + WakeInterruptEventIsr = 0x01, + WakeInterruptEventEnteringD0 = 0x02, + WakeInterruptEventLeavingD0 = 0x04, + WakeInterruptEventD0EntryFailed = 0x08, + WakeInterruptEventLeavingD0NotArmedForWake = 0x10, + WakeInterruptEventNull = 0xFF, +}; + +enum FxWakeInterruptStates { + WakeInterruptInvalid = 0, + WakeInterruptFailed, + WakeInterruptD0, + WakeInterruptDx, + WakeInterruptWaking, + WakeInterruptInvokingEvtIsrPostWake, + WakeInterruptCompletingD0, + WakeInterruptInvokingEvtIsrInD0, + WakeInterruptDxNotArmedForWake, + WakeInterruptInvokingEvtIsrInDxNotArmedForWake, + WakeInterruptMax +}; + +// +// Forward declaration +// +class FxWakeInterruptMachine; +class FxInterrupt; + +typedef +_Must_inspect_result_ +FxWakeInterruptStates +(*PFN_WAKE_INTERRUPT_STATE_ENTRY_FUNCTION)( + __in FxWakeInterruptMachine* This + ); + +struct FxWakeInterruptTargetState { + FxWakeInterruptEvents WakeInterruptEvent; + + FxWakeInterruptStates WakeInterruptState; + +#if FX_SUPER_DBG + BOOLEAN EventDebugged; +#endif +}; + +// +// This type of union is done so that we can +// 1) shrink the array element to the smallest size possible +// 2) keep types within the structure so we can dump it in the debugger +// +union FxWakeInterruptMachineStateHistory { + struct { + FxWakeInterruptStates State1 : 8; + FxWakeInterruptStates State2 : 8; + FxWakeInterruptStates State3 : 8; + FxWakeInterruptStates State4 : 8; + FxWakeInterruptStates State5 : 8; + FxWakeInterruptStates State6 : 8; + FxWakeInterruptStates State7 : 8; + FxWakeInterruptStates State8 : 8; + } S; + + UCHAR History[FxWakeInterruptEventQueueDepth]; +}; + +struct FxWakeInterruptStateTable { + PFN_WAKE_INTERRUPT_STATE_ENTRY_FUNCTION StateFunc; + + const FxWakeInterruptTargetState* TargetStates; + + ULONG TargetStatesCount; +}; + +class FxWakeInterruptMachine : public FxThreadedEventQueue { + + friend FxInterrupt; + +public: + FxWakeInterruptMachine( + __in FxInterrupt * Interrupt + ); + + VOID + ProcessEvent( + __in FxWakeInterruptEvents Event + ); + + static + VOID + _ProcessEventInner( + __inout FxPkgPnp* PkgPnp, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ); + +private: + VOID + ProcessEventInner( + __inout FxPostProcessInfo* Info + ); + + static + FxWakeInterruptStates + Waking( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + Dx( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + DxNotArmedForWake( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + Failed( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + InvokingEvtIsrPostWake( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + InvokingEvtIsrInDxNotArmedForWake( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + InvokingEvtIsrInD0( + __in FxWakeInterruptMachine* This + ); + + static + FxWakeInterruptStates + CompletingD0( + __in FxWakeInterruptMachine* This + ); + +protected: + //FxPkgPnp* m_PkgPnp; + FxInterrupt* m_Interrupt; + // + // Set if the interrupt was left active during Dx transition to handle wake + // events. + // + BOOLEAN m_ActiveForWake; + BOOLEAN m_Claimed; + MxEvent m_IsrEvent; + + // uses FxWakeInterruptStates values + BYTE m_CurrentState; + + // three extra padded bytes are put in here by the compiler + + FxWakeInterruptEvents m_Queue[FxWakeInterruptEventQueueDepth]; + FxWakeInterruptMachineStateHistory m_States; + + static const FxWakeInterruptStateTable m_StateTable[]; + + static const FxWakeInterruptTargetState m_FailedStates[]; + static const FxWakeInterruptTargetState m_D0States[]; + static const FxWakeInterruptTargetState m_DxStates[]; + static const FxWakeInterruptTargetState m_DxNotArmedForWakeStates[]; + static const FxWakeInterruptTargetState m_WakingStates[]; + static const FxWakeInterruptTargetState m_InvokingEvtIsrPostWakeStates[]; + static const FxWakeInterruptTargetState m_CompletingD0States[]; + static const FxWakeInterruptTargetState m_InvokingIsrInD0[]; +}; + +#endif // _FXWAKEINTERRUPTSTATEMACHINE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwatchdog.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwatchdog.hpp new file mode 100644 index 00000000000..68aa34f81ab --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwatchdog.hpp @@ -0,0 +1,116 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxWatchDog.hpp + +Abstract: + + This module implements the watchdog utility class for the power and power + policy state machines + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef __FX_WATCHDOG__ +#define __FX_WATCHDOG__ + +struct FxWatchdog { + FxWatchdog( + __in FxPkgPnp* PkgPnp + ) + { + m_PkgPnp = PkgPnp; + } + + VOID + StartTimer( + __in ULONG State + ) + { + LARGE_INTEGER time; + NTSTATUS status; + + if (State & WdfDevStateNP) { + // + // This is a non-pageable state. So we set the timer watchdog. + // If it fires, it means that the driver stalled, probably due + // to a page fault, which means that the whole machine is wedged. + // We will then attempt to put the failure in the trace log + // and bring the machine down, hopefully getting the reason we + // stopped responding into the crashdump. (This will probably only work + // if the machine is hibernating.) + // + // If the state function returns, then we'll cancel the timer + // and no love will be lost. + // + status = m_Timer.Initialize(this, _WatchdogDpc, 0); + + // + // This code is not used in UM. Hence we can assert and assume that + // timer start will always be successful. + // + WDF_VERIFY_KM_ONLY_CODE(); + + FX_ASSERT_AND_ASSUME_FOR_PREFAST(NT_SUCCESS(status)); + + m_CallingThread = Mx::MxGetCurrentThread(); + + if (m_PkgPnp->m_SharedPower.m_ExtendWatchDogTimer) { + // + // 24 hours: + // 60 = to minutes + // 60 = to hours + // 24 = number of hours + // + time.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60 * 60 * 24); + } + else { + // + // 10 minutes from now (same as the Vista timeout) + // + time.QuadPart = WDF_REL_TIMEOUT_IN_SEC(60 * 10); + } + + m_Timer.Start(time); + } + } + + VOID + CancelTimer( + __in ULONG State + ) + { + if (State & WdfDevStateNP) { + // + // The state was successfully handled without the timer expiring. + // We don't care about the return code in this case. + // + (void) m_Timer.Stop(); + } + } + + static + MdDeferredRoutineType + _WatchdogDpc; + + MxTimer m_Timer; + + FxPkgPnp* m_PkgPnp; + + MxThread m_CallingThread; +}; + +#endif // __FX_WATCHDOG__ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmicompat.h b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmicompat.h new file mode 100644 index 00000000000..9ae3580e8ac --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmicompat.h @@ -0,0 +1,79 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiCompat.hpp + +Abstract: + + Undefines WMI ntos exports used by WPP and redirects them to our own + functions so that we can build User and Kernel libraries. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef __FX_WMI_COMPAT_H__ +#define __FX_WMI_COMPAT_H__ + +#include + +#ifdef WPP_TRACE +#undef WPP_TRACE +#endif + +#define WPP_TRACE FxWmiTraceMessage + +extern "C" +_Must_inspect_result_ +NTSTATUS +FxWmiTraceMessage( + __in TRACEHANDLE LoggerHandle, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + ... + ); + +#define WPP_IFR FxIFR + +extern "C" +_Must_inspect_result_ +NTSTATUS +FxIFR( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in UCHAR MessageLevel, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + ... + ); + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#undef WmiQueryTraceInformation +#define WmiQueryTraceInformation FxWmiQueryTraceInformation + +extern "C" +_Must_inspect_result_ +NTSTATUS +FxWmiQueryTraceInformation( + __in TRACE_INFORMATION_CLASS TraceInformationClass, + __out_bcount(TraceInformationLength) PVOID TraceInformation, + __in ULONG TraceInformationLength, + __out_opt PULONG RequiredLength, + __in_opt PVOID Buffer + ); + +#endif + +#endif __FX_WMI_COMPAT_H__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiinstance.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiinstance.hpp new file mode 100644 index 00000000000..64bddad7386 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiinstance.hpp @@ -0,0 +1,659 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiInstance.hpp + +Abstract: + + This module implements the WMI instance object + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#ifndef _FXWMIINSTANCE_H_ +#define _FXWMIINSTANCE_H_ + + +class FxWmiInstance : public FxNonPagedObject { + + friend FxWmiProvider; + friend FxWmiIrpHandler; + +public: + FxWmiInstance( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in FxWmiProvider* Provider + ); + + ~FxWmiInstance(); + + CfxDevice* + GetDevice( + VOID + ) + { + return m_Provider->GetDevice(); + } + + FxWmiProvider* + GetProvider( + VOID + ) + { + return m_Provider; + } + + _Must_inspect_result_ + NTSTATUS + FireEvent( + __in_bcount_opt(EventBufferSize) PVOID EventBuffer, + __inout ULONG EventBufferSize + ); + + BOOLEAN + IsEnabled( + __in WDF_WMI_PROVIDER_CONTROL Control + ) + { + return m_Provider->IsEnabled(Control); + } + + WDFWMIINSTANCE + GetHandle( + VOID + ) + { + return (WDFWMIINSTANCE) GetObjectHandle(); + } + + virtual + BOOLEAN + IsQueryInstanceSupported( + VOID + ) =0; + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + QueryInstance( + __in ULONG OutBufferSize, + __out_bcount_part(OutBufferSize, *BufferUsed) PVOID OutBuffer, + __out PULONG BufferUsed + ) =0; + + virtual + BOOLEAN + IsSetInstanceSupported( + VOID + ) =0; + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetInstance( + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) =0; + + virtual + BOOLEAN + IsSetItemSupported( + VOID + ) =0; + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetItem( + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) =0; + + virtual + BOOLEAN + IsExecuteMethodSupported( + VOID + ) =0; + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + ExecuteMethod( + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ) =0; + + // begin FxObject overrides + virtual + BOOLEAN + Dispose( + VOID + ); + // end FxObject overrides + +protected: + // + // List entry used by FxWmiProvider to hold the list of WMI instances + // + LIST_ENTRY m_ListEntry; + + // + // Pointer to the parent provider + // + FxWmiProvider* m_Provider; +}; + +struct FxWmiInstanceQueryInstanceCallback : public FxCallback { + + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE m_Method; + + FxWmiInstanceQueryInstanceCallback( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + ~FxWmiInstanceQueryInstanceCallback() + { + } + + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFWMIINSTANCE WmiInstance, + __inout ULONG OutBufferSize, + __out_bcount(OutBufferSize) PVOID OutBuffer, + __out PULONG BufferUsed + ) + { + NTSTATUS status; + + UNREFERENCED_PARAMETER(Device); + + if (m_Method != NULL) { + CallbackStart(); + status = m_Method(WmiInstance, + OutBufferSize, + OutBuffer, + BufferUsed); + CallbackEnd(); + } + else { + status = STATUS_UNSUCCESSFUL; + } + + return status; + } +}; + +struct FxWmiInstanceSetInstanceCallback : public FxCallback { + + PFN_WDF_WMI_INSTANCE_SET_INSTANCE m_Method; + + FxWmiInstanceSetInstanceCallback( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + ~FxWmiInstanceSetInstanceCallback() + { + } + + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFWMIINSTANCE WmiInstance, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) + { + NTSTATUS status; + + UNREFERENCED_PARAMETER(Device); + + if (m_Method != NULL) { + CallbackStart(); + status = m_Method(WmiInstance, InBufferSize, InBuffer); + CallbackEnd(); + } + else { + status = STATUS_WMI_READ_ONLY; + } + + return status; + } +}; + +struct FxWmiInstanceSetItemCallback : public FxCallback { + + PFN_WDF_WMI_INSTANCE_SET_ITEM m_Method; + + FxWmiInstanceSetItemCallback( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + ~FxWmiInstanceSetItemCallback() + { + } + + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFWMIINSTANCE WmiInstance, + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ) + { + NTSTATUS status; + + UNREFERENCED_PARAMETER(Device); + + if (m_Method != NULL) { + CallbackStart(); + status = m_Method(WmiInstance, + DataItemId, + InBufferSize, + InBuffer); + CallbackEnd(); + + } + else { + status = STATUS_WMI_READ_ONLY; + } + + return status; + } +}; + +struct FxWmiInstanceExecuteMethodCallback : public FxCallback { + + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD m_Method; + + FxWmiInstanceExecuteMethodCallback( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + ~FxWmiInstanceExecuteMethodCallback() + { + } + + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFWMIINSTANCE WmiInstance, + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ) + { + NTSTATUS status; + + UNREFERENCED_PARAMETER(Device); + + if (m_Method != NULL) { + CallbackStart(); + status = m_Method(WmiInstance, + MethodId, + InBufferSize, + OutBufferSize, + Buffer, + BufferUsed); + CallbackEnd(); + } + else { + status = STATUS_WMI_GUID_NOT_FOUND; + } + + return status; + } +}; + +class FxWmiInstanceExternal : public FxWmiInstance { +public: + FxWmiInstanceExternal( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WMI_INSTANCE_CONFIG Config, + __in FxWmiProvider* Provider + ); + + VOID + SetContextForQueryLength( + __in ULONG ContextSize + ) + { + m_ContextLength = ContextSize; + } + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxWmiProvider* Provider, + __in PWDF_WMI_INSTANCE_CONFIG WmiInstanceConfig, + __in_opt PWDF_OBJECT_ATTRIBUTES InstanceAttributes, + __out WDFWMIINSTANCE* WmiInstance, + __out FxWmiInstanceExternal** Instance + ); + +protected: + virtual + BOOLEAN + IsQueryInstanceSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + QueryInstance( + __inout ULONG OutBufferSize, + __out_xcount(OutBuffer->size) PVOID OutBuffer, + __out PULONG BufferUsed + ); + + virtual + BOOLEAN + IsSetInstanceSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetInstance( + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ); + + virtual + BOOLEAN + IsSetItemSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetItem( + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ); + + virtual + BOOLEAN + IsExecuteMethodSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + ExecuteMethod( + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ); + +protected: + // + // Attributes associated with this instance + // + FxWmiInstanceQueryInstanceCallback m_QueryInstanceCallback; + + FxWmiInstanceSetInstanceCallback m_SetInstanceCallback; + + FxWmiInstanceSetItemCallback m_SetItemCallback; + + FxWmiInstanceExecuteMethodCallback m_ExecuteMethodCallback; + + ULONG m_ContextLength; + + BOOLEAN m_UseContextForQuery; +}; + +typedef +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +(*PFN_FX_WMI_INSTANCE_QUERY_INSTANCE)( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __inout ULONG OutBufferSize, + __out_bcount(OutBufferSize) PVOID OutBuffer, + __out PULONG BufferUsed + ); + +typedef +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +(*PFN_FX_WMI_INSTANCE_SET_INSTANCE)( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ); + +typedef +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +(*PFN_FX_WMI_INSTANCE_SET_ITEM)( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ); + +typedef +_Must_inspect_result_ +__drv_sameIRQL +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +(*PFN_FX_WMI_INSTANCE_EXECUTE_METHOD)( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* Instance, + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ); + +struct FxWmiInstanceInternalCallbacks { + FxWmiInstanceInternalCallbacks( + VOID + ) + { + RtlZeroMemory(this, sizeof(*this)); + } + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_FX_WMI_INSTANCE_QUERY_INSTANCE QueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_FX_WMI_INSTANCE_SET_INSTANCE SetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_FX_WMI_INSTANCE_SET_ITEM SetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_FX_WMI_INSTANCE_EXECUTE_METHOD ExecuteMethod; +}; + +class FxWmiInstanceInternal : public FxWmiInstance { + +public: + FxWmiInstanceInternal( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxWmiInstanceInternalCallbacks* Callbacks, + __in FxWmiProvider* m_Provider + ); + +protected: + virtual + BOOLEAN + IsQueryInstanceSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + QueryInstance( + __inout ULONG OutBufferSize, + __out_bcount(OutBufferSize) PVOID OutBuffer, + __out PULONG BufferUsed + ); + + virtual + BOOLEAN + IsSetInstanceSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetInstance( + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ); + + virtual + BOOLEAN + IsSetItemSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + SetItem( + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in_bcount(InBufferSize) PVOID InBuffer + ); + + virtual + BOOLEAN + IsExecuteMethodSupported( + VOID + ); + + virtual + _Must_inspect_result_ + __drv_sameIRQL + __drv_maxIRQL(PASSIVE_LEVEL) + NTSTATUS + ExecuteMethod( + __in ULONG MethodId, + __in ULONG InBufferSize, + __inout ULONG OutBufferSize, + __drv_when(InBufferSize >= OutBufferSize, __inout_bcount(InBufferSize)) + __drv_when(InBufferSize < OutBufferSize, __inout_bcount(OutBufferSize)) + PVOID Buffer, + __out PULONG BufferUsed + ); + +protected: + PFN_FX_WMI_INSTANCE_QUERY_INSTANCE m_QueryInstance; + PFN_FX_WMI_INSTANCE_SET_INSTANCE m_SetInstance; + PFN_FX_WMI_INSTANCE_SET_ITEM m_SetItem; + PFN_FX_WMI_INSTANCE_EXECUTE_METHOD m_ExecuteMethod; +}; + +#endif // _FXWMIINSTANCE_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiirphandler.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiirphandler.hpp new file mode 100644 index 00000000000..d1a59995c6e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiirphandler.hpp @@ -0,0 +1,329 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiIrpHandler.hpp + +Abstract: + + This module implements the wmi IRP handler for the driver frameworks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXWMIIRPHANDLER_H_ +#define _FXWMIIRPHANDLER_H_ + +typedef +_Must_inspect_result_ +NTSTATUS +(*PFN_WMI_HANDLER_MINOR_DISPATCH)( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ); + +struct FxWmiMinorEntry { + __in PFN_WMI_HANDLER_MINOR_DISPATCH Handler; + __in BOOLEAN CheckInstance; +}; + +class FxWmiIrpHandler : public FxPackage { + friend FxWmiProvider; + +public: + + FxWmiIrpHandler( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device, + __in WDFTYPE Type = FX_TYPE_WMI_IRP_HANDLER + ); + + ~FxWmiIrpHandler(); + + _Must_inspect_result_ + NTSTATUS + PostCreateDeviceInitialize( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + HandleWmiTraceRequest( + __in PIRP Irp, + __in FxTraceInfo* Info + ); + + virtual + _Must_inspect_result_ + NTSTATUS + Dispatch( + __in PIRP Irp + ); + + _Must_inspect_result_ + NTSTATUS + Register( + VOID + ); + + VOID + Deregister( + VOID + ); + + VOID + Cleanup( + VOID + ); + + VOID + ResetStateForPdoRestart( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + AddProvider( + __in FxWmiProvider* Provider, + __out_opt PBOOLEAN Update = NULL + ); + + _Must_inspect_result_ + NTSTATUS + AddPowerPolicyProviderAndInstance( + __in PWDF_WMI_PROVIDER_CONFIG ProviderConfig, + __in FxWmiInstanceInternalCallbacks* Callbacks, + __inout FxWmiInstanceInternal** Instance + ); + +protected: + static + VOID + CheckAssumptions( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + AddProviderLocked( + __in FxWmiProvider* Provider, + __in KIRQL Irql, + __out_opt PBOOLEAN Update = NULL + ); + + VOID + RemoveProvider( + __in FxWmiProvider* Provider + ); + + VOID + RemoveProviderLocked( + __in FxWmiProvider* Provider + ); + + _Must_inspect_result_ + FxWmiProvider* + FindProviderLocked( + __in LPGUID Guid + ); + + _Must_inspect_result_ + FxWmiProvider* + FindProviderReferenced( + __in LPGUID Guid, + __in PVOID Tag + ); + +private: + static + _Must_inspect_result_ + NTSTATUS + _QueryAllData( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in_opt FxWmiInstance* Instance + ); + + static + _Must_inspect_result_ + NTSTATUS + _QuerySingleInstance( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ); + + static + _Must_inspect_result_ + NTSTATUS + _ChangeSingleInstance( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ); + + static + _Must_inspect_result_ + NTSTATUS + _ChangeSingleItem( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ); + + static + _Must_inspect_result_ + NTSTATUS + _EnableDisableEventsAndCollection( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ); + + static + _Must_inspect_result_ + NTSTATUS + _RegInfo( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in_opt FxWmiProvider* Provider, + __in_opt FxWmiInstance* Instance + ); + + static + _Must_inspect_result_ + NTSTATUS + _ExecuteMethod( + __in FxWmiIrpHandler* This, + __in PIRP Irp, + __in FxWmiProvider* Provider, + __in FxWmiInstance* Instance + ); + + VOID + CompleteWmiQueryAllDataRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ); + + VOID + CompleteWmiQuerySingleInstanceRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ); + + VOID + CompleteWmiExecuteMethodRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ); + + _Must_inspect_result_ + NTSTATUS + CompleteWmiRequest( + __in PIRP Irp, + __in NTSTATUS Status, + __in ULONG BufferUsed + ); + + BOOLEAN + DeferUpdateLocked( + __in KIRQL OldIrql + ); + + static + MX_WORKITEM_ROUTINE _UpdateGuids; + + VOID + UpdateGuids( + VOID + ); + + VOID + IncrementUpdateCount() { + LONG count; + + count = InterlockedIncrement(&m_UpdateCount); + ASSERT(count > 1); + UNREFERENCED_PARAMETER(count); + } + + VOID + DecrementUpdateCount() { + LONG count; + + count = InterlockedDecrement(&m_UpdateCount); + ASSERT(count >= 0); + if (count == 0) { + m_UpdateEvent.Set(); + } + } + + VOID + DecrementUpdateCountAndWait() { + + DecrementUpdateCount(); + + m_UpdateEvent.EnterCRAndWaitAndLeave(); + } + +protected: + enum WmiRegisteredState { + WmiUnregistered = 0, + WmiRegistered, + WmiDeregistered, + WmiCleanedUp + }; + +protected: + static const FxWmiMinorEntry m_WmiDispatchTable[]; + + LIST_ENTRY m_ProvidersListHead; + + ULONG m_NumProviders; + + WmiRegisteredState m_RegisteredState; + + PIO_WORKITEM m_WorkItem; + + // + // count of references taken every time an update is needed + // + LONG m_UpdateCount; + + // + // WMI unregister waits on this event to ensure no upadtes are allowed + // after unregister. + // + FxCREvent m_UpdateEvent; + + PKEVENT m_WorkItemEvent; + + BOOLEAN m_WorkItemQueued; + + +}; + +#endif // _FXWMIIRPHANDLER_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiprovider.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiprovider.hpp new file mode 100644 index 00000000000..65f14e7e0db --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxwmiprovider.hpp @@ -0,0 +1,295 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiDataBlock.hpp + +Abstract: + + This module implements the WMI data block object + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXWMIPROVIDER_H_ +#define _FXWMIPROVIDER_H_ + + +struct FxWmiProviderFunctionControlCallback : public FxCallback { + + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL m_Method; + + FxWmiProviderFunctionControlCallback( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxCallback(FxDriverGlobals), + m_Method(NULL) + { + } + + ~FxWmiProviderFunctionControlCallback() + { + } + + _Must_inspect_result_ + NTSTATUS + Invoke( + __in WDFDEVICE Device, + __in WDFWMIPROVIDER WmiProvider, + __in WDF_WMI_PROVIDER_CONTROL Control, + __in BOOLEAN Enable + ) + { + NTSTATUS status; + + UNREFERENCED_PARAMETER(Device); + + if (m_Method != NULL) { + CallbackStart(); + status = m_Method(WmiProvider, Control, Enable); + CallbackEnd(); + } + else { + status = STATUS_SUCCESS; + } + + return status; + } +}; + +class FxWmiProvider : public FxNonPagedObject { + + friend FxWmiIrpHandler; + +public: + FxWmiProvider( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WMI_PROVIDER_CONFIG Config, + __in CfxDevice* Device + ); + + ~FxWmiProvider(); + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS CallersGlobals, + __in WDFDEVICE Device, + __in_opt PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + __in PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + __out WDFWMIPROVIDER* WmiProvider, + __out FxWmiProvider** Provider + ); + + CfxDevice* + GetDevice( + VOID + ) + { + return m_Parent->GetDevice(); + } + + GUID* + GetGUID( + VOID + ) + { + return &m_Guid; + } + + ULONG + GetFlags( + VOID + ) + { + return m_Flags; + } + + ULONG + GetMinInstanceBufferSize( + VOID + ) + { + return m_MinInstanceBufferSize; + } + + ULONG + GetRegistrationFlagsLocked( + VOID + ); + + BOOLEAN + IsEventOnly( + VOID + ) + { + return FLAG_TO_BOOL(m_Flags, WdfWmiProviderEventOnly); + } + + BOOLEAN + IsEnabled( + __in WDF_WMI_PROVIDER_CONTROL Control + ) + { + switch (Control) { + case WdfWmiEventControl: return m_EventControlEnabled; + case WdfWmiInstanceControl: return m_DataBlockControlEnabled; + default: ASSERT(FALSE); return FALSE; + } + } + + ULONGLONG + GetTracingHandle( + VOID + ) + { + return m_TracingHandle; + } + + VOID + SetTracingHandle( + __in ULONGLONG TracingHandle + ) + { + m_TracingHandle = TracingHandle; + } + + WDFWMIPROVIDER + GetHandle( + VOID + ) + { + return (WDFWMIPROVIDER) GetObjectHandle(); + } + + BOOLEAN + IsFunctionControlSupported( + VOID + ) + { + return m_FunctionControl.m_Method != NULL; + } + + _Must_inspect_result_ + NTSTATUS + FunctionControl( + __in WDF_WMI_PROVIDER_CONTROL Control, + __in BOOLEAN Enable + ); + + _Must_inspect_result_ + NTSTATUS + AddInstance( + __in FxWmiInstance* Instance, + __in BOOLEAN NoErrorIfPresent = FALSE + ); + + VOID + RemoveInstance( + __in FxWmiInstance* Instance + ); + + ULONG + GetInstanceIndex( + __in FxWmiInstance* Instance + ); + + _Must_inspect_result_ + FxWmiInstance* + GetInstanceReferenced( + __in ULONG Index, + __in PVOID Tag + ); + + _Must_inspect_result_ + FxWmiInstance* + GetInstanceReferencedLocked( + __in ULONG Index, + __in PVOID Tag + ); + + // begin FxObject overrides + virtual + BOOLEAN + Dispose( + VOID + ); + // end FxObject overrides + +protected: + enum AddInstanceAction { + AddInstanceToTail, + AddInstanceToHead + }; + + _Must_inspect_result_ + NTSTATUS + AddInstanceLocked( + __in FxWmiInstance* Instance, + __in BOOLEAN NoErrorIfPresent, + __out PBOOLEAN Update, + __in AddInstanceAction Action = AddInstanceToTail + ); + +protected: + // + // List entry used by FxWmiIrpHandler to hold the list of WMI providers + // + LIST_ENTRY m_ListEntry; + + LIST_ENTRY m_InstanceListHead; + + ULONG m_NumInstances; + + FxWmiIrpHandler* m_Parent; + + GUID m_Guid; + + + + + + ULONGLONG m_TracingHandle; + + ULONG m_MinInstanceBufferSize; + + union { + // + // Set with values from WDF_WMI_PROVIDER_FLAGS + // + ULONG m_Flags; + + // + // Not used by the code, but by the debug extension + // + struct { + ULONG EventOnly : 1; + ULONG Expensive : 1; + ULONG Tracing : 1; + } m_FlagsByName; + }; + + FxWmiProviderFunctionControlCallback m_FunctionControl; + + BOOLEAN m_EventControlEnabled; + + BOOLEAN m_DataBlockControlEnabled; + + BOOLEAN m_RemoveGuid; +}; + +#endif // _FXWMIPROVIDER_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/fxworkitem.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/fxworkitem.hpp new file mode 100644 index 00000000000..6fea483d3a9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/fxworkitem.hpp @@ -0,0 +1,231 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWorkItem.hpp + +Abstract: + + This module implements a frameworks managed WorkItem that + can synchrononize with driver frameworks object locks. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#ifndef _FXWORKITEM_H_ +#define _FXWORKITEM_H_ + +// +// Driver Frameworks WorkItem Design: +// +// The driver frameworks provides an optional WorkItem wrapper object that allows +// a reference counted WorkItem object to be created that can synchronize +// automatically with certain frameworks objects. +// +// This provides automatic synchronization between the WorkItems execution, and the +// frameworks objects event callbacks into the device driver. +// +// The WDFWORKITEM object is designed to be re-useable, in which it can be re-linked +// into the WorkItem queue after firing. +// +// Calling GetWorkItemPtr returns the WDM IoWorkItem. +// + +class FxWorkItem : public FxNonPagedObject { + +private: + // + // WDM work item. + // + MxWorkItem m_WorkItem; + + // Ensures only one of either Delete or Cleanup runsdown the object + BOOLEAN m_RunningDown; + + // + // If this is set, a WorkItem has been enqueued + // + BOOLEAN m_Enqueued; + + // + // This count is used to prevent the object from being deleted if + // one worker thread is preempted right after we drop the lock to call + // the client callback and another workitem gets queued and runs + // to completion and signals the event. + // + ULONG m_WorkItemRunningCount; + + // + // This is the Framework object who is associated with the work + // item if supplied + // + FxObject* m_Object; + + // + // This is the callback lock for the object this WorkItem will + // synchronize with + // + FxCallbackLock* m_CallbackLock; + + // + // This is the object whose reference count actually controls + // the lifetime of the m_CallbackLock + // + FxObject* m_CallbackLockObject; + + // + // This is the user supplied callback function and context + // + PFN_WDF_WORKITEM m_Callback; + + // + // This event is signaled when the workitem is done processing + // an Enqueue request. + // + FxCREvent m_WorkItemCompleted; + + // + // This is a pointer to thread object that invoked our workitem + // callback. This value will be used to avoid deadlock when we try + // to flush the workitem. + // + MxThread m_WorkItemThread; + +public: + + static + _Must_inspect_result_ + NTSTATUS + _Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WORKITEM_CONFIG Config, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObject* ParentObject, + __out WDFWORKITEM* WorkItem + ); + +/*++ + +Routine Description: + + Construct an FxWorkItem + +Arguments: + +Returns: + + NTSTATUS + +--*/ + + FxWorkItem( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + virtual + ~FxWorkItem( + ); + + MdWorkItem + GetWorkItemPtr() { + return m_WorkItem.GetWorkItem(); + } + +/*++ + +Routine Description: + + Initialize the WorkItem using either the caller supplied WorkItem + struct, or if NULL, our own internally allocated one + +Arguments: + +Returns: + + NTSTATUS + +--*/ + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_WORKITEM_CONFIG Config, + __in FxObject* ParentObject, + __out WDFWORKITEM* WorkItem + ); + + virtual + BOOLEAN + Dispose( + VOID + ); + + VOID + Enqueue( + ); + + WDFOBJECT + GetAssociatedObject( + ) + { + if( m_Object != NULL ) { + return m_Object->GetObjectHandle(); + } + else { + return NULL; + } + } + + WDFWORKITEM + GetHandle( + VOID + ) + { + return (WDFWORKITEM) GetObjectHandle(); + } + +private: + + // + // Called from Dispose, or cleanup list to perform final flushing of any + // outstanding DPC's and dereferencing of objects. + // + VOID + FlushAndRundown( + ); + + VOID + WorkItemHandler( + ); + + static + MX_WORKITEM_ROUTINE + WorkItemThunk; + + VOID + WaitForSignal( + VOID + ); + +public: + VOID + FlushAndWait( + VOID + ); +}; + +#endif // _FXWORKITEM_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/ifxhascallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/ifxhascallbacks.hpp new file mode 100644 index 00000000000..5a9de97732b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/ifxhascallbacks.hpp @@ -0,0 +1,88 @@ + +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + IFxHasCallbacks.hpp + +Abstract: + + Interface that objects with device driver callbacks and + constraints implement + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef __IFX_HASCALLBACKS_HPP +#define __IFX_HASCALLBACKS_HPP + +// +// Objects that have callbacks into the device driver +// (implemented by deriving a delegate from FxCallback), may +// have constraints specified by the device driver when the object +// or driver was created. +// +// These constraints control synchronization, and execution (IRQL) level +// on callbacks to the device driver. +// +// To provide synchronization an FxCallbackLock may be implemented, at +// either DISPATCH (spinlock) or PASSIVE (mutex lock) level depending +// on whether a passive level constraint is in effect. +// +// This interface allows the constraints, and any associated locks +// to be retrieved in a generic fashion from the object, such as +// for implementing the WdfObjectAcquireLock/WdfObjectReleaseLock APIs. +// + +class IFxHasCallbacks { + +public: + + // + // Returns the constraints in effect for the object. + // + virtual + VOID + GetConstraints( + __out WDF_EXECUTION_LEVEL* ExecutionLevel, + __out WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) = 0; + + // + // This returns the callback lock in effect for the object that + // will serialize with its event callbacks to the device driver. + // + // If no callback locks are in effect, the return value is NULL. + // + // The type of FxCallbackLock returned may be a spinlock, or mutex + // type depending on whether the object has a passive level callback + // constraint in effect. + // + // In addition, optionally returns the object that contains the lock + // providing any serialization constraint. This allows reference counting + // the object who owns the lock, which may not be the target + // object. An example would be a child object sharing its parent + // FxDevice's synchronziation lock. + // + _Must_inspect_result_ + virtual + FxCallbackLock* + GetCallbackLockPtr( + __out_opt FxObject** LockObject + ) = 0; +}; + +#endif // __IFX_HASCALLBACKS_HPP + + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/ifxmemory.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/ifxmemory.hpp new file mode 100644 index 00000000000..8a57e08722c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/ifxmemory.hpp @@ -0,0 +1,161 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +/*++ + +Module Name: + + IFxMemory.hpp + +Abstract: + + Abstract base class for a memory object. It is necessary to split the + memory interface away from an FxObject derived base class so that we can + hand out WDFMEMORY handles that are embedded within other FxObject derived + classes without having to embed another FxObject derived class within the + parent. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef __IFX_MEMORY_HPP__ +#define __IFX_MEMORY_HPP__ + +// begin_wpp enum +enum IFxMemoryFlags { + IFxMemoryFlagReadOnly = 0x0001, +}; +// end_wpp + + +class IFxMemory { +public: + virtual + PVOID + GetBuffer( + VOID + ) =0; + + virtual + size_t + GetBufferSize( + VOID + ) =0; + + virtual + PMDL + GetMdl( + VOID + ) =0; + + virtual + WDFMEMORY + GetHandle( + VOID + ) =0; + + // + // Value returned is a bit field from the enum IFxMemoryFlags + // + virtual + USHORT + GetFlags( + VOID + ) =0; + + virtual + PFX_DRIVER_GLOBALS + GetDriverGlobals( + VOID + ) =0; + + virtual + ULONG + AddRef( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) =0; + + virtual + ULONG + Release( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File + ) =0; + + virtual + VOID + Delete( + VOID + ) =0; + + _Must_inspect_result_ + NTSTATUS + ValidateMemoryOffsets( + __in_opt PWDFMEMORY_OFFSET Offsets + ) + { + NTSTATUS status; + size_t total; + + if (Offsets == NULL) { + return STATUS_SUCCESS; + } + + status = RtlSizeTAdd(Offsets->BufferLength, Offsets->BufferOffset, &total); + + if (!NT_SUCCESS(status)) { + return status; + } + + if (total > GetBufferSize()) { + return STATUS_INTEGER_OVERFLOW; + } + + return STATUS_SUCCESS; + } + + _Must_inspect_result_ + NTSTATUS + CopyFromPtr( + __in_opt PWDFMEMORY_OFFSET DestinationOffsets, + __in_bcount(SourceBufferLength) PVOID SourceBuffer, + __in size_t SourceBufferLength, + __in_opt PWDFMEMORY_OFFSET SourceOffsets + ); + + _Must_inspect_result_ + NTSTATUS + CopyToPtr( + __in_opt PWDFMEMORY_OFFSET SourceOffsets, + __out_bcount(DestinationBufferLength) PVOID DestinationBuffer, + __in size_t DestinationBufferLength, + __in_opt PWDFMEMORY_OFFSET DestinationOffsets + ); + +protected: + static + _Must_inspect_result_ + NTSTATUS + _CopyPtrToPtr( + __in_bcount(SourceBufferLength) PVOID SourceBuffer, + __in size_t SourceBufferLength, + __in_opt PWDFMEMORY_OFFSET SourceOffsets, + __out_bcount(DestinationBufferLength) PVOID DestinationBuffer, + __in size_t DestinationBufferLength, + __in_opt PWDFMEMORY_OFFSET DestinationOffsets + ); +}; + +#endif // __IFX_MEMORY_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/common/stringutil.hpp b/sdk/lib/drivers/wdf/shared/inc/private/common/stringutil.hpp new file mode 100644 index 00000000000..00422864dd9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/common/stringutil.hpp @@ -0,0 +1,41 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _STRINGUTIL_H_ +#define _STRINGUTIL_H_ + +size_t +FxCalculateTotalStringSize( + __in FxCollectionInternal *StringCollection, + __in BOOLEAN Verify = FALSE, + __out_opt PBOOLEAN ContainsOnlyStrings = NULL + ); + +size_t +FxCalculateTotalMultiSzStringSize( + __in __nullnullterminated PCWSTR MultiSz + ); + +PWSTR +FxCopyMultiSz( + __out LPWSTR Buffer, + __in FxCollectionInternal* StringCollection + ); + +_Must_inspect_result_ +NTSTATUS +FxDuplicateUnicodeString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in const UNICODE_STRING* Source, + __out PUNICODE_STRING Destination + ); + +_Must_inspect_result_ +PWCHAR +FxDuplicateUnicodeStringToString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in const UNICODE_STRING* Source + ); + + +#endif // _STRINGUTIL_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxdevicekm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxdevicekm.hpp new file mode 100644 index 00000000000..20050e6b10e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxdevicekm.hpp @@ -0,0 +1,171 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceKM.hpp + +Abstract: + + This is the definition of the FxDevice object KM specific + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#ifndef _FXDEVICEKM_H_ +#define _FXDEVICEKM_H_ + +__inline +FxWdmDeviceExtension* +FxDevice::_GetFxWdmExtension( + __in MdDeviceObject DeviceObject + ) +{ + // + // DeviceObject->DeviceExtension points to our FxDevice allocation. We + // get the underlying DeviceExtension allocated as part of the + // PDEVICE_OBJECT by adding the sizeof(DEVICE_OBJECT) to get the start + // of the DeviceExtension. This is documented behavior on how the + // DeviceExtension can be found. + // + return (FxWdmDeviceExtension*) WDF_PTR_ADD_OFFSET(DeviceObject, + sizeof(*DeviceObject)); +} + +__inline +MdRemoveLock +FxDevice::GetRemoveLock( + VOID + ) +{ + return &FxDevice::_GetFxWdmExtension( + GetDeviceObject())->IoRemoveLock; +} + +__inline +BOOLEAN +FxDevice::IsRemoveLockEnabledForIo( + VOID + ) +{ + if (m_DeviceObject.GetObject() != NULL) { + return (_GetFxWdmExtension(m_DeviceObject.GetObject())->RemoveLockOptionFlags & + WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) ? TRUE : FALSE; + } + else { + return FALSE; + } +} + +__inline +FxDevice* +FxDevice::GetFxDevice( + __in MdDeviceObject DeviceObject + ) +{ + MxDeviceObject deviceObject((MdDeviceObject)DeviceObject); + + // + // DeviceExtension points to the start of the first context assigned to + // WDFDEVICE. We walk backwards from the context to the FxDevice*. + // + return (FxDevice*) CONTAINING_RECORD(deviceObject.GetDeviceExtension(), + FxContextHeader, + Context)->Object; +} + +__inline +VOID +FxDevice::DetachDevice( + VOID + ) +{ + if (m_AttachedDevice.GetObject() != NULL) { + Mx::MxDetachDevice(m_AttachedDevice.GetObject()); + m_AttachedDevice.SetObject(NULL); + } +} + +__inline +VOID +FxDevice::InvalidateDeviceState( + VOID + ) +{ + PDEVICE_OBJECT pdo; + + // + // If the PDO is not yet reported to pnp, do not call the API. In this + // case, the PDO will soon be reported and started and the state that + // was just set will be queried for automatically by pnp as a part of + // start. + // + pdo = GetSafePhysicalDevice(); + + if (pdo != NULL) { + IoInvalidateDeviceState(pdo); + } +} + +VOID +__inline +FxDevice::DeleteSymbolicLink( + VOID + ) +{ + if (m_SymbolicLinkName.Buffer != NULL) { + // + // Must be at PASSIVE_LEVEL for this call + // + if (m_SymbolicLinkName.Length) { + Mx::MxDeleteSymbolicLink(&m_SymbolicLinkName); + } + + FxPoolFree(m_SymbolicLinkName.Buffer); + RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName)); + } +} + +__inline +NTSTATUS +FxDevice::_OpenDeviceRegistryKey( + _In_ MdDeviceObject DeviceObject, + _In_ ULONG DevInstKeyType, + _In_ ACCESS_MASK DesiredAccess, + _Out_ PHANDLE DevInstRegKey + ) +{ + return IoOpenDeviceRegistryKey(DeviceObject, + DevInstKeyType, + DesiredAccess, + DevInstRegKey); +} + +__inline +NTSTATUS +FxDevice::_GetDeviceProperty( + _In_ MdDeviceObject DeviceObject, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ ULONG BufferLength, + _Out_opt_ PVOID PropertyBuffer, + _Out_ PULONG ResultLength + ) +{ + return IoGetDeviceProperty(DeviceObject, + DeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength); +} + +#endif //_FXDEVICEKM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxdmaenabler.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxdmaenabler.hpp new file mode 100644 index 00000000000..5bdb39fec0d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxdmaenabler.hpp @@ -0,0 +1,479 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaEnabler.hpp + +Abstract: + + WDF DMA Enabler support + +Environment: + + Kernel mode only. + +Notes: + + +Revision History: + +--*/ + +#ifndef __FX_DMA_ENABLER_HPP__ +#define __FX_DMA_ENABLER_HPP__ + +#include "FxDmaEnablerCallbacks.hpp" + +// +// Dma Description structure +// +typedef struct _FxDmaDescription { + + DEVICE_DESCRIPTION DeviceDescription; + + PDMA_ADAPTER AdapterObject; + + // + // The size of a preallocated lookaside list for this DMA adapter + // + size_t PreallocatedSGListSize; + + size_t MaximumFragmentLength; + + ULONG NumberOfMapRegisters; + +} FxDmaDescription; + +enum FxDuplexDmaDescriptionType { + FxDuplexDmaDescriptionTypeRead = 0, + FxDuplexDmaDescriptionTypeWrite, + FxDuplexDmaDescriptionTypeMax, +}; + +// +// Make sure the two enums which match to the channels in the enabler match +// corresponding values. +// + +C_ASSERT(((ULONG) FxDuplexDmaDescriptionTypeRead) == ((ULONG) WdfDmaDirectionReadFromDevice)); +C_ASSERT(((ULONG) FxDuplexDmaDescriptionTypeWrite) == ((ULONG) WdfDmaDirectionWriteToDevice)); + +// +// Declare the FxDmaEnabler class +// +class FxDmaEnabler : public FxNonPagedObject { + + friend class FxDmaTransactionBase; + friend class FxDmaPacketTransaction; + friend class FxDmaScatterGatherTransaction; + friend class FxDmaSystemTransaction; + +public: + + FxDmaEnabler( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxDmaEnabler(); + + virtual + BOOLEAN + Dispose( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + Initialize( + __in PWDF_DMA_ENABLER_CONFIG Config, + __inout FxDeviceBase *Device + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureSystemAdapter( + __in PWDF_DMA_SYSTEM_PROFILE_CONFIG Config, + __in WDF_DMA_DIRECTION ConfigDirection + ); + + VOID + AllocateCommonBuffer( + __in size_t Length, + __deref_out_opt PVOID * BufferVA, + __out PHYSICAL_ADDRESS * BufferPA + ); + + VOID + FreeCommonBuffer( + __in size_t Length, + __in PVOID BufferVA, + __in PHYSICAL_ADDRESS BufferPA + ); + + _Must_inspect_result_ + NTSTATUS + PowerUp( + VOID + ); + + _Must_inspect_result_ + NTSTATUS + PowerDown( + VOID + ); + + VOID + RevokeResources( + VOID + ); + + VOID + InitializeTransferContext( + __out PVOID Context, + __in WDF_DMA_DIRECTION Direction + ); + + __inline + size_t + GetMaximumLength( + VOID + ) + { + // + // This value is same for all the channels and equal to the value + // provided in the DMA_ENABLER_CONFIG. + // + return GetReadDmaDescription()->DeviceDescription.MaximumLength; + } + + __inline + size_t + GetAlignment( + VOID + ) + { + return m_CommonBufferAlignment; + } + + __inline + WDFDMAENABLER + GetHandle( + VOID + ) + { + return (WDFDMAENABLER) GetObjectHandle(); + } + + __inline + WDFDEVICE + GetDeviceHandle( + VOID + ) + { + + return m_DeviceBase->GetHandle(); + } + + __inline + size_t + GetMaxSGElements( + VOID + ) + { + return m_MaxSGElements; + } + + __inline + VOID + SetMaxSGElements( + __in size_t MaximumSGElements + ) + { + m_MaxSGElements = (ULONG) MaximumSGElements; + } + + __inline + WDF_DMA_PROFILE + GetProfile( + VOID + ) + { + return m_Profile; + } + + __inline + BOOLEAN + SupportsChainedMdls( + VOID + ) + { + // + // The only case where we don't support chained MDLS is DMAV2 + // with packet mode. + // + + if ((UsesDmaV3() == false) && + (m_IsBusMaster == TRUE) && + (m_IsScatterGather == FALSE)) { + return false; + } else { + return true; + } + } + + __inline + BOOLEAN + IsBusMaster( + VOID + ) + { + return m_IsBusMaster; + } + + __inline + BOOLEAN + IsPacketBased( + ) + { + return m_IsScatterGather ? FALSE : TRUE ; + } + + __inline + FxDmaDescription* + GetDmaDescription( + __in WDF_DMA_DIRECTION Direction + ) + { + if (m_IsDuplexTransfer) { + return &m_DuplexAdapterInfo[Direction]; + } + else { + return &m_SimplexAdapterInfo; + } + } + + + __inline + FxDmaDescription* + GetWriteDmaDescription( + VOID + ) + { + if (m_IsDuplexTransfer) { + return &m_DuplexAdapterInfo[FxDuplexDmaDescriptionTypeWrite]; + } else { + return &m_SimplexAdapterInfo; + } + } + + __inline + FxDmaDescription* + GetReadDmaDescription( + VOID + ) + { + if (m_IsDuplexTransfer) { + return &m_DuplexAdapterInfo[FxDuplexDmaDescriptionTypeRead]; + } else { + return &m_SimplexAdapterInfo; + } + } + + BOOLEAN + UsesDmaV3( + VOID + ) + { + FxDmaDescription* description; + + // + // It doesn't matter which direction we use below. Direction is + // ignored for the simplex enabler, and will be the same for both + // channels in a duplex enabler. + // + + description = GetDmaDescription(WdfDmaDirectionReadFromDevice); + + return description->DeviceDescription.Version == DEVICE_DESCRIPTION_VERSION3; + } + + USHORT + GetTransferContextSize( + VOID + ) + { + return UsesDmaV3() ? DMA_TRANSFER_CONTEXT_SIZE_V1 : 0; + } + +public: + // + // Link into list of FxDmaEnabler pointers maintained by the pnp package. + // + FxTransactionedEntry m_TransactionLink; + +protected: + + PDEVICE_OBJECT m_FDO; + + PDEVICE_OBJECT m_PDO; + + union { + // + // Used if the dma profile is not duplex. Common for both read & write. + // All the information specific to the channel are stored in the struct. + // + FxDmaDescription m_SimplexAdapterInfo; + + // + // Used if the dma profile is duplex. + // + FxDmaDescription m_DuplexAdapterInfo[FxDuplexDmaDescriptionTypeMax]; + }; + + // + // The profile of the DMA enabler. + // + WDF_DMA_PROFILE m_Profile; + + // + // Whether the enabler object is added to the device enabler list. + // + BOOLEAN m_IsAdded : 1; + + // + // Whether the DMA enabler has been configured with DMA resources & has its + // adapters. + // + BOOLEAN m_IsConfigured : 1; + + // + // The DMA profile broken out into individual flags. + // + BOOLEAN m_IsBusMaster : 1; + + BOOLEAN m_IsScatterGather : 1; + + BOOLEAN m_IsDuplexTransfer : 1; + + // + // Has the preallocated scatter gather list (single list or lookaside, + // depending on profile) been allocated. Indicates initialization state + // of m_SGList below. + // + BOOLEAN m_IsSGListAllocated: 1; + + // + // This value is larger of aligment value returned by HAL(which is always 1) + // and the alignment value set on the device by WdfDeviceSetAlignmentRequirement. + // + ULONG m_CommonBufferAlignment; + + // + // The maximum DMA transfer the enabler should support (saved from the enabler + // config) + // + ULONG m_MaximumLength; + + ULONG m_MaxSGElements; + + // + // The size of the preallocated SGList entries, in bytes. This is for entries + // on the lookaside list or the single entry list. + // + size_t m_SGListSize; + + // + // Storage for scatter gather lists. Whether the lookaside or the single entry + // the size in bytes is described by m_SGListSize + // + // The m_IsSGListAllocated bit above indicates whether we've + // initialized this structure or not. + // + union { + + // + // For the scatter gather profile we have a lookaside list of SGLists + // We allocate these dynamically because (a) we can be mapping + // multiple transactions in parallel and (b) the number of map registers + // for SG DMA may be very large and we don't necessarily need one per + // transaction at all times + // + // For duplex channels, the entry size is larger of read & write channels. + // + struct { + NPAGED_LOOKASIDE_LIST Lookaside; + } ScatterGatherProfile; + + // + // A single SGList for use with system DMA transfers. We can use a single + // list because (a) there is only one system DMA transaction being mapped + // at any given time (for this adapter) and (b) we don't use the physical + // addresses or give them to the driver so they don't need to be preserved + // very long (the list is only so the HAL has enough scratch space to tell + // the HAL DMA extension which PA's comprise the transfer) + // + struct { + PSCATTER_GATHER_LIST List; + } SystemProfile; + + // + // NOTE: there is no preallocated entry for packet based bus mastering DMA + // because we could be mapping multiple transactions in parallel but + // the size of the SGList is static and can be allocated on the stack + // + + } m_SGList; + +private: + // + // Power-related callbacks. + // + FxEvtDmaEnablerFillCallback m_EvtDmaEnablerFill; + FxEvtDmaEnablerFlushCallback m_EvtDmaEnablerFlush; + FxEvtDmaEnablerEnableCallback m_EvtDmaEnablerEnable; + FxEvtDmaEnablerDisableCallback m_EvtDmaEnablerDisable; + FxEvtDmaEnablerSelfManagedIoStartCallback m_EvtDmaEnablerSelfManagedIoStart; + FxEvtDmaEnablerSelfManagedIoStopCallback m_EvtDmaEnablerSelfManagedIoStop; + + // + // Note that these fields form an informal state engine. + // + BOOLEAN m_DmaEnablerFillFailed; + BOOLEAN m_DmaEnablerEnableFailed; + BOOLEAN m_DmaEnablerSelfManagedIoStartFailed; + + _Must_inspect_result_ + NTSTATUS + ConfigureBusMasterAdapters( + __in PDEVICE_DESCRIPTION DeviceDescription, + __in PWDF_DMA_ENABLER_CONFIG Config + ); + + _Must_inspect_result_ + NTSTATUS + ConfigureDmaAdapter( + __in PDEVICE_DESCRIPTION DeviceDescription, + __in WDF_DMA_DIRECTION ConfigDirection + ); + + _Must_inspect_result_ + NTSTATUS + InitializeResources( + __inout FxDmaDescription *AdapterInfo + ); + + VOID + ReleaseResources( + VOID + ); + + VOID + FreeResources( + __inout FxDmaDescription *AdapterInfo + ); + +}; // end of class + +#endif // _FXDMAENABLER_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxdmaenablercallbacks.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxdmaenablercallbacks.hpp new file mode 100644 index 00000000000..1317244b331 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxdmaenablercallbacks.hpp @@ -0,0 +1,254 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDmaEnablerCallbacks.hpp + +Abstract: + + This module implements the FxDmaEnabler object callbacks + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXDMAENABLERCALLBACKS_HPP +#define _FXDMAENABLERCALLBACKS_HPP + +enum FxDmaEnablerCallbacks { + + FxEvtDmaEnablerInvalid, + FxEvtDmaEnablerFill, + FxEvtDmaEnablerFlush, + FxEvtDmaEnablerEnable, + FxEvtDmaEnablerDisable, + FxEvtDmaEnablerSelfManagedIoStart, + FxEvtDmaEnablerSelfManagedIoStop, + +}; + +// +// EvtDmaEnablerFill callback delegate +// +class FxEvtDmaEnablerFillCallback : public FxCallback { + +public: + PFN_WDF_DMA_ENABLER_FILL m_Method; + + NTSTATUS m_Status; + + FxEvtDmaEnablerFillCallback( + VOID + ) : + FxCallback(), + m_Method(NULL), + m_Status(STATUS_SUCCESS) + { + } + + NTSTATUS + Invoke( + __in WDFDMAENABLER Handle + ) + { + if (m_Method) { + CallbackStart(); + m_Status = m_Method( Handle ); + CallbackEnd(); + } + else { + m_Status = STATUS_SUCCESS; + } + return m_Status; + } +}; + +// +// EvtDmaEnablerFlush callback delegate +// +class FxEvtDmaEnablerFlushCallback : public FxCallback { + +public: + PFN_WDF_DMA_ENABLER_FLUSH m_Method; + + NTSTATUS m_Status; + + FxEvtDmaEnablerFlushCallback( + VOID + ) : + FxCallback(), + m_Method(NULL), + m_Status(STATUS_SUCCESS) + { + } + + NTSTATUS + Invoke( + __in WDFDMAENABLER Handle + ) + { + if (m_Method) { + CallbackStart(); + m_Status = m_Method( Handle ); + CallbackEnd(); + } + else { + m_Status = STATUS_SUCCESS; + } + return m_Status; + } +}; + +// +// EvtDmaEnablerEnable callback delegate +// +class FxEvtDmaEnablerEnableCallback : public FxCallback { + +public: + PFN_WDF_DMA_ENABLER_ENABLE m_Method; + + NTSTATUS m_Status; + + FxEvtDmaEnablerEnableCallback( + VOID + ) : + FxCallback(), + m_Method(NULL), + m_Status(STATUS_SUCCESS) + { + } + + NTSTATUS + Invoke( + __in WDFDMAENABLER Handle + ) + { + if (m_Method) { + CallbackStart(); + m_Status = m_Method( Handle ); + CallbackEnd(); + } + else { + m_Status = STATUS_SUCCESS; + } + return m_Status; + } +}; + +// +// EvtDmaEnablerDisable callback delegate +// +class FxEvtDmaEnablerDisableCallback : public FxCallback { + +public: + PFN_WDF_DMA_ENABLER_DISABLE m_Method; + + NTSTATUS m_Status; + + FxEvtDmaEnablerDisableCallback( + VOID + ) : + FxCallback(), + m_Method(NULL), + m_Status(STATUS_SUCCESS) + { + } + + NTSTATUS + Invoke( + __in WDFDMAENABLER Handle + ) + { + if (m_Method) { + CallbackStart(); + m_Status = m_Method( Handle ); + CallbackEnd(); + } + else { + m_Status = STATUS_SUCCESS; + } + return m_Status; + } +}; + +// +// EvtDmaEnablerSelfManagedIoStart callback delegate +// +class FxEvtDmaEnablerSelfManagedIoStartCallback : public FxCallback { + +public: + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_START m_Method; + + NTSTATUS m_Status; + + FxEvtDmaEnablerSelfManagedIoStartCallback( + VOID + ) : + FxCallback(), + m_Method(NULL), + m_Status(STATUS_SUCCESS) + { + } + + NTSTATUS + Invoke( + __in WDFDMAENABLER Handle + ) + { + if (m_Method) { + CallbackStart(); + m_Status = m_Method( Handle ); + CallbackEnd(); + } + else { + m_Status = STATUS_SUCCESS; + } + return m_Status; + } +}; + + +// +// EvtDmaEnablerSelfManagedIoStop callback delegate +// +class FxEvtDmaEnablerSelfManagedIoStopCallback : public FxCallback { + +public: + PFN_WDF_DMA_ENABLER_SELFMANAGED_IO_STOP m_Method; + + NTSTATUS m_Status; + + FxEvtDmaEnablerSelfManagedIoStopCallback( + VOID + ) : + FxCallback(), + m_Method(NULL), + m_Status(STATUS_SUCCESS) + { + } + + NTSTATUS + Invoke( + __in WDFDMAENABLER Handle + ) + { + if (m_Method) { + CallbackStart(); + m_Status = m_Method( Handle ); + CallbackEnd(); + } + else { + m_Status = STATUS_SUCCESS; + } + return m_Status; + } +}; + + +#endif // _FXDMAENABLERCALLBACKS_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxglobalskm.h b/sdk/lib/drivers/wdf/shared/inc/private/km/fxglobalskm.h new file mode 100644 index 00000000000..0b4ed6e61cc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxglobalskm.h @@ -0,0 +1,744 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxGlobalsKm.h + +Abstract: + + This module contains kernel-mode specific globals definitions + for the frameworks. + + For common definitions common between km and um please see + FxGlobals.h + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ +#ifdef __cplusplus +extern "C" { +#endif + +extern PCHAR WdfLdrType; + +#define WDF_LDR_STATIC_TYPE_STR "WdfStatic" + +// forward definitions +typedef struct _FX_DRIVER_GLOBALS *PFX_DRIVER_GLOBALS; +typedef struct _FX_DUMP_DRIVER_INFO_ENTRY *PFX_DUMP_DRIVER_INFO_ENTRY; + +struct FxMdlDebugInfo { + PMDL Mdl; + FxObject* Owner; + PVOID Caller; +}; + +#define NUM_MDLS_IN_INFO (16) + +struct FxAllocatedMdls { + FxMdlDebugInfo Info[NUM_MDLS_IN_INFO]; + ULONG Count; + struct FxAllocatedMdls* Next; +}; + +#define DDI_ENTRY_IMPERSONATION_OK() +#define DDI_ENTRY() + +typedef +BOOLEAN +(*PFN_KD_REFRESH)( + ); + +typedef +VOID +(*PFN_KE_FLUSH_QUEUED_DPCS)( + VOID + ); + +typedef +NTSTATUS +(*PFN_IO_SET_COMPLETION_ROUTINE_EX)( + __in PDEVICE_OBJECT DeviceObject, + __in PIRP Irp, + __in PIO_COMPLETION_ROUTINE CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess, + __in BOOLEAN InvokeOnError, + __in BOOLEAN InvokeOnCancel + ); + +typedef +BOOLEAN +(*PFN_KE_REGISTER_BUGCHECK_REASON_CALLBACK) ( + __in PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord, + __in PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine, + __in KBUGCHECK_CALLBACK_REASON Reason, + __in PUCHAR Component + ); + +typedef +BOOLEAN +(*PFN_KE_DEREGISTER_BUGCHECK_REASON_CALLBACK) ( + __in PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecords + ); + +typedef +NTSTATUS +(*PFN_IO_CONNECT_INTERRUPT_EX)( + __inout PIO_CONNECT_INTERRUPT_PARAMETERS Parameters + ); + +typedef +NTSTATUS +(*PFN_IO_DISCONNECT_INTERRUPT_EX)( + __in PIO_DISCONNECT_INTERRUPT_PARAMETERS Parameters + ); + +typedef +NTSTATUS +(*PFN_IO_CONNECT_INTERRUPT)( + __out PKINTERRUPT *InterruptObject, + __in PKSERVICE_ROUTINE ServiceRoutine, + __in_opt PVOID ServiceContext, + __in_opt PKSPIN_LOCK SpinLock, + __in ULONG Vector, + __in KIRQL Irql, + __in KIRQL SynchronizeIrql, + __in KINTERRUPT_MODE InterruptMode, + __in BOOLEAN ShareVector, + __in KAFFINITY ProcessorEnableMask, + __in BOOLEAN FloatingSave + ); + +typedef +VOID +(*PFN_IO_DISCONNECT_INTERRUPT)( + __in PKINTERRUPT InterruptObject + ); + +typedef +KIRQL +(FASTCALL *PFN_KF_RAISE_IRQL) ( + __in KIRQL NewIrql + ); + +typedef +VOID +(FASTCALL *PFN_KF_LOWER_IRQL) ( + __in KIRQL NewIrql + ); + +typedef +PSLIST_ENTRY +(FASTCALL *PFN_INTERLOCKED_POP_ENTRY_SLIST)( + __inout PSLIST_HEADER ListHead + ); + +typedef +PSLIST_ENTRY +(FASTCALL *PFN_INTERLOCKED_PUSH_ENTRY_SLIST)( + __inout PSLIST_HEADER ListHead, + __inout PSLIST_ENTRY ListEntry + ); + +typedef +BOOLEAN +(*PFN_PO_GET_SYSTEM_WAKE)( + __in PIRP Irp + ); + +typedef +VOID +(*PFN_PO_SET_SYSTEM_WAKE)( + __inout PIRP Irp + ); + +typedef +KAFFINITY +(*PFN_KE_QUERY_ACTIVE_PROCESSORS)( + VOID + ); + +typedef +VOID +(*PFN_KE_SET_TARGET_PROCESSOR_DPC)( + __in PRKDPC Dpc, + __in CCHAR Number + ); + +typedef +BOOLEAN +(*PFN_KE_SET_COALESCABLE_TIMER)( + __inout PKTIMER Timer, + __in LARGE_INTEGER DueTime, + __in ULONG Period, + __in ULONG TolerableDelay, + __in_opt PKDPC Dpc + ); + +typedef +ULONG +(*PFN_KE_GET_CURRENT_PROCESSOR_NUMBER)( + VOID + ); + +typedef +ULONG +(*PFN_KE_GET_CURRENT_PROCESSOR_NUMBER_EX)( + __out_opt PPROCESSOR_NUMBER ProcNumber + ); + +typedef +ULONG +(*PFN_KE_QUERY_MAXIMUM_PROCESSOR_COUNT_EX)( + __in USHORT GroupNumber + ); + +typedef +ULONG +(*PFN_KE_QUERY_MAXIMUM_PROCESSOR_COUNT)( + VOID + ); + +typedef +BOOLEAN +(*PFN_KE_ARE_APCS_DISABLED)( + VOID + ); + +typedef +ULONG +(*PFN_KE_GET_RECOMMENDED_SHARED_DATA_ALIGNMENT)( + VOID + ); + +typedef +NTSTATUS +(*PFN_IO_UNREGISTER_PLUGPLAY_NOTIFICATION_EX)( + __in PVOID NotificationEntry + ); + +typedef +NTSTATUS +(*PFN_POX_REGISTER_DEVICE) ( + __in MdDeviceObject Pdo, + __in PPO_FX_DEVICE PoxDevice, + __out POHANDLE * Handle + ); + +typedef +VOID +(*PFN_POX_START_DEVICE_POWER_MANAGEMENT) ( + __in POHANDLE Handle + ); + +typedef +VOID +(*PFN_POX_UNREGISTER_DEVICE) ( + __in POHANDLE Handle + ); + +typedef +(*PFN_POX_ACTIVATE_COMPONENT) ( + __in POHANDLE Handle, + __in ULONG Component, + __in ULONG Flags + ); + +typedef +(*PFN_POX_IDLE_COMPONENT) ( + __in POHANDLE Handle, + __in ULONG Component, + __in ULONG Flags + ); + +typedef +VOID +(*PFN_POX_REPORT_DEVICE_POWERED_ON) ( + __in POHANDLE Handle + ); + +typedef +VOID +(*PFN_POX_COMPLETE_IDLE_STATE) ( + __in POHANDLE Handle, + __in ULONG Component + ); + +typedef +VOID +(*PFN_POX_COMPLETE_IDLE_CONDITION) ( + __in POHANDLE Handle, + __in ULONG Component + ); + +typedef +VOID +(*PFN_POX_COMPLETE_DEVICE_POWER_NOT_REQUIRED) ( + __in POHANDLE Handle + ); + +typedef +VOID +(*PFN_POX_SET_DEVICE_IDLE_TIMEOUT) ( + __in POHANDLE Handle, + __in ULONGLONG IdleTimeout + ); + +typedef +VOID +(*PFN_IO_REPORT_INTERRUPT_ACTIVE) ( + _In_ PIO_REPORT_INTERRUPT_ACTIVE_STATE_PARAMETERS Parameters + ); + +typedef +VOID +(*PFN_IO_REPORT_INTERRUPT_INACTIVE) ( + _In_ PIO_REPORT_INTERRUPT_ACTIVE_STATE_PARAMETERS Parameters + ); + +typedef +VOID +(*PFN_VF_CHECK_NX_POOL_TYPE) ( + _In_ POOL_TYPE PoolType, + _In_ PVOID CallingAddress, + _In_ ULONG PoolTag + ); + +VOID +FxRegisterBugCheckCallback( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PDRIVER_OBJECT DriverObject + ); + +VOID +FxUnregisterBugCheckCallback( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +VOID +FxInitializeBugCheckDriverInfo(); + +VOID +FxUninitializeBugCheckDriverInfo(); + +VOID +FxCacheBugCheckDriverInfo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +VOID +FxPurgeBugCheckDriverInfo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +typedef struct _FX_DRIVER_TRACKER_CACHE_AWARE { + // + // Internal data types. + // +private: + typedef struct _FX_DRIVER_TRACKER_ENTRY { + volatile PFX_DRIVER_GLOBALS FxDriverGlobals; + } FX_DRIVER_TRACKER_ENTRY, *PFX_DRIVER_TRACKER_ENTRY; + + // + // Public interface. + // +public: + _Must_inspect_result_ + NTSTATUS + Initialize(); + + VOID + Uninitialize(); + + _Must_inspect_result_ + NTSTATUS + Register( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + VOID + Deregister( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + // + // Tracks the driver usage on the current processor. + // KeGetCurrentProcessorNumberEx is called directly because the procgrp.lib + // provides the downlevel support for Vista, XP and Win2000. + // + __inline + VOID + TrackDriver( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + { + ASSERT(m_PoolToFree != NULL); + + GetProcessorDriverEntryRef( + KeGetCurrentProcessorIndex())->FxDriverGlobals = + FxDriverGlobals; + } + + // + // Returns the tracked driver (globals) on the current processor. + // KeGetCurrentProcessorNumberEx is called directly because the procgrp.lib + // provides the downlevel support for Vista, XP and Win2000. + // + _Must_inspect_result_ + __inline + PFX_DRIVER_GLOBALS + GetCurrentTrackedDriver() + { + PFX_DRIVER_GLOBALS fxDriverGlobals = NULL; + + ASSERT(m_PoolToFree != NULL); + + fxDriverGlobals = GetProcessorDriverEntryRef( + KeGetCurrentProcessorIndex())->FxDriverGlobals; + + return fxDriverGlobals; + } + + // + // Helper functions. + // +private: + // + // Returns the per-processor cache-aligned driver usage ref structure for + // given processor. + // + __inline + PFX_DRIVER_TRACKER_ENTRY + GetProcessorDriverEntryRef( + __in ULONG Index + ) + { + return ((PFX_DRIVER_TRACKER_ENTRY) (((PUCHAR)m_DriverUsage) + + Index * m_EntrySize)); + } + + // + // Data members. + // +private: + // + // Pointer to array of cache-line aligned tracking driver structures. + // + PFX_DRIVER_TRACKER_ENTRY m_DriverUsage; + + // + // Points to pool of per-proc tracking entries that needs to be freed. + // + PVOID m_PoolToFree; + + // + // Size of each padded tracking driver structure. + // + ULONG m_EntrySize; + + // + // Indicates # of entries in the array of tracking driver structures. + // + ULONG m_Number; +} FX_DRIVER_TRACKER_CACHE_AWARE, *PFX_DRIVER_TRACKER_CACHE_AWARE; + + +#include "FxGlobals.h" + + +// +// This inline function tracks driver usage; This info is used by the +// debug dump callback routine for selecting which driver's log to save +// in the minidump. At this time we track the following OS to framework calls: +// (a) IRP dispatch (general, I/O, PnP, WMI). +// (b) Request's completion callbacks. +// (c) Work Item's (& System Work Item's) callback handlers. +// (d) Timer's callback handlers. +// +__inline +VOID +FX_TRACK_DRIVER( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if (FxDriverGlobals->FxTrackDriverForMiniDumpLog) { + FxLibraryGlobals.DriverTracker.TrackDriver(FxDriverGlobals); + } +} + +_Must_inspect_result_ +__inline +PVOID +FxAllocateFromNPagedLookasideListNoTracking ( + __in PNPAGED_LOOKASIDE_LIST Lookaside + ) + +/*++ + +Routine Description: + + This function removes (pops) the first entry from the specified + nonpaged lookaside list. This function was added to allow request allocated + by a lookaside list to be freed by ExFreePool and hence do no tracking of statistics. + +Arguments: + + Lookaside - Supplies a pointer to a nonpaged lookaside list structure. + +Return Value: + + If an entry is removed from the specified lookaside list, then the + address of the entry is returned as the function value. Otherwise, + NULL is returned. + +--*/ + +{ + + PVOID Entry; + + Entry = InterlockedPopEntrySList(&Lookaside->L.ListHead); + + if (Entry == NULL) { + Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, + Lookaside->L.Size, + Lookaside->L.Tag); + } + + return Entry; +} + +__inline +VOID +FxFreeToNPagedLookasideListNoTracking ( + __in PNPAGED_LOOKASIDE_LIST Lookaside, + __in PVOID Entry + ) +/*++ + +Routine Description: + + This function inserts (pushes) the specified entry into the specified + nonpaged lookaside list. This function was added to allow request allocated + by a lookaside list to be freed by ExFreePool and hence do no tracking of statistics. + +Arguments: + + Lookaside - Supplies a pointer to a nonpaged lookaside list structure. + + Entry - Supples a pointer to the entry that is inserted in the + lookaside list. + +Return Value: + + None. + +--*/ + +{ + if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { + (Lookaside->L.Free)(Entry); + } + else { + InterlockedPushEntrySList(&Lookaside->L.ListHead, + (PSLIST_ENTRY)Entry); + } +} + +__inline +PVOID +FxAllocateFromNPagedLookasideList ( + _In_ PNPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ size_t ElementSize = 0 + ) + +/*++ + +Routine Description: + + This function removes (pops) the first entry from the specified + nonpaged lookaside list. + +Arguments: + + Lookaside - Supplies a pointer to a nonpaged lookaside list structure. + +Return Value: + + If an entry is removed from the specified lookaside list, then the + address of the entry is returned as the function value. Otherwise, + NULL is returned. + +--*/ + +{ + + PVOID Entry; + + UNREFERENCED_PARAMETER(ElementSize); + + Lookaside->L.TotalAllocates += 1; + + Entry = InterlockedPopEntrySList(&Lookaside->L.ListHead); + + if (Entry == NULL) { + Lookaside->L.AllocateMisses += 1; + Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, + Lookaside->L.Size, + Lookaside->L.Tag); + } + + return Entry; +} + +__inline +VOID +FxFreeToNPagedLookasideList ( + __in PNPAGED_LOOKASIDE_LIST Lookaside, + __in PVOID Entry + ) +/*++ + +Routine Description: + + This function inserts (pushes) the specified entry into the specified + nonpaged lookaside list. + +Arguments: + + Lookaside - Supplies a pointer to a nonpaged lookaside list structure. + + Entry - Supples a pointer to the entry that is inserted in the + lookaside list. + +Return Value: + + None. + +--*/ + +{ + Lookaside->L.TotalFrees += 1; + + if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { + Lookaside->L.FreeMisses += 1; + (Lookaside->L.Free)(Entry); + + } + else { + InterlockedPushEntrySList(&Lookaside->L.ListHead, + (PSLIST_ENTRY)Entry); + } +} + +_Must_inspect_result_ +__inline +PVOID +FxAllocateFromPagedLookasideList ( + __in PPAGED_LOOKASIDE_LIST Lookaside + ) + +/*++ + +Routine Description: + + This function removes (pops) the first entry from the specified + paged lookaside list. + +Arguments: + + Lookaside - Supplies a pointer to a paged lookaside list structure. + +Return Value: + + If an entry is removed from the specified lookaside list, then the + address of the entry is returned as the function value. Otherwise, + NULL is returned. + +--*/ + +{ + + PVOID Entry; + + Lookaside->L.TotalAllocates += 1; + + Entry = InterlockedPopEntrySList(&Lookaside->L.ListHead); + if (Entry == NULL) { + Lookaside->L.AllocateMisses += 1; + Entry = (Lookaside->L.Allocate)(Lookaside->L.Type, + Lookaside->L.Size, + Lookaside->L.Tag); + } + + return Entry; +} + +__inline +VOID +FxFreeToPagedLookasideList ( + __in PPAGED_LOOKASIDE_LIST Lookaside, + __in PVOID Entry + ) +/*++ + +Routine Description: + + This function inserts (pushes) the specified entry into the specified + paged lookaside list. + +Arguments: + + Lookaside - Supplies a pointer to a paged lookaside list structure. + + Entry - Supples a pointer to the entry that is inserted in the + lookaside list. + +Return Value: + + None. + +--*/ + +{ + Lookaside->L.TotalFrees += 1; + + if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { + Lookaside->L.FreeMisses += 1; + (Lookaside->L.Free)(Entry); + + } else { + InterlockedPushEntrySList(&Lookaside->L.ListHead, + (PSLIST_ENTRY)Entry); + } +} + +_Must_inspect_result_ +__inline +BOOLEAN +FxIsProcessorGroupSupported( + VOID + ) +{ + // + // Groups are supported in Win 7 and forward. + // + return FxLibraryGlobals.ProcessorGroupSupport; +} + +#ifdef __cplusplus +} +#endif diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxinterruptkm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxinterruptkm.hpp new file mode 100644 index 00000000000..6150820e5c8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxinterruptkm.hpp @@ -0,0 +1,116 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxInterruptKm.hpp + +Abstract: + + This module implements a frameworks managed interrupt object + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#ifndef _FXINTERRUPTKM_H_ +#define _FXINTERRUPTKM_H_ + +#include "FxInterrupt.hpp" + +__inline +struct _KINTERRUPT* +FxInterrupt::GetInterruptPtr( + VOID + ) +{ + struct _KINTERRUPT* interrupt = m_Interrupt; + + if (interrupt == NULL) { + interrupt = m_InterruptCaptured; + } + + return interrupt; +} + +__inline +VOID +FxInterrupt::ResetInternal( + VOID + ) +{ + // + // Does nothing for KMDF + // +} + +__inline +VOID +FxInterrupt::RevokeResourcesInternal( + VOID + ) +{ + // + // Does nothing for KMDF + // +} + +__inline +VOID +FxInterrupt::AssignResourcesInternal( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans, + __in PWDF_INTERRUPT_INFO InterruptInfo + ) +{ + UNREFERENCED_PARAMETER(CmDescRaw); + UNREFERENCED_PARAMETER(CmDescTrans); + UNREFERENCED_PARAMETER(InterruptInfo); + + // + // Does nothing for KMDF + // +} + +__inline +VOID +FxInterrupt::SetPolicyInternal( + __in WDF_INTERRUPT_POLICY Policy, + __in WDF_INTERRUPT_PRIORITY Priority, + __in PGROUP_AFFINITY TargetProcessorSet + ) +{ + UNREFERENCED_PARAMETER(Policy); + UNREFERENCED_PARAMETER(Priority); + UNREFERENCED_PARAMETER(TargetProcessorSet); + + // + // Does nothing for KMDF + // +} + +__inline +BOOLEAN +_SynchronizeExecution( + __in MdInterrupt Interrupt, + __in MdInterruptSynchronizeRoutine SynchronizeRoutine, + __in PVOID SynchronizeContext + ) +{ + return KeSynchronizeExecution(Interrupt, + SynchronizeRoutine, + SynchronizeContext); +} + +#endif // _FXINTERRUPTKM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxioqueuekm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxioqueuekm.hpp new file mode 100644 index 00000000000..559b8f3a2b4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxioqueuekm.hpp @@ -0,0 +1,59 @@ +/*++ + + Copyright (c) Microsoft Corporation + + Module Name: + + FxIoQueueKm.hpp + + Abstract: + + This module implements km specific functions for FxIoQueue. + + Author: + + + + Environment: + + Kernel mode only + + Revision History: + + --*/ + +#ifndef _FXIOQUEUEKM_HPP_ +#define _FXIOQUEUEKM_HPP_ + +__inline +BOOLEAN +FxIoQueue::IsPagingIo( + __in MdIrp Irp + ) +/*++ + + Routine Description: + Paging IO is treated especially depending on what Forward Progress policy + was set on the Queue + --*/ +{ + // + // NOTE: IRP_INPUT_OPERATION has the same value as IRP_SYNCHRONOUS_PAGING_IO + // and IRP_MOUNT_COMPLETION the same as IRP_PAGING_IO so how does one know if + // the IO is a paging IO ? + // + + // One can assume that if IRP_PAGING_IO is set and the MJ code is not + // FILE_SYSTEM_CONTROL then it is a paging I/O. + // + if (Irp->Flags & IRP_PAGING_IO) { + if (IoGetCurrentIrpStackLocation(Irp)->MajorFunction + != IRP_MJ_FILE_SYSTEM_CONTROL) { + return TRUE; + } + } + + return FALSE; +} + +#endif // _FXIOQUEUEKM_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxiotargetkm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxiotargetkm.hpp new file mode 100644 index 00000000000..8707fe9a82d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxiotargetkm.hpp @@ -0,0 +1,270 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxIoTarget.hpp + +Abstract: + + Encapsulation of the target to which FxRequest are sent to. For example, + an FxTarget could represent the next device object in the pnp stack. + Derivations from this class could include bus specific formatters or device + objects outside of the pnp stack of the device. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#ifndef _FXIOTARGETKM_H_ +#define _FXIOTARGETKM_H_ + +__inline +FxIoContext::FxIoContext( + VOID + ) : + FxRequestContext(FX_RCT_IO), + m_MdlToFree(NULL), + m_OriginalMdl(NULL), + m_BufferToFree(NULL), + m_OriginalSystemBuffer(NULL), + m_OriginalUserBuffer(NULL), + m_OtherMemory(NULL), + m_CopyBackToBuffer(FALSE), + m_UnlockPages(FALSE), + m_RestoreState(FALSE), + m_BufferToFreeLength(0), + m_MdlToFreeSize(0) +{ +} + +__inline +FxIoContext::~FxIoContext( + VOID + ) +{ + // + // Free the buffer allocated for the request, reset m_CopyBackToBuffer + // to FALSE. + // NOTE: We delay the freeing of the buffer on purpose. + // + ClearBuffer(); + + // + // Free the MDL allocated for the request + // + if (m_MdlToFree != NULL) { + // + // Being defensive here, MmUnlockPages should have been done in + // ReleaseAndRestore. + // + if (m_UnlockPages) { + MmUnlockPages(m_MdlToFree); + m_UnlockPages = FALSE; + } + + FxMdlFree(m_DriverGlobals, m_MdlToFree); + m_MdlToFree = NULL; + } +} + +__inline +VOID +FxIoContext::ReleaseAndRestore( + __in FxRequestBase* Request + ) +{ + FxIrp* irp = NULL; + + irp = Request->GetSubmitFxIrp(); + + if (m_RestoreState) { + irp->SetSystemBuffer(m_OriginalSystemBuffer); + irp->SetUserBuffer(m_OriginalUserBuffer); + irp->SetMdlAddress(m_OriginalMdl); + irp->SetFlags(m_OriginalFlags); + m_OriginalSystemBuffer = NULL; + m_OriginalUserBuffer = NULL; + m_OriginalMdl = NULL; + m_OriginalFlags = NULL; + + m_RestoreState = FALSE; + } + + // + // If there was a buffer present don't free the buffer here so that + // it can be reused for any request with the same size. + // Similarly if there was an MDL to be freed unlock the pages but dont free + // the Mdl so that it can be reused. + // + if (m_MdlToFree != NULL) { + if (m_UnlockPages) { + MmUnlockPages(m_MdlToFree); + m_UnlockPages = FALSE; + } + + + m_DriverGlobals = Request->GetDriverGlobals(); + } + + // + // Release the 2ndary buffer if we have an outstanding reference + // + if (m_OtherMemory != NULL) { + m_OtherMemory->RELEASE(this); + m_OtherMemory = NULL; + } + + // + // Release the other buffer and all __super related fields + // + __super::ReleaseAndRestore(Request); +} + +__inline +VOID +FxIoContext::ClearBuffer( + VOID + ) +{ + if (m_BufferToFree != NULL) { + FxPoolFree(m_BufferToFree); + m_BufferToFree = NULL; + } + + m_BufferToFreeLength = 0; + m_CopyBackToBuffer = FALSE; +} + +__inline +VOID +FxIoContext::CopyParameters( + __in FxRequestBase* Request + ) +{ + switch (m_MajorFunction) { + case IRP_MJ_WRITE: + m_CompletionParams.Parameters.Write.Length = + m_CompletionParams.IoStatus.Information; + break; + + case IRP_MJ_READ: + m_CompletionParams.Parameters.Read.Length = + m_CompletionParams.IoStatus.Information; + break; + + case IRP_MJ_DEVICE_CONTROL: + case IRP_MJ_INTERNAL_DEVICE_CONTROL: + m_CompletionParams.Parameters.Ioctl.Output.Length = + m_CompletionParams.IoStatus.Information; + break; + + default: + ASSERT(FALSE); + } + + if (m_BufferToFree == NULL) { + return; + } + + if (m_CopyBackToBuffer) { + FxIrp* irp = Request->GetSubmitFxIrp(); + + if (irp->GetUserBuffer() != NULL) { + // + // UserBuffer contains the caller's original output buffer. + // Copy the results back into the original buffer. + // + if (m_MajorFunction == IRP_MJ_DEVICE_CONTROL || + m_MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { + ASSERT(irp->GetInformation() <= m_BufferToFreeLength); + } + + RtlCopyMemory(irp->GetUserBuffer(), + m_BufferToFree, + irp->GetInformation()); + m_CopyBackToBuffer = FALSE; + } + } +} + +__inline +VOID +FxIoContext::CaptureState( + __in FxIrp* Irp + ) +{ + m_RestoreState = TRUE; + m_OriginalSystemBuffer = Irp->GetSystemBuffer(); + m_OriginalUserBuffer = Irp->GetUserBuffer(); + m_OriginalMdl = Irp->GetMdl(); + m_OriginalFlags = Irp->GetFlags(); +} + +__inline +VOID +FxIoContext::SetBufferAndLength( + __in PVOID Buffer, + __in size_t BufferLength, + __in BOOLEAN CopyBackToBuffer + ) +{ + PVOID pOldBuffer; + + pOldBuffer = m_BufferToFree; + m_BufferToFree = Buffer; + m_BufferToFreeLength = BufferLength; + m_CopyBackToBuffer = CopyBackToBuffer; + + if (pOldBuffer != NULL) { + FxPoolFree(pOldBuffer); + } +} + + +__inline +_Must_inspect_result_ +NTSTATUS +FxIoTarget::InitModeSpecific( + __in CfxDeviceBase* Device + ) +{ + UNREFERENCED_PARAMETER(Device); + + DO_NOTHING(); + + return STATUS_SUCCESS; +} + +__inline +BOOLEAN +FxIoTarget::HasValidStackSize( + VOID + ) +{ + return (m_TargetStackSize == 0 ? FALSE : TRUE); +} + +__inline +VOID +FxIoTarget::Send( + _In_ MdIrp Irp + ) +{ + // + // Ignore the return value because once we have sent the request, we + // want all processing to be done in the completion routine. + // + (void) IoCallDriver(m_TargetDevice, Irp); +} + +#endif // _FXIOTARGETKM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxiotargetremotekm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxiotargetremotekm.hpp new file mode 100644 index 00000000000..a8bdc0e714b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxiotargetremotekm.hpp @@ -0,0 +1,81 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxIoTargetRemoteKm.hpp + +Abstract: + + Kernel-mode specific definitions of FxIoTargetRemote + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#ifndef _FXIOTARGETREMOTEKM_H_ +#define _FXIOTARGETREMOTEKM_H_ + +__inline +NTSTATUS +FxIoTargetRemote::InitRemoteModeSpecific( + __in FxDeviceBase* Device + ) +{ + UNREFERENCED_PARAMETER(Device); + + // + // Nothing mode-specific work to do for KM here. + // + DO_NOTHING(); + + return STATUS_SUCCESS; +} + +__inline +VOID +FxIoTargetRemote::RemoveModeSpecific( + VOID + ) +{ + // + // Nothing mode-specific work to do for KM here. + // + DO_NOTHING(); +} + +__inline +_Must_inspect_result_ +NTSTATUS +FxIoTargetRemote::OpenLocalTargetByFile( + _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +{ + UNREFERENCED_PARAMETER(OpenParams); + + // + // Nothing mode-specific work to do for KM here. + // + DO_NOTHING(); + + return STATUS_SUCCESS; +} + +__inline +HANDLE +FxIoTargetRemote::GetTargetHandle( + VOID + ) +{ + return m_TargetHandle; +} + +#endif // _FXIOTARGETREMOTEKM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxirpkm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxirpkm.hpp new file mode 100644 index 00000000000..6cdbe8e451d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxirpkm.hpp @@ -0,0 +1,1347 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIrpKm.hpp + +Abstract: + + This module implements km definitions for FxIrp functions. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +// +// All the functions in this file should use __inline so that KMDF gets +// inlining. FxIrp.hpp does not use __inline on the functions because it +// doesn't work for UMDF (see comments in FxIrp.hpp). +// + +#ifndef _FXIRPKM_HPP_ +#define _FXIRPKM_HPP_ + +typedef PIRP MdIrp; + +typedef DRIVER_CANCEL MdCancelRoutineType, *MdCancelRoutine; +typedef IO_COMPLETION_ROUTINE MdCompletionRoutineType, *MdCompletionRoutine; +typedef REQUEST_POWER_COMPLETE MdRequestPowerCompleteType, *MdRequestPowerComplete; + +typedef +NTSTATUS +(*PFX_COMPLETION_ROUTINE)( + __in FxDevice *Device, + __in FxIrp *Irp, + __in PVOID Context + ); + +typedef +VOID +(*PFX_CANCEL_ROUTINE)( + __in FxDevice *Device, + __in FxIrp *Irp, + __in PVOID CancelContext + ); + +#include "FxIrp.hpp" + + + +__inline +MdIrp +FxIrp::GetIrp( + VOID + ) +{ + return m_Irp; +} + +__inline +VOID +FxIrp::CompleteRequest( + __in CCHAR PriorityBoost + ) +{ + IoCompleteRequest(m_Irp, PriorityBoost); + m_Irp = NULL; +} + +__inline +NTSTATUS +FxIrp::CallDriver( + __in MdDeviceObject DeviceObject + ) +{ + return IoCallDriver(DeviceObject, m_Irp); +} + +__inline +NTSTATUS +FxIrp::PoCallDriver( + __in MdDeviceObject DeviceObject + ) +{ + return ::PoCallDriver(DeviceObject, m_Irp); +} + +__inline +VOID +FxIrp::StartNextPowerIrp( + ) +{ + PoStartNextPowerIrp(m_Irp); +} + +__inline +MdCompletionRoutine +FxIrp::GetNextCompletionRoutine( + VOID + ) +{ + return this->GetNextIrpStackLocation()->CompletionRoutine; +} + + +__inline +VOID +FxIrp::SetCompletionRoutine( + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess, + __in BOOLEAN InvokeOnError, + __in BOOLEAN InvokeOnCancel + ) +{ + IoSetCompletionRoutine( + m_Irp, + CompletionRoutine, + Context, + InvokeOnSuccess, + InvokeOnError, + InvokeOnCancel + ); +} + +__inline +VOID +FxIrp::SetCompletionRoutineEx( + __in MdDeviceObject DeviceObject, + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context, + __in BOOLEAN InvokeOnSuccess, + __in BOOLEAN InvokeOnError, + __in BOOLEAN InvokeOnCancel + ) +{ + if (!NT_SUCCESS(IoSetCompletionRoutineEx( + DeviceObject, + m_Irp, + CompletionRoutine, + Context, + InvokeOnSuccess, + InvokeOnError, + InvokeOnCancel))) { + + IoSetCompletionRoutine( + m_Irp, + CompletionRoutine, + Context, + InvokeOnSuccess, + InvokeOnError, + InvokeOnCancel + ); + } +} + +__inline +MdCancelRoutine +FxIrp::SetCancelRoutine( + __in_opt MdCancelRoutine CancelRoutine + ) +{ + return IoSetCancelRoutine(m_Irp, CancelRoutine); +} + +__inline +NTSTATUS +FxIrp::_IrpSynchronousCompletion( + __in MdDeviceObject DeviceObject, + __in PIRP OriginalIrp, + __in PVOID Context + ) +{ + FxCREvent* event = (FxCREvent*) Context; + + UNREFERENCED_PARAMETER(DeviceObject); + + if (OriginalIrp->PendingReturned) { + // + // No need to propagate the pending returned bit since we are handling + // the request synchronously + // + event->Set(); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +__inline +NTSTATUS +FxIrp::SendIrpSynchronously( + __in MdDeviceObject DeviceObject + ) +{ + NTSTATUS status; + FxCREvent event; + + SetCompletionRoutine(_IrpSynchronousCompletion, + event.GetSelfPointer(), + TRUE, + TRUE, + TRUE); + + status = CallDriver(DeviceObject); + + if (status == STATUS_PENDING) { + event.EnterCRAndWaitAndLeave(); + status = m_Irp->IoStatus.Status; + } + + return status; +} + +__inline +VOID +FxIrp::CopyToNextIrpStackLocation( + __in PIO_STACK_LOCATION Stack + ) +{ + PIO_STACK_LOCATION nextIrpSp = IoGetNextIrpStackLocation(m_Irp); + + RtlCopyMemory(nextIrpSp, + Stack, + FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine) + ); + nextIrpSp->Control = 0; +} + + +__inline +VOID +FxIrp::CopyCurrentIrpStackLocationToNext( + VOID + ) +{ + IoCopyCurrentIrpStackLocationToNext(m_Irp); +} + +__inline +VOID +FxIrp::SetNextIrpStackLocation( + VOID + ) +{ + IoSetNextIrpStackLocation(m_Irp); +} + +__inline +UCHAR +FxIrp::GetMajorFunction( + VOID + ) +{ + return IoGetCurrentIrpStackLocation(m_Irp)->MajorFunction; +} + +__inline +UCHAR +FxIrp::GetMinorFunction( + VOID + ) +{ + return IoGetCurrentIrpStackLocation(m_Irp)->MinorFunction; +} + +__inline +UCHAR +FxIrp::GetCurrentStackFlags( + VOID + ) +{ + return IoGetCurrentIrpStackLocation(m_Irp)->Flags; +} + +__inline +MdFileObject +FxIrp::GetCurrentStackFileObject( + VOID + ) +{ + return IoGetCurrentIrpStackLocation(m_Irp)->FileObject; +} + +__inline +KPROCESSOR_MODE +FxIrp::GetRequestorMode( + VOID + ) +{ + return m_Irp->RequestorMode; +} + +__inline +VOID +FxIrp::SetContext( + __in ULONG Index, + __in PVOID Value + ) +{ + m_Irp->Tail.Overlay.DriverContext[Index] = Value; +} + +__inline +PVOID +FxIrp::GetContext( + __in ULONG Index + ) +{ + return m_Irp->Tail.Overlay.DriverContext[Index]; +} + +__inline +VOID +FxIrp::SetFlags( + __in ULONG Flags + ) +{ + m_Irp->Flags = Flags; +} + +__inline +ULONG +FxIrp::GetFlags( + VOID + ) +{ + return m_Irp->Flags; +} + +__inline +PIO_STACK_LOCATION +FxIrp::GetCurrentIrpStackLocation( + VOID + ) +{ + return IoGetCurrentIrpStackLocation(m_Irp); +} + +__inline +PIO_STACK_LOCATION +FxIrp::GetNextIrpStackLocation( + VOID + ) +{ + return IoGetNextIrpStackLocation(m_Irp); +} + +PIO_STACK_LOCATION +__inline +FxIrp::_GetAndClearNextStackLocation( + __in MdIrp Irp + ) +{ + RtlZeroMemory(IoGetNextIrpStackLocation(Irp), + FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); + return IoGetNextIrpStackLocation(Irp); +} + +__inline +VOID +FxIrp::SkipCurrentIrpStackLocation( + VOID + ) +{ + + + + + + + IoSkipCurrentIrpStackLocation(m_Irp); +} + +__inline +VOID +FxIrp::MarkIrpPending( + ) +{ + IoMarkIrpPending(m_Irp); +} + +__inline +BOOLEAN +FxIrp::PendingReturned( + ) +{ + return m_Irp->PendingReturned; +} + +__inline +VOID +FxIrp::PropagatePendingReturned( + VOID + ) +{ + if (PendingReturned() && m_Irp->CurrentLocation <= m_Irp->StackCount) { + MarkIrpPending(); + } +} + +__inline +VOID +FxIrp::SetStatus( + __in NTSTATUS Status + ) +{ + m_Irp->IoStatus.Status = Status; +} + +__inline +NTSTATUS +FxIrp::GetStatus( + ) +{ + return m_Irp->IoStatus.Status; +} + +__inline +BOOLEAN +FxIrp::Cancel( + VOID + ) +{ + return IoCancelIrp(m_Irp); +} + +__inline +VOID +FxIrp::SetCancel( + __in BOOLEAN Cancel + ) +{ + m_Irp->Cancel = Cancel; +} + +__inline +BOOLEAN +FxIrp::IsCanceled( + ) +{ + return m_Irp->Cancel ? TRUE : FALSE; +} + +__inline +KIRQL +FxIrp::GetCancelIrql( + ) +{ + return m_Irp->CancelIrql; +} + +__inline +VOID +FxIrp::SetInformation( + ULONG_PTR Information + ) +{ + m_Irp->IoStatus.Information = Information; +} + +__inline +ULONG_PTR +FxIrp::GetInformation( + ) +{ + return m_Irp->IoStatus.Information; +} + +__inline +CCHAR +FxIrp::GetCurrentIrpStackLocationIndex( + ) +{ + return m_Irp->CurrentLocation; +} + +__inline +CCHAR +FxIrp::GetStackCount( + ) +{ + return m_Irp->StackCount; +} + +__inline +PLIST_ENTRY +FxIrp::ListEntry( + ) +{ + return &m_Irp->Tail.Overlay.ListEntry; +} + +__inline +PVOID +FxIrp::GetSystemBuffer( + ) +{ + return m_Irp->AssociatedIrp.SystemBuffer; +} + +__inline +PVOID +FxIrp::GetOutputBuffer( + ) +{ + // + // In kernel mode, for buffered I/O, the output and input buffers are + // at same location. + // + return GetSystemBuffer(); +} + +__inline +VOID +FxIrp::SetSystemBuffer( + __in PVOID Value + ) +{ + m_Irp->AssociatedIrp.SystemBuffer = Value; +} + + +__inline +PMDL +FxIrp::GetMdl( + ) +{ + return m_Irp->MdlAddress; +} + +__inline +PMDL* +FxIrp::GetMdlAddressPointer( + ) +{ + return &m_Irp->MdlAddress; +} + +__inline +VOID +FxIrp::SetMdlAddress( + __in PMDL Value + ) +{ + m_Irp->MdlAddress = Value; +} + + +__inline +PVOID +FxIrp::GetUserBuffer( + ) +{ + return m_Irp->UserBuffer; +} + + +__inline +VOID +FxIrp::SetUserBuffer( + __in PVOID Value + ) +{ + m_Irp->UserBuffer = Value; +} + +__inline +VOID +FxIrp::Reuse( + __in NTSTATUS Status + ) +{ + IoReuseIrp(m_Irp, Status); +} + +__inline +VOID +FxIrp::SetMajorFunction( + __in UCHAR MajorFunction + ) +{ + this->GetNextIrpStackLocation()->MajorFunction = MajorFunction; +} + +__inline +VOID +FxIrp::SetMinorFunction( + __in UCHAR MinorFunction + ) +{ + this->GetNextIrpStackLocation()->MinorFunction = MinorFunction; +} + +__inline +SYSTEM_POWER_STATE_CONTEXT +FxIrp::GetParameterPowerSystemPowerStateContext( + ) +{ + return (this->GetCurrentIrpStackLocation())-> + Parameters.Power.SystemPowerStateContext; +} + +__inline +POWER_STATE_TYPE +FxIrp::GetParameterPowerType( + ) +{ + return (this->GetCurrentIrpStackLocation())->Parameters.Power.Type; +} + +__inline +POWER_STATE +FxIrp::GetParameterPowerState( + ) +{ + return (this->GetCurrentIrpStackLocation())->Parameters.Power.State; +} + +__inline +DEVICE_POWER_STATE +FxIrp::GetParameterPowerStateDeviceState( + ) +{ + return (this->GetCurrentIrpStackLocation())-> + Parameters.Power.State.DeviceState; +} + +__inline +SYSTEM_POWER_STATE +FxIrp::GetParameterPowerStateSystemState( + ) +{ + return (this->GetCurrentIrpStackLocation())-> + Parameters.Power.State.SystemState; +} + +__inline +POWER_ACTION +FxIrp::GetParameterPowerShutdownType( + ) +{ + return (this->GetCurrentIrpStackLocation())-> + Parameters.Power.ShutdownType; +} + +__inline +DEVICE_RELATION_TYPE +FxIrp::GetParameterQDRType( + ) +{ + return (this->GetCurrentIrpStackLocation())-> + Parameters.QueryDeviceRelations.Type; +} + +__inline +VOID +FxIrp::SetParameterQDRType( + DEVICE_RELATION_TYPE DeviceRelation + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.QueryDeviceRelations.Type = DeviceRelation; +} + +__inline +PDEVICE_CAPABILITIES +FxIrp::GetParameterDeviceCapabilities( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.DeviceCapabilities.Capabilities; +} + +__inline +MdDeviceObject +FxIrp::GetDeviceObject( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()->DeviceObject; +} + +__inline +VOID +FxIrp::SetCurrentDeviceObject( + __in MdDeviceObject DeviceObject + ) +{ + this->GetCurrentIrpStackLocation()->DeviceObject = DeviceObject; +} + +__inline +VOID +FxIrp::SetParameterDeviceCapabilities( + __in PDEVICE_CAPABILITIES DeviceCapabilities + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities; +} + +__inline +LONGLONG +FxIrp::GetParameterWriteByteOffsetQuadPart( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.Write.ByteOffset.QuadPart; +} + +__inline +VOID +FxIrp::SetNextParameterWriteByteOffsetQuadPart( + __in LONGLONG DeviceOffset + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.Write.ByteOffset.QuadPart = DeviceOffset; +} + +__inline +VOID +FxIrp::SetNextParameterWriteLength( + __in ULONG IoLength + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.Write.Length = IoLength; +} + +__inline +PVOID* +FxIrp::GetNextStackParameterOthersArgument1Pointer( + ) +{ + PIO_STACK_LOCATION nextStack; + + nextStack = this->GetNextIrpStackLocation(); + + return &nextStack->Parameters.Others.Argument1; +} + +__inline +VOID +FxIrp::SetNextStackParameterOthersArgument1( + __in PVOID Argument1 + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.Others.Argument1 = Argument1; +} + +__inline +PVOID* +FxIrp::GetNextStackParameterOthersArgument2Pointer( + ) +{ + PIO_STACK_LOCATION nextStack; + + nextStack = this->GetNextIrpStackLocation(); + + return &nextStack->Parameters.Others.Argument2; +} + +__inline +PVOID* +FxIrp::GetNextStackParameterOthersArgument4Pointer( + ) +{ + PIO_STACK_LOCATION nextStack; + + nextStack = this->GetNextIrpStackLocation(); + + return &nextStack->Parameters.Others.Argument4; +} + +__inline +PCM_RESOURCE_LIST +FxIrp::GetParameterAllocatedResources( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.StartDevice.AllocatedResources; +} + +__inline +VOID +FxIrp::SetParameterAllocatedResources( + __in PCM_RESOURCE_LIST AllocatedResources + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.StartDevice.AllocatedResources = AllocatedResources; +} + +__inline +PCM_RESOURCE_LIST +FxIrp::GetParameterAllocatedResourcesTranslated( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.StartDevice.AllocatedResourcesTranslated; +} + +__inline +VOID +FxIrp::SetParameterAllocatedResourcesTranslated( + __in PCM_RESOURCE_LIST AllocatedResourcesTranslated + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.StartDevice.AllocatedResourcesTranslated = + AllocatedResourcesTranslated; +} + +__inline +LCID +FxIrp::GetParameterQueryDeviceTextLocaleId( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.QueryDeviceText.LocaleId; +} + +__inline +DEVICE_TEXT_TYPE +FxIrp::GetParameterQueryDeviceTextType( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.QueryDeviceText.DeviceTextType; +} + +__inline +BOOLEAN +FxIrp::GetParameterSetLockLock( + ) +{ + return this->GetCurrentIrpStackLocation()->Parameters.SetLock.Lock; +} + +__inline +BUS_QUERY_ID_TYPE +FxIrp::GetParameterQueryIdType( + ) +{ + return this->GetCurrentIrpStackLocation()->Parameters.QueryId.IdType; +} + +__inline +PINTERFACE +FxIrp::GetParameterQueryInterfaceInterface( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.QueryInterface.Interface; +} + +__inline +const GUID* +FxIrp::GetParameterQueryInterfaceType( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.QueryInterface.InterfaceType; +} + +__inline +MdFileObject +FxIrp::GetFileObject( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()->FileObject; +} + +__inline +USHORT +FxIrp::GetParameterQueryInterfaceVersion( + ) +{ + return this->GetCurrentIrpStackLocation()->Parameters.QueryInterface.Version; +} + +__inline +USHORT +FxIrp::GetParameterQueryInterfaceSize( + ) +{ + return this->GetCurrentIrpStackLocation()->Parameters.QueryInterface.Size; +} + +__inline +PVOID +FxIrp::GetParameterQueryInterfaceInterfaceSpecificData( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.QueryInterface.InterfaceSpecificData; +} + +__inline +DEVICE_USAGE_NOTIFICATION_TYPE +FxIrp::GetParameterUsageNotificationType( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.UsageNotification.Type; +} + +__inline +BOOLEAN +FxIrp::GetParameterUsageNotificationInPath( + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.UsageNotification.InPath; +} + +__inline +VOID +FxIrp::SetParameterUsageNotificationInPath( + __in BOOLEAN InPath + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.UsageNotification.InPath = InPath; +} + +__inline +BOOLEAN +FxIrp::GetNextStackParameterUsageNotificationInPath( + ) +{ + return this->GetNextIrpStackLocation()-> + Parameters.UsageNotification.InPath; +} + + + +__inline +ULONG +FxIrp::GetParameterIoctlCode( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.DeviceIoControl.IoControlCode; +} + +__inline +ULONG +FxIrp::GetParameterIoctlCodeBufferMethod( + VOID + ) +{ + return METHOD_FROM_CTL_CODE(GetParameterIoctlCode()); +} + +__inline +ULONG +FxIrp::GetParameterIoctlOutputBufferLength( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.DeviceIoControl.OutputBufferLength; +} + +__inline +ULONG +FxIrp::GetParameterIoctlInputBufferLength( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.DeviceIoControl.InputBufferLength; +} + +__inline +VOID +FxIrp::SetParameterIoctlCode( + __in ULONG DeviceIoControlCode + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.DeviceIoControl.IoControlCode = DeviceIoControlCode; +} + +__inline +VOID +FxIrp::SetParameterIoctlInputBufferLength( + __in ULONG InputBufferLength + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; +} + +__inline +VOID +FxIrp::SetParameterIoctlOutputBufferLength( + __in ULONG OutputBufferLength + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; +} + +__inline +VOID +FxIrp::SetParameterIoctlType3InputBuffer( + __in PVOID Type3InputBuffer + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.DeviceIoControl.Type3InputBuffer = Type3InputBuffer; +} + +__inline +PVOID +FxIrp::GetParameterIoctlType3InputBuffer( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()-> + Parameters.DeviceIoControl.Type3InputBuffer; +} + +__inline +VOID +FxIrp::SetParameterQueryInterfaceInterface( + __in PINTERFACE Interface + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.QueryInterface.Interface = Interface; +} + +__inline +VOID +FxIrp::SetParameterQueryInterfaceType( + __in const GUID* InterfaceType + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.QueryInterface.InterfaceType = InterfaceType; +} + +__inline +VOID +FxIrp::SetParameterQueryInterfaceVersion( + __in USHORT Version + ) +{ + this->GetNextIrpStackLocation()->Parameters.QueryInterface.Version = Version; +} + +__inline +VOID +FxIrp::SetParameterQueryInterfaceSize( + __in USHORT Size + ) +{ + this->GetNextIrpStackLocation()->Parameters.QueryInterface.Size = Size; +} + +__inline +VOID +FxIrp::SetParameterQueryInterfaceInterfaceSpecificData( + __in PVOID InterfaceSpecificData + ) +{ + this->GetNextIrpStackLocation()-> + Parameters.QueryInterface.InterfaceSpecificData = InterfaceSpecificData; +} + +__inline +VOID +FxIrp::SetNextStackFlags( + __in UCHAR Flags + ) +{ + this->GetNextIrpStackLocation()->Flags = Flags; +} + +__inline +VOID +FxIrp::SetNextStackFileObject( + _In_ MdFileObject FileObject + ) +{ + this->GetNextIrpStackLocation()->FileObject = FileObject; +} + + +__inline +VOID +FxIrp::ClearNextStack( + VOID + ) +{ + PIO_STACK_LOCATION stack; + + stack = this->GetNextIrpStackLocation(); + RtlZeroMemory(stack, sizeof(IO_STACK_LOCATION)); +} + + + + +__inline +VOID +FxIrp::ClearNextStackLocation( + VOID + ) +{ + RtlZeroMemory(this->GetNextIrpStackLocation(), + FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); +} + +__inline +VOID +FxIrp::InitNextStackUsingStack( + __in FxIrp* Irp + ) +{ + PIO_STACK_LOCATION srcStack, destStack; + + srcStack = Irp->GetCurrentIrpStackLocation(); + destStack = this->GetNextIrpStackLocation(); + + *destStack = *srcStack; +} + +_Must_inspect_result_ +__inline +MdIrp +FxIrp::AllocateIrp( + _In_ CCHAR StackSize, + _In_opt_ FxDevice* Device + ) +{ + UNREFERENCED_PARAMETER(Device); + + return IoAllocateIrp(StackSize, FALSE); +} + +__inline +MdIrp +FxIrp::GetIrpFromListEntry( + __in PLIST_ENTRY Ple + ) +{ + return CONTAINING_RECORD(Ple, IRP, Tail.Overlay.ListEntry); +} + +__inline +ULONG +FxIrp::GetParameterReadLength( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()->Parameters.Read.Length; +} + +__inline +ULONG +FxIrp::GetParameterWriteLength( + VOID + ) +{ + return this->GetCurrentIrpStackLocation()->Parameters.Write.Length; +} + +_Must_inspect_result_ +__inline +NTSTATUS +FxIrp::RequestPowerIrp( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in MdRequestPowerComplete CompletionFunction, + __in PVOID Context + ) +{ + // + // Prefast enforces that NULL is passed for IRP parameter (last parameter) + // since the IRP might complete before the function returns. + // + return PoRequestPowerIrp( + DeviceObject, + MinorFunction, + PowerState, + CompletionFunction, + Context, + NULL); +} + +__inline +ULONG +FxIrp::GetCurrentFlags( + VOID + ) +{ + return (this->GetCurrentIrpStackLocation())->Flags; +} + +__inline +PVOID +FxIrp::GetCurrentParametersPointer( + VOID + ) +{ + return &(this->GetCurrentIrpStackLocation())->Parameters; +} + +__inline +MdEThread +FxIrp::GetThread( + VOID + ) +{ + return m_Irp->Tail.Overlay.Thread; +} + +__inline +BOOLEAN +FxIrp::Is32bitProcess( + VOID + ) +{ + +#if defined(_WIN64) + +#if BUILD_WOW64_ENABLED + + return IoIs32bitProcess(m_Irp); + +#else // BUILD_WOW64_ENABLED + + return FALSE; + +#endif // BUILD_WOW64_ENABLED + +#else // defined(_WIN64) + + return TRUE; + +#endif // defined(_WIN64) + +} + +__inline +VOID +FxIrp::FreeIrp( + VOID + ) +{ + IoFreeIrp(m_Irp); +} + +__inline +PIO_STATUS_BLOCK +FxIrp::GetStatusBlock( + VOID + ) +{ + return &m_Irp->IoStatus; +} + +__inline +PVOID +FxIrp::GetDriverContext( + VOID + ) +{ + return m_Irp->Tail.Overlay.DriverContext; +} + +__inline +ULONG +FxIrp::GetDriverContextSize( + VOID + ) +{ + return sizeof(m_Irp->Tail.Overlay.DriverContext); +} + +__inline +VOID +FxIrp::CopyParameters( + _Out_ PWDF_REQUEST_PARAMETERS Parameters + ) +{ + RtlMoveMemory(&Parameters->Parameters, + GetCurrentParametersPointer(), + sizeof(Parameters->Parameters)); +} + +__inline +VOID +FxIrp::CopyStatus( + _Out_ PIO_STATUS_BLOCK StatusBlock + ) +{ + RtlCopyMemory(StatusBlock, + GetStatusBlock(), + sizeof(*StatusBlock)); +} + +__inline +BOOLEAN +FxIrp::HasStack( + _In_ UCHAR StackCount + ) +{ + return (GetCurrentIrpStackLocationIndex() >= StackCount); +} + +__inline +BOOLEAN +FxIrp::IsCurrentIrpStackLocationValid( + VOID + ) +{ + return (GetCurrentIrpStackLocationIndex() <= GetStackCount()); +} + +__inline +FxAutoIrp::~FxAutoIrp() +{ + if (m_Irp != NULL) { + IoFreeIrp(m_Irp); + } +} + +#endif // _FXIRPKM_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxperftracekm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxperftracekm.hpp new file mode 100644 index 00000000000..5d495d3ca48 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxperftracekm.hpp @@ -0,0 +1,117 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPerfTrace.hpp + +Abstract: + + This is header file for perf trace methods. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +Notes: + +--*/ + +#pragma once + +// +// Version starts from 2 to be in sync with ETW versioning +// +#define WDF_DPC_EVENT_VERSION_2 2 +#define WDF_INTERRUPT_EVENT_VERSION_2 2 +#define WDF_WORK_ITEM_EVENT_VERSION_2 2 + +FORCEINLINE +VOID +FxPerfTraceDpc( + _In_ PVOID DriverCallback + ) +{ + PWMI_WDF_NOTIFY_ROUTINE perfTraceCallback = NULL; + + // + // Trace driver's ISR using perf trace callback. If the perf trace callback + // is NULL, it means either perf tracing is not enabled, or this OS + // doesn't support perf tracing for WDF (note only win8+ supports WDF perf + // trace callbacks). + // + perfTraceCallback = FxLibraryGlobals.PerfTraceRoutines->DpcNotifyRoutine; + if (perfTraceCallback != NULL) { + (perfTraceCallback) (DriverCallback, // event data + sizeof(PVOID), // sizeof event + PERF_WDF_DPC, // group mask + PERFINFO_LOG_TYPE_WDF_DPC, // hook id + WDF_DPC_EVENT_VERSION_2 // version + ); + } +} + +FORCEINLINE +VOID +FxPerfTraceInterrupt( + _In_ PVOID DriverCallback + ) +{ + PWMI_WDF_NOTIFY_ROUTINE perfTraceCallback = NULL; + + perfTraceCallback = FxLibraryGlobals.PerfTraceRoutines->InterruptNotifyRoutine; + if (perfTraceCallback != NULL) { + (perfTraceCallback) (DriverCallback, // event data + sizeof(PVOID), // sizeof event + PERF_WDF_INTERRUPT, // group mask + PERFINFO_LOG_TYPE_WDF_INTERRUPT, // hook id + WDF_INTERRUPT_EVENT_VERSION_2 // version + ); + } +} + +FORCEINLINE +VOID +FxPerfTracePassiveInterrupt( + _In_ PVOID DriverCallback + ) +{ + PWMI_WDF_NOTIFY_ROUTINE perfTraceCallback = NULL; + + perfTraceCallback = FxLibraryGlobals.PerfTraceRoutines->InterruptNotifyRoutine; + if (perfTraceCallback != NULL) { + (perfTraceCallback) (DriverCallback, + sizeof(PVOID), + PERF_WDF_INTERRUPT, + PERFINFO_LOG_TYPE_WDF_PASSIVE_INTERRUPT, + WDF_INTERRUPT_EVENT_VERSION_2 + ); + } +} + +FORCEINLINE +VOID +FxPerfTraceWorkItem( + _In_ PVOID DriverCallback + ) +{ + PWMI_WDF_NOTIFY_ROUTINE perfTraceCallback = NULL; + + perfTraceCallback = FxLibraryGlobals.PerfTraceRoutines->WorkItemNotifyRoutine; + if (perfTraceCallback != NULL) { + (perfTraceCallback) (DriverCallback, + sizeof(PVOID), + PERF_WORKER_THREAD, + PERFINFO_LOG_TYPE_WDF_WORK_ITEM, + WDF_WORK_ITEM_EVENT_VERSION_2 + ); + } +} + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxrequestbasekm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxrequestbasekm.hpp new file mode 100644 index 00000000000..4e6eeb3b46d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxrequestbasekm.hpp @@ -0,0 +1,68 @@ +/*++ + + Copyright (c) Microsoft Corporation + + Module Name: + + FxRequestBaseKm.hpp + + Abstract: + + This module implements km specific functions for FxRequestBase. + + Author: + + + + Environment: + + Kernel mode only + + Revision History: + + --*/ + +#ifndef _FXREQUESTBASEKM_HPP_ +#define _FXREQUESTBASEKM_HPP_ + + +VOID +__inline +FxRequestBase::FreeMdls( + VOID + ) +{ + PMDL pMdl, pNext; + + if (IsAllocatedFromIo() || IsCanComplete()) { + return; + } + + pMdl = m_Irp.GetIrp()->MdlAddress; + + // + // Free any PMDLs that the lower layer allocated. Since we are going + // to free the PIRP ourself and not call IoCompleteRequest, we must mimic + // the behavior in IoCompleteRequest which does the same thing. + // + while (pMdl != NULL) { + pNext = pMdl->Next; + + if (pMdl->MdlFlags & MDL_PAGES_LOCKED) { + MmUnlockPages(pMdl); + } + else if (GetDriverGlobals()->FxVerifierOn) { + DbgPrint("pMdl %p, Flags 0x%x in PIRP %p should be locked", + pMdl, pMdl->MdlFlags, m_Irp.GetIrp()); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + FxIrpMdlFree(pMdl); + pMdl = pNext; + } + + m_Irp.GetIrp()->MdlAddress = NULL; +} + +#endif // _FXREQUESTBASEKM_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxrequestbufferkm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxrequestbufferkm.hpp new file mode 100644 index 00000000000..66759959c32 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxrequestbufferkm.hpp @@ -0,0 +1,111 @@ +/*++ + + Copyright (c) Microsoft Corporation + + Module Name: + + FxRequestBufferKm.hpp + + Abstract: + + This module implements km specific functions for FxRequestBuffer. + + Author: + + + + Environment: + + Kernel mode only + + Revision History: + + --*/ + +#ifndef _FXREQUESTBUFFERKM_HPP_ +#define _FXREQUESTBUFFERKM_HPP_ + +__inline +VOID +FxRequestBuffer::SetMdl( + __in PMDL Mdl, + __in ULONG Length + ) +{ + DataType = FxRequestBufferMdl; + u.Mdl.Mdl = Mdl; + u.Mdl.Length = Length; +} + +FORCEINLINE +NTSTATUS +FxRequestBuffer::GetOrAllocateMdlWorker( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __deref_out PMDL* Mdl, + __in BOOLEAN * ReuseMdl, + __in LONG Length, + __in PVOID Buffer, + __inout size_t* SizeOfMdl, + __in BOOLEAN UnlockWhenFreed, + __deref_out_opt PMDL* MdlToFree + ) +{ + size_t sizeofCurrentMdl; + sizeofCurrentMdl = MmSizeOfMdl(Buffer, Length); + + // + // Caller of this function (GetOrAllocateMdl) verifies that pages + // are already unlocked. Asserting here, in case we start using this + // function elsewhere. + // + // This is why we don't unlock pages either in reuse or non-reuse case. + // + ASSERT(UnlockWhenFreed == FALSE); + UNREFERENCED_PARAMETER(UnlockWhenFreed); //for fre build + + // + // If ReuseMdl is TRUE then the Mdl to be reused is passed in. + // + if (*ReuseMdl && sizeofCurrentMdl <= *SizeOfMdl) { + MmPrepareMdlForReuse(*MdlToFree); + *Mdl = *MdlToFree; + } + else { + *ReuseMdl = FALSE; + + // + // Since *Mdl may have the original IRP Mdl + // free *MdlToFree and not *Mdl + // + if (*MdlToFree != NULL) { + FxMdlFree(FxDriverGlobals, *MdlToFree); + *MdlToFree = NULL; + if (SizeOfMdl != NULL) { + *SizeOfMdl = 0; + } + } + + *Mdl = FxMdlAllocate(FxDriverGlobals, + NULL, // owning FxObject + Buffer, + Length, + FALSE, + FALSE); + + if (*Mdl == NULL) { + + ASSERT(SizeOfMdl ? (*SizeOfMdl == 0) : TRUE); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (SizeOfMdl != NULL) { + *SizeOfMdl = sizeofCurrentMdl; + } + } + + return STATUS_SUCCESS; +} + + +#endif // _FXREQUESTBUFFERKM_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxtelemetrykm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxtelemetrykm.hpp new file mode 100644 index 00000000000..972020a211a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxtelemetrykm.hpp @@ -0,0 +1,196 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetryKm.hpp + +Abstract: + + This is header file for telemetry methods. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +Notes: + +--*/ + +#pragma once + +#include "fxldr.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +// +// Event name: KmdfCensusEvtDeviceStart +// +// Source: KMDF only +// +// Description: Written when a FDO completes start successfully. +// +// Frequency: If FX_TELEMETRY_ENABLED, once per driver session. This is tracked using the +// DoOnceFlag in the telemetry context. Also not to exceed +// once in 24 hours (last write time stored in registry). +// +// +#define KMDF_CENSUS_EVT_WRITE_DEVICE_START(TraceHandle , Globals, DriverConfig, SetupClass, BusEnum, HwID, Manafacturer) \ + TraceLoggingWrite(TraceHandle, \ + "KmdfCensusEvtDeviceStart", \ + WDF_TELEMETRY_EVT_KEYWORDS, \ + WDF_CENSUS_EVT_DATA_COMMON(Globals), \ + TraceLoggingString((Globals)->Public.DriverName, "DriverServiceName"), \ + TraceLoggingKmdfDriverConfigInfo(DriverConfig, "DriverConfigInfo"), \ + TraceLoggingWideString(SetupClass.m_UnicodeString.Buffer, "SetupClass"), \ + TraceLoggingWideString(BusEnum.m_UnicodeString.Buffer, "BusEnumerator"), \ + TraceLoggingWideString(HwID.m_UnicodeString.Buffer, "HardwareId"), \ + TraceLoggingWideString(Manafacturer.m_UnicodeString.Buffer, "ManufacturerString") \ + ); + +// +// This is part of the data for KmdfCensusEvtDeviceStart event. +// +#define TraceLoggingKmdfDriverConfigInfo(info, fieldName) \ + \ + TraceLoggingStruct(23, fieldName), \ + \ + TraceLoggingUInt8(info.bitmap.IsNonPnpDriver, "IsNonPnpDriver" ), \ + TraceLoggingUInt8(info.bitmap.IsNoDispatchOverride, "IsNoDispatchOverride" ), \ + TraceLoggingUInt8(info.bitmap.IsVerifierOn, "IsVerifierOn" ), \ + TraceLoggingUInt8(info.bitmap.IsEnhancedVerifierOn, "IsEnhancedVerifierOn" ), \ + TraceLoggingUInt8(info.bitmap.IsFilter, "IsFilter" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsUsingRemoveLockOption, "IsUsingRemoveLockOption" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingNonDefaultHardwareReleaseOrder, "IsUsingNonDefaultHardwareReleaseOrder" ), \ + TraceLoggingUInt8(info.bitmap.IsPowerPolicyOwner, "IsPowerPolicyOwner" ), \ + TraceLoggingUInt8(info.bitmap.IsS0IdleWakeFromS0Enabled, "IsS0IdleWakeFromS0Enabled" ), \ + TraceLoggingUInt8(info.bitmap.IsS0IdleUsbSSEnabled, "IsS0IdleUsbSSEnabled" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsS0IdleSystemManaged, "IsS0IdleSystemManaged" ), \ + TraceLoggingUInt8(info.bitmap.IsSxWakeEnabled, "IsSxWakeEnabled" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingLevelTriggeredLineInterrupt, "IsUsingLevelTriggeredLineInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingEdgeTriggeredLineInterrupt, "IsUsingEdgeTriggeredLineInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingMsiXOrSingleMsi22Interrupt, "IsUsingMsiXOrSingleMsi22Interrupt" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsUsingMsi22MultiMessageInterrupt, "IsUsingMsi22MultiMessageInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingMultipleInterrupt, "IsUsingMultipleInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingPassiveLevelInterrupt, "IsUsingPassiveLevelInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingBusMasterDma, "IsUsingBusMasterDma" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingSystemDma, "IsUsingSystemDma" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsUsingSystemDmaDuplex, "IsUsingSystemDmaDuplex" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingStaticBusEnumration, "IsUsingStaticBusEnumration" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingDynamicBusEnumeration, "IsUsingDynamicBusEnumeration" ) \ + +// +// When changing the structure, do update TraceLoggingKmdfDriverConfigInfo +// for fields name and TraceLoggingStruct(count) as well. It is good to keep +// fields order the same but it is not required. +// +union FxTelemetryDriverInfo { + struct { + DWORD IsNonPnpDriver : 1; + DWORD IsNoDispatchOverride : 1; + DWORD IsVerifierOn : 1; + DWORD IsEnhancedVerifierOn : 1; + DWORD IsFilter : 1; + DWORD IsUsingRemoveLockOption : 1; + DWORD IsUsingNonDefaultHardwareReleaseOrder : 1; + DWORD IsPowerPolicyOwner : 1; + DWORD IsS0IdleWakeFromS0Enabled : 1; + DWORD IsS0IdleUsbSSEnabled : 1; + DWORD IsS0IdleSystemManaged : 1; + DWORD IsSxWakeEnabled : 1; + DWORD IsUsingLevelTriggeredLineInterrupt : 1; + DWORD IsUsingEdgeTriggeredLineInterrupt : 1; + DWORD IsUsingMsiXOrSingleMsi22Interrupt : 1; + DWORD IsUsingMsi22MultiMessageInterrupt : 1; + DWORD IsUsingMultipleInterrupt : 1; + DWORD IsUsingPassiveLevelInterrupt : 1; + DWORD IsUsingBusMasterDma : 1; + DWORD IsUsingSystemDma : 1; + DWORD IsUsingSystemDmaDuplex : 1; + DWORD IsUsingStaticBusEnumration : 1; + DWORD IsUsingDynamicBusEnumeration : 1; + } bitmap; + DWORD Dword; +}; + + +VOID +RegistryWriteCurrentTime( + _In_ PFX_DRIVER_GLOBALS DriverGlobals + ); + +VOID +RegistryReadLastLoggedTime( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _Out_ PLARGE_INTEGER CurrentTime + ); + +NTSTATUS +GetHardwareIdAndSetupclassFromRegistry( + _In_ FxDevice* Fdo, + _Out_ PUNICODE_STRING HwIds, + _Out_ PUNICODE_STRING SetupClass + ); + +BOOLEAN +IsLoggingEnabledAndNeeded( + _In_ PFX_DRIVER_GLOBALS DriverGlobals + ); + +_Must_inspect_result_ +NTSTATUS +FxQueryData( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_ HANDLE Key, + _In_ PCUNICODE_STRING ValueName, + _In_ ULONG Tag, + _Out_ PKEY_VALUE_PARTIAL_INFORMATION* Info + ); + +VOID +GetDriverInfo( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ FxDevice* Fdo, + _Out_ FxTelemetryDriverInfo* DriverInfo + ); + +VOID +FxGetDevicePropertyString( + _In_ FxDevice* Fdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _Out_ PUNICODE_STRING PropertyString + ); + +VOID +GetFirstHardwareId( + _Inout_ PUNICODE_STRING HardwareIds + ); + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +QueryAndAllocString( + _In_ HANDLE Key, + _In_ PFX_DRIVER_GLOBALS Globals, + _In_ PCUNICODE_STRING ValueName, + _Out_ PKEY_VALUE_PARTIAL_INFORMATION* Info + ); + + +#if defined(__cplusplus) +} +#endif + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxtypedefskm.hpp b/sdk/lib/drivers/wdf/shared/inc/private/km/fxtypedefskm.hpp new file mode 100644 index 00000000000..38c51debb15 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxtypedefskm.hpp @@ -0,0 +1,56 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxtypedefsKm.hpp + +Abstract: + + KMDF side defines for common names for the types + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#pragma once + +typedef FxDevice CfxDevice; +typedef FxDeviceBase CfxDeviceBase; +//typedef FxDeviceInterface CfxDeviceInterface; + +typedef PIRP MdIrp; + +typedef DRIVER_CANCEL MdCancelRoutineType, *MdCancelRoutine; +typedef IO_COMPLETION_ROUTINE MdCompletionRoutineType, *MdCompletionRoutine; +typedef REQUEST_POWER_COMPLETE MdRequestPowerCompleteType, *MdRequestPowerComplete; + +typedef +NTSTATUS +(*PFX_COMPLETION_ROUTINE)( + __in FxDevice *Device, + __in FxIrp *Irp, + __in PVOID Context + ); + +typedef +VOID +(*PFX_CANCEL_ROUTINE)( + __in FxDevice *Device, + __in FxIrp *Irp, + __in PVOID CancelContext + ); + +// +// CSQ abstraction +// +typedef IO_CSQ_IRP_CONTEXT MdIoCsqIrpContext,*PMdIoCsqIrpContext; diff --git a/sdk/lib/drivers/wdf/shared/inc/private/km/fxverifierkm.h b/sdk/lib/drivers/wdf/shared/inc/private/km/fxverifierkm.h new file mode 100644 index 00000000000..93539bcfd13 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/km/fxverifierkm.h @@ -0,0 +1,72 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxVerifierKm.cpp + +Abstract: + + Verifier code specific to KMDF + +Environment: + + kernel mode + +Revision History: + + + +--*/ + +#ifndef _FXVERIFIERKM_H_ +#define _FXVERIFIERKM_H_ + +FORCEINLINE +VOID +FxVerifierCheckNxPoolType( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ POOL_TYPE PoolType, + _In_ ULONG PoolTag + ) + +/*++ + +Routine Description: + + This function performs the "no execute" pool type check for KMDF + client drivers. + + N.B. It is important to keep this function inlined to make sure + _ReturnAddress() produces the correct calling function. + +Arguments: + + FxDriverGlobals - Supplies a pointer to the WDF driver object + globals. + + PoolType - Supplies the pool type. + + PoolTag - Supplies an optional pool tag. + +Return Value: + + None. + +--*/ + +{ + if (FxDriverGlobals->FxVerifierOn && + FxLibraryGlobals.VfCheckNxPoolType != NULL) { + + // + // Forward the call to Driver Verifier. This will provide a consistent + // behavior across all verified drivers. + // + + FxLibraryGlobals.VfCheckNxPoolType(PoolType, _ReturnAddress(), PoolTag); + } +} + +#endif // _FXVERIFIERKM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/device_common.h b/sdk/lib/drivers/wdf/shared/inc/private/um/device_common.h new file mode 100644 index 00000000000..7dd0d8d6018 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/device_common.h @@ -0,0 +1,46 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + device_common.h + +Abstract: + + This file contains common types for device objects that are used in + all three components (Wudfx, Wudfhost, WudfRd). + +Author: + + + +Revision History: + + + +--*/ + +#pragma once + +typedef struct _STACK_DEVICE_CAPABILITIES { + // + // The capabilities as garnered from IRP_MN_QUERY_CAPABILITIES. + // + DEVICE_CAPABILITIES DeviceCaps; + + // + // The lowest-power D-state that a device can be in and still generate + // a wake signal, indexed by system state. (PowerSystemUnspecified is + // an unused slot in this array.) + // + DEVICE_WAKE_DEPTH DeepestWakeableDstate[PowerSystemHibernate+1]; +} STACK_DEVICE_CAPABILITIES, *PSTACK_DEVICE_CAPABILITIES; + +#define ERROR_STRING_HW_ACCESS_NOT_ALLOWED \ + "Hardware access not allowed. Set the INF directive " \ + "UmdfDirectHardwareAccess to AllowDirectHardwareAccess " \ + "in driver's INF file to enable direct hardware access" + +#define WUDF_POWER_POLICY_SETTINGS L"WudfPowerPolicySettings" + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxdeviceum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxdeviceum.hpp new file mode 100644 index 00000000000..88cc1bc82a5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxdeviceum.hpp @@ -0,0 +1,460 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceUM.hpp + +Abstract: + + This is the definition of the FxDevice object UM specific + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#ifndef _FXDEVICEUM_H_ +#define _FXDEVICEUM_H_ + +#define WDF_PATH_SEPARATOR L"\\" +#define WUDF_SUB_KEY L"WUDF" +#define WUDF_ADDITIONAL_SUB_KEY L"WDF" + +#define FX_DIRECT_HARDWARE_ACCESS L"DirectHardwareAccess" +#define FX_DIRECT_HARDWARE_ACCESS_DEFAULT (WdfRejectDirectHardwareAccess) + +#define FX_REGISTER_ACCESS_MODE L"RegisterAccessMode" +#define FX_REGISTER_ACCESS_MODE_DEFAULT (WdfRegisterAccessUsingSystemCall) + +#define FX_FILE_OBJECT_POLICY L"FileObjectPolicy" +#define FX_FILE_OBJECT_POLICY_DEFAULT (WdfRejectNullAndUnknownFileObjects) + +#define FX_FS_CONTEXT_USE_POLICY L"FsContextUsePolicy" +#define FX_FS_CONTEXT_USE_POLICY_DEFAULT (WdfDefaultFsContextUsePolicy) + +#define FX_KERNEL_MODE_CLIENT_POLICY L"KernelModeClientPolicy" +#define FX_METHOD_NEITHER_ACTION L"MethodNeitherAction" +#define FX_PROCESS_SHARING_ENABLED L"HostProcessSharingEnabled" +#define FX_DEVICE_GROUP_ID L"DeviceGroupId" +#define FX_FILE_OBJECT_POLICY L"FileObjectPolicy" + +// +// READ/WRITE_REGISTER_Xxx macros need compiler and memory barrier. Each +// platform has a different set of compiler intrinsics to support that. +// In kernel, x86 READ/WRITE macros are implemented in assembly and use +// lock prefix to force real access. For amd64, _ReadWriteBarrier +// (compiler barrier) is used for reads and __faststorefence (CPU barrier) for +// writes. For ARM, _ReadWriteBarrier (compiler barrier) is used for reads and +// both _ReadWriteBarrier and __emit(Value) for writes. +// +// Because of this variation, UMDF will use the macros directly from wdm.h +// by autogenerating those macros from wdm.h into a private UMDF header. +// For x86, there are no macros so either UMDF could directly link to the +// ntosrtl.lib (that has these macros implemented in assembly), or implement +// its own macros that use MemoryBarrier() macro from winnt.h. +// +// Below is UMDF's implementation for x86. The macros for other platforms are +// in WudfWdm_private.h. +// +#if defined(_X86_) + +#define READ_REGISTER_UCHAR(x) \ + (MemoryBarrier(), *(volatile UCHAR * const)(x)) + +#define READ_REGISTER_USHORT(x) \ + (MemoryBarrier(), *(volatile USHORT * const)(x)) + +#define READ_REGISTER_ULONG(x) \ + (MemoryBarrier(), *(volatile ULONG * const)(x)) + +#define READ_REGISTER_ULONG64(x) \ + (MemoryBarrier(), *(volatile ULONG64 * const)(x)) + +#define READ_REGISTER_BUFFER_UCHAR(x, y, z) { \ + PUCHAR registerBuffer = x; \ + PUCHAR readBuffer = y; \ + ULONG readCount; \ + MemoryBarrier(); \ + for (readCount = z; readCount--; readBuffer++, registerBuffer++) { \ + *readBuffer = *(volatile UCHAR * const)(registerBuffer); \ + } \ +} + +#define READ_REGISTER_BUFFER_USHORT(x, y, z) { \ + PUSHORT registerBuffer = x; \ + PUSHORT readBuffer = y; \ + ULONG readCount; \ + MemoryBarrier(); \ + for (readCount = z; readCount--; readBuffer++, registerBuffer++) { \ + *readBuffer = *(volatile USHORT * const)(registerBuffer); \ + } \ +} + +#define READ_REGISTER_BUFFER_ULONG(x, y, z) { \ + PULONG registerBuffer = x; \ + PULONG readBuffer = y; \ + ULONG readCount; \ + MemoryBarrier(); \ + for (readCount = z; readCount--; readBuffer++, registerBuffer++) { \ + *readBuffer = *(volatile ULONG * const)(registerBuffer); \ + } \ +} + +#define READ_REGISTER_BUFFER_ULONG64(x, y, z) { \ + PULONG64 registerBuffer = x; \ + PULONG64 readBuffer = y; \ + ULONG readCount; \ + MemoryBarrier(); \ + for (readCount = z; readCount--; readBuffer++, registerBuffer++) { \ + *readBuffer = *(volatile ULONG64 * const)(registerBuffer); \ + } \ +} + +#define WRITE_REGISTER_UCHAR(x, y) { \ + *(volatile UCHAR * const)(x) = y; \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_USHORT(x, y) { \ + *(volatile USHORT * const)(x) = y; \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_ULONG(x, y) { \ + *(volatile ULONG * const)(x) = y; \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_ULONG64(x, y) { \ + *(volatile ULONG64 * const)(x) = y; \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_BUFFER_UCHAR(x, y, z) { \ + PUCHAR registerBuffer = x; \ + PUCHAR writeBuffer = y; \ + ULONG writeCount; \ + for (writeCount = z; writeCount--; writeBuffer++, registerBuffer++) { \ + *(volatile UCHAR * const)(registerBuffer) = *writeBuffer; \ + } \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_BUFFER_USHORT(x, y, z) { \ + PUSHORT registerBuffer = x; \ + PUSHORT writeBuffer = y; \ + ULONG writeCount; \ + for (writeCount = z; writeCount--; writeBuffer++, registerBuffer++) { \ + *(volatile USHORT * const)(registerBuffer) = *writeBuffer; \ + } \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_BUFFER_ULONG(x, y, z) { \ + PULONG registerBuffer = x; \ + PULONG writeBuffer = y; \ + ULONG writeCount; \ + for (writeCount = z; writeCount--; writeBuffer++, registerBuffer++) { \ + *(volatile ULONG * const)(registerBuffer) = *writeBuffer; \ + } \ + MemoryBarrier(); \ +} + +#define WRITE_REGISTER_BUFFER_ULONG64(x, y, z) { \ + PULONG64 registerBuffer = x; \ + PULONG64 writeBuffer = y; \ + ULONG writeCount; \ + for (writeCount = z; writeCount--; writeBuffer++, registerBuffer++) { \ + *(volatile ULONG64 * const)(registerBuffer) = *writeBuffer; \ + } \ + MemoryBarrier(); \ +} + +#endif // _X86_ + +__inline +SIZE_T +FxDevice::ReadRegister( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register + ) +{ + SIZE_T value = 0; + + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_READ_FROM_HARDWARE_START( + WdfDeviceHwAccessTargetTypeRegister, Size, 0); + + switch(Size) { + case WdfDeviceHwAccessTargetSizeUchar: + value = READ_REGISTER_UCHAR((PUCHAR)Register); + break; + case WdfDeviceHwAccessTargetSizeUshort: + value = READ_REGISTER_USHORT((PUSHORT)Register); + break; + case WdfDeviceHwAccessTargetSizeUlong: + value = READ_REGISTER_ULONG((PULONG)Register); + break; + case WdfDeviceHwAccessTargetSizeUlong64: +#if defined(_WIN64) + value = READ_REGISTER_ULONG64((PULONG64)Register); +#else + FX_VERIFY(DRIVER(BadArgument, TODO), CHECK("Invalid call to ULONG64 " + "hardware access function", FALSE)); +#endif + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Unexpected")); + break; + } + + // + // ETW end event for perf measurement + // + EventWriteEVENT_UMDF_FX_READ_FROM_HARDWARE_END( + WdfDeviceHwAccessTargetTypeRegister, Size, 0); + + return value; +} + +__inline +VOID +FxDevice::ReadRegisterBuffer( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register, + __out_ecount_full(Count) PVOID Buffer, + __in ULONG Count + ) +{ + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_READ_FROM_HARDWARE_START( + WdfDeviceHwAccessTargetTypeRegisterBuffer, Size, Count); + + switch(Size) { + case WdfDeviceHwAccessTargetSizeUchar: + READ_REGISTER_BUFFER_UCHAR(((PUCHAR)Register), (PUCHAR)Buffer, Count ); + break; + case WdfDeviceHwAccessTargetSizeUshort: +#pragma prefast(suppress:26000, "The Size parameter dictates the buffer size") + READ_REGISTER_BUFFER_USHORT(((PUSHORT)Register), (PUSHORT)Buffer, Count ); + break; + case WdfDeviceHwAccessTargetSizeUlong: + READ_REGISTER_BUFFER_ULONG(((PULONG)Register), (PULONG)Buffer, Count ); + break; + case WdfDeviceHwAccessTargetSizeUlong64: +#if defined(_WIN64) + READ_REGISTER_BUFFER_ULONG64(((PULONG64)Register), (PULONG64)Buffer, Count ); +#else + FX_VERIFY(DRIVER(BadArgument, TODO), CHECK("Invalid call to ULONG64 " + "hardware access function", FALSE)); +#endif + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Unexpected")); + break; + } + + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_READ_FROM_HARDWARE_END( + WdfDeviceHwAccessTargetTypeRegisterBuffer, Size, Count); +} + +__inline +VOID +FxDevice::WriteRegister( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register, + __in SIZE_T Value + ) +{ + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_WRITE_TO_HARDWARE_START( + WdfDeviceHwAccessTargetTypeRegister, Size, 0); + + switch(Size) { + case WdfDeviceHwAccessTargetSizeUchar: + WRITE_REGISTER_UCHAR((PUCHAR)Register, (UCHAR)Value); + break; + case WdfDeviceHwAccessTargetSizeUshort: + WRITE_REGISTER_USHORT((PUSHORT)Register, (USHORT)Value); + break; + case WdfDeviceHwAccessTargetSizeUlong: + WRITE_REGISTER_ULONG((PULONG)Register, (ULONG)Value); + break; + case WdfDeviceHwAccessTargetSizeUlong64: +#if defined(_WIN64) + WRITE_REGISTER_ULONG64((PULONG64)Register, (ULONG64)Value); +#else + FX_VERIFY(DRIVER(BadArgument, TODO), CHECK("Invalid call to ULONG64 " + "hardware access function", FALSE)); +#endif + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Unexpected")); + break; + } + + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_WRITE_TO_HARDWARE_END( + WdfDeviceHwAccessTargetTypeRegister, Size, 0); +} + +__inline +VOID +FxDevice::WriteRegisterBuffer( + __in WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + __in PVOID Register, + __in_ecount(Count) PVOID Buffer, + __in ULONG Count + ) +{ + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_WRITE_TO_HARDWARE_START( + WdfDeviceHwAccessTargetTypeRegisterBuffer, Size, Count); + + switch(Size) { + case WdfDeviceHwAccessTargetSizeUchar: + WRITE_REGISTER_BUFFER_UCHAR(((PUCHAR)Register), (PUCHAR)Buffer, Count); + break; + case WdfDeviceHwAccessTargetSizeUshort: +#pragma prefast(suppress:26000, "The Size parameter dictates the buffer size") + WRITE_REGISTER_BUFFER_USHORT(((PUSHORT)Register), (PUSHORT)Buffer, Count); + break; + case WdfDeviceHwAccessTargetSizeUlong: + WRITE_REGISTER_BUFFER_ULONG(((PULONG)Register), (PULONG)Buffer, Count); + break; + case WdfDeviceHwAccessTargetSizeUlong64: +#if defined(_WIN64) + WRITE_REGISTER_BUFFER_ULONG64(((PULONG64)Register), (PULONG64)Buffer, Count); +#else + FX_VERIFY(DRIVER(BadArgument, TODO), CHECK("Invalid call to ULONG64 " + "hardware access function", FALSE)); +#endif + break; + default: + FX_VERIFY(INTERNAL, TRAPMSG("Unexpected")); + break; + } + + // + // ETW start event for perf measurement + // + EventWriteEVENT_UMDF_FX_WRITE_TO_HARDWARE_END( + WdfDeviceHwAccessTargetTypeRegisterBuffer, Size, Count); +} + +__inline +FxWdmDeviceExtension* +FxDevice::_GetFxWdmExtension( + __in MdDeviceObject DeviceObject + ) +{ + return (FxWdmDeviceExtension*) + ((static_cast (DeviceObject))->GetDeviceExtension()); +} + +__inline +BOOLEAN +FxDevice::IsRemoveLockEnabledForIo( + VOID + ) +{ + return FALSE; +} + +__inline +MdRemoveLock +FxDevice::GetRemoveLock( + VOID + ) +{ + return &FxDevice::_GetFxWdmExtension( + GetDeviceObject())->IoRemoveLock; +} + +__inline +NTSTATUS +FxDevice::WmiPkgRegister( + VOID + ) +{ + // + // WMI doesn't apply for UMDF + // + DO_NOTHING(); + return STATUS_SUCCESS; +} + +__inline +VOID +FxDevice::WmiPkgDeregister( + VOID + ) +{ + // + // WMI doesn't apply for UMDF + // + DO_NOTHING(); +} + +__inline +VOID +FxDevice::WmiPkgCleanup( + VOID + ) +{ + // + // WMI doesn't apply for UMDF + // + DO_NOTHING(); +} + +__inline +IWudfDeviceStack* +FxDevice::GetDeviceStack( + VOID + ) +{ + return m_DevStack; +} + +__inline +IWudfDeviceStack2 * +FxDevice::GetDeviceStack2( + ) +{ + IWudfDeviceStack2 *pDeviceStack2; + HRESULT hrQI; + + hrQI = m_DevStack->QueryInterface(IID_IWudfDeviceStack2, + (PVOID*)&pDeviceStack2); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pDeviceStack2)); + + m_DevStack->Release(); + + return pDeviceStack2; +} + +#endif //_FXDEVICEUM_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxfileobjectum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxfileobjectum.hpp new file mode 100644 index 00000000000..56ca5ad130c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxfileobjectum.hpp @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFileObjectUm.hpp + +Abstract: + + This module implements a frameworks managed FileObject + +Author: + + + +Environment: + + User mode only + +Revision History: + + +--*/ + +#ifndef _FXFILEOBJECTUM_H_ +#define _FXFILEOBJECTUM_H_ + +#include "FxFileObject.hpp" + +#endif // _FXFILEOBJECTUM_H_ + + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxforwardum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxforwardum.hpp new file mode 100644 index 00000000000..a2b309eedca --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxforwardum.hpp @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxForwardUm.hpp + +Abstract: + + UMDF forward defines + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#pragma once +class FxMessageDispatch; +class AWDFDevice; +class AWDFDeviceInitialize; +class AWdfDeviceInterface; + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxglobalsum.h b/sdk/lib/drivers/wdf/shared/inc/private/um/fxglobalsum.h new file mode 100644 index 00000000000..472848dafd4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxglobalsum.h @@ -0,0 +1,184 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxGlobalsUm.h + +Abstract: + + This module contains user-mode specific globals definitions + for the frameworks. + + For common definitions common between km and um please see + FxGlobals.h + +Author: + +Environment: + + kernel mode only + +Revision History: + + +--*/ +#ifdef __cplusplus +extern "C" { +#endif + +#include "FxGlobals.h" + +extern IUMDFPlatform *g_IUMDFPlatform; +extern IWudfHost2 *g_IWudfHost2; + +_Must_inspect_result_ +__inline +BOOLEAN +FxIsProcessorGroupSupported( + VOID + ) +{ + // + // UMDF 2.0 is targeted for platforms that support processor groups. + // + return TRUE; +} + + +__inline +VOID +FX_TRACK_DRIVER( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + // + // Not yet supported for UMDF + // +} + +_Must_inspect_result_ +__inline +PVOID +FxAllocateFromNPagedLookasideListNoTracking ( + __in PNPAGED_LOOKASIDE_LIST Lookaside + ) +{ + UNREFERENCED_PARAMETER(Lookaside); + ASSERTMSG("Not implemented for UMDF!\n", FALSE); + return NULL; +} + +__inline +PVOID +FxAllocateFromNPagedLookasideList ( + _In_ PNPAGED_LOOKASIDE_LIST Lookaside, + _In_opt_ size_t ElementSize = 0 + ) +{ + UNREFERENCED_PARAMETER(Lookaside); + + // + // UMDF doesn't yet use a look-aside list, so just alloc memory from pool. + // + return MxMemory::MxAllocatePoolWithTag(NonPagedPool, // not used + ElementSize, + 0 // not used + ); +} + +__inline +PVOID +FxAllocateFromPagedLookasideList ( + __in PPAGED_LOOKASIDE_LIST Lookaside + ) +{ + UNREFERENCED_PARAMETER(Lookaside); + ASSERTMSG("Not implemented for UMDF!\n", FALSE); + return NULL; +} + +__inline +VOID +FxFreeToNPagedLookasideListNoTracking ( + __in PNPAGED_LOOKASIDE_LIST Lookaside, + __in PVOID Entry + ) +{ + UNREFERENCED_PARAMETER(Lookaside); + UNREFERENCED_PARAMETER(Entry); + ASSERTMSG("Not implemented for UMDF!\n", FALSE); +} + +__inline +VOID +FxFreeToPagedLookasideList ( + __in PPAGED_LOOKASIDE_LIST Lookaside, + __in PVOID Entry + ) +{ + UNREFERENCED_PARAMETER(Lookaside); + UNREFERENCED_PARAMETER(Entry); + ASSERTMSG("Not implemented for UMDF!\n", FALSE); +} + +__inline +VOID +FxFreeToNPagedLookasideList ( + __in PNPAGED_LOOKASIDE_LIST Lookaside, + __in PVOID Entry + ) +{ + UNREFERENCED_PARAMETER(Lookaside); + + MxMemory::MxFreePool(Entry); +} + +__inline +BOOL +IsCurrentThreadImpersonated( ) +{ + return g_IWudfHost2->IsCurrentThreadImpersonated(); +} + +__inline +PWDF_ACTIVATION_FRAME * +GetActivationList( + VOID + ) +{ + return g_IUMDFPlatform->GetActivationListHead(); +} + +// +// This has to be a macro (as opposed an inline function) beacause of the activation frame is +// allocated in the caller's stack. +// +// NOTE: This must not be wrapped in {}'s since that puts the activation frame in a very +// short lived scope. It's destructor will be called when control leaves the block +// rather than when the function returns and that defeats the entire purpose of the +// activation frame (which is to live for the life of the DDI call). +// +// NOTE 2: +// WDF_ACTIVATION constructor includes a default argument which is the _ReturnAddress() +// instrinsic. This macro should be placed in methods such that the _ReturnAddress +// points to calling driver code. +// + +#define DDI_ENTRY_IMPERSONATION_OK() \ + WDF_ACTIVATION activationFrame(GetActivationList()); \ + +#define DDI_ENTRY() \ + DDI_ENTRY_IMPERSONATION_OK() \ + FX_VERIFY( \ + DRIVER(BadArgument, TODO), \ + CHECK("It is illegal to invoke this DDI while " \ + "thread is impersonated", \ + (FALSE == IsCurrentThreadImpersonated())) \ + ); + +#ifdef __cplusplus +} +#endif diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxinterruptthreadpoolum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxinterruptthreadpoolum.hpp new file mode 100644 index 00000000000..48967d1f873 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxinterruptthreadpoolum.hpp @@ -0,0 +1,195 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxInterruptThreadpoolUm.hpp + +Abstract: + + This file contains the class definition for the threadpool for interrupt object. + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ +#pragma once + +#define MINIMUM_THREAD_COUNT_DEFAULT (1) +class FxInterrupt; + +class FxInterruptThreadpool : FxGlobalsStump +{ + +private: + + // + // Pointer to structure representing thread pool + // + PTP_POOL m_Pool; + + // + // Structure representing callback environment for thread pool + // + TP_CALLBACK_ENVIRON m_CallbackEnvironment; + + // + // Minimum thread pool thread count + // + ULONG m_MinimumThreadCount; + + + HRESULT + Initialize( + ); + +public: + + FxInterruptThreadpool( + PFX_DRIVER_GLOBALS FxDriverGlobals + ); + + ~FxInterruptThreadpool(); + + static + HRESULT + _CreateAndInit( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _Out_ FxInterruptThreadpool** ppThreadpool + ); + + PTP_CALLBACK_ENVIRON + GetCallbackEnvironment( + VOID + ) + { + return &m_CallbackEnvironment; + } + + PTP_WAIT + CreateThreadpoolWait( + __in PTP_WAIT_CALLBACK pfnwa, + __inout_opt PVOID Context + ) + { + return ::CreateThreadpoolWait(pfnwa, Context, &m_CallbackEnvironment); + } + + HRESULT + UpdateThreadPoolThreadLimits( + _In_ ULONG InterruptCount + ); +}; + +class FxInterruptWaitblock : FxGlobalsStump +{ + +private: + + // + // threadpool wait block + // + PTP_WAIT m_Wait; + + // + // auto reset event + // + HANDLE m_Event; + + + HRESULT + Initialize( + __in FxInterruptThreadpool* Threadpool, + __in FxInterrupt* Interrupt, + __in PTP_WAIT_CALLBACK WaitCallback + ); + +public: + + static + HRESULT + _CreateAndInit( + _In_ FxInterruptThreadpool* Threadpool, + _In_ FxInterrupt* Interrupt, + _In_ PTP_WAIT_CALLBACK WaitCallback, + _Out_ FxInterruptWaitblock** Waitblock + ); + + FxInterruptWaitblock( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxGlobalsStump(FxDriverGlobals), + m_Wait(NULL), + m_Event(NULL) + { + } + + ~FxInterruptWaitblock(); + + VOID + CloseThreadpoolWait( + VOID + ) + { + ::CloseThreadpoolWait(m_Wait); + } + + VOID + SetThreadpoolWait( + VOID + ) + { + // + // associates event with wait block and queues it + // to thread pool queue. + // + ::SetThreadpoolWait(m_Wait, m_Event, NULL); + } + + VOID + ClearThreadpoolWait( + VOID + ) + { + // + // Passing a NULL handle clears the wait + // + ::SetThreadpoolWait(m_Wait, NULL, NULL); + } + + VOID + WaitForOutstandingCallbackToComplete( + VOID + ) + { + ::WaitForThreadpoolWaitCallbacks(m_Wait, FALSE); + } + + HANDLE + GetEventHandle( + VOID + ) + { + return m_Event; + } + + VOID + ResetEvent( + VOID + ) + { + ::ResetEvent(m_Event); + } + +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxinterruptum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxinterruptum.hpp new file mode 100644 index 00000000000..c637ab24b92 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxinterruptum.hpp @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxInterruptUm.hpp + +Abstract: + + This module implements a frameworks managed interrupt object + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ +#ifndef _FXINTERRUPTUM_H_ +#define _FXINTERRUPTUM_H_ + +#include "FxInterrupt.hpp" + +__inline +struct _KINTERRUPT* +FxInterrupt::GetInterruptPtr( + VOID + ) +{ + // + // m_Interrupt is always NULL in UMDF. + // + return NULL; +} + +#endif // _FXINTERRUPTUM_H_ + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxioqueueum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxioqueueum.hpp new file mode 100644 index 00000000000..4d9fe790218 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxioqueueum.hpp @@ -0,0 +1,231 @@ +/*++ + + Copyright (c) Microsoft Corporation + + Module Name: + + FxIoQueueUm.hpp + + Abstract: + + This module implements um specific functions for FxIoQueue. + + Author: + + + + Environment: + + User mode only + + Revision History: + + --*/ + +#ifndef _FXIOQUEUEUM_HPP_ +#define _FXIOQUEUEUM_HPP_ + +__inline +BOOLEAN +IsPagingIo( + __in PIRP Irp + ) +/*++ + +Routine Description: + Dummy UM implementation. +--*/ +{ + UNREFERENCED_PARAMETER(Irp); + return TRUE; +} + +__inline +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueForwardProgressIrpLocked( + __in MdIrp Irp + ) +{ + UNREFERENCED_PARAMETER(Irp); + + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + + +__inline +_Must_inspect_result_ +MdIrp +FxIoQueue::GetForwardProgressIrpLocked( + __in_opt PFILE_OBJECT FileObject + ) +/*++ + + Routine Description: + Remove an IRP from the pending irp list if it matches with the input + fileobject. If the fileobject value is NULL, return the first one from + the pending list. + +--*/ +{ + UNREFERENCED_PARAMETER(FileObject); + + UfxVerifierTrapNotImpl(); + return NULL; + +} + +__inline +VOID +FxIoQueue::FreeAllReservedRequests( + __in BOOLEAN Verify + ) +/*++ + +Routine Description: + Called from dispose to Free all the reserved requests. + + Verify - + TRUE - Make sure the number of request freed matches with the count of + request created. + FALSE - Called when we fail to allocate all the reserved requests + during config at init time. So we don't verify because the + count of request freed wouldn't match with the configured value. +--*/ +{ + UNREFERENCED_PARAMETER(Verify); + + UfxVerifierTrapNotImpl(); + return; + +} + +__inline +VOID +FxIoQueue::ReturnReservedRequest( + __in FxRequest *ReservedRequest + ) +/*++ + +Routine Description: + Reuse the ReservedRequest if there are pended IRPs otherwise + add it back to the reserve list. + +--*/ +{ + + UNREFERENCED_PARAMETER(ReservedRequest); + + UfxVerifierTrapNotImpl(); + return ; + +} + +__inline +VOID +FxIoQueue::GetForwardProgressIrps( + __in PLIST_ENTRY IrpListHead, + __in_opt MdFileObject FileObject + ) +/*++ + +Routine Description: + + This function is called to retrieve the list of reserved queued IRPs. + The IRP's Tail.Overlay.ListEntry field is used to link these structs together. + +--*/ +{ + UNREFERENCED_PARAMETER(IrpListHead); + UNREFERENCED_PARAMETER(FileObject); + + UfxVerifierTrapNotImpl(); + return; + +} + +__inline +VOID +FxIoQueue::FlushQueuedDpcs( + VOID + ) +/*++ + +Routine Description: + + This is the kernel mode routine to flush queued DPCs. + +Arguments: + +Return Value: + +--*/ +{ + UfxVerifierTrapNotImpl(); +} + + +__inline +VOID +FxIoQueue::InsertQueueDpc( + VOID + ) +/*++ + +Routine Description: + + This is the kernel mode routine to insert a dpc. + +Arguments: + +Return Value: + +--*/ +{ + UfxVerifierTrapNotImpl(); +} + +__inline +_Must_inspect_result_ +NTSTATUS +FxIoQueue::GetReservedRequest( + __in MdIrp Irp, + __deref_out_opt FxRequest **ReservedRequest + ) +/*++ + +Routine Description: + Use the policy configured on the queue to decide whether to allocate a + reserved request. + +--*/ +{ + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(ReservedRequest); + + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +__inline +_Must_inspect_result_ +NTSTATUS +FxIoQueue::AssignForwardProgressPolicy( + __in PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Policy + ) +/*++ + +Routine Description: + Configure the queue for forward Progress. + +--*/ +{ + UNREFERENCED_PARAMETER(Policy); + + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + + +#endif // _FXIOQUEUEUM_HPP diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxiotargetremoteum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxiotargetremoteum.hpp new file mode 100644 index 00000000000..46de9f8feb8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxiotargetremoteum.hpp @@ -0,0 +1,141 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxIoTargetRemoteUm.hpp + +Abstract: + + User-mode specific definitions of FxIoTargetRemote + +Author: + + +Environment: + + User mode only + +Revision History: + +--*/ + +#pragma once + +class FxIoTargetRemoteNotificationCallback : + public FxGlobalsStump, + public IWudfTargetCallbackDeviceChange +{ +private: + + LONG m_cRefs; + + FxIoTargetRemote* m_RemoteTarget; + +public: + + FxIoTargetRemoteNotificationCallback( + PFX_DRIVER_GLOBALS FxDriverGlobals, + FxIoTargetRemote* Target + ) : + FxGlobalsStump(FxDriverGlobals), + m_RemoteTarget(Target), + m_cRefs(1) + { + } + + ~FxIoTargetRemoteNotificationCallback() {}; + + WUDF_TARGET_CONTEXT + GetRegistrationId( + VOID + ) + { + return m_RemoteTarget->m_TargetNotifyHandle; + } + + BOOL + __stdcall + OnQueryRemove( + _In_ WUDF_TARGET_CONTEXT RegistrationID + ); + + VOID + __stdcall + OnRemoveCanceled( + _In_ WUDF_TARGET_CONTEXT RegistrationID + ); + + VOID + __stdcall + OnRemoveComplete( + _In_ WUDF_TARGET_CONTEXT RegistrationID + ); + + VOID + __stdcall + OnCustomEvent( + _In_ WUDF_TARGET_CONTEXT RegistrationID, + _In_ REFGUID Event, + _In_reads_bytes_(DataSize) BYTE * Data, + _In_ DWORD DataSize, + _In_ DWORD NameBufferOffset + ); + + HRESULT + __stdcall + QueryInterface( + __in const IID& iid, + __out void ** ppv + ) + { + if (NULL == ppv) { + return E_INVALIDARG; + } + + *ppv = NULL; + + if ( iid == IID_IUnknown) { + *ppv = static_cast (this); + } + else if ( iid == IID_IWudfTargetCallbackDeviceChange) { + *ppv = static_cast (this); + } + else { + return E_INVALIDARG; + } + + this->AddRef(); + return S_OK; + } + + ULONG + __stdcall + AddRef( + ) + { + LONG cRefs = InterlockedIncrement( &m_cRefs ); + return cRefs; + } + + ULONG + __stdcall + Release( + ) + { + LONG cRefs = InterlockedDecrement( &m_cRefs ); + if (0 == cRefs) { + // + // The lifetime of this object is controlled by FxIoTargetRemote + // object (the container object), and not by this ref count. This + // method is implemented just to satisfy the interface implemetation + // requirement. + // + DO_NOTHING(); + } + + return cRefs; + } +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxiotargetum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxiotargetum.hpp new file mode 100644 index 00000000000..faa02a582dc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxiotargetum.hpp @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxIoTargetUm.hpp + +Abstract: + +Author: + + + +Environment: + + +Revision History: + +--*/ + +#ifndef _FXIOTARGETUM_H_ +#define _FXIOTARGETUM_H_ + +__inline +FxIoContext::FxIoContext( + VOID + ) : + FxRequestContext(FX_RCT_IO), + m_OtherMemory(NULL), + m_RestoreState(FALSE) +{ + ZeroMemory(&m_OriginalBufferInfo, sizeof(m_OriginalBufferInfo)); +} + +__inline +FxIoContext::~FxIoContext( + VOID + ) +{ +} + +__inline +VOID +FxIoContext::ReleaseAndRestore( + __in FxRequestBase* Request + ) +{ + FxIrp* irp = NULL; + + irp = Request->GetSubmitFxIrp(); + + if (m_RestoreState) { + irp->GetIoIrp()->RestoreCurrentBuffer(&m_OriginalBufferInfo); + m_RestoreState = FALSE; + } + + // + // Release the 2ndary buffer if we have an outstanding reference + // + if (m_OtherMemory != NULL) { + m_OtherMemory->RELEASE(this); + m_OtherMemory = NULL; + } + + // + // Release the other buffer and all __super related fields + // + __super::ReleaseAndRestore(Request); +} + +__inline +VOID +FxIoContext::CopyParameters( + __in FxRequestBase* Request + ) +{ + switch (m_MajorFunction) { + case IRP_MJ_WRITE: + m_CompletionParams.Parameters.Write.Length = + m_CompletionParams.IoStatus.Information; + break; + + case IRP_MJ_READ: + m_CompletionParams.Parameters.Read.Length = + m_CompletionParams.IoStatus.Information; + break; + + case IRP_MJ_DEVICE_CONTROL: + case UMINT::WdfRequestInternalIoctl: + m_CompletionParams.Parameters.Ioctl.Output.Length = + m_CompletionParams.IoStatus.Information; + break; + + + + + + + + + + + + + + + default: + FX_VERIFY(INTERNAL, CHECK("Non Io Irp passed to CopyParameters", FALSE)); + } +} + +__inline +VOID +FxIoContext::SwapIrpBuffer( + _In_ FxRequestBase* Request, + _In_ ULONG NewInputBufferCb, + _In_reads_bytes_opt_(NewInputBufferCb) PVOID NewInputBuffer, + _In_ ULONG NewOutputBufferCb, + _In_reads_bytes_opt_(NewOutputBufferCb) PVOID NewOutputBuffer + ) +{ + FxIrp* irp = NULL; + + irp = Request->GetSubmitFxIrp(); + + m_RestoreState = TRUE; + irp->GetIoIrp()->SwapCurrentBuffer( + true, + NewInputBufferCb, + NewInputBuffer, + NewOutputBufferCb, + NewOutputBuffer, + &m_OriginalBufferInfo + ); +} + +__inline +BOOLEAN +FxIoTarget::HasValidStackSize( + VOID + ) +{ + + + + + + + return TRUE; +} + +__inline +VOID +FxIoTarget::Send( + _In_ MdIrp Irp + ) +{ + Forward(Irp); +} + +#endif // _FXIOTARGETUM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxirpum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxirpum.hpp new file mode 100644 index 00000000000..356516bfa68 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxirpum.hpp @@ -0,0 +1,16 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _FXIRPUM_HPP_ +#define _FXIRPUM_HPP_ + +typedef struct { + ULONG Type; + MdIrp Irp; + PIO_CSQ Csq; +} MdIoCsqIrpContext, *PMdIoCsqIrpContext; + +#include "FxIrp.hpp" + + +#endif // _FXIRPUM_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxldrum.h b/sdk/lib/drivers/wdf/shared/inc/private/um/fxldrum.h new file mode 100644 index 00000000000..6d06db10505 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxldrum.h @@ -0,0 +1,256 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxldrum.h + +Abstract: + + This is the UMDF version of wdfldr.h + + +--*/ +#ifndef __FXLDRUM_H__ +#define __FXLDRUM_H__ + +#define WDF_COMPONENT_NAME(a) L#a + +typedef +VOID +(*WDFFUNC)( + VOID + ); + +typedef ULONG WDF_MAJOR_VERSION; +typedef ULONG WDF_MINOR_VERSION; +typedef ULONG WDF_BUILD_NUMBER; + +// +// Version container +// +typedef struct _WDF_VERSION { + WDF_MAJOR_VERSION Major; + WDF_MINOR_VERSION Minor; + WDF_BUILD_NUMBER Build; +} WDF_VERSION; + +// +// WDF bind information structure. +// +typedef struct _WDF_BIND_INFO { + ULONG Size; + PWCHAR Component; + WDF_VERSION Version; + ULONG FuncCount; + __field_bcount(FuncCount*sizeof(WDFFUNC)) WDFFUNC* FuncTable; + + + + + + // + // This field is not used in UMDF + // + PVOID Module; + + + +} WDF_BIND_INFO, * PWDF_BIND_INFO; + +typedef PVOID WDF_COMPONENT_GLOBALS, *PWDF_COMPONENT_GLOBALS; + +typedef +NTSTATUS +(*PFNLIBRARYCOMMISSION)( + VOID + ); + +typedef +NTSTATUS +(*PFNLIBRARYDECOMMISSION)( + VOID + ); + +typedef +NTSTATUS +(*PFNLIBRARYREGISTERCLIENT)( + PWDF_BIND_INFO Info, + PWDF_COMPONENT_GLOBALS * ComponentGlobals, + PVOID * Context + ); + +typedef +NTSTATUS +(*PFNLIBRARYUNREGISTERCLIENT)( + PWDF_BIND_INFO Info, + PWDF_COMPONENT_GLOBALS DriverGlobals + ); + + +typedef struct _WDF_LIBRARY_INFO { + ULONG Size; + PFNLIBRARYCOMMISSION LibraryCommission; + PFNLIBRARYDECOMMISSION LibraryDecommission; + PFNLIBRARYREGISTERCLIENT LibraryRegisterClient; + PFNLIBRARYUNREGISTERCLIENT LibraryUnregisterClient; + WDF_VERSION Version; +} WDF_LIBRARY_INFO, *PWDF_LIBRARY_INFO; + +typedef +PWDF_LIBRARY_INFO +(*PFX_GET_LIBRARY_INFO_UM)( + VOID + ); + +// +// Framework 2.x's driver object. +// +typedef struct _DRIVER_OBJECT_UM *PDRIVER_OBJECT_UM; +struct IWudfDeviceStack; +struct IWudfDeviceStack2; +struct IWudfDevice; +struct IWudfIrp; +struct IUnknown; +typedef enum _WDF_DEVICE_IO_BUFFER_RETRIEVAL *PWDF_DEVICE_IO_BUFFER_RETRIEVAL; +typedef enum RdWmiPowerAction; +typedef const GUID *LPCGUID; +typedef UINT64 WUDF_INTERFACE_CONTEXT; +class FxDriver; + +// +// Valid flags for use in the DRIVER_OBJECT_UM::Flags field. +// +enum FxDriverObjectUmFlags : USHORT { + DriverObjectUmFlagsLoggingEnabled = 0x1 +}; + +// +// Driver object's basic interface. +// +typedef +NTSTATUS +DRIVER_ADD_DEVICE_UM ( + _In_ PDRIVER_OBJECT_UM DriverObject, + _In_ PVOID Context, + _In_ IWudfDeviceStack * DevStack, + _In_ LPCWSTR KernelDeviceName, + _In_opt_ HKEY hPdoKey, + _In_ LPCWSTR pwszServiceName, + _In_ LPCWSTR pwszDevInstanceID, + _In_ ULONG ulDriverID + ); + +typedef DRIVER_ADD_DEVICE_UM *PFN_DRIVER_ADD_DEVICE_UM; + +typedef +VOID +DRIVER_DISPATCH_UM ( + _In_ IWudfDevice * DeviceObject, + _In_ IWudfIrp * Irp, + _In_opt_ IUnknown * Context + ); + +typedef DRIVER_DISPATCH_UM *PFN_DRIVER_DISPATCH_UM; + +typedef +VOID +DRIVER_UNLOAD_UM ( + _In_ PDRIVER_OBJECT_UM DriverObject + ); + +typedef DRIVER_UNLOAD_UM *PFN_DRIVER_UNLOAD_UM; + +typedef struct _DRIVER_OBJECT_UM { + ULONG Size; + + // + // The following links all of the devices created by a single driver + // together on a list, and the Flags word provides an extensible flag + // location for driver objects. + // + ULONG Flags; + + // + // The driver name field is used by the error log thread + // determine the name of the driver that an I/O request is/was bound. + // + UNICODE_STRING DriverName; + + // + // Store FxDriver + // + FxDriver* FxDriver; + + // + // Host device stack. This field is only valid while initializing + // the driver, such as during DriverEntry, and is NULL at all other times. + // + IWudfDeviceStack2* WudfDevStack; + + // + // Callback environment for driver workitems. + // + TP_CALLBACK_ENVIRON ThreadPoolEnv; + + // + // Group that tracks thread pool callbacks. + // + PTP_CLEANUP_GROUP ThreadPoolGroup; + + // + // A global number that driver IFR and framework IFR can opt into + // using as their record ordering number. This allows the framework + // and driver IFR record lists to be merged and sorted before being + // displayed. + // + LONG IfrSequenceNumber; + + // + // The following section describes the entry points to this particular + // driver. Note that the major function dispatch table must be the last + // field in the object so that it remains extensible. + // + PFN_DRIVER_ADD_DEVICE_UM AddDevice; + PFN_DRIVER_UNLOAD_UM DriverUnload; + PFN_DRIVER_DISPATCH_UM MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1]; + +} DRIVER_OBJECT_UM; + +typedef struct _CLIENT_INFO { + // + // Size of this structure + // + ULONG Size; + + // + // registry service path of client driver + // + PUNICODE_STRING RegistryPath; + +} CLIENT_INFO, *PCLIENT_INFO; + +// +// Event name: WdfCensusEvtLinkClientToCx +// +// Source: WudfHost (UM loader) +// +// Description: Written when a client is binding to a class extension. +// WdfVersionBindClass which is called from the client's stub, +// will load/reference the Cx and add it to the fx library's +// list of clients. The client driver's class extension list is +// also updated at that time, which is when this event is written. +// +// Frequency: Everytime a client driver binds to a class extension. +// +// +#define WDF_CENSUS_EVT_WRITE_LINK_CLIENT_TO_CX(TraceHandle, CxImageName, ClientImageName) \ + TraceLoggingWrite(TraceHandle, \ + "WdfCensusEvtLinkClientToCx", \ + WDF_TELEMETRY_EVT_KEYWORDS, \ + TraceLoggingWideString(CxImageName, "CxImageName"), \ + TraceLoggingWideString(ClientImageName, "ClientImageName" ) \ + ); + +#endif // __FXLDRUM_H__ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxmessagedispatchum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxmessagedispatchum.hpp new file mode 100644 index 00000000000..b0087c52b56 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxmessagedispatchum.hpp @@ -0,0 +1,253 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + WudfDispatcher.h + +Abstract: + + This file contains the class definition of the WUDF dispatcher object. + +Author: + + + +Environment: + + User mode only + +Revision History: + + + +--*/ +#pragma once + +extern const GUID IID_FxMessageDispatch; +extern const GUID IID_FxMessageDispatch2; + +class FxMessageDispatch; + +class FxMessageDispatch : + public FxStump, + public IFxMessageDispatch2 +{ + // + // Manager functions. + // +private: + FxMessageDispatch( + _In_ FxDevice* Device + ) : + m_cRefs(1), + m_Device(Device) + { + } + +public: + ~FxMessageDispatch() + { + // SAFE_RELEASE(m_Device); + } + + static + NTSTATUS + _CreateAndInitialize( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_ FxDevice* Device, + _Out_ FxMessageDispatch ** ppWudfDispatcher + ); + + // + // IUnknown + // +public: + HRESULT + __stdcall + QueryInterface( + _In_ REFIID riid, + _Out_ LPVOID* ppvObject + ); + + ULONG + __stdcall + AddRef(); + + ULONG + __stdcall + Release(); + + // + // IFxMessageDispatch + // +public: + virtual void __stdcall + DispatchPnP( + _In_ IWudfIrp * pIrp + ); + + virtual void __stdcall + CreateFile( + _In_ IWudfIoIrp * pCreateIrp + ); + + virtual void __stdcall + DeviceControl( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ); + + virtual void __stdcall + ReadFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ); + + virtual void __stdcall + WriteFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ); + + virtual void __stdcall + CleanupFile( + _In_ IWudfIoIrp * pIrp, + _In_ IUnknown * pFxContext + ); + + virtual void __stdcall + CloseFile( + _In_ IWudfIoIrp * pIrp, + _In_ IUnknown * pFxContext + ); + + virtual + VOID + __stdcall + GetPreferredTransferMode( + _Out_ UMINT::WDF_DEVICE_IO_BUFFER_RETRIEVAL *RetrievalMode, + _Out_ UMINT::WDF_DEVICE_IO_TYPE *RWPreference, + _Out_ UMINT::WDF_DEVICE_IO_TYPE *IoctlPreference + ); + + virtual void __stdcall + FlushBuffers( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ); + + virtual void __stdcall + QueryInformationFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ); + + virtual void __stdcall + SetInformationFile( + _In_ IWudfIoIrp * pIrp, + _In_opt_ IUnknown * pFxContext + ); + + virtual NTSTATUS __stdcall + ProcessWmiPowerQueryOrSetData( + _In_ RdWmiPowerAction Action, + _Out_ BOOLEAN *QueryResult + ); + + // + // We should remove these methods from this interface. + // + virtual WUDF_INTERFACE_CONTEXT __stdcall + RemoteInterfaceArrival( + _In_ LPCGUID pDeviceInterfaceGuid, + _In_ PCWSTR pSymbolicLink + ); + + virtual void __stdcall + RemoteInterfaceRemoval( + _In_ WUDF_INTERFACE_CONTEXT RemoteInterfaceID + ); + + virtual BOOL __stdcall + TransportQueryID( + _In_ DWORD Id, + _In_ PVOID DataBuffer, + _In_ SIZE_T cbDataBufferSize + ); + + virtual ULONG __stdcall + GetDirectTransferThreshold( + VOID + ); + + virtual void __stdcall + PoFxDevicePowerRequired( + VOID + ); + + virtual void __stdcall + PoFxDevicePowerNotRequired( + VOID + ); + + // + // Additional public functions. + // +public: + // + // Returns the Dispatcher object from the given interface without + // incrementing the refcount. + // + static + FxMessageDispatch* + _GetObjFromItf( + _In_ IFxMessageDispatch* pIFxMessageDispatch + ); + + // + // Returns the specified interface from the given object without + // incrementing the refcount. + // + static + IFxMessageDispatch* + _GetDispatcherItf( + _In_ FxMessageDispatch* pWudfDispatcher + ); + + // + // Returns a weak ref to the embedded user-mode driver object. + // + PDRIVER_OBJECT_UM + GetDriverObject( + VOID + ) + { + return m_Device->GetDriver()->GetDriverObject(); + } + + MdDeviceObject + GetDeviceObject( + VOID + ) + { + return m_Device->GetDeviceObject(); + } + + // + // Data members. + // +private: + // + // Reference count for debugging purposes. The lifetime is managed by + // FxDevice. + // + LONG m_cRefs; + + // + // Device object associated with this dispatcher object. + // + FxDevice * m_Device; +}; + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxrequestbaseum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxrequestbaseum.hpp new file mode 100644 index 00000000000..409a2039226 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxrequestbaseum.hpp @@ -0,0 +1,29 @@ +/*++ + + Copyright (c) Microsoft Corporation + + Module Name: + + FxRequestBaseUm.hpp + + Abstract: + + This module implements km specific functions for FxRequestBase. + + Author: + + + + Environment: + + User mode only + + Revision History: + + --*/ + +#ifndef _FXREQUESTBASEUM_HPP_ +#define _FXREQUESTBASEUM_HPP_ + +#endif // _FXREQUESTBASEUM_HPP + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxrequestbufferum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxrequestbufferum.hpp new file mode 100644 index 00000000000..54ad9ee47c3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxrequestbufferum.hpp @@ -0,0 +1,69 @@ +/*++ + + Copyright (c) Microsoft Corporation + + Module Name: + + FxRequestBufferUm.hpp + + Abstract: + + This module implements um specific functions for FxRequestBuffer. + + Author: + + + + Environment: + + User mode only + + Revision History: + + --*/ + +#ifndef _FXREQUESTBUFFERUM_HPP_ +#define _FXREQUESTBUFFERUM_HPP_ + +__inline +VOID +FxRequestBuffer::SetMdl( + __in PMDL Mdl, + __in ULONG Length + ) +{ + UNREFERENCED_PARAMETER(Mdl); + UNREFERENCED_PARAMETER(Length); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +__inline +NTSTATUS +FxRequestBuffer::GetOrAllocateMdlWorker( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __deref_out PMDL* Mdl, + __in BOOLEAN * ReuseMdl, + __in LONG Length, + __in PVOID Buffer, + __inout size_t* SizeOfMdl, + __in BOOLEAN UnlockWhenFreed, + __deref_out_opt PMDL* MdlToFree + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + UNREFERENCED_PARAMETER(Mdl); + UNREFERENCED_PARAMETER(ReuseMdl); + UNREFERENCED_PARAMETER(Length); + UNREFERENCED_PARAMETER(Buffer); + UNREFERENCED_PARAMETER(SizeOfMdl); + UNREFERENCED_PARAMETER(UnlockWhenFreed); + UNREFERENCED_PARAMETER(MdlToFree); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_UNSUCCESSFUL; +} + + +#endif // _FXREQUESTBUFFERUM_HPP_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxtelemetryum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxtelemetryum.hpp new file mode 100644 index 00000000000..8c4599cdcfb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxtelemetryum.hpp @@ -0,0 +1,130 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetryUm.hpp + +Abstract: + + This is header file for telemetry methods. + +Author: + + + +Environment: + + User mode only + +Revision History: + +Notes: + +--*/ + +#pragma once + +#include "fxldrum.h" + +// +// Event name: UmdfCensusEvtDeviceStart +// +// Source: Mode agnostic (UMDF and KMDF) +// +// Description: Written when a FDO completes start successfully. +// +// Frequency: If FX_TELEMETRY_ENABLED, once per driver session. This is tracked using the +// DoOnceFlag in the telemetry context. +// +#define UMDF_CENSUS_EVT_WRITE_DEVICE_START(TraceHandle , Globals, DriverConfig, SetupClass, BusEnum, HwID, Manafacturer) \ + TraceLoggingWrite(TraceHandle, \ + "UmdfCensusEvtDeviceStart", \ + WDF_TELEMETRY_EVT_KEYWORDS, \ + WDF_CENSUS_EVT_DATA_COMMON(Globals), \ + TraceLoggingString((Globals)->Public.DriverName, "DriverServiceName"), \ + TraceLoggingUmdfDriverConfigInfo(DriverConfig, "DriverConfigInfo"), \ + TraceLoggingWideString(SetupClass, "SetupClass"), \ + TraceLoggingWideString(BusEnum, "BusEnumerator"), \ + TraceLoggingWideString(HwID, "HardwareId"), \ + TraceLoggingWideString(Manafacturer, "ManufacturerString") \ + ); + +// +// This is part of the data for UmdfCensusEvtDeviceStart event. +// +#define TraceLoggingUmdfDriverConfigInfo(info, fieldName) \ + \ + TraceLoggingStruct(20, fieldName), \ + \ + TraceLoggingUInt8(info.bitmap.IsFilter, "IsFilter" ), \ + TraceLoggingUInt8(info.bitmap.IsPowerPolicyOwner, "IsPowerPolicyOwner" ), \ + TraceLoggingUInt8(info.bitmap.IsS0IdleWakeFromS0Enabled, "IsS0IdleWakeFromS0Enabled" ), \ + TraceLoggingUInt8(info.bitmap.IsS0IdleUsbSSEnabled, "IsS0IdleUsbSSEnabled" ), \ + TraceLoggingUInt8(info.bitmap.IsS0IdleSystemManaged, "IsS0IdleSystemManaged" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsSxWakeEnabled, "IsSxWakeEnabled" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingLevelTriggeredLineInterrupt, "IsUsingLevelTriggeredLineInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingEdgeTriggeredLineInterrupt, "IsUsingEdgeTriggeredLineInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingMsiXOrSingleMsi22Interrupt, "IsUsingMsiXOrSingleMsi22Interrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingMsi22MultiMessageInterrupt, "IsUsingMsi22MultiMessageInterrupt" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsUsingMultipleInterrupt, "IsUsingMultipleInterrupt" ), \ + TraceLoggingUInt8(info.bitmap.IsDirectHardwareAccessAllowed, "IsDirectHardwareAccessAllowed" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingUserModemappingAccessMode, "IsUsingUserModemappingAccessMode" ), \ + TraceLoggingUInt8(info.bitmap.IsKernelModeClientAllowed, "IsKernelModeClientAllowed" ), \ + TraceLoggingUInt8(info.bitmap.IsNullFileObjectAllowed, "IsNullFileObjectAllowed" ), \ + \ + TraceLoggingUInt8(info.bitmap.IsPoolingDisabled, "IsPoolingDisabled" ), \ + TraceLoggingUInt8(info.bitmap.IsMethodNeitherActionCopy, "IsMethodNeitherActionCopy" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingDirectIoForReadWrite, "IsUsingDirectIoForReadWrite" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingDirectIoForIoctl, "IsUsingDirectIoForIoctl" ), \ + TraceLoggingUInt8(info.bitmap.IsUsingDriverWppRecorder, "IsUsingDriverWppRecorder" ) \ + +// +// bit-map for driver info stream +// +// When changing the structure, do update TraceLoggingUmdfDriverConfigInfo +// for fields name and TraceLoggingStruct(count) as well. It is good to keep +// fields order the same but it is not required. +// +union UFxTelemetryDriverInfo { + struct { + DWORD IsFilter : 1; + DWORD IsPowerPolicyOwner : 1; + DWORD IsS0IdleWakeFromS0Enabled : 1; + DWORD IsS0IdleUsbSSEnabled : 1; + DWORD IsS0IdleSystemManaged : 1; + DWORD IsSxWakeEnabled : 1; + DWORD IsUsingLevelTriggeredLineInterrupt : 1; + DWORD IsUsingEdgeTriggeredLineInterrupt : 1; + DWORD IsUsingMsiXOrSingleMsi22Interrupt : 1; + DWORD IsUsingMsi22MultiMessageInterrupt : 1; + DWORD IsUsingMultipleInterrupt : 1; + DWORD IsDirectHardwareAccessAllowed : 1; + DWORD IsUsingUserModemappingAccessMode : 1; + DWORD IsKernelModeClientAllowed : 1; + DWORD IsNullFileObjectAllowed : 1; + DWORD IsPoolingDisabled : 1; + DWORD IsMethodNeitherActionCopy : 1; + DWORD IsUsingDirectIoForReadWrite : 1; + DWORD IsUsingDirectIoForIoctl : 1; + DWORD IsUsingDriverWppRecorder : 1; + } bitmap; + DWORD Dword; +}; + +typedef struct _UMDF_DRIVER_REGSITRY_INFO { + BOOLEAN IsKernelModeClientAllowed; + BOOLEAN IsNullFileObjectAllowed; + BOOLEAN IsMethodNeitherActionCopy; + BOOLEAN IsHostProcessSharingDisabled; +} UMDF_DRIVER_REGSITRY_INFO, *PUMDF_DRIVER_REGSITRY_INFO; + +VOID +GetDriverInfo( + _In_ FxDevice* Fdo, + _In_ PUMDF_DRIVER_REGSITRY_INFO RegInfo, + _Out_ UFxTelemetryDriverInfo* DriverInfo + ); diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxtypedefsum.hpp b/sdk/lib/drivers/wdf/shared/inc/private/um/fxtypedefsum.hpp new file mode 100644 index 00000000000..66fbddb392b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxtypedefsum.hpp @@ -0,0 +1,29 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + fxtypedefsKm.hpp + +Abstract: + + UMDF side defines for common names for the types + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#pragma once + +typedef FxDevice CfxDevice; +typedef FxDeviceBase CfxDeviceBase; + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/fxverifierum.h b/sdk/lib/drivers/wdf/shared/inc/private/um/fxverifierum.h new file mode 100644 index 00000000000..8f20ac7c6ae --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/fxverifierum.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxVerifierUm.cpp + +Abstract: + + Verifier code specific to UMDF + +Environment: + + user mode + +Revision History: + + + +--*/ + +#ifndef _FXVERIFIERUM_H_ +#define _FXVERIFIERUM_H_ + +__inline +VOID +FxVerifierCheckNxPoolType( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ POOL_TYPE PoolType, + _In_ ULONG PoolTag + ) + +/*++ + +Routine Description: + + This function is an empty stub for UMDF. We don't perform "no execute" + pool type checks for UMDF client drivers. + +Arguments: + + FxDriverGlobals - Supplies a pointer to the WDF driver object + globals. + + PoolType - Supplies the pool type. + + PoolTag - Supplies an optional pool tag. + +Return Value: + + None. + +--*/ + +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + UNREFERENCED_PARAMETER(PoolType); + UNREFERENCED_PARAMETER(PoolTag); +} + +#endif //_FXVERIFIERUM_H_ diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/ufxverifier.h b/sdk/lib/drivers/wdf/shared/inc/private/um/ufxverifier.h new file mode 100644 index 00000000000..12faadb4077 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/ufxverifier.h @@ -0,0 +1,26 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + UfxVerifier.h + +Abstract: + + This file contains UMDF verifier functions which are consumed by shared um + code but are implemented in drivers depot by UMDF framework. + +Environment: + + User mode only + +Revision History: + + + +--*/ + +VOID +UfxVerifierTrapNotImpl( + ); diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/umusb.h b/sdk/lib/drivers/wdf/shared/inc/private/um/umusb.h new file mode 100644 index 00000000000..695cf983193 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/umusb.h @@ -0,0 +1,260 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#pragma once + +#include + +#define UMURB_FUNCTION_SELECT_CONFIGURATION 0x0000 +#define UMURB_FUNCTION_SELECT_INTERFACE 0x0001 +#define UMURB_FUNCTION_ABORT_PIPE 0x0002 +#define UMURB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 +#define UMURB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 +#define UMURB_FUNCTION_GET_FRAME_LENGTH 0x0005 +#define UMURB_FUNCTION_SET_FRAME_LENGTH 0x0006 +#define UMURB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 +#define UMURB_FUNCTION_CONTROL_TRANSFER 0x0008 +#define UMURB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 +#define UMURB_FUNCTION_ISOCH_TRANSFER 0x000A +#define UMURB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B +#define UMURB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C +#define UMURB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D +#define UMURB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E +#define UMURB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F +#define UMURB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 +#define UMURB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 +#define UMURB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 +#define UMURB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 +#define UMURB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 +#define UMURB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 +#define UMURB_FUNCTION_RESERVED_0X0016 0x0016 +#define UMURB_FUNCTION_VENDOR_DEVICE 0x0017 +#define UMURB_FUNCTION_VENDOR_INTERFACE 0x0018 +#define UMURB_FUNCTION_VENDOR_ENDPOINT 0x0019 +#define UMURB_FUNCTION_CLASS_DEVICE 0x001A +#define UMURB_FUNCTION_CLASS_INTERFACE 0x001B +#define UMURB_FUNCTION_CLASS_ENDPOINT 0x001C +#define UMURB_FUNCTION_RESERVE_0X001D 0x001D +#define UMURB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E +#define UMURB_FUNCTION_GET_INTERFACE 0x0027 +#define UMURB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 +#define UMURB_FUNCTION_RESET_PORT 0x0029 + +// +//These are specific to user-mode (WinUsb) and have no km counterpart +// +#define UMURB_FUNCTION_QUERY_PIPE 0x0101 //in km this is done as a part of Interface info +#define UMURB_FUNCTION_SET_PIPE_POLICY 0x0102 +#define UMURB_FUNCTION_GET_PIPE_POLICY 0x0103 +#define UMURB_FUNCTION_SET_INTERFACE_POWER_POLICY 0x0104 +#define UMURB_FUNCTION_GET_INTERFACE_POWER_POLICY 0x0105 +#define UMURB_FUNCTION_ENABLE_INTERFACE_IDLE 0x0106 +#define UMURB_FUNCTION_DISABLE_INTERFACE_IDLE 0x0107 +#define UMURB_FUNCTION_FLUSH_PIPE 0x0108 +#define UMURB_FUNCTION_GET_ASSOCIATED_INTERFACE 0x0109 +#define UMURB_FUNCTION_GET_DEVICE_INFORMATION 0x010A +#define UMURB_FUNCTION_GET_DESCRIPTOR 0x010B //WinUsb has a common function for all descriptors +#define UMURB_FUNCTION_RELEASE_ASSOCIATED_INTERFACE 0x010C + +struct _UMURB_HEADER +{ + // + // Fields filled in by client driver + // + IN USHORT Length; + IN USHORT Function; + IN WINUSB_INTERFACE_HANDLE InterfaceHandle; + + OUT DWORD Status; //obtained using GetLastError(); +}; + +typedef _UMURB_HEADER* PUMURB_HEADER; + +struct _UMURB_PIPE_REQUEST { + struct _UMURB_HEADER Hdr; // function code indicates get or set. + IN UCHAR PipeID; + IN ULONG Reserved; +}; + +struct _UMURB_SELECT_INTERFACE { + struct _UMURB_HEADER Hdr; // function code indicates get or set. + IN UCHAR AlternateSetting; +}; + +struct _UMURB_CONTROL_TRANSFER { + struct _UMURB_HEADER Hdr; // function code indicates get or set. + IN UCHAR Reserved; //maybe use for PipeID + IN OUT PVOID TransferBuffer; + IN OUT ULONG TransferBufferLength; + IN WINUSB_SETUP_PACKET SetupPacket; +}; + +struct _UMURB_BULK_OR_INTERRUPT_TRANSFER { + struct _UMURB_HEADER Hdr; // function code indicates get or set. + IN UCHAR PipeID; + IN BOOL InPipe; //in km this is determined based on the pipe, + //but WinUsb has two different functions + //since host can't store pipe type and it would be expensive to discover it + //with every transfer, it is better if direction is sent in as a parameter + IN OUT ULONG TransferBufferLength; + IN OUT PVOID TransferBuffer; +}; + +struct _UMURB_CONTROL_DESCRIPTOR_REQUEST { + struct _UMURB_HEADER Hdr; // function code indicates get or set. + IN PVOID Reserved; + IN ULONG Reserved0; + IN OUT ULONG TransferBufferLength; + OUT PVOID TransferBuffer; + IN UCHAR Index; + IN UCHAR DescriptorType; + IN USHORT LanguageId; + IN USHORT Reserved2; +}; + +struct _UMURB_PIPE_POLICY_REQUEST +{ + struct _UMURB_HEADER Hdr; + IN UCHAR PipeID; + IN ULONG PolicyType; + IN OUT ULONG ValueLength; + IN OUT PVOID Value; +}; + +struct _UMURB_INTERFACE_POLICY_REQUEST +{ + struct _UMURB_HEADER Hdr; + IN ULONG PolicyType; + IN OUT ULONG ValueLength; + IN OUT PVOID Value; +}; + +struct _UMURB_QUERY_PIPE +{ + struct _UMURB_HEADER Hdr; + IN UCHAR AlternateSetting; + IN UCHAR PipeID; + OUT WINUSB_PIPE_INFORMATION PipeInformation; +}; + +struct _UMURB_CONTROL_GET_INTERFACE_REQUEST { + struct _UMURB_HEADER Hdr; // function code indicates get or set. + IN UCHAR InterfaceIndex; +}; + +struct _UMURB_GET_ASSOCIATED_INTERFACE { + IN struct _UMURB_HEADER Hdr; + IN UCHAR InterfaceIndex; + OUT WINUSB_INTERFACE_HANDLE InterfaceHandle; +}; + +struct _UMURB_INTERFACE_INFORMATION { + IN struct _UMURB_HEADER Hdr; + IN UCHAR AlternateSetting; + OUT USB_INTERFACE_DESCRIPTOR UsbInterfaceDescriptor; +}; + +struct _UMURB_DEVICE_INFORMATION { + IN struct _UMURB_HEADER Hdr; + IN ULONG InformationType; + IN OUT ULONG BufferLength; + OUT PVOID Buffer; +}; + +struct _UMURB_DESCRIPTOR_REQUEST { + IN struct _UMURB_HEADER Hdr; + IN UCHAR DescriptorType; + IN UCHAR Index; + IN USHORT LanguageID; + IN OUT ULONG BufferLength; + OUT PVOID Buffer; +}; + +typedef struct _UMURB { + union { + struct _UMURB_HEADER + UmUrbHeader; + + struct _UMURB_SELECT_INTERFACE + UmUrbSelectInterface; + + + + + + + struct _UMURB_PIPE_REQUEST + UmUrbPipeRequest; + + + + + + + + + + + + + struct _UMURB_CONTROL_TRANSFER + UmUrbControlTransfer; + + struct _UMURB_BULK_OR_INTERRUPT_TRANSFER + UmUrbBulkOrInterruptTransfer; + + // for standard control transfers on the default pipe + struct _UMURB_CONTROL_DESCRIPTOR_REQUEST + UmUrbControlDescriptorRequest; + + + + + + + + + + + struct _UMURB_CONTROL_GET_INTERFACE_REQUEST + UmUrbControlGetInterfaceRequest; + + + + + + + + + + + + + struct _UMURB_INTERFACE_POLICY_REQUEST + UmUrbInterfacePolicyRequest; + struct _UMURB_PIPE_POLICY_REQUEST + UmUrbPipePolicyRequest; + struct _UMURB_QUERY_PIPE + UmUrbQueryPipe; + struct _UMURB_GET_ASSOCIATED_INTERFACE + UmUrbGetAssociatedInterface; + struct _UMURB_INTERFACE_INFORMATION + UmUrbInterfaceInformation; + struct _UMURB_DEVICE_INFORMATION + UmUrbDeviceInformation; + struct _UMURB_DESCRIPTOR_REQUEST + UmUrbDescriptorRequest; + }; +} UMURB, *PUMURB; + + +#define FILE_DEVICE_UMDF ((ULONG)(0x8002)) + +// +// Device IO Control +// +#define UMDF_IOCTL_CODE(id) \ + CTL_CODE(FILE_DEVICE_UMDF, (id), METHOD_BUFFERED, FILE_READ_ACCESS|FILE_WRITE_ACCESS) + +#define IOCTL_INETRNAL_USB_SUBMIT_UMURB UMDF_IOCTL_CODE(0x100) + diff --git a/sdk/lib/drivers/wdf/shared/inc/private/um/wdffileobject_private.h b/sdk/lib/drivers/wdf/shared/inc/private/um/wdffileobject_private.h new file mode 100644 index 00000000000..27fd452bbeb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/inc/private/um/wdffileobject_private.h @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + wdffileobject_private.h + +Abstract: + + Defines private DDIs for WDF File Object + +Environment: + + User mode + +Revision History: + +--*/ + +#ifndef _WDFFILEOBJECT_PRIVATE_H_ +#define _WDFFILEOBJECT_PRIVATE_H_ + +// +// Interface available through WdfObjectQuery +// +// a4870f73-7c63-4e8d-ab57-ab191b522aca +DEFINE_GUID(GUID_WDFP_FILEOBJECT_INTERFACE, + 0xa4870f73, 0x7c63, 0x4e8d, 0xab, 0x57, 0xab, 0x19, 0x1b, 0x52, 0x2a, 0xca); + +typedef +NTSTATUS +(*PFN_WDFP_FILEOBJECT_INCREMENT_PROCESS_KEEP_ALIVE_COUNT)( + _In_ PWDF_DRIVER_GLOBALS WdfDriverGlobals, + _In_ WDFFILEOBJECT FileObject + ); + +typedef +NTSTATUS +(*PFN_WDFP_FILEOBJECT_DECREMENT_PROCESS_KEEP_ALIVE_COUNT)( + _In_ PWDF_DRIVER_GLOBALS WdfDriverGlobals, + _In_ WDFFILEOBJECT FileObject + ); + +// +// Structure passed in by the driver and populated by WdfObjectQuery +// +typedef struct _WDFP_FILEOBJECT_INTERFACE { + + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Private DDIs exposed through WdfObjectQuery + // + PFN_WDFP_FILEOBJECT_INCREMENT_PROCESS_KEEP_ALIVE_COUNT + WdfpFileObjectIncrementProcessKeepAliveCount; + + PFN_WDFP_FILEOBJECT_DECREMENT_PROCESS_KEEP_ALIVE_COUNT + WdfpFileObjectDecrementProcessKeepAliveCount; + +} WDFP_FILEOBJECT_INTERFACE, *PWDFP_FILEOBJECT_INTERFACE; + +// +// Used by a driver to initialize this structure +// +VOID +__inline +WDFP_FILEOBJECT_INTERFACE_INIT( + _Out_ PWDFP_FILEOBJECT_INTERFACE FileObjectInterface + ) +{ + RtlZeroMemory(FileObjectInterface, sizeof(WDFP_FILEOBJECT_INTERFACE)); + + FileObjectInterface->Size = sizeof(WDFP_FILEOBJECT_INTERFACE); +} + +#endif // _WDFFILEOBJECT_PRIVATE_H_ diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/default/fxdefaultirphandler.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/default/fxdefaultirphandler.cpp new file mode 100644 index 00000000000..517cb0cfea3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/default/fxdefaultirphandler.cpp @@ -0,0 +1,97 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDefaultIrpHandler.cpp + +Abstract: + + This module implements the default handler for IRPs that WDF does not handle + automatically for an FxDevice + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#define FX_IS_USER_MODE (TRUE) +#define FX_IS_KERNEL_MODE (FALSE) +#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#define FX_IS_USER_MODE (FALSE) +#define FX_IS_KERNEL_MODE (TRUE) +#endif + +extern "C" { +#include "mx.h" +} +#include "FxMin.hpp" + +extern "C" { +#include "FxDefaultIrpHandler.tmh" +} + +FxDefaultIrpHandler::FxDefaultIrpHandler( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ) : + FxPackage(FxDriverGlobals, Device, FX_TYPE_DEFAULT_IRP_HANDLER) +{ +} + +_Must_inspect_result_ +NTSTATUS +FxDefaultIrpHandler::Dispatch( + __in MdIrp Irp + ) +{ + UCHAR major, minor; + FxIrp fxIrp(Irp); + + major = fxIrp.GetMajorFunction(); + minor = fxIrp.GetMinorFunction(); + + if (FxDevice::_RequiresRemLock(major, minor) == FxDeviceRemLockRequired) { + if (major == IRP_MJ_POWER) { + // + // Required to be called before the power irp is completed + // + fxIrp.StartNextPowerIrp(); + } + + fxIrp.SetStatus(STATUS_INVALID_DEVICE_REQUEST); + fxIrp.SetInformation(0); + + fxIrp.CompleteRequest(IO_NO_INCREMENT); + + // + // If we are in this function, m_Device is still valid, so we can use it + // to get the WDM remove lock and not have to get it out of the + // device object from current irp stack location. + // + Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), Irp); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (m_Device->IsFilter()) { + fxIrp.SkipCurrentIrpStackLocation(); + return fxIrp.CallDriver(m_Device->GetAttachedDevice()); + } + else { + fxIrp.SetStatus(STATUS_INVALID_DEVICE_REQUEST); + fxIrp.SetInformation(0); + + fxIrp.CompleteRequest(IO_NO_INCREMENT); + return STATUS_INVALID_DEVICE_REQUEST; + } +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/general/fxpkggeneral.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/general/fxpkggeneral.cpp new file mode 100644 index 00000000000..61a8e356dd3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/general/fxpkggeneral.cpp @@ -0,0 +1,2057 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgGeneral.cpp + +Abstract: + + This module implements the wmi package for the driver frameworks. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#define FX_IS_USER_MODE (TRUE) +#define FX_IS_KERNEL_MODE (FALSE) +#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#define FX_IS_USER_MODE (FALSE) +#define FX_IS_KERNEL_MODE (TRUE) +#endif + +extern "C" { +#include "mx.h" +} +#include "FxMin.hpp" + +extern "C" { +#include "FxPkgGeneral.tmh" +} + + +FxPkgGeneral::FxPkgGeneral( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ) : + FxPackage(FxDriverGlobals, Device, FX_TYPE_PACKAGE_GENERAL) +{ + // + // The count is biased to one and not zero for control device objects. When + // a control devobj is deleted, we will decrement this bias out so that we + // know when the last handle has been closed and it is now safe to free the + // FxDevice. + // + m_OpenHandleCount = 1; + + // + // List of file object info. + // + InitializeListHead(&m_FileObjectInfoHeadList); + + m_Flags = 0; + m_ExecutionLevel = WdfExecutionLevelInheritFromParent; + m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent; + m_CallbackLockPtr = NULL; + m_CallbackLockObjectPtr = NULL; + m_DriverCreatedQueue = NULL; + m_DefaultQueueForCreates = NULL; +} + +FxPkgGeneral::~FxPkgGeneral() +{ + PLIST_ENTRY next; + + ASSERT(m_OpenHandleCount <= 1); + + // + // Delete the file object info list if present. + // + while (!IsListEmpty(&m_FileObjectInfoHeadList)) { + next = RemoveHeadList(&m_FileObjectInfoHeadList); + FxFileObjectInfo* info; + info = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + InitializeListHead(next); + delete info; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::Initialize( + __in PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + Initiliazes how the driver will handle fileobjects and their associated + event callbacks (create, close, cleanup). + + Assumes that FileObjectAttributes has been validated by the caller. + +Arguments: + DeviceInit - Chain of device_init and cx_device_init with file object config. + +Return Value: + STATUS_SUCCESS or other NTSTATUS values. + + --*/ +{ + NTSTATUS status; + PLIST_ENTRY next; + FxFileObjectInfo* fileObjInfo; + PFX_DRIVER_GLOBALS fxDriverGlobals; + + fxDriverGlobals = GetDriverGlobals(); + + // + // Init file object info. + // + if (DeviceInit->FileObject.Set) { + fileObjInfo = new(fxDriverGlobals) FxFileObjectInfo(); + if (fileObjInfo == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(fxDriverGlobals, + TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object FileObjectInfo, " + "%!STATUS!", status); + goto Done; + } + + fileObjInfo->ClassExtension = FALSE; + fileObjInfo->FileObjectClass = DeviceInit->FileObject.Class; + fileObjInfo->Attributes = DeviceInit->FileObject.Attributes; + + fileObjInfo->AutoForwardCleanupClose = + DeviceInit->FileObject.AutoForwardCleanupClose; + + fileObjInfo->EvtFileCreate.Method = + DeviceInit->FileObject.Callbacks.EvtDeviceFileCreate; + + fileObjInfo->EvtFileCleanup.Method = + DeviceInit->FileObject.Callbacks.EvtFileCleanup; + + fileObjInfo->EvtFileClose.Method = + DeviceInit->FileObject.Callbacks.EvtFileClose; + + InsertTailList(&m_FileObjectInfoHeadList, &fileObjInfo->ListEntry); + + m_Flags |= FX_PKG_GENERAL_FLAG_CLIENT_INFO; + + if (fileObjInfo->EvtFileCreate.Method != NULL) { + m_Flags |= FX_PKG_GENERAL_FLAG_CLIENT_CREATE; + } + } + + // + // Build file object info chain for any class extension. + // + for (next = DeviceInit->CxDeviceInitListHead.Flink; + next != &DeviceInit->CxDeviceInitListHead; + next = next->Flink) { + + PWDFCXDEVICE_INIT cxInit; + + cxInit = CONTAINING_RECORD(next, WDFCXDEVICE_INIT, ListEntry); + + if (cxInit->FileObject.Set == FALSE) { + continue; + } + + fileObjInfo = new(fxDriverGlobals) FxFileObjectInfo(); + if (fileObjInfo == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(fxDriverGlobals, + TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object FileObjectInfo, " + "%!STATUS!", status); + goto Done; + } + + fileObjInfo->ClassExtension = TRUE; + fileObjInfo->FileObjectClass = cxInit->FileObject.Class; + fileObjInfo->Attributes = cxInit->FileObject.Attributes; + + fileObjInfo->AutoForwardCleanupClose = + cxInit->FileObject.AutoForwardCleanupClose; + + fileObjInfo->EvtCxFileCreate.Method = + cxInit->FileObject.Callbacks.EvtCxDeviceFileCreate; + + fileObjInfo->EvtFileCleanup.Method = + cxInit->FileObject.Callbacks.EvtFileCleanup; + + fileObjInfo->EvtFileClose.Method = + cxInit->FileObject.Callbacks.EvtFileClose; + + fileObjInfo->CxDeviceInfo = cxInit->CxDeviceInfo; + + InsertTailList(&m_FileObjectInfoHeadList, &fileObjInfo->ListEntry); + + m_Flags |= FX_PKG_GENERAL_FLAG_CX_INFO; + + if (fileObjInfo->EvtCxFileCreate.Method != NULL) { + m_Flags |= FX_PKG_GENERAL_FLAG_CX_CREATE; + } + } + + // + // Nothing to do if list if empty. + // + if (IsListEmpty(&m_FileObjectInfoHeadList)) { + status = STATUS_SUCCESS; + goto Done; + } + + // + // We will enable this once the unlocking model is figured out. + // It's not okay to sent request downstack with the presentation lock held. + // + status = ConfigureConstraints(&m_FileObjectInfoHeadList); + if(!NT_SUCCESS(status)) { + goto Done; + } + + // + // Configure file object class. + // + status = ConfigureFileObjectClass(&m_FileObjectInfoHeadList); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = STATUS_SUCCESS; + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::ConfigureConstraints( + __in PLIST_ENTRY FileObjInfoList + ) +/*++ + +Routine Description: + + Configure the callback synchronization according to the configuration supplied by the + client and class extension device driver. + It is a requirement for this driver chain (CXs and client driver) to use the same settings. + +Arguments: + FileObjInfoList - List of FxFileObjectInfo structs. + +Returns: + NTSTATUS + +--*/ +{ + WDF_EXECUTION_LEVEL execLevel, parentExecLevel; + WDF_SYNCHRONIZATION_SCOPE synchScope, parentSynchScope; + BOOLEAN automaticLockingRequired; + PLIST_ENTRY next; + FxFileObjectInfo *fileObjInfo; + NTSTATUS status; + PFX_DRIVER_GLOBALS fxDriverGlobals; + + automaticLockingRequired = FALSE; + fxDriverGlobals = GetDriverGlobals(); + + ASSERT(!IsListEmpty(FileObjInfoList)); + + // + // Get parent values. + // + m_Device->GetConstraints(&parentExecLevel, &parentSynchScope); + + // + // Default constraints settings when driver uses WDF_NO_OBJECT_ATTRIBUTES: + // + // v1.9 and below: + // WdfExecutionLevelDispatch and WdfSynchronizationScopeNone + // + // v1.11 and above: + // WdfExecutionLevelPassive and WdfSynchronizationScopeNone + // + // In v1.9 and below if driver used WDF_NO_OBJECT_ATTRIBUTES for + // the file object's attributes, the synchronization scope and execution + // level were left uninitialized (i.e., zero), which means that WDF + // defaulted to WdfSynchronizationScopeInvalid and WdfExecutionLevelInvalid, + // WDF interpreted these values as no_passive and no_synchronization. + // + // This default execution level is used when disposing the device's + // general package object and file object object. + // Independently of these settings WDF guarantees that Create, + // Cleanup and Close callbacks are always called at passive level. + // + m_ExecutionLevel = fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11) ? + WdfExecutionLevelPassive : + WdfExecutionLevelDispatch; + + m_SynchronizationScope = WdfSynchronizationScopeNone; + + // + // Make sure file object info chain follow these constrains: + // Cx's synch scope: none + // + for (next = FileObjInfoList->Blink; + next != FileObjInfoList; + next = next->Blink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + // + // Size is zero if driver didn't specify any attributes. + // + if (0 == fileObjInfo->Attributes.Size) { + continue; + } + + // + // Execution level checks. + // + execLevel = fileObjInfo->Attributes.ExecutionLevel; + if (WdfExecutionLevelInheritFromParent == execLevel) { + execLevel = parentExecLevel; + } + + // + // Passive level wins over DPC level. + // + if (WdfExecutionLevelPassive == execLevel) { + m_ExecutionLevel = WdfExecutionLevelPassive; + } + + // + // Synchronization scope checks. + // + synchScope = fileObjInfo->Attributes.SynchronizationScope; + if (WdfSynchronizationScopeInheritFromParent == synchScope) { + synchScope = parentSynchScope; + } + + // + // Make sure the Cx's synch scope is none. + // + if (fileObjInfo->ClassExtension) { + if (synchScope != WdfSynchronizationScopeNone) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Driver 0x%p - Device 0x%p - synchronization scope: " + "%!WDF_SYNCHRONIZATION_SCOPE! should be" + "WdfSynchronizationScopeNone, %!STATUS!", + m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), + m_Device->GetHandle(), + synchScope, + status + ); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + } + else { + // + // Always use client's synch scope for file object. + // + m_SynchronizationScope = synchScope; + } + } + + if(m_SynchronizationScope == WdfSynchronizationScopeQueue) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WdfSynchronizationScopeQueue is not allowed on " + "FileObject, %!STATUS!", + status); + goto Done; + } + + if (m_ExecutionLevel == WdfExecutionLevelPassive) { + + // + // Mark FxObject as passive level to ensure that Dispose and Destroy + // callbacks are passive to the driver + // + MarkPassiveCallbacks(ObjectDoNotLock); + // + // We aren't going to use a workitem to defer the invocation of fileevents + // to passive-level if the caller is at DISPATCH_LEVEL because we wouldn't + // be able to guarantee the caller's context for fileevents. It's up to the + // driver writer to ensure that the layer above doesn't send create requests + // at dispatch-level. + // + } + + if(m_SynchronizationScope == WdfSynchronizationScopeNone) { + status = STATUS_SUCCESS; + goto Done; + } + + if(m_SynchronizationScope == WdfSynchronizationScopeDevice) { + // + // Since FileEvents can be invoked only at passive-level, we check the + // parent executionlevel to see if it's set to passive. If not, we return an error + // because we can't use the presentation lock of the device. + // + if(parentExecLevel != WdfExecutionLevelPassive) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WdfSynchronizationScopeDevice or " + "WdfSynchronizationScopeInheritFromParent " + "allowed only if the parent WDFDEVICE 0x%p, " + "ExecutionLevel is passive, %!STATUS!", + m_Device->GetHandle(), status); + goto Done; + } + + m_CallbackLockPtr = m_Device->GetCallbackLockPtr(&m_CallbackLockObjectPtr); + automaticLockingRequired = TRUE; + } + + // + // Set lock constraint in client's callbacks object only. + // + if (automaticLockingRequired) { + if (!IsListEmpty(FileObjInfoList)) { + fileObjInfo = CONTAINING_RECORD(FileObjInfoList->Flink, + FxFileObjectInfo, + ListEntry); + + if (FALSE == fileObjInfo->ClassExtension) { + fileObjInfo->EvtFileCreate.SetCallbackLockPtr(m_CallbackLockPtr); + fileObjInfo->EvtFileCleanup.SetCallbackLockPtr(m_CallbackLockPtr); + fileObjInfo->EvtFileClose.SetCallbackLockPtr(m_CallbackLockPtr); + } + } + } + + status = STATUS_SUCCESS; + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::ConfigureFileObjectClass( + __in PLIST_ENTRY FileObjInfoList + ) +/*++ + +Routine Description: + + Configure the file object class for this device. + + These are the possible class settings: + + WdfFileObjectNotRequired + WdfFileObjectWdfCanUseFsContext* + WdfFileObjectWdfCanUseFsContext2*, + WdfFileObjectWdfCannotUseFsContexts* + + * these can also be combined with WdfFileObjectCanBeOptional flag. + + Logic: + + - default: not_required. + - if cx/driver selects not_required, skip it. + - if cx/driver selects !not_required, than + . if everyone agrees on the setting, use that setting. + . else use cannot_use_fs_contexts. + +Arguments: + FileObjInfoList - List of FxFileObjectInfo structs. + +Returns: + NTSTATUS + +--*/ +{ + PLIST_ENTRY next; + FxFileObjectInfo* fileObjInfo; + NTSTATUS status; + PFX_DRIVER_GLOBALS fxDriverGlobals; + WDF_FILEOBJECT_CLASS fileObjClass; + FxCxDeviceInfo* previousCxInfo; + + fxDriverGlobals = GetDriverGlobals(); + fileObjClass = WdfFileObjectNotRequired; + previousCxInfo = NULL; + + ASSERT(!IsListEmpty(FileObjInfoList)); + + // + // Compute the execution level and synchronization scope for all the chain. + // + for (next = FileObjInfoList->Blink; + next != FileObjInfoList; + next = next->Blink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + // + // If not required, skip it. + // + if (WdfFileObjectNotRequired == fileObjInfo->FileObjectClass) { + continue; + } + + // + // If the same, skip it. + // + if (fileObjClass == fileObjInfo->FileObjectClass) { + continue; + } + + // + // If not set yet, use new value. + // + if (WdfFileObjectNotRequired == fileObjClass) { + fileObjClass = fileObjInfo->FileObjectClass; + previousCxInfo = fileObjInfo->CxDeviceInfo; + continue; + } + + // + // Make sure optional flag is compatible. + // + if (FxIsFileObjectOptional(fileObjClass) != + FxIsFileObjectOptional(fileObjInfo->FileObjectClass)) { + + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + fxDriverGlobals, + TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Device 0x%p - " + "Driver 0x%p - WdfFileObjectCanBeOptional (%d) is not " + "compatible with wdf extension " + "Driver 0x%p - WdfFileObjectCanBeOptional (%d), %!STATUS!", + m_Device->GetHandle(), + m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), + FxIsFileObjectOptional(fileObjInfo->FileObjectClass) ? 1:0, + previousCxInfo->Driver->GetHandle(), + FxIsFileObjectOptional(fileObjClass) ? 1:0, + status + ); + + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Drivers do not agree on the location, set cannot use fx contexts. + // + fileObjClass = WdfFileObjectWdfCannotUseFsContexts; + if (FxIsFileObjectOptional(fileObjInfo->FileObjectClass)) { + fileObjClass = (WDF_FILEOBJECT_CLASS) + ((ULONG)fileObjClass | WdfFileObjectCanBeOptional); + } + + DoTraceLevelMessage( + fxDriverGlobals, + TRACE_LEVEL_INFORMATION, TRACINGDEVICE, + "Converting file object class for Driver 0x%p - Device 0x%p, " + "from 0x%x to 0x%x", + m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), + m_Device->GetHandle(), + fileObjInfo->FileObjectClass, + fileObjClass + ); + } + + // + // Set the file object support level on the FxDevice + // + m_Device->SetFileObjectClass(fileObjClass); + + status = STATUS_SUCCESS; + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::PostCreateDeviceInitialize( + __in PWDFDEVICE_INIT Init + ) +/*++ + +Routine Description: + Optionally registers a shutdown and last chance shutdown notification on + behalf of the device. + +Arguments: + Init - Initialization structure which will indicate if registration is required + +Return Value: + NTSTATUS + + --*/ +{ + MdDeviceObject pDevice; + NTSTATUS status; + WDF_IO_QUEUE_CONFIG queueConfig; + WDF_OBJECT_ATTRIBUTES attributes; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + status = STATUS_SUCCESS; + + + + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + if (Init->Control.Flags != 0) { + pDevice = m_Device->GetDeviceObject(); + + if (Init->Control.Flags & WdfDeviceShutdown) { + status = IoRegisterShutdownNotification(pDevice); + } + + if (NT_SUCCESS(status) && + (Init->Control.Flags & WdfDeviceLastChanceShutdown)) { + status = IoRegisterLastChanceShutdownNotification(pDevice); + + } + + if (NT_SUCCESS(status)) { + // + // IoDeleteDevice will automatically unregister the shutdown + // notifications if the device is deleted before the machine is + // shutdown, so we don't need to track registration beyond this point. + // + m_EvtDeviceShutdown.m_Method = Init->Control.ShutdownNotification; + } + else { + // + // This unregisters both the normal and last chance notifications + // + IoUnregisterShutdownNotification(pDevice); + } + } +#else + UNREFERENCED_PARAMETER(Init); + UNREFERENCED_PARAMETER(pDevice); +#endif + + if (NT_SUCCESS(status) && (m_Flags & FX_PKG_GENERAL_FLAG_CREATE)) { + // + // Create an internal queue to track create requests presented to the driver. + // This special queue is used so that we can invoke the events in the context + // of the caller. + // + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchManual); + + // + // non power managed queue because we don't anticipate drivers touching + // hardware in the fileevent callbacks. If they do, then they should make sure + // to power up the device. + // + queueConfig.PowerManaged = WdfFalse; + + // + // Queue inherits the sync & exec level of fileobject. + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ExecutionLevel = m_ExecutionLevel; + attributes.SynchronizationScope = m_SynchronizationScope; + + status = m_Device->m_PkgIo->CreateQueue(&queueConfig, + &attributes, + NULL, + &m_DefaultQueueForCreates); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Unable to create an internal queue for creates for WDFDEVICE " + "0x%p, %!STATUS!", m_Device->GetHandle(), status); + return status; + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::ConfigureForwarding( + __in FxIoQueue* TargetQueue + ) +/*++ + +Routine Description: + + Used to register driver specified for dispatching create requests. + +Arguments: + +Return Value: + + NTSTATUS + + --*/ +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + KIRQL irql; + + status = STATUS_SUCCESS; + pFxDriverGlobals = GetDriverGlobals(); + + if(TargetQueue->IsIoEventHandlerRegistered(WdfRequestTypeCreate) == FALSE){ + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Must have EvtIoDefault registered to receive " + "WdfRequestTypeCreate requests for WDFQUEUE 0x%p, " + "%!STATUS!", TargetQueue->GetObjectHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + Lock(&irql); + + if (m_DriverCreatedQueue) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Another WDFQUEUE 0x%p is already configured for auto dispatching " + "create request, %!STATUS!", + m_DriverCreatedQueue->GetObjectHandle(), status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + else { + m_DriverCreatedQueue = TargetQueue; + } + + Unlock(irql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::Dispatch( + __inout MdIrp Irp + ) +/*++ + +Routine Description: + + Dispatch routine for handling create, cleanup, close, and shutdown requests. + +Arguments: + + +Return Value: + + NTSTATUS + + --*/ +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + FxIrp fxIrp(Irp); + + FX_TRACK_DRIVER(pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ! IRP 0x%p", + m_Device->GetHandle(), m_Device->GetDeviceObject(), + fxIrp.GetMajorFunction(), Irp); + + switch (fxIrp.GetMajorFunction()) { + case IRP_MJ_CREATE: + status = OnCreate(&fxIrp); + break; + + case IRP_MJ_CLOSE: + status = OnClose(&fxIrp); + break; + + case IRP_MJ_CLEANUP: + status = OnCleanup(&fxIrp); + break; + + case IRP_MJ_SHUTDOWN: + status = OnShutdown(&fxIrp); + break; + + default: + ASSERT(FALSE); + status = STATUS_NOT_SUPPORTED; + fxIrp.SetStatus(status); + fxIrp.CompleteRequest(IO_NO_INCREMENT); + break; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::OnCreate( + __inout FxIrp* FxIrp + ) +/*++ + +Routine Description: + + 1) Allow only one handle to be open for exclusive device. + 2) Create a WDFFILEOBJECT to represent the WDM fileobject. This + fileobject is created only if the driver registers for EvtFile events and + doesn't specify WdfFileObjectNotRequired. If the file-events are not + registered, the default FileobjectClass is WdfFileObjectNotRequired - set + during DeviceInit. + 3) If the EvtFileCreate event is *not* set or any driver queue is not configured, + then complete or forward the request to the lower + driver depending on AutoForwardCleanupClose. AutoForwardCleanupClose + is set to TRUE by default for filter drivers. + 4) Create a FxRequest. + 5) First try to dispatch it to a driver specified queue. + 6) If there is no driver specified queue, then check to see if the driver has + registered EvtDeviceFileCreate event. + 7) If EvtFileCreate is set then dispatch the request to to an internal + manual queue, retrieve the request by fileobject and present the request to + the driver in the EvtFileCreate event. This allow the driver to forward the request + to another queue to mark the request cancelable and complete it later. + +Arguments: + +Return Value: + + NTSTATUS + + --*/ +{ + NTSTATUS status; + FxFileObject* pFxFO ; + WDFFILEOBJECT hwdfFO; + FxRequest * pRequest; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + MdFileObject fileObject; + LONG count; + BOOLEAN inCriticalRegion; + BOOLEAN inDefaultQueue; + FxFileObjectInfo* fileObjInfo; + WDF_OBJECT_ATTRIBUTES attributes; + PLIST_ENTRY next; + + pFxFO = NULL; + hwdfFO = NULL; + pRequest = NULL; + inCriticalRegion = FALSE; + inDefaultQueue = FALSE; + pFxDriverGlobals = GetDriverGlobals(); + fileObject = FxIrp->GetFileObject(); + fileObjInfo = NULL; + + // + // Check for exclusivity. + // + count = InterlockedIncrement(&m_OpenHandleCount); + + // + // The count is biased by one to help track when to delete the control + // device, so we need to check for 2, not 1. + // + if (m_Device->IsExclusive() && count > 2) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Exclusive WDFDEVICE 0x%p, only one open handle is allowed", + m_Device->GetHandle()); + status = STATUS_ACCESS_DENIED; + goto Error; + } + + // ------------------------------------------------------------------------ + // + // Create WDFFILEOBJECT. By default we allocate the root driver's file obj + // context; then we attach the other file obj contexts. + // + + // + // Init the file obj's attributes. Use default if not present (legacy behavior). + // + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + if (!IsListEmpty(&m_FileObjectInfoHeadList)) { + // + // file obj info is set, use the top most driver's info, i.e., cx if present. + // + fileObjInfo = CONTAINING_RECORD(m_FileObjectInfoHeadList.Blink, + FxFileObjectInfo, + ListEntry); + + // + // Use this layer's attributes if present. + // Size is zero if driver didn't specify file object's attributes. + // + if (0 != fileObjInfo->Attributes.Size) { + ASSERT(fileObjInfo->Attributes.Size == sizeof(WDF_OBJECT_ATTRIBUTES)); + attributes = fileObjInfo->Attributes; + } + + // + // Use computed constraint settings. + // + attributes.ExecutionLevel = m_ExecutionLevel; + attributes.SynchronizationScope = m_SynchronizationScope; + } + + // + // Create the file object. + // + status = FxFileObject::_CreateFileObject( + m_Device, + FxIrp->GetIrp(), + m_Device->GetFileObjectClass(), + &attributes, + fileObject, + &pFxFO + ); + + if (!NT_SUCCESS(status) ) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not create WDFFILEOBJECT for WDFDEVICE 0x%p, failing " + "IRP_MJ_CREATE %!STATUS!", m_Device->GetHandle(), status); + goto Error; + } + + if (pFxFO != NULL) { + hwdfFO = pFxFO->GetHandle(); + + // + // If any, attach the file obj's contexts of the other drivers in this chain. + // + for (next = m_FileObjectInfoHeadList.Blink->Blink; // skip one. + next != &m_FileObjectInfoHeadList; + next = next->Blink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + attributes = fileObjInfo->Attributes; + + // + // Size is zero if driver didn't specify file object's attributes. + // + if (0 == attributes.Size) { + continue; + } + + // + // Don't need these settings for extra contexts. + // + attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent; + attributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent; + attributes.ParentObject = NULL; + + status = FxObjectAllocateContext(pFxFO, + &attributes, + TRUE, + NULL); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Couldn't allocate file object context 0x%p for " + "device 0x%p - driver 0x%p, %!STATUS!", + &fileObjInfo->Attributes, + m_Device->GetHandle(), + m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), + status + ); + + goto Error; + } + } + } + + // ------------------------------------------------------------------------ + // + // If there is no driver configured queue or m_EvtFileCreate is not registered, + // complete the request with status-success. The reason for making this + // check after creating the fileobject is to allow WdfRequestGetFileObject even + // if the driver hasn't registered any file-event callbacks. + // + if (m_DriverCreatedQueue == NULL && + (m_Flags & FX_PKG_GENERAL_FLAG_CREATE) == 0) { + + // + // Check to see if the driver has opted to autoforward cleanup and close. + // If so, we should forward create requests also. Else, we should + // complete the request with STATUS_SUCCESS. Note, if the driver is + // a filter driver, the default value of m_AutoForwardCleanupClose is TRUE. + // + // + if (m_Device->m_AutoForwardCleanupClose) { + status = ForwardCreateRequest(FxIrp, _CreateCompletionRoutine, this); + // + // _CreateCompletionRoutine will do the cleanup when the request is + // completed with error status by the lower driver. + // + } + else { + status = STATUS_SUCCESS; + FxIrp->SetStatus(status); + FxIrp->SetInformation(0); + FxIrp->CompleteRequest(IO_NO_INCREMENT); + } + + goto RequestIsGone; + } + + // ------------------------------------------------------------------------ + // + // Create a FxRequest for this IRP. By default we allocate the top most driver's request + // context; then we attach the other request contexts. + // + + // + // Init the request's attributes. + // + if (!IsListEmpty(&m_FileObjectInfoHeadList)) { + // + // file obj info is set, use the top most driver's info, i.e., cx if present. + // + fileObjInfo = CONTAINING_RECORD(m_FileObjectInfoHeadList.Blink, + FxFileObjectInfo, + ListEntry); + if (fileObjInfo->ClassExtension) { + attributes = fileObjInfo->CxDeviceInfo->RequestAttributes; + } + else { + attributes = *m_Device->GetRequestAttributes(); + } + } + else { + attributes = *m_Device->GetRequestAttributes(); + } + + if (m_Device->IsCxInIoPath()) { + // + // Apply cx's constrains for create requests: + // + attributes.ExecutionLevel = WdfExecutionLevelDispatch; + attributes.SynchronizationScope = WdfSynchronizationScopeNone; + attributes.ParentObject = NULL; + } + + // + // Create the request. + // + status = FxRequest::_CreateForPackage(m_Device, + &attributes, + FxIrp->GetIrp(), + &pRequest); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not create request for WDFDEVICE 0x%p, %!STATUS!", + m_Device->GetHandle(), status); + goto Error; + } + + // + // If any, attach the request's contexts of the other drivers in this chain. + // + for (next = m_FileObjectInfoHeadList.Blink->Blink; // skip one. + next != &m_FileObjectInfoHeadList; + next = next->Blink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + if (fileObjInfo->ClassExtension) { + attributes = fileObjInfo->CxDeviceInfo->RequestAttributes; + } + else { + attributes = *m_Device->GetRequestAttributes(); + } + + // + // Size is zero if driver didn't specify request's attributes. + // + if (0 == attributes.Size) { + continue; + } + + // + // Don't need these settings for extra contexts. + // + attributes.ExecutionLevel = WdfExecutionLevelInheritFromParent; + attributes.SynchronizationScope = WdfSynchronizationScopeInheritFromParent; + attributes.ParentObject = NULL; + + status = FxObjectAllocateContext( + pRequest, + &attributes, + TRUE, + NULL); + + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Couldn't allocate request context for " + "device 0x%p - driver 0x%p, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetCxDriver(fileObjInfo->CxDeviceInfo)->GetHandle(), + status + ); + + goto Error; + } + } + + // + // Disable thread suspension beyond this point by entering critical region. + // + if (Mx::MxGetCurrentIrql() <= APC_LEVEL) + { + Mx::MxEnterCriticalRegion(); + inCriticalRegion = TRUE; + } + + // ------------------------------------------------------------------------ + // + // Queue request in default queue before invoking cx or client's create callbacks. + // + if ((m_Flags & FX_PKG_GENERAL_FLAG_CX_CREATE) || + m_DriverCreatedQueue == NULL) { + + FxRequest* outputRequest; + + ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CREATE); + + // + // Make sure we are calling FileEvents at the right IRQL level. + // + if (m_ExecutionLevel == WdfExecutionLevelPassive && + Mx::MxGetCurrentIrql() >= DISPATCH_LEVEL) { + + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFDEVICE 0x%p cannot handle create request at or above " + "dispatch-level, fail the Irp: 0x%p, %!STATUS!", + m_Device->GetObjectHandle(), FxIrp->GetIrp(), status); + + goto Error; + } + + // + // Now queue and immediately retrieve the request by FileObject. + // QueueRequest will return an error if the queue is not accepting request + // or the request is already cancelled. Either way, the request is completed by + // the FxIoQueue. + // + status = m_DefaultQueueForCreates->QueueRequest(pRequest); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!", + m_DefaultQueueForCreates->GetObjectHandle(), status); + goto RequestIsGone; + } + + status = m_DefaultQueueForCreates->GetRequest(fileObject, + NULL, + &outputRequest); + if (!NT_SUCCESS(status)) { + // + // Oops, request got cancelled and completed by another thread. + // + ASSERT(status == STATUS_NO_MORE_ENTRIES); + status = STATUS_PENDING; // IRP was already marked pending. + goto RequestIsGone; + } + + ASSERT(outputRequest == pRequest); + + inDefaultQueue = TRUE; + } + + // ------------------------------------------------------------------------ + // + // Invoke Cx's create callbacks. Here we add the cx's file obj and request contexts. + // + if (m_Flags & FX_PKG_GENERAL_FLAG_CX_CREATE) { + + // + // Loop through all cx's file obj info. + // + for (next = m_FileObjectInfoHeadList.Blink; + next != &m_FileObjectInfoHeadList; + next = next->Blink) { + + // + // Get ready to invoke next layer cx's create. + // + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + // + // Do not invoke the client driver's create callback (if any). For compatibility + // we need to check first the driver 'create' queue. + // + if (FALSE == fileObjInfo->ClassExtension) { + break; + } + + ASSERT(fileObjInfo->EvtFileCreate.Method == NULL); + ASSERT(fileObjInfo->EvtCxFileCreate.Method != NULL); + + // + // Keep track where we stopped (end, not inclusive node). + // Note that we cannot do this after the Invoke b/c File Object + // may be gone by the time callback returns. + // + if (pFxFO) { + pFxFO->SetPkgCleanupCloseContext(next->Blink); + } + + // + // Invoke knows how to handle NULL callbacks. + // + if (fileObjInfo->EvtCxFileCreate.Invoke( + m_Device->GetHandle(), + (WDFREQUEST)pRequest->GetObjectHandle(), + hwdfFO)) { + // + // Callback claimed the request. + // + status = STATUS_PENDING; // IRP was already marked pending. + goto RequestIsGone; + } + } + } + + //------------------------------------------------------------------------- + // + // First check for driver configured queue. If there is one, dispatch the request + // to that queue. + // + if (m_DriverCreatedQueue != NULL) { + if (inDefaultQueue) { + ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CX_INFO); + + status = m_DefaultQueueForCreates->ForwardRequest( + m_DriverCreatedQueue, + pRequest); + + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!", + m_DriverCreatedQueue->GetObjectHandle(), status); + + pRequest->Complete(status); + } + + status = STATUS_PENDING; // IRP was already marked pending. + goto RequestIsGone; + } + else { + ASSERT(pRequest->GetRefCnt() == 1); + // + // QueueRequest will return an error if the queue is not accepting request + // or the request is already cancelled. Either way, the request is completed by + // the FxIoQueue. + // + status = m_DriverCreatedQueue->QueueRequest(pRequest); + if(!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Couldn't forward request to the WDFQUEUE 0x%p, %!STATUS!", + m_DriverCreatedQueue->GetObjectHandle(), status); + } + + goto RequestIsGone; + } + } + + //------------------------------------------------------------------------- + // + // At this point invoke the client driver callback if present. + // + if (m_Flags & FX_PKG_GENERAL_FLAG_CLIENT_CREATE) { + ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CLIENT_INFO); + ASSERT(TRUE == inDefaultQueue); + ASSERT(fileObjInfo->EvtFileCreate.Method != NULL); + ASSERT(fileObjInfo->EvtCxFileCreate.Method == NULL); + + // + // Invoke the client driver create requests. + // + fileObjInfo->EvtFileCreate.Invoke( + m_Device->GetHandle(), + (WDFREQUEST)pRequest->GetObjectHandle(), + hwdfFO); + // + // QueueRequest has already marked the request pending. + // + status = STATUS_PENDING; + goto RequestIsGone; + } + + // + // We should be here only if CX's create returned 'continue' but client didn't have + // a create callback. + // + ASSERT(m_Flags & FX_PKG_GENERAL_FLAG_CX_INFO); + + // + // Check to see if the driver has opted to autoforward cleanup and close. + // If so, we should forward create requests to lower drivers. Else, we should + // complete the request with STATUS_SUCCESS. Note, if the driver is + // a filter driver, the default value of m_AutoForwardCleanupClose is TRUE. + // + if (m_Device->m_AutoForwardCleanupClose) { + (void)ForwardCreateRequest(FxIrp, _CreateCompletionRoutine2, pRequest); + // + // _CreateCompletionRoutine2 will complete the WDF request. + // + } + else { + pRequest->Complete(STATUS_SUCCESS); + } + + // + // Done processing this request. + // + status = STATUS_PENDING; // IRP was already marked pending. + goto RequestIsGone; + +Error: + if (pRequest != NULL) { + pRequest->DeleteFromFailedCreate(); + pRequest = NULL; + } + + ASSERT(!NT_SUCCESS(status)); + + if (pFxFO != NULL) { + pFxFO->DeleteFileObjectFromFailedCreate(); + pFxFO = NULL; + } + + // + // NOTE: after this call, this object may have been deleted! + // + DecrementOpenHandleCount(); + + FxIrp->SetStatus(status); + FxIrp->SetInformation(0); + FxIrp->CompleteRequest(IO_NO_INCREMENT); + + // fallthrough + +RequestIsGone: + + // + // We have lost the ownership of the request. We have either successfully + // presented the request to the driver or the queue function we called to + // present the request returned error but completed the FxRequest on its own. + // Either way we don't need to worry about cleaning up the resources + // (fileobject, handle-count, etc) because the FxRequest:Completion routine + // will call FxPkgGeneral::CreateCompleted to post process IRP upon completion. + // + if (inCriticalRegion) { + Mx::MxLeaveCriticalRegion(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::ForwardCreateRequest( + __in FxIrp* Irp, + __in MdCompletionRoutine CompletionRoutine, + __in PVOID Context + ) +{ + NTSTATUS status; + + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), + CompletionRoutine, + Context); + status = Irp->CallDriver(m_Device->GetAttachedDevice()); + + return status; +} + +VOID +FxPkgGeneral::CreateCompleted( + __in FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is called when the WDFREQUEST for Irp + is completed either by the driver or framework. + + Here, we check the completion status of the IRP and if + it's not success, we destroy the fileobject and decrement + the openhandle count on the device. + +Arguments: + +Return Value: + + VOID + + --*/ +{ + NTSTATUS status = Irp->GetStatus(); + + // + // If the create is completed with error status, + // we destroy the WDFFILEOBJECT since the IoMgr will destroy + // the PFILE_OBJECT if the IRP_MJ_CREATE fails and wouldn't send + // Cleanup or Close IRP. + // + if (!NT_SUCCESS(status)) { + + // Now destroy the WDFFILEOBJECT + FxFileObject::_DestroyFileObject( + m_Device, + m_Device->GetFileObjectClass(), + Irp->GetFileObject() + ); + + DecrementOpenHandleCount(); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::_CreateCompletionRoutine( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in_opt PVOID Context + ) +/*++ + +Routine Description: + + This completion routine is set only when the IRP is forwarded + directly by the framework to the lower driver. Framework forwards + the IRP request if: + 1) The driver happens to be a filter and hasn't registered any + callbacks to handle create request. + 2) The driver is not a filter but has explicitly requested the + framework to autoforward create/cleanup/close requests down. + + We need to intercept the create in the completion path to find + out whether the lower driver has succeeded or failed the request. + If the request is failed, we should inform the package so that + it can cleanup the state because I/O manager wouldn't send + cleanup & close requests if the create is failed. + +Arguments: + +Return Value: + + NTSTATUS + + --*/ +{ + FxPkgGeneral* pFxPkgGeneral; + FxIrp irp(OriginalIrp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pFxPkgGeneral = (FxPkgGeneral*) Context; + + ASSERT(pFxPkgGeneral != NULL); + + // + // Let the package know that create is completed + // so that it can cleanup the state. + // + pFxPkgGeneral->CreateCompleted(&irp); + + // + // Let the irp continue on its way. + // + irp.PropagatePendingReturned(); + + return irp.GetStatus(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::_CreateCompletionRoutine2( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in_opt PVOID Context + ) +/*++ + +Routine Description: + + Routine Description: + + This completion routine is set only when the create request is forwarded by the + framework to the lower driver. Framework forwards the create request using this + completion routine if: + + 1) Class extension's create callback is set by did not claim the request. + 2) Client driver did not register for a create callback or a create queue. + +Arguments: + +Return Value: + + STATUS_MORE_PROCESSING_REQUIRED + + --*/ +{ + FxRequest* request; + FxIrp irp(OriginalIrp); + + UNREFERENCED_PARAMETER(DeviceObject); + + request = (FxRequest*) Context; + + ASSERT(request != NULL); + + irp.PropagatePendingReturned(); + + request->Complete(irp.GetStatus()); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::OnCleanup( + __inout FxIrp* FxIrp + ) +/*++ + +Routine Description: + + Called in response to IRP_MJ_CLEANUP. This means an handle to + the device is closed. After invoking the driver registered callback + event, flush all the queues to cancel requests that belong to the + file handle being closed. There is however a possibility for + new requests to come in with the same fileobject. + + + + + +Arguments: + +Return Value: + + NTSTATUS + + --*/ +{ + NTSTATUS status; + FxFileObject* pFxFO = NULL; + WDFFILEOBJECT hwdfFO = NULL; + PLIST_ENTRY next; + FxFileObjectInfo* fileObjInfo; + MxFileObject fileObject; + + + + + + + // + // Check to see if the fileobject represents a stream fileobject + // created using IoCreateStreamFileObjectLite. + // + fileObject.SetFileObject(FxIrp->GetFileObject()); + if (FxIrp->GetFileObject() && + (fileObject.GetFlags() & FO_STREAM_FILE)){ + status = STATUS_SUCCESS; + goto Passthru; + } + + status = FxFileObject::_GetFileObjectFromWdm( + m_Device, + m_Device->GetFileObjectClass(), + FxIrp->GetFileObject(), + &pFxFO + ); + + ASSERT(status == STATUS_SUCCESS); + + if (pFxFO != NULL && NT_SUCCESS(status)) { + hwdfFO = pFxFO->GetHandle(); + } + + // + // Invoke cleanup callbacks. + // + if (NULL == pFxFO) { + // + // Invoke cleanup callbacks of next layer (cx or client driver) based on the + // autoforward setting of previous layer. (top to bottom). + // AutoforwardCleanupClose set to FALSE with a not null create callback + // means that create request was never forwarded to lower layer. + // + for (next = m_FileObjectInfoHeadList.Blink; + next != &m_FileObjectInfoHeadList; + next = next->Blink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + if (WdfFalse == fileObjInfo->AutoForwardCleanupClose && + fileObjInfo->EvtCxFileCreate.Method != NULL) { + next = next->Blink; // one before the real start entry. + break; + } + } + } + else { + // + // 'OnCreate' sets this package context. + // + next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext(); + if (NULL == next) { + next = &m_FileObjectInfoHeadList; + } + } + + // + // Invoke cleanup callbacks only if this layer (cx or client driver) had the + // opprtunity to see the create request. + // + for (next = next->Flink; + next != &m_FileObjectInfoHeadList; + next = next->Flink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + fileObjInfo->EvtFileCleanup.Invoke(hwdfFO); + } + + // + // hwdfFO could be NULL depending on the FileObjectClass + // + + // + // Scan all the I/O queues associated with this device + // and cancel the requests that matches with the handle + // being closed. We will be able to cancel only requests that + // are waiting to be dispatched. If the requests are already + // presented to the driver then it's the responsibility of the + // driver to complete them when the cleanup callback is invoked. + // + if(FxIrp->GetFileObject() != NULL ) { + FxPkgIo* pPkgIo; + + pPkgIo = (FxPkgIo*)m_Device->m_PkgIo; + pPkgIo->FlushAllQueuesByFileObject(FxIrp->GetFileObject()); + } + +Passthru: + if (m_Device->m_AutoForwardCleanupClose) { + FxIrp->SkipCurrentIrpStackLocation(); + status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); + } else { + FxIrp->SetStatus(status); + FxIrp->SetInformation(0); + FxIrp->CompleteRequest(IO_NO_INCREMENT); + } + + return status; + +} + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::OnClose( + __inout FxIrp* FxIrp + ) +/*++ + +Routine Description: + + Called in response to IRP_MJ_CLOSE. Invoke EvtFileClose event + if registered and destroy the WDFFILEOBJECT. + +Arguments: + +Return Value: + + NTSTATUS + + --*/ +{ + NTSTATUS status; + FxFileObject* pFxFO = NULL; + WDFFILEOBJECT hwdfFO = NULL; + BOOLEAN isStreamFileObject = FALSE; + BOOLEAN acquiredRemLock = FALSE; + PLIST_ENTRY next; + FxFileObjectInfo* fileObjInfo; + MxFileObject fileObject; + MdIrp irp; + + // + // FxIrp.CompleteRequest NULLs the m_Irp so store m_Irp separately + // for use in ReleaseRemoveLock. + // + irp = FxIrp->GetIrp(); + + // + // Check to see if the fileobject represents a stream fileobject + // created using IoCreateStreamFileObjectLite. If so, this is a + // is spurious close sent by the I/O manager when it invalidates + // the volumes (IopInvalidateVolumesForDevice). + // + fileObject.SetFileObject(FxIrp->GetFileObject()); + if (FxIrp->GetFileObject() && + (fileObject.GetFlags() & FO_STREAM_FILE)){ + isStreamFileObject = TRUE; + status = STATUS_SUCCESS; + goto Passthru; + } + + status = FxFileObject::_GetFileObjectFromWdm( + m_Device, + m_Device->GetFileObjectClass(), + FxIrp->GetFileObject(), + &pFxFO + ); + + ASSERT(status == STATUS_SUCCESS); + + if (pFxFO != NULL && NT_SUCCESS(status)) { + hwdfFO = pFxFO->GetHandle(); + } + + // + // Invoke close callbacks. + // + if (NULL == pFxFO) { + // + // Invoke close callbacks of next layer (cx or client driver) based on the autoforward + // setting of previous layer. (top to bottom). + // AutoforwardCleanupClose set to FALSE with a not null create callback + // means that create request was never forwarded to lower layer. + // + for (next = m_FileObjectInfoHeadList.Blink; + next != &m_FileObjectInfoHeadList; + next = next->Blink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + + if (WdfFalse == fileObjInfo->AutoForwardCleanupClose && + fileObjInfo->EvtCxFileCreate.Method != NULL) { + next = next->Blink; // one before the real start entry. + break; + } + } + } + else { + // + // 'OnCreate' sets this package context. + // + next = (PLIST_ENTRY) pFxFO->GetPkgCleanupCloseContext(); + if (NULL == next) { + next = &m_FileObjectInfoHeadList; + } + } + + // + // Invoke close callbacks only if this layer (cx or client driver) had the opprtunity + // to see the create request. + // + for (next = next->Flink; + next != &m_FileObjectInfoHeadList; + next = next->Flink) { + + fileObjInfo = CONTAINING_RECORD(next, FxFileObjectInfo, ListEntry); + fileObjInfo->EvtFileClose.Invoke(hwdfFO); + } + + // + // Destroy the WDFFILEOBJECT. This will result in + // fileobject EvtCleanup and EvtDestroy event. + // + FxFileObject::_DestroyFileObject( + m_Device, + m_Device->GetFileObjectClass(), + FxIrp->GetFileObject() + ); + +Passthru: + + if (m_Device->m_AutoForwardCleanupClose) { + FxIrp->SkipCurrentIrpStackLocation(); + status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); + } else { + // + // We're about to complete the request, but we need to decrement the + // open handle count after we complete the request. However, completing + // the request immediately opens the gate for the remove IRP to arrive + // and run down the device. Hence we'll acquire the remove lock in order + // to ensure that the device is not removed before we've decremented the + // open handle count. + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + acquiredRemLock = AcquireRemoveLockForClose(FxIrp); +#endif + FxIrp->SetStatus(status); + FxIrp->SetInformation(0); + FxIrp->CompleteRequest(IO_NO_INCREMENT); + } + + if (isStreamFileObject == FALSE) { + // + // Note that after this call returns, this object may have been deleted! + + + + + + + + + DecrementOpenHandleCount(); + } + + if (acquiredRemLock) { + Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), + irp); + } + + return status; + +} + +BOOLEAN +FxPkgGeneral::AcquireRemoveLockForClose( + __in FxIrp* FxIrp + ) +/*++ + +Routine Description: + + For PNP devices, this routine acquires the remove lock when handling the + close IRP. + +Arguments: + Irp - Pointer to the close IRP + +Return Value: + + A BOOLEAN value that indicates whether or not the function actually acquired + the remove lock + + --*/ +{ + NTSTATUS status; + BOOLEAN lockAcquired; + FxWdmDeviceExtension * wdmExtension = FxDevice::_GetFxWdmExtension( + m_Device->GetDeviceObject()); + + // + // Initialization + // + lockAcquired = FALSE; + + // + // We attempt to acquire the remove lock only for PNP device objects + // + if (m_Device->IsPnp() == FALSE) { + goto Done; + } + + // + // If driver has opted in for remove lock for I/O operations we have + // already acquired remove lock for Close so no need to do it again. + // + if (wdmExtension->RemoveLockOptionFlags & + WDF_REMOVE_LOCK_OPTION_ACQUIRE_FOR_IO) { + goto Done; + } + + status = Mx::MxAcquireRemoveLock( + m_Device->GetRemoveLock(), + FxIrp->GetIrp()); + if (NT_SUCCESS(status)) { + // + // Successfully acquired the remove lock + // + lockAcquired = TRUE; + } else { + // + // This is likely to have failed because we got the remove IRP and + // called IoReleaseRemoveLockAndWait on another thread. This would + // happen if there's a bug in the driver above us in the stack that + // caused it to forward us the remove IRP before we completed the close + // IRP. + // + // There's not much we can do now, since we're already racing against + // the remove IRP. + // + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + DoTraceLevelMessage( + pFxDriverGlobals, + TRACE_LEVEL_ERROR, + TRACINGIO, + "Unable to acquire remove lock while handling the close IRP" + " 0x%p, %!STATUS!", + FxIrp->GetIrp(), status); + + if (pFxDriverGlobals->IsVerificationEnabled(1,9, OkForDownLevel)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + +Done: + return lockAcquired; +} + + +_Must_inspect_result_ +NTSTATUS +FxPkgGeneral::OnShutdown( + __inout FxIrp* FxIrp + ) +/*++ + +Routine Description: + + Called in response to IRP_MJ_SHUTDOWN. + +Arguments: + +Return Value: + + NTSTATUS + + --*/ +{ + NTSTATUS status; + + m_EvtDeviceShutdown.Invoke(m_Device->GetHandle()); + + if(m_Device->IsFilter()) { + FxIrp->SkipCurrentIrpStackLocation(); + status = FxIrp->CallDriver(m_Device->GetAttachedDevice()); + } + else { + status = STATUS_SUCCESS; + FxIrp->SetStatus(status); + FxIrp->SetInformation(0); + FxIrp->CompleteRequest(IO_NO_INCREMENT); + } + + return status; + +} + +VOID +FxPkgGeneral::DecrementOpenHandleCount( + VOID + ) +{ + if (InterlockedDecrement(&m_OpenHandleCount) == 0 && m_Device->IsLegacy()) { + m_Device->ControlDeviceDelete(); + } +} + +BOOLEAN +FxPkgGeneral::CanDestroyControlDevice( + VOID + ) +{ + // + // Remove the bias of one that we use to track if a control device should be + // deleted. + // + if (InterlockedDecrement(&m_OpenHandleCount) == 0) { + return TRUE; + } + else { + return FALSE; + } + +} + +VOID +FxPkgGeneral::GetConstraintsHelper( + __out_opt WDF_EXECUTION_LEVEL* ExecutionLevel, + __out_opt WDF_SYNCHRONIZATION_SCOPE* SynchronizationScope + ) +/*++ + +Routine Description: + This routine is the helper routine and is used by FxFileObject to get the + ExecutionLevel and SynchronizationScope. + +Arguments: + +Return Value: + VOID + +--*/ + +{ + if (ExecutionLevel != NULL) { + *ExecutionLevel = m_ExecutionLevel; + } + + if (SynchronizationScope != NULL) { + *SynchronizationScope = m_SynchronizationScope; + } +} + +FxCallbackLock* +FxPkgGeneral::GetCallbackLockPtrHelper( + __deref_out_opt FxObject** LockObject + ) +/*++ + +Routine Description: + This routine is the helper routine and is used by FxFileObject to get the + LockObject. + + +Arguments: + +Return Value: + FxCallbackLock * + +--*/ + +{ + if (LockObject != NULL) { + *LockObject = m_CallbackLockObjectPtr; + } + + return m_CallbackLockPtr; +} + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/io/fxioqueue.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/io/fxioqueue.cpp new file mode 100644 index 00000000000..2989c5be3b3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/io/fxioqueue.cpp @@ -0,0 +1,6527 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoQueue.cpp + +Abstract: + + This module implements the FxIoQueue object and C interfaces + +Author: + + + + +Revision History: + + + + +--*/ + +#include "ioprivshared.hpp" +#include "FxIoQueue.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoQueue.tmh" +#endif +} + +// +// Public constructors +// +FxIoQueue::FxIoQueue( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxPkgIo* PkgIo + ) : + FxNonPagedObject(FX_TYPE_QUEUE, sizeof(FxIoQueue), FxDriverGlobals), + m_CallbackSpinLock(FxDriverGlobals), + m_CallbackMutexLock(FxDriverGlobals), + m_IoPkgListNode(FxIoQueueNodeTypeQueue) + { + m_Configured = FALSE; + m_Disposing = FALSE; + m_PowerManaged = FALSE; + m_PowerState = FxIoQueuePowerOn; + m_PowerReferenced = FALSE; + m_AllowZeroLengthRequests = FALSE; + m_IsDevicePowerPolicyOwner = FALSE; + m_Type = WdfIoQueueDispatchSequential; + + // A newly created queue can not accept requests until initialized + m_QueueState = (FX_IO_QUEUE_STATE)0; + + // + // Set our Cancel callbacks + // + m_Queue.Initialize(this, _IrpCancelForQueue); + + m_DriverCancelable.Initialize(this, _IrpCancelForDriver); + + InitializeListHead(&m_Cancelled); + + InitializeListHead(&m_CanceledOnQueueList); + + InitializeListHead(&m_DriverOwned); + + InitializeListHead(&m_PowerNotify); + + InitializeListHead(&m_PowerDriverNotified); + + m_PowerSListEntry.Next = NULL; + + // + // We do not reference count the I/O package instance + // since it contains us. The fact we exist, the I/O + // package instance exists. + // + m_PkgIo = PkgIo; + m_CxDeviceInfo = NULL; + + m_Device = PkgIo->GetDevice(); + + m_IsDevicePowerPolicyOwner = (m_Device->IsPnp() && + m_Device->m_PkgPnp->IsPowerPolicyOwner()); + + m_Dispatching = 0L; + + m_TransitionFromEmpty = FALSE; + m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE; + + m_DriverIoCount = 0L; + m_TwoPhaseCompletions = 0L; + + m_SystemWorkItem = NULL; + + m_IdleComplete.Method = NULL; + m_IdleCompleteContext = NULL; + + m_PurgeComplete.Method = NULL; + m_PurgeCompleteContext = NULL; + + m_ReadyNotify.Method = NULL; + m_ReadyNotifyContext = NULL; + + m_CallbackLockPtr = NULL; + m_CallbackLockObjectPtr = NULL; + +#if FX_IS_KERNEL_MODE + + // Initialize the DPC used for deferrals + KeInitializeDpc( + &m_Dpc, + _DeferredDispatchDpcThunk, + this + ); +#endif + + m_DpcQueued = FALSE; + + m_WorkItemQueued = FALSE; + + m_RequeueDeferredDispatcher = FALSE; + + m_Deleted = FALSE; + m_SupportForwardProgress = FALSE; + m_PassiveLevel = FALSE; + + m_ExecutionLevel = WdfExecutionLevelInheritFromParent; + m_SynchronizationScope = WdfSynchronizationScopeInheritFromParent; + + m_FwdProgContext = NULL; + MarkPassiveDispose(ObjectDoNotLock); + m_MaxParallelQueuePresentedRequests = (ULONG)-1; + + return; +} + +FxIoQueue::~FxIoQueue() +{ + ASSERT(m_SystemWorkItem == NULL); + + if (m_PkgIo != NULL) { + m_PkgIo = NULL; + } + + ASSERT(IsListEmpty(&m_Cancelled)); + ASSERT(IsListEmpty(&m_CanceledOnQueueList)); + ASSERT(IsListEmpty(&m_DriverOwned)); + ASSERT(IsListEmpty(&m_PowerNotify)); + ASSERT(IsListEmpty(&m_PowerDriverNotified)); + ASSERT(!m_PowerReferenced); + ASSERT(!m_DpcQueued); + ASSERT(!m_WorkItemQueued); + ASSERT(!m_RequeueDeferredDispatcher); + ASSERT(m_TwoPhaseCompletions == 0); +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::_Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_IO_QUEUE_CONFIG Config, + __in_opt FxDriver* Caller, + __in FxPkgIo* PkgIo, + __in BOOLEAN InitialPowerStateOn, + __deref_out FxIoQueue** Object + ) +{ + NTSTATUS status; + FxIoQueue* pQueue; + + *Object = NULL; + + pQueue = new(DriverGlobals, Attributes) FxIoQueue(DriverGlobals, PkgIo); + + if (pQueue == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Memory allocation failed: %!STATUS!", status); + return status; + } + + // + // Initialize it, creating the handle to pass the driver + // and configuring its callbacks and queue type + // + status = pQueue->Initialize(Config, + Attributes, + Caller, + InitialPowerStateOn); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not configure queue: %!STATUS!", status); + goto Done; + } +Done: + if (NT_SUCCESS(status)) { + *Object = pQueue; + } + else { + // + // Release our newly allocated Queue object + // + pQueue->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::Initialize( + __in PWDF_IO_QUEUE_CONFIG pConfig, + __in_opt PWDF_OBJECT_ATTRIBUTES QueueAttributes, + __in_opt FxDriver* Caller, + __in BOOLEAN InitialPowerStateOn + ) + +/*++ + +Routine Description: + + Initialize the IoQueue after creating. + + This creates the handle required for passing to the driver. + +Arguments: + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS Status; + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + Status = m_PowerIdle.Initialize(NotificationEvent, FALSE); + if (!NT_SUCCESS(Status)) { + return Status; + } + + Status = m_FinishDisposing.Initialize(NotificationEvent, FALSE); + if (!NT_SUCCESS(Status)) { + return Status; + } + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + Status = m_RequestWaitEventUm.Initialize(SynchronizationEvent, FALSE); + if (!NT_SUCCESS(Status)) { + return Status; + } +#endif + + MarkDisposeOverride(ObjectDoNotLock); + + // + // Set the execution level and callback synchronization based on + // configuration + // + Status = ConfigureConstraints(QueueAttributes, Caller); + if (!NT_SUCCESS(Status)) { + return Status; + } + + // + // Validate dispatch type. + // + if (pConfig->DispatchType <= WdfIoQueueDispatchInvalid || + pConfig->DispatchType >= WdfIoQueueDispatchMax) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Invalid dispatch type " + "specified %d, Queue 0x%p %!STATUS!", + pConfig->DispatchType, + GetObjectHandle(), + STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + + // + // If not a manual queue, must set at least IoStart, or one of + // read|write|devicecontrol + // + if ((pConfig->DispatchType != WdfIoQueueDispatchManual) && + (pConfig->EvtIoDefault == NULL)) { + + if ((pConfig->EvtIoDefault == NULL) && + (pConfig->EvtIoRead == NULL) && + (pConfig->EvtIoWrite == NULL) && + (pConfig->EvtIoDeviceControl == NULL) && + (pConfig->EvtIoInternalDeviceControl == NULL)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "At least one of EvtIoDefault|EvtIoRead|EvtIoWrite|" + "EvtIoDeviceControl|EvtIoInternalDeviceControl " + "must be set %!STATUS!", STATUS_WDF_NO_CALLBACK); + return STATUS_WDF_NO_CALLBACK; + } + } + + // + // A manual queue should not set any callback function + // pointers since they will not get invoked. + // + if (pConfig->DispatchType == WdfIoQueueDispatchManual) { + + if ((pConfig->EvtIoDefault != NULL) || + (pConfig->EvtIoRead != NULL) || + (pConfig->EvtIoWrite != NULL) || + (pConfig->EvtIoDeviceControl != NULL) || + (pConfig->EvtIoInternalDeviceControl != NULL)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot set io callback events " + "on a manual WDFQUEUE 0x%p %!STATUS!", + GetObjectHandle(), + STATUS_INVALID_PARAMETER); + return STATUS_INVALID_PARAMETER; + } + } + + // + // For version less than v1.9 m_MaxParallelQueuePresentedRequests is set to + // -1 by the FxIoQueue Constructor. + // By checking > below we mean v1.9 and above (public API already did the official + // validation). + // + if (pConfig->Size > sizeof(WDF_IO_QUEUE_CONFIG_V1_7)) { + if (pConfig->Settings.Parallel.NumberOfPresentedRequests != 0 && + (pConfig->DispatchType == WdfIoQueueDispatchSequential || + pConfig->DispatchType == WdfIoQueueDispatchManual)) { + Status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot have NumberOfPresentedRequests other " + "than 0 on a Sequential or manual WDFQUEUE 0x%p." + "Make Sure you set NumberOfPresentedRequests" + " to 0, %!STATUS!", + GetObjectHandle(), + Status + ); + return Status; + + } + else{ + m_MaxParallelQueuePresentedRequests = + pConfig->Settings.Parallel.NumberOfPresentedRequests; + } + } + + // + // Initialize our workitem if we have to support passive callbacks + // + if (m_PassiveLevel) { + + Status = FxSystemWorkItem::_Create(FxDriverGlobals, + m_Device->GetDeviceObject(), + &m_SystemWorkItem + ); + + if (!NT_SUCCESS(Status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not allocate workitem: %!STATUS!", Status); + return Status; + } + } + + m_Type = pConfig->DispatchType; + + switch(pConfig->PowerManaged) { + + case WdfUseDefault: + if(m_Device->IsFilter()){ + m_PowerManaged = FALSE; + } else { + m_PowerManaged = TRUE; + } + break; + + case WdfTrue: + m_PowerManaged = TRUE; + break; + + case WdfFalse: + m_PowerManaged = FALSE; + break; + default: + ASSERTMSG("Invalid value in WDF_IO_QUEUE_CONFIG PowerManaged field\n", FALSE); + break; + } + + // + // Queues for NonPnp devices can't be power managed. + // + if(m_Device->IsLegacy()) { + m_PowerManaged = FALSE; + } + + // + // If power managed queue, ensure its initial power state + // is same as the device. + // + if (m_PowerManaged) { + if (InitialPowerStateOn) { + m_PowerState = FxIoQueuePowerOn; + } + else { + m_PowerState = FxIoQueuePowerOff; + } + } else { + m_PowerState = FxIoQueuePowerOn; + } + + m_AllowZeroLengthRequests = pConfig->AllowZeroLengthRequests; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "EvtIoDefault 0x%p, EvtIoRead 0x%p, EvtIoWrite 0x%p, " + "EvtIoDeviceControl 0x%p for WDFQUEUE 0x%p", + pConfig->EvtIoDefault, + pConfig->EvtIoRead, + pConfig->EvtIoWrite, + pConfig->EvtIoDeviceControl, GetObjectHandle()); + + m_IoDefault.Method = pConfig->EvtIoDefault; + m_IoStop.Method = pConfig->EvtIoStop; + m_IoResume.Method = pConfig->EvtIoResume; + m_IoRead.Method = pConfig->EvtIoRead; + m_IoWrite.Method = pConfig->EvtIoWrite; + m_IoDeviceControl.Method = pConfig->EvtIoDeviceControl; + m_IoInternalDeviceControl.Method = pConfig->EvtIoInternalDeviceControl; + m_IoCanceledOnQueue.Method = pConfig->EvtIoCanceledOnQueue; + + + // A newly created queue can accept and dispatch requests once initialized + SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetAcceptRequests|FxIoQueueSetDispatchRequests)); + + m_Configured = TRUE; + + return STATUS_SUCCESS; +} + +BOOLEAN +FxIoQueue::Dispose( + ) +/*++ + +Routine Description: + + Should be called at PASSIVE_LEVEL because of the synchronous call + to drain requests, workitems, and dpcs associated with this queue. + +Arguments: + +Returns: + + TRUE or FALSE + +--*/ +{ + KIRQL irql; + + if (IsCommitted() == FALSE) { + // + // We called DeleteFromFailedCreate because we couldn't commit the + // object. + // + goto End; + } + + // + // If object is commited means we are added to the FxPkgIo queue list. + // + // + // Purge the queue asynchrnously without providing any callback. That way, + // we allow the driver to have an outstanding purge request while the delete + // is in progress. + // + (VOID) QueuePurge(TRUE, TRUE, NULL, NULL); + + Lock(&irql); + + // + // Mark that this queue is disposing + // + + ASSERT(m_Disposing == FALSE); + + m_Disposing = TRUE; + + // + // Just make sure the state hasn't changed after the purge. + // + ASSERT(IsState(WdfIoQueueAcceptRequests) == FALSE); + + // + // Call the FxPkgIo to remove its references to this queue + // + // Note: We are holding the queue lock to prevent races, and + // FxPkgIo never calls FxIoQueue methods while holding + // its lock. + // + m_PkgIo->RemoveQueueReferences(this); + + DispatchEvents(irql); + + // + // Wait for the finished event to be signalled. This event will + // be signalled when the queue is in a disposed state and there + // are no more pending events. + // + GetDriverGlobals()->WaitForSignal(m_FinishDisposing.GetSelfPointer(), + "waiting for the queue to be deleted, WDFQUEUE", GetHandle(), + GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + + + ASSERT(m_Deleted == TRUE); + + ASSERT(m_Queue.GetRequestCount() == 0); + ASSERT(m_DriverIoCount == 0); + + if (IsForwardProgressQueue()) { + FreeAllReservedRequests(TRUE); + ASSERT(IsListEmpty(&m_FwdProgContext->m_ReservedRequestList)); + ASSERT(IsListEmpty(&m_FwdProgContext->m_PendedIrpList)); + } + + if (m_FwdProgContext != NULL) { + m_FwdProgContext->m_PendedReserveLock.Uninitialize(); + FxPoolFree(m_FwdProgContext); + m_FwdProgContext = NULL; + } + + // + // Rundown the workitem. + // + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->DeleteObject(); + m_SystemWorkItem = NULL; + } + + // + // Rundown the DPCs + // + if (m_DpcQueued) { + FlushQueuedDpcs(); + } + + // + // All callbacks into the device driver acquire and release a + // reference on the queue. This ensures that the queue will + // not actually complete deleting until return from any + // outstanding event callbacks into the device driver. + // + // See DispatchRequestToDriver() + // +End: + + __super::Dispose(); + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::ConfigureConstraints( + __in_opt PWDF_OBJECT_ATTRIBUTES ObjectAttributes, + __in_opt FxDriver* Caller + ) + +/*++ + +Routine Description: + + Configures the locking and threading model for the + Queue according to parameters specified by the device + driver when it initialized. + +Arguments: + +Returns: + + NTSTATUS + +--*/ + +{ + WDF_EXECUTION_LEVEL ParentLevel; + WDF_SYNCHRONIZATION_SCOPE ParentScope; + BOOLEAN AutomaticLockingRequired; + + AutomaticLockingRequired = FALSE; + ASSERT(m_Device != NULL); + + // + // Initialize both spin and mutex locks + // + m_CallbackSpinLock.Initialize(this); + m_CallbackMutexLock.Initialize(this); + + // + // If WDF_OBJECT_ATTRIBUTES is specified, these override any + // default settings. + // + if (ObjectAttributes != NULL) { + m_ExecutionLevel = ObjectAttributes->ExecutionLevel; + m_SynchronizationScope = ObjectAttributes->SynchronizationScope; + } + + // + // If no WDFQUEUE specific attributes are specified, we + // get them from WDFDEVICE, which allows WDFDEVICE to + // provide a default for all WDFQUEUE's created. + // + m_Device->GetConstraints(&ParentLevel, &ParentScope); + ASSERT(ParentLevel != WdfExecutionLevelInheritFromParent); + ASSERT(ParentScope != WdfSynchronizationScopeInheritFromParent); + + if (m_ExecutionLevel == WdfExecutionLevelInheritFromParent) { + m_ExecutionLevel = ParentLevel; + } + + if (m_SynchronizationScope == WdfSynchronizationScopeInheritFromParent) { + m_SynchronizationScope = ParentScope; + } + + // + // For backward compatibility purposes always have a lock associated with the + // object even for WdfSynchronizationScopeNone. This is so that we return a non-null + // presentation lock for the WDFQUEUE object. + // + if (m_ExecutionLevel == WdfExecutionLevelPassive) { + // + // Mark FxObject as passive level to ensure that Dispose and Destroy + // callbacks are passive to the driver + // + MarkPassiveCallbacks(ObjectDoNotLock); + m_PassiveLevel = TRUE; + + // + // Passive Callbacks constraint has been set, we use a mutex for the + // callback lock. + // + m_CallbackLockPtr = &m_CallbackMutexLock; + m_CallbackLockObjectPtr = this; + } + else { + // + // If no passive level constraint is specified, then spinlocks + // are used for callbacks since they are lightweight and work with + // DPC's and Timer's + // + m_CallbackLockPtr = &m_CallbackSpinLock; + m_CallbackLockObjectPtr = this; + } + + // + // Configure synchronization scope + // + if (m_SynchronizationScope == WdfSynchronizationScopeDevice) { + NTSTATUS status; + + // + // WDF extensions are not allowed to use this type of synchronization. + // + if (Caller != NULL && Caller != GetDriverGlobals()->Driver) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p Synchronization scope is set to " + "device; WDF extension drivers are not allowed " + "to use this type of synchronization, %!STATUS!", + GetObjectHandle(), status); + return status; + } + + // + // If we inherit the Sync. scope from parent or device + // and if the parent/device has Exec. Level different from Queue + // then disallow that case. + // FUTURE PROOF NOTE: Adding a new Execution Level will need reevaluation + // of the check below. + // + if (ParentLevel != m_ExecutionLevel) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p Synchronization scope is set to device" + " but the Device ExecutionLevel: 0x%x" + " doesn't match Queue ExecutionLevel: 0x%x, %!STATUS!", + GetObjectHandle(), ParentLevel, + m_ExecutionLevel, status); + return status; + } + // + // Per device automatic callback synchronization, so we update our + // callback lock ptr to point to the devices lock + // + AutomaticLockingRequired = TRUE; + + // + // Get the callback lock and object from the device + // + m_CallbackLockPtr = m_Device->GetCallbackLockPtr(&m_CallbackLockObjectPtr); + } + else if (m_SynchronizationScope == WdfSynchronizationScopeQueue) { + // + // Per object automatic serialization + // + AutomaticLockingRequired = TRUE; + + // m_CallbackLockPtr has been set above in execution level constraint + } + + + if (AutomaticLockingRequired) { + // + // If automatic locking has been configured, set the lock + // on the FxCallback object delegates + // + m_IoDefault.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoStop.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoResume.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoRead.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoWrite.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoDeviceControl.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoInternalDeviceControl.SetCallbackLockPtr(m_CallbackLockPtr); + m_PurgeComplete.SetCallbackLockPtr(m_CallbackLockPtr); + m_ReadyNotify.SetCallbackLockPtr(m_CallbackLockPtr); + m_IoCanceledOnQueue.SetCallbackLockPtr(m_CallbackLockPtr); + + m_IoCancelCallbackLockPtr = m_CallbackLockPtr; + } + else { + // + // No automatic locking specified + // + m_IoDefault.SetCallbackLockPtr(NULL); + m_IoStop.SetCallbackLockPtr(NULL); + m_IoResume.SetCallbackLockPtr(NULL); + m_IoRead.SetCallbackLockPtr(NULL); + m_IoWrite.SetCallbackLockPtr(NULL); + m_IoDeviceControl.SetCallbackLockPtr(NULL); + m_IoInternalDeviceControl.SetCallbackLockPtr(NULL); + m_PurgeComplete.SetCallbackLockPtr(NULL); + m_ReadyNotify.SetCallbackLockPtr(NULL); + m_IoCanceledOnQueue.SetCallbackLockPtr(NULL); + + m_IoCancelCallbackLockPtr = NULL; + + } + + return STATUS_SUCCESS; +} + +WDF_IO_QUEUE_STATE +FxIoQueue::GetState( + __out_opt PULONG pQueueCount, + __out_opt PULONG pDriverCount + ) +{ + int stat; + ULONG QueueCount, DriverCount; + + // Get request counts + GetRequestCount(&QueueCount, &DriverCount); + + if (pQueueCount ) *pQueueCount = QueueCount; + + if (pDriverCount ) *pDriverCount = DriverCount; + + // + // First fill in the values that are kept up to date at runtime + // + stat = (int)m_QueueState & (int)(WdfIoQueueAcceptRequests | WdfIoQueueDispatchRequests); + + // + // Set additional information bits from information retrieved + // from other sources. It's cheaper to get this info at the infrequent + // GetStatus time, rather than keep the bits up to date at each + // request and queue transition. + // + if (QueueCount == 0) { + stat = stat | (int)WdfIoQueueNoRequests; + } + + if (DriverCount == 0) { + stat = stat | (int)WdfIoQueueDriverNoRequests; + } + + if(m_PowerManaged) { + + if (m_PowerState != FxIoQueuePowerOn) { + stat = stat | (int)WdfIoQueuePnpHeld; + } + } + + return (WDF_IO_QUEUE_STATE)stat; +} + +VOID +FxIoQueue::SetState( + __in FX_IO_QUEUE_SET_STATE NewStatus + ) +{ + int AllowedBits; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + // + // Only allow setting of valid bits + // + AllowedBits = (int)(FxIoQueueSetAcceptRequests | + FxIoQueueClearAcceptRequests | + FxIoQueueSetDispatchRequests | + FxIoQueueClearDispatchRequests | + FxIoQueueSetShutdown | + FxIoQueueClearShutdown + ); + + if ((int)NewStatus & ~AllowedBits) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Invalid WDFQUEUE 0x%p state", + GetObjectHandle()); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return; + } + + // + // Clear the high bit used to prevent accidental mixing of + // WDF_IO_QUEUE_STATE and FX_IO_QUEUE_SET_STATE + // + NewStatus = (FX_IO_QUEUE_SET_STATE)((int)NewStatus & 0x7FFFFFFF); + + if (NewStatus & (int)FxIoQueueClearShutdown) { + m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState & ~(int)FxIoQueueShutdown); + } + + if (NewStatus & (int)FxIoQueueSetShutdown) { + m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState | (int)FxIoQueueShutdown); + } + + if (NewStatus & (int)FxIoQueueSetAcceptRequests) { + if (IsState(FxIoQueueShutdown) == FALSE) { + m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState | (int)WdfIoQueueAcceptRequests); + } + else { + DoTraceLevelMessage(FxDriverGlobals, + TRACE_LEVEL_INFORMATION, TRACINGIO, + "WDFQUEUE 0x%p is shut down, preventing queue " + "from accepting requests", + GetObjectHandle()); + } + } + + if (NewStatus & (int)FxIoQueueClearAcceptRequests) { + m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState & ~(int)WdfIoQueueAcceptRequests); + } + + if (NewStatus & (int)FxIoQueueSetDispatchRequests) { + m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState | (int)WdfIoQueueDispatchRequests); + // + // If the queue is allowed to dispatch new requests, we must clear this flag. + // See also WdfIoQueueStopAndPurge for more info about the flag. + // + m_CancelDispatchedRequests = FALSE; + } + + if (NewStatus & (int)FxIoQueueClearDispatchRequests) { + m_QueueState = (FX_IO_QUEUE_STATE)((int)m_QueueState & ~(int)WdfIoQueueDispatchRequests); + } + + return; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyGetRequestUpdateFlags) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* TagRequest + ) +{ + KIRQL irql; + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if (TagRequest != NULL) { + // + // WdfIoQueueRetrieveFoundRequest is only valid on manual queues. + // v1.11 and above: driver is not required to find the request + // using WdfIoQueueFindRequest. + // v1.9 and below: driver is required to find the request + // using WdfIoQueueFindRequest. + // + if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + if (m_Type != WdfIoQueueDispatchManual) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WdfIoQueueRetrieveFoundRequest is allowed " + "only on a manual queue 0x%p, %!STATUS!", + GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return status; + } + } + else { + // + // Legacy validation. + // + TagRequest->Lock(&irql); + status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals); + TagRequest->Unlock(irql); + if (!NT_SUCCESS(status)) { + return status; + } + } + } + + Lock(&irql); + if ((m_Type == WdfIoQueueDispatchSequential) && (m_DriverIoCount == 0)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Driver called WdfIoQueueRetrieveNextRequest on a sequential WDFQUEUE 0x%p with no " + "outstanding requests. This can cause a race with automatically dispatched " + "requests. Call WdfIoQueueRetrieveNextRequest before completing the current request(s)", + GetObjectHandle()); + + FxVerifierDbgBreakPoint(FxDriverGlobals); + + // Allow them to continue, though this is a race condition in their driver + } + Unlock(irql); + + return STATUS_SUCCESS; +} + +VOID +FX_VF_METHOD(FxIoQueue, VerifyGetRequestRestoreFlags)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* pRequest + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + KIRQL irql; + + PAGED_CODE_LOCKED(); + pRequest->Lock(&irql); + + pRequest->ClearVerifierFlagsLocked(FXREQUEST_FLAG_TAG_REQUEST); + pRequest->SetVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED); + + pRequest->Unlock(irql); +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::GetRequest( + __in_opt MdFileObject FileObject, + __in_opt FxRequest* TagRequest, + __deref_out FxRequest** pOutRequest + ) +/*++ + +Routine Description: + + This method is called by + + WdfIoQueueRetrieveNextRequest + WdfIoQueueRetrieveRequestByFileObject + WdfIoQueueRetrieveFoundRequest + + to retrieve a request from the queue. + +Arguments: + +Returns: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + FxRequest* pRequest = NULL; + FxRequestCompletionState oldState; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + + status = VerifyGetRequestUpdateFlags(pFxDriverGlobals, TagRequest); + if(!NT_SUCCESS(status)){ + return status; + } + + // + // Don't allow on parallel queues + // + if ((m_Type != WdfIoQueueDispatchManual) && + (m_Type != WdfIoQueueDispatchSequential)) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot be called on a parallel WDFQUEUE 0x%p, %!STATUS!", + GetObjectHandle(), status); + return status; + } + + Lock(&irql); + + // + // Only if the queue state allows requests to be retrieved. + // It's okay to retrieve requests while the queue is in a transitioning state. + // + if (m_PowerState == FxIoQueuePowerOff) { + status = STATUS_WDF_PAUSED; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p is powered off, %!STATUS!", + GetObjectHandle(), status); + Unlock(irql); + return status; + } + + // + // See if the queue is (still) processing requests + // + if (!IsState(WdfIoQueueDispatchRequests)) { + status = STATUS_WDF_PAUSED; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p is stopped, %!STATUS!", + GetObjectHandle(), status); + Unlock(irql); + return status; + } + + #pragma warning(disable:4127) + while (TRUE) { + + #pragma warning(default:4127) + // + // Get the next FxRequest from the cancel safe queue + // + status = FxRequest::GetNextRequest(&m_Queue, FileObject, TagRequest, &pRequest); + if (!NT_SUCCESS(status)) { + // + // This code address the following race condition: + // 1) Queue has only one request (count 1). + // 2) Request in queue is cancelled. + // 3) Request's cancellation logic starts to run on thread 1. + // 4) But before cancellation logic gets the queue's lock + // thread 2 calls WdfIoQueueRetrieveNextRequest. + // 5) WdfIoQueueRetrieveNextRequest returns no more requests. + // Driver waits for the ReadyNotify callback. (count 1) + // 6) Thread 3 adds a new request in queue. (count 1->2) + // 7) Thread 1 finally runs. (count 2->1). + // 8) At this point driver stops responding b/c it never receives ReadyNotify. + // + // This code below forces the queue logic to send a ReadyNotify + // callback the next time a new request is added (in step 6 above). + // + if (STATUS_NO_MORE_ENTRIES == status && + NULL == FileObject && // WdfIoQueueRetrieveNextRequest + NULL == TagRequest && // WdfIoQueueRetrieveNextRequest + m_Queue.GetRequestCount() > 0L) { + + m_ForceTransitionFromEmptyWhenAddingNewRequest = TRUE; + } + + Unlock(irql); + return status; + } + + // + // If we don't allow zero length read/write's to the driver, + // complete it now with success and attempt to get another + // request from the queue. + // + if (!m_AllowZeroLengthRequests) { + + + + + + (VOID)pRequest->GetCurrentIrpStackLocation(); + + FxIrp* pIrp = pRequest->GetFxIrp(); + UCHAR majorFunction = pIrp->GetMajorFunction(); + + if ((majorFunction == IRP_MJ_READ) && + (pIrp->GetParameterReadLength() == 0)) { + + Unlock(irql); + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Zero length WDFREQUEST 0x%p completed automatically by WDFQUEUE 0x%p", + pRequest->GetHandle(),GetObjectHandle()); + pRequest->CompleteWithInformation(STATUS_SUCCESS, 0); + pRequest->RELEASE(FXREQUEST_COMPLETE_TAG); + + Lock(&irql); + + // Get another request from the queue + continue; + } + else if ((majorFunction == IRP_MJ_WRITE) && + (pIrp->GetParameterWriteLength() == 0)) { + + Unlock(irql); + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Zero length WDFREQUEST 0x%p completed automatically by WDFQUEUE 0x%p", + pRequest->GetHandle(), GetObjectHandle()); + + pRequest->CompleteWithInformation(STATUS_SUCCESS, 0); + pRequest->RELEASE(FXREQUEST_COMPLETE_TAG); + + Lock(&irql); + + // Get another request from the queue + continue; + } + } + + break; + } + + // Increase the driver owned request count + InsertInDriverOwnedList(pRequest); + + Unlock(irql); + + // + // We don't need to check for PurgeComplete since + // we are giving the request to the driver + // + + // pRequest is not cancellable now + + // + // We are now going to return the request + // to the driver, and it must complete it. + // + + // + // Set a completion event, this takes a reference + // + oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue); + ASSERT(oldState == FxRequestCompletionStateNone); + UNREFERENCED_PARAMETER(oldState); + + // + // Track that we have given the request to the driver + // + VerifyGetRequestRestoreFlags(pFxDriverGlobals, pRequest); + + pRequest->SetPresented(); + + // + // Release our original reference. The FxRequest::Complete + // will release the final one since we have registered a completion + // callback handler + // + // We now have one reference count on the FxRequest object until + // its completion routine runs since the completion event made + // an extra reference, and will dereference it when it fires, or + // its canceled. + // + + pRequest->RELEASE(FXREQUEST_STATE_TAG); + + // Return it to the driver + *pOutRequest = pRequest; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyPeekRequest) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* TagRequest + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + TagRequest->Lock(&irql); + status = TagRequest->VerifyRequestIsTagRequest(FxDriverGlobals); + TagRequest->Unlock(irql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::PeekRequest( + __in_opt FxRequest* TagRequest, + __in_opt MdFileObject FileObject, + __out_opt PWDF_REQUEST_PARAMETERS Parameters, + __deref_out FxRequest** pOutRequest + ) +/*++ + +Routine Description: + + This method is called by WdfIoQueueFindRequest to + look for a specific request from the queue. If tagrequest + is not specified then this method will return the very + first request from the queue. + + If the fileobject is specified then fileobject is also + used as one of the constrain for returing the request. + + Important point to remember is that only request information + is returned to the caller. The request is still present in + the queue. + + If the request is returned, there is an additional reference + taken on the queue to prevent it from deletion while the + caller is using the request handle. The caller has to + explicitly drop the reference once he is done using the + request handle. + +Arguments: + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + FxRequest* pRequest = NULL; + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + + // + // FindRequest is allowed only on a manual queue. + // + if (m_Type != WdfIoQueueDispatchManual) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "FindRequest is allowed only on a manaul queue 0x%p, %!STATUS!", + GetHandle(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + if (TagRequest != NULL) { + status = VerifyPeekRequest(pFxDriverGlobals, TagRequest); + if (!NT_SUCCESS(status)) { + return status; + } + } + + // + // Get the next FxRequest from the cancel safe queue + // + // If success, it will return a referenced FxRequest in + // which the caller must release the reference. + // + Lock(&irql); + + status = FxRequest::PeekRequest( + &m_Queue, + TagRequest, + FileObject, + Parameters, + &pRequest + ); + + // + // This code address the following potential race condition: + // 1) Queue has only one request (count 1). + // 2) Request in queue is cancelled. + // 3) Request's cancellation logic starts to run on thread 1. + // 4) But before cancellation logic gets the queue's lock + // thread 2 calls WdfIoQueueFindRequest to find any request. + // 5) WdfIoQueueFindRequest returns no more requests. + // Driver waits for the ReadyNotify callback. (count 1) + // 6) Thread 3 adds a new request in queue. (count 1->2) + // 7) Thread 1 finally runs. (count 2->1). + // 8) At this point driver stops responding b/c it never receives ReadyNotify. + // + // This code below forces the queue logic to send a ReadyNotify + // callback the next time a new request is added (in step 6 above). + // + if (STATUS_NO_MORE_ENTRIES == status && + NULL == FileObject && // WdfIoQueueFindRequest(any request) + NULL == TagRequest && // WdfIoQueueFindRequest(any request) + m_Queue.GetRequestCount() > 0L) { + + m_ForceTransitionFromEmptyWhenAddingNewRequest = TRUE; + } + + Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Mark it as a tag request to detect abuse since its not + // driver owned. + // + if (pFxDriverGlobals->FxVerifierOn) { + pRequest->SetVerifierFlags(FXREQUEST_FLAG_TAG_REQUEST); + } + + // Return it to the driver + *pOutRequest = pRequest; + + return status; +} + +SHORT +FX_VF_METHOD(FxIoQueue, VerifyForwardRequestUpdateFlags) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* Request + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + SHORT OldFlags = 0; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + Request->Lock(&irql); + + // Save old flags to put them back if forward fails + OldFlags = Request->GetVerifierFlagsLocked(); + + // + // Set that the request was forwarded. This effects + // cancel behavior. + // + Request->SetVerifierFlagsLocked(FXREQUEST_FLAG_FORWARDED); + + ASSERT((Request->GetVerifierFlagsLocked() & FXREQUEST_FLAG_DRIVER_OWNED) != 0); + + // Set that the request is no longer driver owned + Request->ClearVerifierFlagsLocked( + FXREQUEST_FLAG_DRIVER_OWNED | FXREQUEST_FLAG_DRIVER_DISPATCH); + + Request->Unlock(irql); + + return OldFlags; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::ForwardRequestWorker( + __in FxRequest* Request, + __in FxIoQueue* DestQueue + ) +{ + NTSTATUS status; + FxRequestCompletionState oldState; + PLIST_ENTRY ple; + SHORT OldFlags; + KIRQL irql; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + OldFlags = 0; + + // + // The request has only one reference, held by the completion + // callback function. We need to take another one before cancelling + // this function, otherwise we will lose the request object + // + Request->ADDREF(FXREQUEST_STATE_TAG); + + // + // Cancel its current completion event for this queue + // + oldState = Request->SetCompletionState(FxRequestCompletionStateNone); + ASSERT(oldState == FxRequestCompletionStateQueue); + + OldFlags = VerifyForwardRequestUpdateFlags(FxDriverGlobals, Request); + + // + // Remove it from this queues driver owned list. + // + // This must be done before forward since new queue will + // use the list entry in the FxRequest + // + // We can't use RemoveFromDriverOwnedList since we want the + // m_DriverIoCount to be left alone in case the forward fails. + // If we don't, another thread can run when we drop the lock, notice + // that there are no more requests, and raise the purged and empty + // events. But if the forward fails, the request will wind up back + // on the queue! So m_DriverIoCount is used as a gate to prevent + // these events from firing until we are really sure this queue + // is done with the request. + // + + + + + + + + + + + + Lock(&irql); + ple = Request->GetListEntry(FxListEntryDriverOwned); + RemoveEntryList(ple); + InitializeListHead(ple); + Unlock(irql); + + // + // Attempt to pass the request onto the target queue + // + status = DestQueue->QueueRequestFromForward(Request); + if (!NT_SUCCESS(status)) { + + // + // Target queue did not accept the request, so we + // restore the original completion callback function + // and flags + // + oldState = Request->SetCompletionState(oldState); + ASSERT(oldState == FxRequestCompletionStateNone); + UNREFERENCED_PARAMETER(oldState); + + if (FxDriverGlobals->FxVerifierOn) { + Request->SetVerifierFlags(OldFlags); + } + + // Release the extra reference we took + Request->RELEASE(FXREQUEST_STATE_TAG); + + Lock(&irql); + // Place it back on the driver owned list + InsertTailList(&m_DriverOwned, ple); + Unlock(irql); + } + else { + + Lock(&irql); + + // Request is no longer part of the I/O count for this queue + m_DriverIoCount--; + + ASSERT(m_DriverIoCount >= 0); + + // + // Don't run the event dispatcher if we are called from a + // dispath routine in order to prevent stack recursion. + // Since some other thread (possibly this thread higher on + // the stack) is running the dispatcher, no events will get lost. + // + // + // This returns with the IoQueue lock released + // + DispatchInternalEvents(irql); + + // + // We don't dereference the request object since the new IoQueue + // will release it when it is done. + // + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyForwardRequestToParent) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxIoQueue* DestQueue, + _In_ FxRequest* Request + ) +{ + KIRQL irql; + NTSTATUS status; + + PAGED_CODE_LOCKED(); + + if (m_Device->m_ParentDevice == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "No parent device for WDFQUEUE 0x%p Device, %!STATUS!", + DestQueue->m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + Request->Lock(&irql); + + status = Request->VerifyRequestIsDriverOwned(FxDriverGlobals); + + if (NT_SUCCESS(status)) { + status = Request->VerifyRequestIsNotCancelable(FxDriverGlobals); + } + + Request->Unlock(irql); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (DestQueue == this) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot forward a request to the same WDFQUEUE 0x%p" + " %!STATUS!", GetObjectHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + if (m_Device->m_ParentDevice != DestQueue->m_Device) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot forward a request to " + "a different WDFDEVICE 0x%p which is not the " + "parent, %!STATUS!", + DestQueue->m_Device->GetHandle(), + status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + if (Request->IsReserved()) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot forward reserved WDFREQUEST 0x%p to a " + "parent WDFDEVICE 0x%p, %!STATUS!", + Request->GetHandle(), + DestQueue->m_Device->GetHandle(), + status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + + // + // Make sure the child device is a PDO + // + ASSERT(m_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 (m_Device->IsPnp() + && + m_Device->GetPdoPkg()->m_AllowForwardRequestToParent == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WdfPdoInitSetForwardRequestToParent not called on " + "WDFDEVICE 0x%p, %!STATUS!", m_Device->GetHandle(), + status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + goto Done; + } + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::ForwardRequestToParent( + __in FxIoQueue* DestQueue, + __in FxRequest* Request, + __in PWDF_REQUEST_FORWARD_OPTIONS ForwardOptions + ) + +/*++ + +Routine Description: + + ForwardRequest is called from the drivers EvtIoDefault routine + and the following conditions apply: + + Request is not on a CSQ and not cancellable + + Request is FXREQUEST_FLAG_DRIVER_OWNED + + m_DriverIoCount has been incremented to reflect the request + + Request has an I/O completion callback function pointing to + FxIoQueueRequestComplete with the context for this Queue + + The Request has one reference count from the I/O completion callback. + + If a driver calls this API, it will not complete the request + as a result of this queues EvtIoDefault, and does not own + the request until it has been re-presented by the Destination + Queue. + +Arguments: + +Returns: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + BOOLEAN forwardRequestToParent; + FxIrp* pIrp; + + UNREFERENCED_PARAMETER(ForwardOptions); + + pFxDriverGlobals = GetDriverGlobals(); + + forwardRequestToParent = Request->m_ForwardRequestToParent; + + status = VerifyForwardRequestToParent(pFxDriverGlobals, + DestQueue, + Request); + if(!NT_SUCCESS(status)){ + return status; + } + + pIrp = Request->GetFxIrp(); + + pIrp->CopyCurrentIrpStackLocationToNext(); + pIrp->SetNextIrpStackLocation(); + + // + // Save a pointer to the device object for this request so that it can + // be used later in completion. + // + pIrp->SetCurrentDeviceObject(m_Device->m_ParentDevice->GetDeviceObject()); + + Request->SetDeviceBase((CfxDeviceBase *)m_Device->m_ParentDevice); + Request->m_ForwardRequestToParent = TRUE; + + status = ForwardRequestWorker(Request, DestQueue); + + // + // Undo the actions of changing the FxDevice and + // changing the deviceObject and stack location in the IRP + // + if (!NT_SUCCESS(status)) { + Request->SetDeviceBase((CfxDeviceBase *)m_Device); + pIrp = Request->GetFxIrp(); + pIrp->SkipCurrentIrpStackLocation(); + ASSERT(pIrp->GetDeviceObject() == m_Device->GetDeviceObject()); + + // + // Set the value of m_ForwardRequestToParent to the previous + // value so that if the Request has been forwarded to Parent + // successfully but fails to be forwarded to the grandparent + // from the parent then we free it back using ExFreePool + // instead of the Lookaside buffer . + // + Request->m_ForwardRequestToParent = forwardRequestToParent; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyForwardRequest) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxIoQueue* pDestQueue, + _In_ FxRequest* pRequest + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + pRequest->Lock(&irql); + + status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals); + if (NT_SUCCESS(status)) { + status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals); + } + + pRequest->Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + + if (pDestQueue == this) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot forward a request to the same WDFQUEUE 0x%p" + " %!STATUS!", + GetObjectHandle(), + STATUS_INVALID_DEVICE_REQUEST); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return STATUS_INVALID_DEVICE_REQUEST; + } + + if ((m_Device != pDestQueue->m_Device)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Cannot forward a request to a different WDFDEVICE 0x%p", + pDestQueue->m_Device->GetHandle()); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return STATUS_INVALID_DEVICE_REQUEST; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::ForwardRequest( + __in FxIoQueue* pDestQueue, + __in FxRequest* pRequest + ) +/*++ + +Routine Description: + + ForwardRequest is called from the drivers EvtIoDefault routine + and the following conditions apply: + + Request is not on a CSQ and not cancellable + + Request is FXREQUEST_FLAG_DRIVER_OWNED + + m_DriverIoCount has been incremented to reflect the request + + Request has an I/O completion callback function pointing to + FxIoQueueRequestComplete with the context for this Queue + + The Request has one reference count from the I/O completion callback. + + If a driver calls this API, it will not complete the request + as a result of this queues EvtIoDefault, and does not own + the request until it has been re-presented by the Destination + Queue. + +Arguments: + +Returns: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + status = VerifyForwardRequest(FxDriverGlobals, pDestQueue, pRequest); + if (!NT_SUCCESS(status)) { + return status; + } + + status = ForwardRequestWorker(pRequest, pDestQueue); + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyQueueDriverCreatedRequest) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* Request, + _Inout_ SHORT* OldFlags + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + Request->Lock(&irql); + + *OldFlags = Request->GetVerifierFlagsLocked(); + ASSERT((FXREQUEST_FLAG_DRIVER_DISPATCH & (*OldFlags)) == 0); + + status = Request->VerifyRequestIsNotCancelable(FxDriverGlobals); + if (NT_SUCCESS(status)) { + // Clear the driver owned flag. + ASSERT((FXREQUEST_FLAG_DRIVER_OWNED & (*OldFlags)) != 0); + Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED); + } + + Request->Unlock(irql); + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueDriverCreatedRequest( + __in FxRequest* Request, + __in BOOLEAN ParentQueue + ) +/*++ + +Routine Description: + + Insert a driver-created-request into this queue. + The following conditions apply: + + Request is not on a CSQ and not cancellable. + + Request doesn't have the FXREQUEST_FLAG_DRIVER_OWNED set yet. + + Request doesn't have an I/O completion callback function pointing to + FxIoQueueRequestComplete since the original queue is NULL. + + The Request has one reference count from WdfRequestCreate[FromIrp]. + + On a successful return, the request is owned by the queue. Driver can complete + this request only after it has been re-presented to the driver. + +Arguments: + + Request - Driver created request (already validated by public API) to + insert in queue. + + ParentQueue - TRUE if the queue is owned by the parent device. + +Returns: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + CfxDeviceBase * origDeviceBase; + SHORT oldFlags = 0; + FxIrp* fxIrp; + + PFX_DRIVER_GLOBALS fxDriverGlobals = GetDriverGlobals(); + fxIrp = Request->GetFxIrp(); + + status = VerifyQueueDriverCreatedRequest(fxDriverGlobals, Request, &oldFlags); + if(!NT_SUCCESS(status)) { + return status; + } + + ASSERT(Request->SetCompletionState(FxRequestCompletionStateNone) == + FxRequestCompletionStateNone); + + // + // If this is the parent queue, we need to adjust the IRP's stack. + // + if (ParentQueue) { + + // + // IRP should not have a completion routine set yet. + // + + ASSERT(fxIrp->GetNextCompletionRoutine() == NULL); + + fxIrp->CopyCurrentIrpStackLocationToNext(); + fxIrp->SetNextIrpStackLocation(); + + // + // Save a pointer to the device object for this request so that it can + // be used later in completion. + // + fxIrp->SetCurrentDeviceObject(m_Device->GetDeviceObject()); + } + + origDeviceBase = Request->GetDeviceBase(); + Request->SetDeviceBase((CfxDeviceBase *)m_Device); + + // + // Attempt to insert the request into the queue + // + status = QueueRequestFromForward(Request); + if (!NT_SUCCESS(status)) { + // + // Request was not accepted, restore the original DeviceBase and flags. + // + ASSERT(Request->SetCompletionState(FxRequestCompletionStateNone) == + FxRequestCompletionStateNone); + + // + // Restore original device/info. + // + Request->SetDeviceBase(origDeviceBase); + + if (fxDriverGlobals->FxVerifierOn) { + Request->SetVerifierFlags(oldFlags); + } + + // + // If this is the parent queue, we need to adjust the IRP's stack. + // + if (ParentQueue) { + fxIrp->SkipCurrentIrpStackLocation(); + // + // There is no completion routine. See above assert. + // + Request->m_Irp.ClearNextStack(); + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyRequeue) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* pRequest + ) +{ + NTSTATUS status = STATUS_SUCCESS; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + pRequest->Lock(&irql); + + status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals); + if (NT_SUCCESS(status)) { + status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals); + } + + if (NT_SUCCESS(status)) { + pRequest->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED | + FXREQUEST_FLAG_DRIVER_DISPATCH); + } + pRequest->Unlock(irql); + + return status; +} + + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::Requeue( + __in FxRequest* pRequest + ) +{ + NTSTATUS status; + FxRequestCompletionState oldState; + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + + status = VerifyRequeue(FxDriverGlobals, pRequest); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Requeue is allowed only on Manual queue. + // + if(pRequest->GetCurrentQueue()->m_Type != WdfIoQueueDispatchManual) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Requeue is allowed only for " + "a manual queue, WDFREQUEST 0x%p " + "%!STATUS!", + pRequest, + STATUS_INVALID_DEVICE_REQUEST); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // The request has only one reference, held by the completion + // callback function. We need to take another one before cancelling + // this function, otherwise we will lose the request object + // + pRequest->ADDREF(FXREQUEST_STATE_TAG); + + // Cancel the request complete callback (deletes a reference) + oldState = pRequest->SetCompletionState(FxRequestCompletionStateNone); + ASSERT(oldState == FxRequestCompletionStateQueue); + UNREFERENCED_PARAMETER(oldState); + + Lock(&irql); + + // + // We are going to place the request back on the queue + // + + + // Driver did not accept the I/O + RemoveFromDriverOwnedList(pRequest); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFREQUEST 0x%p", pRequest->GetHandle()); + + // + // Check if we need to delete this request. + // + if (m_CancelDispatchedRequests) { + // + // Do not requeue this request. + // + status = STATUS_CANCELLED; + } + else { + // + // Place the request back at the head of the main queue + // so as not to re-order requests + // + status = pRequest->InsertHeadIrpQueue(&m_Queue, NULL); + } + + if (!NT_SUCCESS(status)) { + + // Request did not get placed in queue + ASSERT(status == STATUS_CANCELLED); + // + // Let the caller think the request is requeued successfully + // because this is no different from the request cancelling + // while it's in the queue. By returning STATUS_CANCELLED + // the caller can't take any recovery action anyways + // because the request is gone. + // + status = STATUS_SUCCESS; + + // + // We must add a reference since the CancelForQueue path + // assumes we were on the FxIrpQueue with the extra reference + // + pRequest->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForQueue(pRequest, irql); + + Lock(&irql); + } + else { + // Check if went from no requests to have requests + CheckTransitionFromEmpty(); + } + + // + // Visit the DispatchEvent so that we can deliver EvtIoReadyNotify + // + DispatchEvents(irql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoQueue, VerifyRequestCancelable) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* pRequest, + _In_ BOOLEAN Cancelable + ) +{ + NTSTATUS status; + KIRQL irql; + + PAGED_CODE_LOCKED(); + + pRequest->Lock(&irql); + + // Make sure the driver owns the request + status = pRequest->VerifyRequestIsDriverOwned(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (Cancelable) { + // + // Make sure the request is not cancelable for it to be made + // cancelable. + // + status = pRequest->VerifyRequestIsNotCancelable(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + } + else { + // + // Make sure the request is cancelable for it to be made + // uncancelable. + // + status = pRequest->VerifyRequestIsCancelable(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + goto Done; + } + } + +Done: + pRequest->Unlock(irql); + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::RequestCancelable( + __in FxRequest* pRequest, + __in BOOLEAN Cancelable, + __in_opt PFN_WDF_REQUEST_CANCEL EvtRequestCancel, + __in BOOLEAN FailIfIrpIsCancelled + ) +/*++ + + Routine Description: + + This is called to mark or unmark the request cancelable. + + Arguments: + + FxRequest* - Request that is completing + + Cancelable - if TRUE, mark the request cancellable + if FALSE, mark the request not cancelable + if it's previously marked canceelable. + + EvtRequestCancel - points to driver provided cancel routine + if the cancelable flag is TRUE. + + FailIfIrpIsCancelled - if FALSE and the IRP is already cancelled, + call the provided cancel routine and + return success. + if TRUE and the IRP is already cancelled, + return STATUS_CANCELLED. + + Returns: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + + status = VerifyRequestCancelable(FxDriverGlobals, pRequest, Cancelable); + if(!NT_SUCCESS(status)) { + return status; + } + + if (Cancelable) { + + if (FxDriverGlobals->FxVerifierOn) { + pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE); + } + // + // Set the Request for cancel status by inserting in the driver owned + // CSQ. Note: This could fire the cancel callback right away + // if the IRP was already cancelled. + // + + ASSERT(EvtRequestCancel); + + Lock(&irql); + + pRequest->m_CancelRoutine.m_Cancel = EvtRequestCancel; + + // + // Check if we need to delete this request. + // + if (m_CancelDispatchedRequests) { + // + // Purge is in progress, cancel this request. + // + status = STATUS_CANCELLED; + } + else { + status = pRequest->InsertTailIrpQueue(&m_DriverCancelable, NULL); + } + + if (NT_SUCCESS(status)) { + Unlock(irql); + } + else if (FailIfIrpIsCancelled == FALSE) { + + ASSERT(status == STATUS_CANCELLED); + + // This is not an error to the driver + status = STATUS_SUCCESS; + + pRequest->m_Canceled = TRUE; + + Unlock(irql); + + // + // We must add a reference since the CancelForDriver path + // assumes we were on the FxIrpQueue with the extra reference + // + pRequest->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForDriver(pRequest); + } + else { + + ASSERT(status == STATUS_CANCELLED); + + pRequest->m_CancelRoutine.m_Cancel = NULL; + + // + // Let the caller complete the request with STATUS_CANCELLED. + // + Unlock(irql); + + if (FxDriverGlobals->FxVerifierOn) { + pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE); + } + } + + return status; + } + else { + // + // This can return STATUS_CANCELLED if the request + // has been canceled already + // + Lock(&irql); + status = pRequest->RemoveFromIrpQueue(&m_DriverCancelable); + + if (NT_SUCCESS(status)) { + pRequest->m_CancelRoutine.m_Cancel = NULL; + } + else { + // + // In the failure case, the cancel routine has won the race and will + // be invoked on another thread. + // + DO_NOTHING(); + } + Unlock(irql); + + if (FxDriverGlobals->FxVerifierOn) { + + // We got the request back, can clear the cancelable flag + if (NT_SUCCESS(status)) { + pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE); + } + } + + return status; + } +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueRequest( + __in FxRequest* pRequest + ) + +/*++ + + Routine Description: + + Enqueue a request to the end of the queue. + + Note: This routine owns the final disposition of + the Request object, and must handle it and + dereference even if the driver does not. + + Arguments: + + pRequest - Pointer to Request object + + Returns: + + NTSTATUS +--*/ + +{ + NTSTATUS Status; + KIRQL irql; + MdIrp pIrp; + FxIrp* pFxIrp; + + // Get IoQueue Object Lock + Lock(&irql); + + ASSERT(pRequest->GetRefCnt() == 1); + + // + // If the request is reserved, take an additional reference. This reference + // will be released when the request is completed. This additional reference + // enables us to detect 2 to 1 transition in the completion path so that + // we can reclaim the reserved request for reuse. + // + if (pRequest->IsReserved()) { + pRequest->ADDREF(FXREQUEST_FWDPRG_TAG); + } + + // + // If queue is not taking new requests, fail now + // + if (!IsState(WdfIoQueueAcceptRequests)) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFQUEUE 0x%p is not accepting requests, " + "state is %!WDF_IO_QUEUE_STATE!, %s" + "completing WDFREQUEST 0x%p %!STATUS!", + GetObjectHandle(), m_QueueState, + IsState(FxIoQueueShutdown) ? + "power stopping (Drain) in progress," : "", + pRequest->GetHandle(), + STATUS_INVALID_DEVICE_STATE); + + // Must release IoQueue object Lock + Unlock(irql); + + Status = STATUS_INVALID_DEVICE_STATE; + + // Complete it with error + pRequest->CompleteWithInformation(Status, 0); + + // Dereference request object + pRequest->RELEASE(FXREQUEST_COMPLETE_TAG); + + return Status; + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p", + pRequest->GetHandle(),GetObjectHandle()); + + (VOID)pRequest->GetIrp(&pIrp); + + pFxIrp = pRequest->GetFxIrp(); + + pFxIrp->MarkIrpPending(); + + // + // If the request is reserved, we may be called to dispatch + // a pending reserved IRP from within the context of the completion routine. + // So to avoid recursion, we will insert the request in the queue and try + // to dispatch in the return path. If the request is not reserved then we + // will dispatch it directly because this path is meant for dispatching new + // incoming I/O. There is no concern for running into recursion in that + // scenario. + // + if (pRequest->IsReserved() && m_Dispatching != 0) { + InsertNewRequestLocked(&pRequest, irql); + Unlock(irql); + } + else { + DispatchEvents(irql, pRequest); + } + + // We always return status pending through the frameworks + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueRequestFromForward( + __in FxRequest* pRequest + ) + +/*++ + + Routine Description: + + Enqueue a request to the end of the queue. + + This is an internal version that does not fail + the request if it can not be enqueued. + + Arguments: + + pRequest - Pointer to Request object + + Returns: + + STATUS_SUCCESS on success +--*/ + +{ + NTSTATUS status; + KIRQL irql; + BOOLEAN fromIo; + + // Get IoQueue Object Lock + Lock(&irql); + + // + // If queue is not taking new requests, fail now + // + if (!IsState(WdfIoQueueAcceptRequests)) { + + status = STATUS_WDF_BUSY; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIO, + "WDFQUEUE 0x%p is not accepting requests " + "state is %!WDF_IO_QUEUE_STATE!, %s" + "WDFREQUEST 0x%p %!STATUS!", + GetObjectHandle(), m_QueueState, + IsState(FxIoQueueShutdown) ? + "power stopping (Drain) in progress," : "", + pRequest->GetHandle(), status); + + Unlock(irql); + + return status; + } +#if FX_VERBOSE_TRACE + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Queuing WDFREQUEST 0x%p on WDFQUEUE 0x%p", + pRequest->GetHandle(), GetObjectHandle()); +#endif + // + // The Request has one reference count, and no completion + // callback function. It has been completely removed from + // its previous queue. + // + + // + // Cache this info b/c the request can be delete and freed by the time we use it. + // + fromIo = pRequest->IsAllocatedFromIo(); + + // + // Insert it in the Cancel Safe Queue + // + // This will mark the IRP pending + // + status = pRequest->InsertTailIrpQueue(&m_Queue, NULL); + + if (!NT_SUCCESS(status)) { + + pRequest->SetCurrentQueue(this); + + ASSERT(status == STATUS_CANCELLED); + + // + // We must add a reference since the CancelForQueue path + // assumes we were on the FxIrpQueue with the extra reference + // + pRequest->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForQueue(pRequest, irql); + + Lock(&irql); + } + else { + pRequest->SetCurrentQueue(this); + + // Check if went from no requests to have requests + CheckTransitionFromEmpty(); + } + + // + // If the request is driver-created, we may be called to dispatch + // a request from within the context of the completion routine. + // So to avoid recursion, we will try to dispatch in the return path. + // If the request is not driver-created then we will dispatch it directly because + // this path is meant for dispatching new incoming I/O. There is no concern for + // running into recursion in that scenario. + // + if (fromIo == FALSE && m_Dispatching != 0) { + Unlock(irql); + } + else { + // + // Attempt to dispatch any new requests. + // + // This releases, and re-acquires the IoQueue lock + // + DispatchEvents(irql); + } + + return STATUS_SUCCESS; +} + +VOID +FxIoQueue::DeferredDispatchRequestsFromDpc( + ) + +/*++ + + Routine Description: + + Dispatch requests from the queue to the driver + from within the m_Dpc + + Arguments: + + Returns: + +--*/ + +{ + KIRQL irql; + + Lock(&irql); + + ASSERT(m_DpcQueued != FALSE); + + m_RequeueDeferredDispatcher = FALSE; + + DispatchEvents(irql); + + // + // DispatchEvents drops the lock before returning. So reacquire the lock. + // + Lock(&irql); + + if (m_Deleted == FALSE && m_RequeueDeferredDispatcher) { + InsertQueueDpc(); + } else { + m_RequeueDeferredDispatcher = FALSE; + m_DpcQueued = FALSE; + } + + Unlock(irql); + + return; +} + +VOID +FxIoQueue::DeferredDispatchRequestsFromWorkerThread( + ) + +/*++ + + Routine Description: + + Dispatch requests from the queue to the driver + from within the m_WorkItem. + + Arguments: + + Returns: + +--*/ + +{ + KIRQL irql; + + Lock(&irql); + + ASSERT(m_WorkItemQueued != FALSE); + + m_RequeueDeferredDispatcher = FALSE; + + DispatchEvents(irql); + + // + // DispatchEvents drops the lock before returning. So reacquire + // the lock. + // + Lock(&irql); + + if (m_Deleted == FALSE && + m_RequeueDeferredDispatcher && + m_SystemWorkItem->Enqueue(_DeferredDispatchThreadThunk, this)) { + // + // Workitem is queued. + // + DO_NOTHING(); + } else { + m_RequeueDeferredDispatcher = FALSE; + m_WorkItemQueued = FALSE; + } + + Unlock(irql); + + return; +} + +NTSTATUS +FxIoQueue::InsertNewRequestLocked( + __deref_in FxRequest** Request, + __in KIRQL PreviousIrql + ) +/*++ + + Routine Description: + + Purpose of this function is to insert the request that's dispatched + by the IoPkg into FxIrpQueue. This function has been added to improve + the performance of queueing logic. Prior to version 1.7, when a + request is dispatched to a queue, it was first inserted into queue, + various checks for the readiness of queue made, and then the request + is removed from the queue to be presented to the driver. + + To improve the I/O performance, dispatching logic has been changed + such that the request will not be inserted into the queue if the queue + is ready to dispatch the request. If the queue is not ready or if there + are other events to be dispatched before dispatching the new incoming request, + we will queue the request first using this function before releasing the lock + so that we don't change the ordering of requests in the queue. + +--*/ +{ + NTSTATUS status; + + status = (*Request)->InsertTailIrpQueue(&m_Queue, NULL); + + if (!NT_SUCCESS(status)) { + // + // Request was never presented to the driver + // so there is no need to call CancelForQueue + // in this case. + // + ASSERT(status == STATUS_CANCELLED); + + Unlock(PreviousIrql); + + (*Request)->CompleteWithInformation(status, 0); + + (*Request)->RELEASE(FXREQUEST_COMPLETE_TAG); + + Lock(&PreviousIrql); + } + else { + (*Request)->SetCurrentQueue(this); + + // Check if went from no requests to have requests + CheckTransitionFromEmpty(); + } + + // + // Request is either inserted into the queue or completed. Clear + // the field to prevent touching the request. + // + *Request = NULL; + + return status; +} + +_Must_inspect_result_ +BOOLEAN +FxIoQueue::CanThreadDispatchEventsLocked( + __in KIRQL PreviousIrql + ) +/*++ + + Routine Description: + + Dispatch events and requests from the queue to the driver. + + The IoQueue object lock must be held on entry. This routine + should not drop and reacquire the lock to ensure the request + is not queued out of order. + + Returns: + + TRUE - if the thread meets all the sychronization and + execution contraints to dispatch the events. + FALSE - if the dispatching of events to be defered to + another thread - either DPC or workitem. +--*/ +{ + // + // If the current irql is not at passive-level and the queue is configured + // to receive events only at passive-level then we should queue a + // workitem to defer the processing. + // + if ((PreviousIrql > PASSIVE_LEVEL) && m_PassiveLevel) { + ASSERT(PreviousIrql <= DISPATCH_LEVEL); + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIO, + "Current thread 0x%p is not at the passive-level" + " %!irql!, posting to worker thread for WDFQUEUE" + " 0x%p", + Mx::MxGetCurrentThread(), + PreviousIrql, + GetObjectHandle()); + // + // We only need to post this once + // + if (m_WorkItemQueued == FALSE) { + + m_WorkItemQueued = TRUE; + + if (!m_SystemWorkItem->Enqueue(_DeferredDispatchThreadThunk, this)) { + ASSERT(FALSE); + m_WorkItemQueued = FALSE; + } + } + + return FALSE; + } + + // + // If the current thread is holding the presentation lock, we + // must defer to a DPC or work item. + // This is the result of the device driver calling + // WdfRequestForwardToIoQueue, or WdfIoQueueStart/Stop from + // within I/O dispatch handler. This can also occur if a driver + // attempts to forward a request among a circular series of Queues + // that are configured to have locking constraints. + // + if (m_CallbackLockPtr && m_CallbackLockPtr->IsOwner()) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIO, + "Presentation lock for WDFQUEUE 0x%p is " + "already held, deferring to dpc or workitem", + GetObjectHandle()); + + if (m_PassiveLevel) { + + if(m_WorkItemQueued == FALSE) { + + m_WorkItemQueued = TRUE; + + if (!m_SystemWorkItem->Enqueue(_DeferredDispatchThreadThunk, this)) { + ASSERT(FALSE); + m_WorkItemQueued = FALSE; + } + } + } + else { + // + // We only need to post this once + // + if (m_DpcQueued == FALSE) { + + m_DpcQueued = TRUE; + + InsertQueueDpc(); + } + } + + return FALSE; + } + + return TRUE; +} + +_Releases_lock_(this->m_SpinLock.m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxIoQueue::DispatchEvents( + __in __drv_restoresIRQL KIRQL PreviousIrql, + __in_opt FxRequest* NewRequest + ) +/*++ + + Routine Description: + + Dispatch events and requests from the queue to the driver. + + The IoQueue object lock must be held on entry, but this routine can release + and re-acquire the lock multiple times while processing. + + It returns to the caller with the lock released, but queue state may have + changed. + + The main processing loop checks for various Queue state change events + delivering them to the driver, and then finally any WDFREQUEST objects + that are pending in the Queue. + + The design also handles the recursive case with the m_Dispatching + field so that a driver that completes requests from within the + callback does not cause a stack or lock recursion. + + All event callbacks to the device driver are provided though the + FxCallback object which manages lock acquire and release as required + by the locking model. + + In addition these may be passive or dispatch level locks. + If configured for passive level callbacks, + must defer to a work item if current thread is DISPATCH_LEVEL + when not owning the current FxIoQueue lock + + Arguments: + + NewRequest - This is a new incoming request from the driver above. + It will be either presented to the driver or saved into + a queue if the conditions are not right to dispatch. + + Returns: + + FALSE if the queue is in a deleted state else TRUE. + Caller should check for return value only if it's waiting + on the some events to be invoked by this call. + +--*/ +{ + FxRequest* pRequest; + ULONG totalIoCount; + NTSTATUS status; + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + if (m_Deleted) { + ASSERT(NewRequest == NULL); + Unlock(PreviousIrql); + return FALSE; + } + + // + // The design of the I/O Queue allows all "events" to notify the driver of + // to be deferred until the opportune time to deliver them. + // Depending on the drivers configured locking and threading + // mode, this may have to be deferred to a worker thread or a DPC + // to be in a compatible IRQL level, or to prevent a lock recursion + // when a parent objects lock is in effect. + // + + if (CanThreadDispatchEventsLocked(PreviousIrql) == FALSE) { + // + // Previous workitem or Dpc might be running the DispatchEvents right now. + // But it may be at a point where it might miss out to process the event + // that we have been asked to dispatch. This is possible because the + // DispatchEvent is reentrant as it acquires and drops lock along + // the way. So we make a note of this, so that when the current Dpc or + // workItem runs to completion, it will requeue itself to handle our message. + // + m_RequeueDeferredDispatcher = TRUE; + + // + // Queue the request in to FxIrpQueue and return. + // + InsertNewRequest(&NewRequest, PreviousIrql); + Unlock(PreviousIrql); + return TRUE; + } + + // + // This must be incremented before attempting to deliver any + // events to the driver. This prevents recursion on the presentation lock, + // and limits the stack depth in a Start/Complete/Start/... recursion + // + m_Dispatching++; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Thread %p is processing WDFQUEUE 0x%p", + Mx::MxGetCurrentThread(), GetObjectHandle()); + + // + // At this point all constaints such as IRQL level, locks held, + // and stack recursion protection has been satisfied, and we can + // make callbacks into the device driver. + // + // Process events and requests until we either have an empty queue, + // the driver stops taking requests, or some queue state does not + // allow the driver to take new requests + // + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + // + // totoalIoCount is sum of requests pending in the queue and requests + // currently owned by the driver. + // + totalIoCount = m_Queue.GetRequestCount() + m_DriverIoCount; + + // + // Increment the count if there is a new request to be dispatched. + // + totalIoCount += ((NewRequest != NULL) ? 1 : 0); + + if (!IsListEmpty(&this->m_Cancelled)) { + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + // + // This can drop and re-acquire the queue lock + // ProcessCancelledRequests returns FALSE if the queue is + // notifying driver about power state changes. + // + if(ProcessCancelledRequests(&PreviousIrql)) { + continue; + } + } + + if (!IsListEmpty(&this->m_CanceledOnQueueList)) { + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + // + // This can drop and re-acquire the queue lock + // ProcessCancelledRequests returns FALSE if the queue is + // notifying driver about power state changes. + // + if (ProcessCancelledRequestsOnQueue(&PreviousIrql)) { + continue; + } + } + + if (m_IdleComplete.Method != NULL && + m_Dispatching == 1L && + m_DriverIoCount == 0L) { + + InsertNewRequest(&NewRequest, PreviousIrql); + + // no more driver owned requests, we can clear the following flag: + m_CancelDispatchedRequests = FALSE; + + // This can drop and re-acquire the queue lock + ProcessIdleComplete(&PreviousIrql); + continue; + } + + if (m_PurgeComplete.Method != NULL && + totalIoCount == 0L && + m_Dispatching == 1L) { + + InsertNewRequest(&NewRequest, PreviousIrql); + + // no more driver owned requests, we can clear the following flag: + m_CancelDispatchedRequests = FALSE; + + // This can drop and re-acquire the queue lock + ProcessPurgeComplete(&PreviousIrql); + continue; + } + + if (m_IsDevicePowerPolicyOwner && + m_PowerManaged && + m_PowerReferenced && + totalIoCount == 0L && + m_Dispatching == 1L) { + + // + // Queue has no requests, and is going idle. Notify + // PNP/Power. + // + m_Device->m_PkgPnp->PowerDereference(); + m_PowerReferenced = FALSE; + continue; + } + + // + // Look for power state transitions + // + if (m_PowerState != FxIoQueuePowerOn && + m_PowerState != FxIoQueuePowerOff) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFQUEUE 0x%p Power Transition State " + "%!FxIoQueuePowerState!", GetObjectHandle(), + m_PowerState); + + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + // Process intermediate power state + // This can drop and re-acquire the queue lock + if (ProcessPowerEvents(&PreviousIrql)) { + continue; + } + else { + + // + // Return, awaiting some response from the driver + // + goto Done; + } + } + else { + // Queue is either in PowerOn or PowerOff state + DO_NOTHING(); + } + + // + // Check for queue disposing should be made after processing all + // the events. + // + if (m_Disposing && + totalIoCount == 0L && + m_Dispatching == 1L) { + + m_Deleted = TRUE; + + // + // After this point, no other thread will be able to dispatch + // events from this queue. Also threads that are about to call + // this function as soon as we drop the lock below should have + // a reference on the queue to prevent queue object from being + // freed when we signal the dispose thread to run through. + // + Unlock(PreviousIrql); + + m_FinishDisposing.Set(); + return TRUE; + } + + + // + // Return if power is off, can't deliver any request oriented events + // to the driver. + // + if (m_PowerState == FxIoQueuePowerOff) { + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + goto Done; + } + + // + // See if the queue is (still) processing requests + // + if (!IsState(WdfIoQueueDispatchRequests)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO, + "WDFQUEUE 0x%p not in dispatching state, " + "current state is %!WDF_IO_QUEUE_STATE!", + GetObjectHandle(), m_QueueState); + + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + goto Done; + } + + // + // A manual dispatch queue can have a request ready notification + // + if (m_Type == WdfIoQueueDispatchManual) { + + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + if (m_ReadyNotify.Method != NULL && m_TransitionFromEmpty) { + + // This can drop and re-acquire the lock to callback to the driver + ProcessReadyNotify(&PreviousIrql); + continue; + } + + goto Done; + } + + if (m_Type == WdfIoQueueDispatchSequential && m_DriverIoCount > 0) { + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + goto Done; + } + + // + // For counted Queue's dont dispatch request to driver if the + // m_DriverIoCount exceeds the one set by the driver writer. + // + if (m_Type == WdfIoQueueDispatchParallel && + (ULONG)m_DriverIoCount >= m_MaxParallelQueuePresentedRequests) { + status = InsertNewRequest(&NewRequest, PreviousIrql); + if (!NT_SUCCESS(status)) { + continue; // totalIoCount may be zero now. + } + + goto Done; + } + + // + // If there is a request in the queue, then retrieve that. + // + pRequest = NULL; + if (m_Queue.GetRequestCount() > 0L) { + pRequest = FxRequest::GetNextRequest(&m_Queue); + } + + // + // The request from the queue should be dispatched first + // to preserve the ordering. + // + if (pRequest != NULL) { + InsertNewRequest(&NewRequest, PreviousIrql); + } + else { + // + // If there is no request in the queue then dispatch + // the incoming one. + // + pRequest = NewRequest; + if (pRequest != NULL) { + pRequest->SetCurrentQueue(this); + SetTransitionFromEmpty(); + NewRequest = NULL; + } + else { + goto Done; + } + } + + // + // pRequest is not cancellable now + // + InsertInDriverOwnedList(pRequest); + + Unlock(PreviousIrql); + + DispatchRequestToDriver(pRequest); + + Lock(&PreviousIrql); + } + +Done: + m_Dispatching--; + Unlock(PreviousIrql); + return TRUE; +} + +VOID +FxIoQueue::DispatchRequestToDriver( + __in FxRequest* pRequest + ) + +/*++ + + Routine Description: + + Dispatch the next request to the driver. + + The IoQueue object lock is *not* held. + + It returns to the caller with the lock *not* held. + + This is called by DispatchRequests(), and should not be + called directly in order to maintain queue processing model. + + Arguments: + + Returns: + +--*/ + +{ + PFX_DRIVER_GLOBALS FxDriverGlobals; + NTSTATUS Status; + FxRequestCompletionState oldState; + WDFREQUEST hRequest; + FxIrp* pIrp; + + FxDriverGlobals = GetDriverGlobals(); + + + + + + (VOID)pRequest->GetCurrentIrpStackLocation(); + + pIrp = pRequest->GetFxIrp(); + + // The Irp does not have a cancel function right now +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + ASSERT(pIrp->GetCurrentIrpStackLocation() != NULL); +#endif + + // + // Set our completion callback on the request now before + // calling the driver since the driver can complete the + // request in the callback handler, and to avoid races with + // the drivers completion thread. + // + // This takes a reference on the request object. + // + oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue); + ASSERT(oldState == FxRequestCompletionStateNone); + UNREFERENCED_PARAMETER(oldState); + + if (FxDriverGlobals->FxVerifierOn) { + // + // If the verifier is on, we do not release the extra + // reference so we can mark the request as no longer + // being dispatched to the driver on return from the + // event callback to the driver + // + + ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) == 0); + + // Mark the request as being "owned" by the driver + pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED | + FXREQUEST_FLAG_DRIVER_DISPATCH); + } + else { + + // + // Release our original reference. The FxRequest::Complete + // will release the final one since we have registered a completion + // callback handler + // + // We now have one reference count on the FxRequest object until + // its completion routine runs since the completion event made + // an extra reference, and will dereference it when it fires, or + // its canceled. + // + + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + + // + // Attempt to dispatch it to the driver + // + + // + // Note: A driver that changes its callback pointers at runtime + // could run into a race here since we released the queue + // lock. Currently, changing parameters on a processing + // queue is undefined. + // + // The C DDI's force the callbacks to be registered at + // queue creation time and avoid this race. + // + + hRequest = pRequest->GetHandle(); + + UCHAR majorFunction = pIrp->GetMajorFunction(); + + if ((majorFunction == IRP_MJ_READ) && m_IoRead.Method) { + ULONG readLength = pIrp->GetParameterReadLength(); + + // + // Complete zero length reads with STATUS_SUCCESS unless the + // driver specified it wants them delivered. + // + if ((readLength == 0) && + !m_AllowZeroLengthRequests) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Zero length WDFREQUEST 0x%p completed automatically " + "by WDFQUEUE 0x%p", hRequest, GetObjectHandle()); + + pRequest->Complete(STATUS_SUCCESS); + if (FxDriverGlobals->FxVerifierOn) { + // + // Release the reference taken in the call to SetCompletionState + // at the top of the function. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + return; + } + + pRequest->SetPresented(); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Calling driver EvtIoRead for WDFREQUEST 0x%p", + hRequest); + + m_IoRead.Invoke( + GetHandle(), + hRequest, + readLength + ); + } + else if ((majorFunction == IRP_MJ_WRITE) && m_IoWrite.Method) { + ULONG writeLength = pIrp->GetParameterWriteLength(); + + // + // Complete zero length writes with STATUS_SUCCESS unless the + // driver specified it wants them delivered. + // + if ((writeLength == 0) && + !m_AllowZeroLengthRequests) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Zero length WDFREQUEST 0x%p completed automatically " + "by WDFQUEUE 0x%p", hRequest, GetObjectHandle()); + + pRequest->Complete(STATUS_SUCCESS); + + if (FxDriverGlobals->FxVerifierOn) { + // + // Release the reference taken in the call to SetCompletionState + // at the top of the function. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + return; + } + + pRequest->SetPresented(); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Calling driver EvtIoWrite for WDFREQUEST 0x%p", + pRequest->GetObjectHandle()); + + m_IoWrite.Invoke( + GetHandle(), + hRequest, + writeLength + ); + } + else if ((majorFunction == IRP_MJ_DEVICE_CONTROL) && m_IoDeviceControl.Method) { + + pRequest->SetPresented(); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Calling driver EvtIoDeviceControl for " + "WDFREQUEST 0x%p", hRequest); + + m_IoDeviceControl.Invoke( + GetHandle(), + hRequest, + pIrp->GetParameterIoctlOutputBufferLength(), + pIrp->GetParameterIoctlInputBufferLength(), + pIrp->GetParameterIoctlCode() + ); + } + + else if ( (majorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) && m_IoInternalDeviceControl.Method) { + + pRequest->SetPresented(); + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Calling driver EvtIoInternalDeviceControl for WDFREQUEST 0x%p", + hRequest); + + m_IoInternalDeviceControl.Invoke( + GetHandle(), + hRequest, + pIrp->GetParameterIoctlOutputBufferLength(), + pIrp->GetParameterIoctlInputBufferLength(), + pIrp->GetParameterIoctlCode() + ); + } + else { + + // + // If we have an IoStart registered, call it + // + if (m_IoDefault.Method) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Calling driver EvtIoDefault for WDFREQUEST 0x%p", hRequest); + + + // + // If we don't allow zero length requests, we must dig in whether + // its a read or a write + // + if (!m_AllowZeroLengthRequests) { + + if (majorFunction == IRP_MJ_READ) { + + if (pIrp->GetParameterReadLength() == 0) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Zero length WDFREQUEST 0x%p completed automatically " + "by WDFQUEUE 0x%p", hRequest, GetObjectHandle()); + + pRequest->Complete(STATUS_SUCCESS); + if (FxDriverGlobals->FxVerifierOn) { + // + // Release the reference taken in the call to SetCompletionState + // at the top of the function. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + return; + } + } + else if (majorFunction == IRP_MJ_WRITE) { + + if (pIrp->GetParameterWriteLength() == 0) { + + pRequest->Complete(STATUS_SUCCESS); + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Zero length WDFREQUEST 0x%p completed automatically " + "by WDFQUEUE 0x%p", hRequest, GetObjectHandle()); + + if (FxDriverGlobals->FxVerifierOn) { + // + // Release the reference taken in the call to SetCompletionState + // at the top of the function. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + return; + } + } + } + + pRequest->SetPresented(); + + m_IoDefault.Invoke(GetHandle(), hRequest); + } + else { + Status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Driver has no event callback " + "for %!WDF_REQUEST_TYPE!, completing WDFREQUEST 0x%p with " + "%!STATUS!", + majorFunction, + pRequest, + Status); + + pRequest->Complete(Status); + + if (FxDriverGlobals->FxVerifierOn) { + // + // Release our extra verifier reference now + // + // Release the reference taken in the call to SetCompletionState + // at the top of the function. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + + return; + } + } + + // ****************************** + // Request may now be a freed object unless verifier is on. Only touch + // request if verifier is on. + // ****************************** + + if (FxDriverGlobals->FxVerifierOn) { + + // + // If the request has been forwarded, don't clear this + // since the new queue may already be dispatching in a new thread or DPC + // + if ((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_FORWARDED) == 0x0) { + pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_DISPATCH); + } + + // + // Release our extra verifier reference now + // + // Release the reference taken in the call to SetCompletionState + + // at the top of the function. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } + + // Driver accepted a request + return; +} + + +// +// Register a callback when the Queue has a request. +// +// Only valid for a manual Queue. +// +_Must_inspect_result_ +NTSTATUS +FxIoQueue::ReadyNotify( + __in PFN_WDF_IO_QUEUE_STATE QueueReady, + __in_opt WDFCONTEXT Context + ) +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + NTSTATUS status; + + // Only valid for a manually dispatched Queue + if (m_Type != WdfIoQueueDispatchManual) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p is " + "not a Manual queue, ReadyNotify is only valid " + "on a manual Queue, %!STATUS!", + GetObjectHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return status; + } + + Lock(&irql); + + // If the queue is deleted, requests will not be serviced anymore + if (m_Deleted) { + Unlock(irql); + return STATUS_DELETE_PENDING; + } + + if (QueueReady != NULL) { + + // + // Only one ReadyNotify registration per Queue is allowed + // + if (m_ReadyNotify.Method != NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p " + "already has a ReadyNotify callback 0x%p" + "registered, %!STATUS!",GetObjectHandle(), + &m_ReadyNotify, status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + Unlock(irql); + return status; + } + + m_ReadyNotify.Method = QueueReady; + m_ReadyNotifyContext = Context; + } + else { + + // + // A request to cancel ready notifications + // + + // If already cancelled, the driver is confused, notify it + if (m_ReadyNotify.Method == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p " + "does not have a ReadyNotify to cancel, %!STATUS!", + GetObjectHandle(), status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + Unlock(irql); + return status; + } + + // + // The queue should be stopped from dispatching requests to + // avoid missing state transistions between clear and set. + // + if(IsState(WdfIoQueueDispatchRequests)) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p " + "should be stopped before clearing ReadyNotify callback " + "0x%p registered, %!STATUS!",GetObjectHandle(), + &m_ReadyNotify, status); + FxVerifierDbgBreakPoint(FxDriverGlobals); + Unlock(irql); + return status; + + } + + m_ReadyNotify.Method = NULL; + m_ReadyNotifyContext = NULL; + } + + // + // Check for ready notification since there may already be an event + // + DispatchEvents(irql); + + return STATUS_SUCCESS; +} + +VOID +FxIoQueue::QueueStart( + ) +{ + KIRQL irql; + + Lock(&irql); + + SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetAcceptRequests | FxIoQueueSetDispatchRequests) ); + + // + // We should set the flag to notify the driver on queue start in case + // the driver stops the queue while the ReadyNotify callback is executing. + // If that happens, the request will be left in the manual queue with + // m_TransitionFromEmpty cleared. + // + if (m_Queue.GetRequestCount() > 0L) { + m_TransitionFromEmpty = TRUE; + m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE; + } + + // + // We may have transitioned to a status that resumes + // processing, so call dispatch function. + // + + DispatchEvents(irql); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueIdle( + __in BOOLEAN CancelRequests, + __in_opt PFN_WDF_IO_QUEUE_STATE IdleComplete, + __in_opt WDFCONTEXT Context + ) + +/*++ + +Routine Description: + + Idle (stop) the Queue. + + If CancelRequests == TRUE, + 1) any requests in the Queue that have not been presented to the device driver are + completed with STATUS_CANCELLED. + 2) any requests that the driver is operating on that are cancelable will have an + I/O Cancel done on them. + 3) any forward progress queued IRPs are completed with STATUS_CANCELLED. + +Arguments: + +Returns: + +--*/ + +{ + PFX_DRIVER_GLOBALS fxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + NTSTATUS status; + LIST_ENTRY fwrIrpList = {0}; + FxRequest* request; + + + Lock(&irql); + + // If the queue is deleted, requests will not be serviced anymore + if (m_Deleted) { + status = STATUS_DELETE_PENDING; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p is already deleted, %!STATUS!", + GetObjectHandle(), status); + Unlock(irql); + + return status; + } + + // + // If a IdleComplete callback is supplied, we must register it up + // front since a transition empty could occur in another thread. + // + if (IdleComplete != NULL) { + + // + // Only one Idle or Purge Complete callback can be outstanding + // at a time per Queue + // + if (m_IdleComplete.Method != NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p already has a " + "IdleComplete callback registered 0x%p, " + "%!STATUS!", GetObjectHandle(), + m_IdleComplete.Method, + status); + Unlock(irql); + + return status; + } + + m_IdleComplete.Method = IdleComplete; + m_IdleCompleteContext = Context; + } + + // Set Accept request and Clear dispatch requests + SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetAcceptRequests | FxIoQueueClearDispatchRequests)); + + // + // Get ready to cancel current queued requests. Note that we don't want to + // prevent new requests from being queue, i.e., it is legal for an upper + // driver can resend another request in its completion routine. + // + if (CancelRequests) { + // + // Driver wants to abort/complete all queued request and cancel or + // wait for all requests the driver is currently handling. Thus we must + // prevent the driver from requeuing stale requests. + // The 'cancel driver requests' field gives us this ability. + // It is set here, and cleared when: + // (a) Driver doesn't own any more requests, or + // (b) the driver calls WdfIoQueueStart again (dispatch gate is opened). + // When set, the framework automatically deletes any request that the + // driver requeues. + // + m_CancelDispatchedRequests = TRUE; + + request = NULL; // Initial tag used by PeekRequest. + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + status = FxRequest::PeekRequest(&m_Queue, // in:queue + request, // in:tag. + NULL, // in:file_obj + NULL, // out:parameters + &request); // out:request. + if (status != STATUS_SUCCESS) { + ASSERT(status != STATUS_NOT_FOUND); + break; + } + + // + // Tag this request and release the extra ref that Peek() takes. + // + request->m_Canceled = TRUE; + +#pragma prefast(suppress:__WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "This is the tag value used in the ADDREF of Peek()") + request->RELEASE(NULL); + } + + // + // Move forward progress IRPs to a temp list; we use this logic to + // allow new IRPs to be pended to the original list. + // + if (IsForwardProgressQueue()) { + InitializeListHead(&fwrIrpList); + GetForwardProgressIrps(&fwrIrpList, NULL); + } + } + + // Unlock queue lock + Unlock(irql); + + if (CancelRequests) { + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + // + // Get the next FxRequest from the cancel safe queue + // + Lock(&irql); + request = FxRequest::GetNextRequest(&m_Queue); + if (request == NULL) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "All WDFQUEUE 0x%p requests cancelled", + GetObjectHandle()); + Unlock(irql); + break; + } + + // Irp is not cancellable now + + // + // Make sure to purged requests only if: + // (a) the request was present when we started this operation. + // (b) any following request that is marked as cancelled. + // + if (request->IsCancelled() == FALSE) { + status = request->InsertHeadIrpQueue(&m_Queue, NULL); + if (NT_SUCCESS(status)) { + Unlock(irql); + break; + } + + ASSERT(status == STATUS_CANCELLED); + } + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO, + "Cancelling WDFREQUEST 0x%p, WDFQUEUE 0x%p", + request->GetHandle(),GetObjectHandle()); + + // + // We must add a reference since the CancelForQueue path + // assumes we were on the FxIrpQueue with the extra reference + // + request->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForQueue(request, irql); + } + + // + // Walk the driver cancelable list cancelling the requests. + // + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + // + // Get the next request of driver cancelable requests + // + Lock(&irql); + request = FxRequest::GetNextRequest(&m_DriverCancelable); + if (request == NULL) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "All driver cancellable requests cancelled " + " in WDFQUEUE 0x%p", + GetObjectHandle()); + Unlock(irql); + break; + } + + request->m_Canceled = TRUE; + + Unlock(irql); + + // + // If the driver follows the pattern of removing cancel status + // from the request before completion, then there is no race + // with this routine since we will not be able to retrieve any + // requests the driver has made non-cancellable in preparation + // for completion. + // + request->ADDREF(FXREQUEST_QUEUE_TAG); + + CancelForDriver(request); + + // The request could have been completed and released by the driver + } + + // + // Cleanup forward progress IRP list. + // + if (IsForwardProgressQueue()) { + CancelIrps(&fwrIrpList); + } + } + + // + // Since we set that no new requests may be dispatched, + // if both m_Queue.GetRequestCount(), m_DriverIoCount == 0, and + // m_Dispatch == 0, right now the queue is completely idle. + // + + // + // We check if our m_PurgeComplete callback is still set + // since it may have been called by another thread when + // we dropped the lock above + // + Lock(&irql); + DispatchEvents(irql); + + // + // If the driver registered an IdleComplete callback, and it was + // not idle in the above check, it will be called when the final + // callback handler from the device driver returns. + // + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueIdleSynchronously( + __in BOOLEAN CancelRequests + ) +/*++ + +Routine Description: + + Idle the Queue and wait for the driver-owned requests to complete. + +Arguments: + + CancelRequests - If TRUE, functions tries to cancel outstanding requests. + +Returns: + +--*/ +{ + NTSTATUS status; +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer(); +#else + MxEvent eventOnStack; + // + // Note that initialize always succeeds in KM so return is not checked. + // + eventOnStack.Initialize(NotificationEvent, FALSE); + MxEvent* event = eventOnStack.GetSelfPointer(); +#endif + + status = QueueIdle(CancelRequests, _IdleComplete, event->GetSelfPointer()); + + if(NT_SUCCESS(status)) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Waiting for %d requests to complete " + "on WDFQUEUE 0x%p", + m_DriverIoCount, + GetObjectHandle()); + + Mx::MxEnterCriticalRegion(); + + GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(), + "waiting for queue to stop, WDFQUEUE", GetHandle(), + GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + + + Mx::MxLeaveCriticalRegion(); + } + + return status; + +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueuePurge( + __in BOOLEAN CancelQueueRequests, + __in BOOLEAN CancelDriverRequests, + __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete, + __in_opt WDFCONTEXT Context + ) +/*++ + +Routine Description: + + Purge the Queue. + + If CancelQueueRequests == TRUE, any requests in the + Queue that have not been presented to the device driver are + completed with STATUS_CANCELLED. + + If CancelDriverRequests == TRUE, any requests that the + driver is operating on that are cancelable will have an + I/O Cancel done on them. + +Arguments: + +Returns: + +--*/ +{ + FxRequest* pRequest; + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + NTSTATUS status; + + Lock(&irql); + + // + // If the Queue is deleted, there can't be any requests + // to purge, and the queue is no longer executing its + // event dispatch loop, so we would stop responding if we + // registered now. + // + // We could try and silently succeed this, but if we do, we + // must invoke the PurgeComplete callback, and without our + // queue state machine excuting, we can not ensure any + // callback constraints are handled such as locking, queueing + // to passive level, etc. So we just fail to indicate to the + // driver we *will not* be invoking its PurgeComplete function. + // + if (m_Deleted) { + status = STATUS_DELETE_PENDING; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p is already deleted %!STATUS!", + GetObjectHandle(), status); + Unlock(irql); + + return status; + } + + // + // If a PurgeComplete callback is supplied, we must register it up + // front since a transition empty could occur in another thread. + // + if (PurgeComplete != NULL) { + + // + // Only one PurgeComplete callback can be outstanding + // at a time per Queue + // + if (m_PurgeComplete.Method != NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFQUEUE 0x%p already has a " + "PurgeComplete callback registered 0x%p " + "%!STATUS!", GetObjectHandle(), + m_PurgeComplete.Method, status); + Unlock(irql); + + return status; + } + + m_PurgeComplete.Method = PurgeComplete; + m_PurgeCompleteContext = Context; + } + + // Clear accept requests + SetState(FxIoQueueClearAcceptRequests); + + if (CancelQueueRequests && CancelDriverRequests && + FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + // + // Driver wants to abort/complete all queued request and cancel or + // wait for all requests the driver is currently handling. Thus we must + // prevent the driver from requeuing stale requests. + // This flag is set here, and cleared when: + // (a) Driver doesn't own any more requests, or + // (b) the driver calls WdfIoQueueStart again (dispatch gate is opened). + // When set, the framework automatically deletes any request that the + // driver requeues. + // For compatibility we do this only for drivers v1.11 and above. + // + m_CancelDispatchedRequests = TRUE; + } + + // Unlock queue lock + Unlock(irql); + + if (CancelQueueRequests) { + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + // + // Get the next FxRequest from the cancel safe queue + // + Lock(&irql); + pRequest = FxRequest::GetNextRequest(&m_Queue); + if (pRequest == NULL) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "All WDFQUEUE 0x%p requests cancelled", + GetObjectHandle()); + Unlock(irql); + break; + } + + // Irp is not cancellable now + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO, + "Cancelling WDFREQUEST 0x%p, WDFQUEUE 0x%p", + pRequest->GetHandle(),GetObjectHandle()); + + // + // We must add a reference since the CancelForQueue path + // assumes we were on the FxIrpQueue with the extra reference + pRequest->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForQueue(pRequest, irql); + + } + } + + if (CancelDriverRequests) { + + // + // Walk the driver cancelable list cancelling + // the requests. + // + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + // + // Get the next request of driver cancelable requests + // + Lock(&irql); + pRequest = FxRequest::GetNextRequest(&m_DriverCancelable); + if (pRequest == NULL) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "All driver cancellable requests cancelled " + " in WDFQUEUE 0x%p", + GetObjectHandle()); + Unlock(irql); + break; + } + + pRequest->m_Canceled = TRUE; + + Unlock(irql); + + // + // If the driver follows the pattern of removing cancel status + // from the request before completion, then there is no race + // with this routine since we will not be able to retrieve any + // requests the driver has made non-cancellable in preparation + // for completion. + // + pRequest->ADDREF(FXREQUEST_QUEUE_TAG); + + CancelForDriver(pRequest); + + // The request could have been completed and released by the driver + } + } + + if (IsForwardProgressQueue()) { + PurgeForwardProgressIrps(NULL); + } + + // + // Since we set that no new requests may be enqueued, + // if both m_Queue.GetRequestCount() and m_DriverIoCount == 0 right + // now the queue is completely purged. + // + + // + // We check if our m_PurgeComplete callback is still set + // since it may have been called by another thread when + // we dropped the lock above + // + Lock(&irql); + + DispatchEvents(irql); + + // + // If the driver registered a PurgeComplete callback, and it was + // not empty in the above check, it will be called when a + // request complete from the device driver completes the + // final request. + // + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueuePurgeSynchronously( + ) +/*++ + +Routine Description: + + Purge the queue and wait for it to complete. + When this call returns, there are no requests in the queue or device + driver and the queue state is set to reject new requests. + +--*/ +{ + NTSTATUS status; + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer(); +#else + MxEvent eventOnStack; + // + // Note that initialize always succeeds in KM so return is not checked. + // + eventOnStack.Initialize(NotificationEvent, FALSE); + MxEvent* event = eventOnStack.GetSelfPointer(); +#endif + + status = QueuePurge(TRUE, TRUE, _PurgeComplete, event->GetSelfPointer()); + + if(NT_SUCCESS(status)) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Waiting for %d requests to complete " + "on WDFQUEUE 0x%p", + (m_DriverIoCount + m_Queue.GetRequestCount()), + GetObjectHandle()); + + Mx::MxEnterCriticalRegion(); + + GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(), + "waiting for queue to purge, WDFQUEUE", GetHandle(), + GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + + Mx::MxLeaveCriticalRegion(); + } + + return status; + +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueDrain( + __in_opt PFN_WDF_IO_QUEUE_STATE PurgeComplete, + __in_opt WDFCONTEXT Context + ) +{ + // + // We drain the queue by calling QueuePurge with CancelQueueRequests + // and CancelDriverRequests == FALSE. The Queue will reject new + // requests, but allow the device driver to continue processing + // requests currently on the Queue. The DrainComplete callback is + // invoked when there are no requests in Queue or device driver. + // + + return QueuePurge(FALSE, FALSE, PurgeComplete, Context); + +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueDrainSynchronously( + ) +/*++ + +Routine Description: + + Drain the queue and wait for it to complete. + When this call returns, there are no requests in the queue or device + driver and the queue state is set to reject new requests. + +--*/ +{ + NTSTATUS status; +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + MxEvent* event = this->m_RequestWaitEventUm.GetSelfPointer(); +#else + MxEvent eventOnStack; + // + // Note that initialize always succeeds in KM so return is not checked. + // + eventOnStack.Initialize(NotificationEvent, FALSE); + MxEvent* event = eventOnStack.GetSelfPointer(); +#endif + + status = QueueDrain(_PurgeComplete, event->GetSelfPointer()); + + if(NT_SUCCESS(status)) { + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Waiting for %d requests to complete " + "on WDFQUEUE 0x%p", + (m_DriverIoCount + m_Queue.GetRequestCount()), + GetObjectHandle()); + + Mx::MxEnterCriticalRegion(); + + GetDriverGlobals()->WaitForSignal(event->GetSelfPointer(), + "waiting for queue to drain, WDFQUEUE", GetHandle(), + GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + + Mx::MxLeaveCriticalRegion(); + } + + return status; + +} + + +VOID +FxIoQueue::GetRequestCount( + __out_opt PULONG pQueuedRequests, + __out_opt PULONG pDriverPendingRequests + ) +/*++ + +Routine Description: + + Return the count of requests currently on the queue + and owned by the driver. + +Arguments: + +Returns: + +--*/ +{ + if (pQueuedRequests != NULL) { + *pQueuedRequests = m_Queue.GetRequestCount(); + } + + if (pDriverPendingRequests != NULL) { + *pDriverPendingRequests = m_DriverIoCount; + } + + return; +} + +VOID +FxIoQueue::FlushByFileObject( + __in MdFileObject FileObject + ) +/*++ + +Routine Description: + + Scan the queue and cancel all the requests that have + the same fileobject as the input argument. + + This function is called when the IoPkg receives a + IRP_MJ_CLEANUP requests. + + Additional reference is already taken on the object by the caller + to prevent the queue from being deleted. + +Return Value: + +--*/ +{ + FxRequest* pRequest = NULL; + NTSTATUS status; + KIRQL irql; + + if (IsForwardProgressQueue()) { + PurgeForwardProgressIrps(FileObject); + } + + Lock(&irql); + + #pragma warning(disable:4127) + while (TRUE) { + #pragma warning(default:4127) + + // + // Get the next FxRequest from the cancel safe queue + // + status = FxRequest::GetNextRequest(&m_Queue, FileObject, NULL, &pRequest); + if(status == STATUS_NO_MORE_ENTRIES) { + break; + } + if(!NT_SUCCESS(status)) { + ASSERTMSG("GetNextRequest failed\n", FALSE); + break; + } + + // + // We must add a reference since the CancelForQueue path + // assumes we were on the FxIrpQueue with the extra reference + // + pRequest->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForQueue(pRequest, irql); + + // + // Reacquire the lock because CancelForQueue visits the dispatch-loop + // and releases the lock. + // + Lock(&irql); + } + + DispatchEvents(irql); + + return; + +} + +_Releases_lock_(this->m_SpinLock.m_Lock) +VOID +FxIoQueue::CancelForQueue( + __in FxRequest* pRequest, + __in __drv_restoresIRQL KIRQL PreviousIrql + ) +/*++ + + Routine Description: + + This routine performs the actions when notified of a cancel + on a request that has not been presented to the driver + + Return Value: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + FxRequestCompletionState oldState; + + // This is not an error, but want to make sure cancel testing works + if (FxDriverGlobals->FxVerifierOn) { + + // Clear cancellable status, otherwise verifier in FxRequest::Complete will complain + pRequest->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_CANCELABLE); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO, + "WDFREQUEST 0x%p " + "was cancelled while on WDFQUEUE 0x%p", + pRequest->GetHandle(),GetObjectHandle()); + } + + pRequest->m_Canceled = TRUE; + + pRequest->MarkRemovedFromIrpQueue(); + + // + // Drop the extra reference taken when it was added to the queue + // because the request is now leaving the queue. + // + pRequest->RELEASE(FXREQUEST_QUEUE_TAG); + + // + // If the driver has registered m_CanceledOnQueue callback, and if + // the request was ever presented to the driver then we need to + // notify the driver + // + if(m_IoCanceledOnQueue.Method && pRequest->m_Presented) { + + // + // Set the state to indicate the request has come from a queue. + // + oldState = pRequest->SetCompletionState(FxRequestCompletionStateQueue); + ASSERT(oldState == FxRequestCompletionStateNone); + UNREFERENCED_PARAMETER(oldState); + + // Insert it on the driver owned list + InsertInDriverOwnedList(pRequest); + + if (FxDriverGlobals->FxVerifierOn) { + ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) == 0); + pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED); + } + + // + // Also insert the request in to m_CanceledOnQueueList so + // that we can notify the driver when we visit the DispatchEvents + // + InsertTailList(&m_CanceledOnQueueList, pRequest->GetListEntry(FxListEntryQueueOwned)); + + // + // Release the reference taken in the call to SetCompletionState. + // + pRequest->RELEASE(FXREQUEST_STATE_TAG); + } else { + + Unlock(PreviousIrql); + + // Its gone from our list, so complete it cancelled + pRequest->CompleteWithInformation(STATUS_CANCELLED, 0); + + // Dereference the request objects final reference + pRequest->RELEASE(FXREQUEST_COMPLETE_TAG); + + Lock(&PreviousIrql); + } + + // This may have caused the queue to be emptied + DispatchInternalEvents(PreviousIrql); + + return; +} + +VOID +FxIoQueue::_IrpCancelForQueue( + __in FxIrpQueue* IrpQueue, + __in MdIrp Irp, + __in PMdIoCsqIrpContext CsqContext, + __in KIRQL Irql + ) +/*++ + +Routine Description: + This is our Cancel Safe Queue Callback from FxIrpQueue notifying us of an + I/O cancellation on the main (pre driver) Queue. + + Note this callback is called with the queue lock held. + +Arguments: + IrpQueue - Queue the request was on + + Irp - the irp being cancelled + + CsqContext - the context associated with the irp + +Return Value: + None + + --*/ +{ + FxIoQueue* ioQueue; + FxRequest* pRequest; + + ioQueue = CONTAINING_RECORD(IrpQueue, FxIoQueue, m_Queue); + pRequest = FxRequest::RetrieveFromCsqContext(CsqContext); + + // + // Must reference the queue since this could be the final + // request on a deleting queue + // + ioQueue->ADDREF(Irp); + + // + // We cannot drop the lock here because we may have to insert the + // request in the driver owned list if the driver has registered + // for canceled-on-queue callback. If we drop the lock and if the request + // happens to be last request, the delete will run thru and put + // the state of the queue to deleted state and prevent further dispatching + // of requests. + // + ioQueue->CancelForQueue(pRequest, Irql); + + ioQueue->RELEASE(Irp); +} + +VOID +FX_VF_METHOD(FxIoQueue, VerifyValidateCompletedRequest)( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* Request + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + + PAGED_CODE_LOCKED(); + + PLIST_ENTRY pEntry; + KIRQL irql; + + Request->Lock(&irql); + + (VOID) Request->VerifyRequestIsDriverOwned(FxDriverGlobals); + Request->ClearVerifierFlagsLocked(FXREQUEST_FLAG_DRIVER_OWNED); + + Request->Unlock(irql); + + // Driver no longer owns it once completed + + // Request can't be on a cancel list + pEntry = Request->GetListEntry(FxListEntryQueueOwned); + if( !IsListEmpty(pEntry) ) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "WDFREQUEST 0x%p is on a cancellation list for WDFQUEUE 0x%p", + Request->GetHandle(), GetObjectHandle()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } +} + +VOID +FX_VF_METHOD(FxIoQueue, VerifyCancelForDriver) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* Request + ) +{ + PLIST_ENTRY pEntry; + + PAGED_CODE_LOCKED(); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIO, + "WDFREQUEST 0x%p " + "was cancelled in driver for WDFQUEUE 0x%p", + Request->GetHandle(), GetObjectHandle()); + + // Verifier code assures this is available to the cancel processing + pEntry = Request->GetListEntry(FxListEntryQueueOwned); + if (!IsListEmpty(pEntry)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDFREQUEST 0x%p is " + "already on list, FxRequest::m_ListEntry is busy!, " + "WDFQUEUE 0x%p", + Request->GetHandle(), GetObjectHandle()); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } +} + +VOID +FxIoQueue::CancelForDriver( + __in FxRequest* pRequest + ) +/*++ + +Routine Description: + + This is called when a driver-owned cancelable request is canceled. + This routine will add the request to m_Canceled list so that the + dispatcher and call the driver cancel-routine to notify the driver. + + Queue lock is not held. + +Arguments: + + pRequest - is a driver owned cancelable request. + +Return Value: + +--*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + KIRQL irql; + + // This is not an error, but want to make sure cancel testing works + VerifyCancelForDriver(FxDriverGlobals, pRequest); + + // + // We are called with no locks held, but + // can be in arbitrary thread context from + // a cancel occuring from another driver within + // a driver stack. + // + + // + // The Csq has removed this request from the driver pending + // queue, and it no longer has a cancel function if the + // driver does not accept the cancel right now. + // + // When callside eventually goes to remove it from the queue + // by CsqContext, the Csq's will return NULL. + // + // Irp and FxRequest is still valid until the driver calls + // WdfRequestComplete either as a result of this cancel + // callback, or at its leasure if it chooses to ignore it. + // + // The insert of FxRequest onto the FxIrpQueue took out a + // reference, and when an IRP gets cancelled, we are responsible + // for this final dereference after calling into the driver. + // + + // + // Cancellations are dispatched as events to the device driver + // using the standard DispatchEvents processing loop. In order + // to support this, we must defer it by linking this request + // into a list of cancelled requests. + // + // The requests will be removed from this list and cancel notified + // to the device driver by the processing loop. + // + + pRequest->MarkRemovedFromIrpQueue(); + + // + // Queue it on the cancelled list + // + Lock(&irql); + + InsertTailList(&m_Cancelled, pRequest->GetListEntry(FxListEntryQueueOwned)); + + // + // Visit the event dispatcher + // + DispatchInternalEvents(irql); + + return; +} + +VOID +FxIoQueue::_IrpCancelForDriver( + __in FxIrpQueue* IrpQueue, + __in MdIrp Irp, + __in PMdIoCsqIrpContext CsqContext, + __in KIRQL Irql + ) +/*++ + +Routine Description: + This is our Cancel Safe Queue Callback from FxIrpQueue notifying us of an + I/O cancellation on a driver owned request (driver queue) + + Note this callback is called with the queue lock held. + +Arguments: + IrpQueue - Queue the request was on + + Irp - the irp being cancelled + + CsqContext - the context associated with the irp + + +Return Value: + None + + --*/ +{ + FxIoQueue* ioQueue; + FxRequest* pRequest; + + ioQueue = CONTAINING_RECORD(IrpQueue, FxIoQueue, m_DriverCancelable); + pRequest = FxRequest::RetrieveFromCsqContext(CsqContext); + + pRequest->m_Canceled = TRUE; + + // + // Must reference the queue since this could be the final + // request on a deleting queue. + // + ioQueue->ADDREF(Irp); + + // + // We can drop the lock because this request is a driver owned request and + // it is tracked by m_DriverIoCount. As a result delete will be blocked + // until the request is completed. + // + ioQueue->Unlock(Irql); + + ioQueue->CancelForDriver(pRequest); + + ioQueue->RELEASE(Irp); +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +FxIoQueue::ProcessIdleComplete( + __out PKIRQL PreviousIrql + ) +/*++ + +Routine Description: + + Handle IdleComplete. + Calls back the driver if conditions are met. + Called with Queue lock held, but can drop and re-acquire + it when delivering the event callback to the device driver. + +Arguments: + IrpQueue - Queue the request was on + + Irp - the irp being cancelled + + CsqContext - the context associated with the irp + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + WDFCONTEXT ctx; + FxIoQueueIoState callback; + + + callback = m_IdleComplete; + ctx = m_IdleCompleteContext; + + m_IdleComplete.Method = NULL; + m_IdleCompleteContext = NULL; + + Unlock(*PreviousIrql); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFQUEUE 0x%p is idle, calling driver callback", + GetHandle()); + + // Notify driver by callback + if (callback.Method != NULL) { + callback.Invoke(GetHandle(), ctx); + } + + Lock(PreviousIrql); + + return; +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +FxIoQueue::ProcessPurgeComplete( + __out PKIRQL PreviousIrql + ) +/*++ + +Routine Description: + + + Handle PurgeComplete. + + Calls back the driver if conditions are met. + + Called with Queue lock held, but can drop and re-acquire + it when delivering the event callback to the device driver. + + +Arguments: + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + WDFCONTEXT ctx; + FxIoQueueIoState callback; + + callback = m_PurgeComplete; + ctx = m_PurgeCompleteContext; + + m_PurgeComplete.Method = NULL; + m_PurgeCompleteContext = NULL; + + Unlock(*PreviousIrql); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFQUEUE 0x%p is purged, calling driver callback", + GetObjectHandle()); + + // Notify driver by callback + if (callback.Method != NULL) { + callback.Invoke(GetHandle(), ctx); + } + + Lock(PreviousIrql); + + return; +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +FxIoQueue::ProcessReadyNotify( + __out PKIRQL PreviousIrql + ) +/*++ + +Routine Description: + + Callback the driver for a Queue ready notify + Called with the Queue lock held, and may release + and re-acquire it in calling back the driver + +Arguments: + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + WDFCONTEXT ctx; + FxIoQueueIoState callback; + + // + // A callback to the driver "consumes" the notification. + // Since we drop the lock when we call the driver, there is + // a chance for the queue to be stopped or powered-off before + // the driver tries to retrieve the request. So make sure + // to set this flag when you power-on or start the queue to + // avoid abandoning the requests in the queue. + // + m_TransitionFromEmpty = FALSE; + + // + // Save a local copy since another thread could + // cancel the ready notification out from under us + // when we drop the lock + // + callback = m_ReadyNotify; + + ctx = m_ReadyNotifyContext; + + Unlock(*PreviousIrql); + + if (callback.Method != NULL) { + callback.Invoke(GetHandle(), ctx); + } + else { + if (FxDriverGlobals->FxVerifierOn) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "ReadyNotify notify method is NULL " + "on WDFQUEUE 0x%p", GetObjectHandle()); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + } + + Lock(PreviousIrql); + + return; +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxIoQueue::ProcessCancelledRequests( + __out PKIRQL PreviousIrql + ) +/*++ + + Routine Description: + + Process any cancelled requests + Called with the Queue lock held + Can drop and re-acquire the queue lock + Returns with the Queue lock held + + Arguments: + + Return Value: + None + + --*/ +{ + PLIST_ENTRY pEntry; + FxRequest* pRequest; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + if (IsPowerStateNotifyingDriver()) { + // + // We will not process cancelled request while the driver is being + // notified to stop processing request to avoid double completion + // of the request. + // + return FALSE; + } + + while (!IsListEmpty(&m_Cancelled)) { + pEntry = m_Cancelled.Flink; + + RemoveEntryList(pEntry); + + // FxRequest ensures its not on any list on checked builds + InitializeListHead(pEntry); + + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryQueueOwned, pEntry); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO, + "Calling CancelRoutine routine " + "for WDFREQUEST 0x%p on WDFQUEUE 0x%p", + pRequest->GetHandle(), GetObjectHandle()); + + if (FxDriverGlobals->FxVerifierOn) { + + // Set cancelled status, otherwise verifier in FxRequest::Complete will complain + pRequest->SetVerifierFlags(FXREQUEST_FLAG_CANCELLED); + } + + Unlock(*PreviousIrql); + + if (FxDriverGlobals->FxVerifierOn) { + ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) != 0); + } + + // + // Notify the driver of cancel desire + // + pRequest->m_CancelRoutine.InvokeCancel( + m_IoCancelCallbackLockPtr, + pRequest->GetHandle() + ); + + // + // Release the reference that FxRequest took out on itself + // when it was placed onto the FxIrpQueue. It is now leaving + // the FxIrpQueue due to cancel, and we own this final + // release. + // + pRequest->RELEASE(FXREQUEST_QUEUE_TAG); + + Lock(PreviousIrql); + } + + return TRUE; +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxIoQueue::ProcessCancelledRequestsOnQueue( + __out PKIRQL PreviousIrql + ) +/*++ + + Routine Description: + + Process any cancelled requests + Called with the Queue lock held + Can drop and re-acquire the queue lock + Returns with the Queue lock held + + Arguments: + + Return Value: + None + + --*/ +{ + PLIST_ENTRY pEntry; + FxRequest* pRequest; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + if (IsPowerStateNotifyingDriver()) { + // + // We will not process cancelled request while the driver is being + // notified to stop/resume processing request to avoid double + // completion of the request. + // + return FALSE; + } + + while (!IsListEmpty(&m_CanceledOnQueueList)) { + pEntry = m_CanceledOnQueueList.Flink; + + RemoveEntryList(pEntry); + + // FxRequest ensures its not on any list on checked builds + InitializeListHead(pEntry); + + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryQueueOwned, pEntry); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIO, + "Calling CanceledOnQueue routine " + "for WDFREQUEST 0x%p on WDFQUEUE 0x%p", + pRequest->GetHandle(), GetObjectHandle()); + + if (FxDriverGlobals->FxVerifierOn) { + + // Set cancelled status, otherwise verifier in FxRequest::Complete will complain + pRequest->SetVerifierFlags(FXREQUEST_FLAG_CANCELLED); + } + + Unlock(*PreviousIrql); + + if (FxDriverGlobals->FxVerifierOn) { + ASSERT((pRequest->GetVerifierFlags() & FXREQUEST_FLAG_DRIVER_OWNED) != 0); + } + + // + // Notify the driver + // + m_IoCanceledOnQueue.Invoke(GetHandle(), pRequest->GetHandle()); + + Lock(PreviousIrql); + } + + return TRUE; +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxIoQueue::ProcessPowerEvents( + __out PKIRQL PreviousIrql + ) +/*++ + +Routine Description: + + Processes the power state machine for I/O queues. + + Called with Queue lock held, but can drop and re-acquire + it when it has to deliver event callbacks to the device driver. + + This can modify queue state as it transits the state machine, and + is called from the main event processing loop DispatchEvents(). + + Handling "in-flight" I/O requests in the device driver due + to a power state transition (stopping) is tricky, and + involves a complex state machine. + + The device driver must ensure that all in-flight I/O is stopped + before it can release the thread calling into the driver to + perform the power state transition, otherwise a system crash + can result from accessing hardware after resources have been removed. + + In WDF, this burden is placed on FxIoQueue, so that the device driver + does not have to implement the more complex aspects of this code, + but can rely on notifications from the queue serialized under the + IRQL level and locking it has configured. + + + Implementation of FxIoQueue Power state machine: + ------------------------------------------ + + Since we must drop our lock to callback into the device + driver for power notifications, the processing must occur + as a state machine with three lists. + + On entry to the power stop state, any "in-flight" I/O requests + are recorded on the m_DriverOwned list using + FxRequest::FxListEntryDriverOwned for linkage. + + All of the requests on m_DriverOwned are moved to m_PowerNotify + while holding the lock, with m_DriverOwned cleared. The state is changed + to indicate that the driver is now being notified of requests. + + While in the driver notification state, requests are taken from the + m_PowerNotify list, and moved on to the m_PowerDriverNotified list while + under the lock, and the request is notified to the device driver + by the callback while dropping the lock and re-acquiring the lock. + + As the driver acknowledges the power notification, it calls + WdfRequestStopAcknowledge (FxIoQueue::StopAcknowledge) which moves the + request from the m_PowerDriverNotified list back to the m_DriverOwned + list. + + The device driver could also complete requests, in which case they + just dis-appear from the lists by the completion code doing + a RemoveEntryList on FxRequest::FxListEntryDriverOwned. + + This occurs until the m_PowerNotify list is empty, in which case + the state is changed to driver notified. + + While in the driver notified state, the queue event processing continues + until the m_PowerDriverNotified list is empty, and when it is, the + stopped state is set, and the event m_PowerIdle is set. This releases + the thread waiting on the power state transition in which all of the + device drivers "in-flight" I/O has been stopped and accounted for. + + State Transitions: + -------------- + + During Stop: + + FxIoQueuePowerOn + --> FxIoQueuePowerStartingTransition + --> FxIoQueuePowerStopping + --> FxIoQueuePowerStoppingNotifyingDriver + --> FxIoQueuePowerStoppingDriverNotified + --> FxIoQueuePowerOff + + During Purge: + + FxIoQueuePowerPurge + --> FxIoQueuePowerPurgeNotifyingDriver + --> FxIoQueuePowerPurgeDriverNotified + --> FxIoQueuePowerOff + + + During Resume: + + FxIoQueuePowerOff + --> FxIoQueuePowerRestarting + --> FxIoQueuePowerRestartingNotifyingDriver + --> FxIoQueuePowerRestartingDriverNotified + --> FxIoQueuePowerOn + +Arguments: + +Return Value: + + TRUE - Continue processing the event loop + FALSE - Stop processing event loop + +--*/ +{ + PLIST_ENTRY Entry; + FxRequest* pRequest; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + switch(m_PowerState) { + + case FxIoQueuePowerStartingTransition: + if (m_Dispatching == 1) { + + // + // If we are the last routine actively dispatching callbacks to + // the device driver under a Power stop, then we must set the + // event specifying no more callbacks are active. + // + m_PowerIdle.Set(); + } + + return FALSE; + + case FxIoQueuePowerStopping: + // + // Set state to FxIoQueuePowerPurgeNotifyingDriver + // + m_PowerState = FxIoQueuePowerStoppingNotifyingDriver; + + // This should be empty on entry to this state + ASSERT(IsListEmpty(&this->m_PowerNotify)); + + if (!IsListEmpty(&m_DriverOwned)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: WDFQUEUE 0x%p is powering off " + "with in-flight requests", + GetObjectHandle()); + + + // Ensure the logic of m_DriverOwned is correct + ASSERT(m_DriverOwned.Flink->Blink == &m_DriverOwned); + ASSERT(m_DriverOwned.Blink->Flink == &m_DriverOwned); + + // + // Move all requests on m_DriverOwned to m_PowerNotify + // + m_PowerNotify.Flink = m_DriverOwned.Flink; + m_PowerNotify.Blink = m_DriverOwned.Blink; + m_PowerNotify.Flink->Blink = &m_PowerNotify; + m_PowerNotify.Blink->Flink = &m_PowerNotify; + + // This is now empty + InitializeListHead(&m_DriverOwned); + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: WDFQUEUE 0x%p is powering off without " + "in-flight requests",GetObjectHandle()); + } + + // + // Return to main processing loop which will callback to + // process notifications + // + return TRUE; + + case FxIoQueuePowerPurge: + // + // Set state to FxIoQueuePowerPurgeNotifyingDriver + // + m_PowerState = FxIoQueuePowerPurgeNotifyingDriver; + + // This should be empty on entry to this state + ASSERT(IsListEmpty(&this->m_PowerNotify)); + + if (!IsListEmpty(&m_DriverOwned)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: WDFQUEUE 0x%p is purging with " + "in-flight requests",GetObjectHandle()); + + // Ensure the logic of m_DriverOwned is correct + ASSERT(m_DriverOwned.Flink->Blink == &m_DriverOwned); + ASSERT(m_DriverOwned.Blink->Flink == &m_DriverOwned); + + // + // Move all requests on m_DriverOwned to m_PowerNotify + // + m_PowerNotify.Flink = m_DriverOwned.Flink; + m_PowerNotify.Blink = m_DriverOwned.Blink; + m_PowerNotify.Flink->Blink = &m_PowerNotify; + m_PowerNotify.Blink->Flink = &m_PowerNotify; + + // This is now empty + InitializeListHead(&m_DriverOwned); + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power purge: WDFQUEUE 0x%p is purging without " + "in-flight requests", GetObjectHandle()); + } + + // + // Return to main processing loop which will callback to + // process notifications + // + return TRUE; + + case FxIoQueuePowerStoppingNotifyingDriver: { + + FxIoQueueIoStop stopCallback; + + // + // If the list of requests to notify the driver about is + // empty, change to the notified state. + // + if (IsListEmpty(&m_PowerNotify)) { + m_PowerState = FxIoQueuePowerStoppingDriverNotified; + + // + // Return to main processing loop which will callback to + // process the wait/signaling for the driver to acknowledge + // all stops. + // + return TRUE; + } + + // + // Notify each entry in m_PowerNotify into the driver + // + + // Remove from the notify list, place it on the driver notified list + Entry = RemoveHeadList(&m_PowerNotify); + + InsertTailList(&m_PowerDriverNotified, Entry); + + // Retrieve the FxRequest + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, Entry); + + stopCallback = m_IoStop; + + // + // Notify driver by callback. + // + // If no callback is registered, the power thread will in effect + // wait until the driver completes or cancels all requests. + // + if (stopCallback.Method != NULL && pRequest->m_Canceled == FALSE) { + ULONG ActionFlags = WdfRequestStopActionSuspend; + + if(pRequest->IsInIrpQueue(&m_DriverCancelable)) { + ActionFlags |= WdfRequestStopRequestCancelable; + } + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop Notifying Driver, WDFQUEUE 0x%p, WDFREQUEST 0x%p", + GetObjectHandle(), pRequest->GetObjectHandle()); + + // Driver could be calling RequestComplete as we attempt to stop + pRequest->ADDREF(FXREQUEST_HOLD_TAG); + + Unlock(*PreviousIrql); + + if (FxDriverGlobals->FxVerifierOn) { + pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT); + } + + stopCallback.Invoke(GetHandle(), pRequest->GetHandle(), ActionFlags); + + pRequest->RELEASE(FXREQUEST_HOLD_TAG); + + Lock(PreviousIrql); + } + + // + // As they are acknowledged, they will move back to m_DriverOwned. + // + // If the driver completes them, they go away. + // + + // Return to main processing loop and continue processing notifications + return TRUE; + } + + case FxIoQueuePowerPurgeNotifyingDriver: { + + FxIoQueueIoStop stopCallback; + + // + // If the list of requests to notify the driver about is + // empty, change to the notified state. + // + if (IsListEmpty(&m_PowerNotify)) { + m_PowerState = FxIoQueuePowerPurgeDriverNotified; + + // + // Return to main processing loop which will callback to + // process the wait/signaling for the driver to acknowledge + // all stops. + // + return TRUE; + } + + // + // Notify each entry in m_PowerNotify into the driver + // + + // Remove from the notify list, place it on the driver notified list + Entry = RemoveHeadList(&m_PowerNotify); + + InsertTailList(&m_PowerDriverNotified, Entry); + + // Retrieve the FxRequest + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, Entry); + + stopCallback = m_IoStop; + + // + // Make sure power stop state is cleared before invoking the stop callback. + // + pRequest->ClearPowerStopState(); + + // + // Notify driver by callback. + // + // If no callback is registered, the power thread will in effect + // wait until the driver completes or cancels all requests. + // + if (stopCallback.Method != NULL && pRequest->m_Canceled == FALSE) { + ULONG ActionFlags = WdfRequestStopActionPurge; + + if(pRequest->IsInIrpQueue(&m_DriverCancelable)) { + ActionFlags |= WdfRequestStopRequestCancelable; + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Purge Notifying Driver " + "WDFQUEUE 0x%p, WDFREQUEST 0x%p", + GetObjectHandle(),pRequest->GetHandle()); + + // Driver could be calling RequestComplete as we attempt to stop + pRequest->ADDREF(FXREQUEST_HOLD_TAG); + + Unlock(*PreviousIrql); + + if (FxDriverGlobals->FxVerifierOn) { + pRequest->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT); + } + + stopCallback.Invoke(GetHandle(), pRequest->GetHandle(), ActionFlags); + + pRequest->RELEASE(FXREQUEST_HOLD_TAG); + + Lock(PreviousIrql); + } + + // + // As they are acknowledged, they will move back to m_DriverOwned. + // + // If the driver completes them, they go away. + // + + // Return to main processing loop and continue processing notifications + return TRUE; + } + + case FxIoQueuePowerStoppingDriverNotified: + case FxIoQueuePowerPurgeDriverNotified: { + + PLIST_ENTRY thisEntry, nextEntry, listHead; + LIST_ENTRY acknowledgedList; + BOOLEAN continueProcessing = FALSE; + + InitializeListHead(&acknowledgedList); + + // + // First move all the acknowledged requests to local list and then + // process the local list. We have do that in two steps because + // ProcessAcknowledgedRequests drops and reacquires the lock. + // + listHead = &m_PowerDriverNotified; + + for (thisEntry = listHead->Flink; + thisEntry != listHead; + thisEntry = nextEntry) { + + // Retrieve the FxRequest + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, thisEntry); + + nextEntry = thisEntry->Flink; + + if (pRequest->IsPowerStopAcknowledged()) { + RemoveEntryList(thisEntry); + InsertTailList(&acknowledgedList, thisEntry); + } + } + + // + // Process all the acknowledged request from the local list. + // + while (!IsListEmpty(&acknowledgedList)) + { + thisEntry = RemoveHeadList(&acknowledgedList); + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, thisEntry); + ProcessAcknowledgedRequests(pRequest, PreviousIrql); + + // + // When this function drops the lock, other threads may attempt + // to dispatch but fail since we are currently dispatching. + // We need to be sure to process any pending events that other + // threads initiated but could not be dispatch. The acknowledged + // list will eventually be cleared out, allowing exit paths from + // this function to return control to the driver. + // + continueProcessing = TRUE; + } + + // + // Check to see if there are any unacknowledged requests. + // + if (!IsListEmpty(&m_PowerDriverNotified)) { + + // + // If there are still entries on the list, we potentially return + // FALSE to tell the main event dispatching loop to return to + // the device driver, since we are awaiting response from + // the driver while in this state. + // + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: Waiting for Driver to complete or " + "acknowledge in-flight requests on WDFQUEUE 0x%p", + GetObjectHandle()); + + return continueProcessing; + } + + // + // Check to see if there are any requests in the middle of two-phase-completion. + // If so, bail out and wait. + // + if (m_TwoPhaseCompletions != 0) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: Waiting for Driver to complete or " + "acknowledge in-flight requests on WDFQUEUE 0x%p", + GetObjectHandle()); + + return continueProcessing; + } + + // + // All the requests are acknowledged. We will signal the pnp thread waiting + // in StopProcessingForPower to continue if we are the last one to visit + // the dispatch event loop. + // + // + if ( m_Dispatching == 1) { + + // + // If we are the last routine actively dispatching callbacks to + // the device driver under a Power stop, then we must set the + // event specifying no more callbacks are active. + // + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: WDFQUEUE 0x%p is now powered off with no " + "in-flight requests",GetObjectHandle()); + + m_PowerState = FxIoQueuePowerOff; + + m_PowerIdle.Set(); + + return TRUE; + } + + // + // The driver has acknowledged all requests, and the + // notification list is empty. But, there are still outstanding + // dispatch calls into the driver (m_Dispatching != 1), so we potentially + // return false here to hopefully unwind to the final dispatch routine, + // which will set the power off state. + // + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Stop: Driver has acknowledged all in-flight " + "requests, but WDFQUEUE 0x%p has outstanding callbacks", + GetObjectHandle()); + + return continueProcessing; + } + case FxIoQueuePowerRestarting: + + // + // Power is being resumed to the device. We notify the + // device driver by an event callback for all driver + // owned requests that it has idled due to a previous + // power stop. + // + m_PowerState = FxIoQueuePowerRestartingNotifyingDriver; + + // This should be empty on entry to this state + ASSERT(IsListEmpty(&this->m_PowerNotify)); + + if (!IsListEmpty(&m_DriverOwned)) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Resume: Driver has power paused requests " + "on WDFQUEUE 0x%p",GetObjectHandle()); + + // Ensure the logic of m_DriverOwned is correct + ASSERT(m_DriverOwned.Flink->Blink == &m_DriverOwned); + ASSERT(m_DriverOwned.Blink->Flink == &m_DriverOwned); + + // + // Move all requests on m_DriverOwned to m_PowerNotify + // + m_PowerNotify.Flink = m_DriverOwned.Flink; + m_PowerNotify.Blink = m_DriverOwned.Blink; + m_PowerNotify.Flink->Blink = &m_PowerNotify; + m_PowerNotify.Blink->Flink = &m_PowerNotify; + + // This is now empty + InitializeListHead(&m_DriverOwned); + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Resume: Driver has no power paused requests " + "on WDFQUEUE 0x%p", GetObjectHandle()); + } + + // + // Return to main processing loop which will callback to + // process notifications + // + return TRUE; + + + case FxIoQueuePowerRestartingNotifyingDriver: { + + FxIoQueueIoResume resumeCallback; + + // + // If the list of requests to notify the driver about is + // empty, change to the notified state. + // + if (IsListEmpty(&m_PowerNotify)) { + + m_PowerState = FxIoQueuePowerRestartingDriverNotified; + + // + // Return to main processing loop which will callback to + // process the next state + // + return TRUE; + } + + // + // Notify each entry in m_PowerNotify into the driver, placing them + // back on the m_DriverOwned list. + // + + // Remove from the notify list, place it on the driver owned list + Entry = RemoveHeadList(&m_PowerNotify); + + InsertTailList(&m_DriverOwned, Entry); + + // Retrieve the FxRequest + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryDriverOwned, Entry); + + resumeCallback = m_IoResume; + + // Notify driver by callback + if (resumeCallback.Method != NULL && pRequest->m_Canceled == FALSE) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Resume, Notifying Driver, WDFQUEUE 0x%p, " + "WDFREQUEST 0x%p", + GetObjectHandle(), + pRequest->GetObjectHandle()); + + // Driver could be calling RequestComplete as we attempt to resume + pRequest->ADDREF(FXREQUEST_HOLD_TAG); + + Unlock(*PreviousIrql); + + resumeCallback.Invoke(GetHandle(), pRequest->GetHandle()); + + pRequest->RELEASE(FXREQUEST_HOLD_TAG); + + Lock(PreviousIrql); + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Resume: Driver has no callback for " + "EvtIoResume registered on WDFQUEUE 0x%p",GetObjectHandle()); + } + + // Return to main processing loop and continue processing notifications + return TRUE; + } + + case FxIoQueuePowerRestartingDriverNotified: + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Power Resume: WDFQUEUE 0x%p is now powered on and " + "I/O has resumed",GetObjectHandle()); + + // Power state has resumed + m_PowerState = FxIoQueuePowerOn; + + // + // We will resume dispatching I/O after all the queues + // are moved into PowerOn state. + // + return FALSE; + + + default: + // Called on invalid state + ASSERT(FALSE); + return FALSE; + } + + /* NOTREACHED*/ +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +FxIoQueue::ProcessAcknowledgedRequests( + __in FxRequest* Request, + __out PKIRQL PreviousIrql + ) +/*++ + +Routine Description: + + Process requests that are acknowledged by the driver. + + Called with the queue lock held. This function can drop + and reacquire the lock if needed. + +Return Value: + +--*/ +{ + PLIST_ENTRY Entry; + BOOLEAN requeue; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + ASSERT(Request->IsPowerStopAcknowledged()); + + requeue = Request->IsPowerStopAcknowledgedWithRequeue(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Acknowledging WDFREQUEST %p on WDFQUEUE %p %s requeue option", + Request->GetObjectHandle(), GetObjectHandle(), + (requeue ? "with" : "without")); + + Request->ClearPowerStopState(); + + // + // Remove the request from the m_PowerDriverNotified list and + // place it back on the m_DriverOwned list. + // + // N.B. Our caller guarantees that we have already been removed, thus we + // must not explicitly remove here. + // + Entry = Request->GetListEntry(FxListEntryDriverOwned); + + InitializeListHead(Entry); + + InsertTailList(&this->m_DriverOwned, Entry); + + if (pFxDriverGlobals->FxVerifierOn) { + // + // As soon as we drop the lock below the request may get completed. + // So take an addition reference so that we can safely clear the + // flag. + // + Request->ADDREF(FXREQUEST_HOLD_TAG); + } + + Unlock(*PreviousIrql); + + if (pFxDriverGlobals->FxVerifierOn) { + Request->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_IN_EVTIOSTOP_CONTEXT); + Request->RELEASE(FXREQUEST_HOLD_TAG); + } + + if (requeue) { + FxRequestCompletionState oldState; + NTSTATUS status; + + if (pFxDriverGlobals->FxVerifierOn) { + Request->ClearVerifierFlags(FXREQUEST_FLAG_DRIVER_OWNED | + FXREQUEST_FLAG_DRIVER_DISPATCH); + } + + // + // If the device driver requests it back on the queue, we will place it + // on the front and it will be re-delivered in the normal EvtIoDefault, ... path. + // + // EvtIoResume *will not* be called on power resume for this request. + // + + // + // The request has only one reference, held by the completion + // callback function. We need to take another one before cancelling + // this function, otherwise we will lose the request object + // + Request->ADDREF(FXREQUEST_STATE_TAG); + + // Cancel the request complete callback (deletes a reference) + oldState = Request->SetCompletionState(FxRequestCompletionStateNone); + ASSERT(oldState == FxRequestCompletionStateQueue); + UNREFERENCED_PARAMETER(oldState); + + Lock(PreviousIrql); + + // + // We are going to place the request back on the queue + // + + // Driver is returning I/O + RemoveFromDriverOwnedList(Request); + + // + // Check if we need to delete this request. + // + if (m_CancelDispatchedRequests) { + // + // Do not requeue this request. + // + status = STATUS_CANCELLED; + } + else { + // + // Place the request back at the head of the main queue + // so as not to re-order requests + // + status = Request->InsertHeadIrpQueue(&m_Queue, NULL); + } + + if (!NT_SUCCESS(status)) { + + // Request not placed in queue, cancel it + ASSERT(status == STATUS_CANCELLED); + + status = STATUS_SUCCESS; + + // + // We must add a reference since the CancelForQueue path + // assumes we were on the FxIrpQueue with the extra reference + // + Request->ADDREF(FXREQUEST_QUEUE_TAG); + + // + // Mark the request as cancelled, place it on the cancel list, + // and schedule the cancel event to the driver + // + CancelForQueue(Request, *PreviousIrql); + + // + // Reacquire the lock because CancelForQueue visits the dispatch-loop + // and releases the lock. + // + Lock(PreviousIrql); + } + else { + // Check if went from no requests to have requests + CheckTransitionFromEmpty(); + } + + } else { + Lock(PreviousIrql); + } + + return; +} + +VOID +FxIoQueue::StartPowerTransitionOff( + ) +/*++ + + Routine Description: + + Purpose of this routine is to put the queue in state that would + prevent any new requests from being dispatched to the driver. + +Arguments: + +Return Value: + + VOID + +--*/ +{ + KIRQL irql; + BOOLEAN result; + + if(m_PowerManaged == FALSE) { + return; + } + + Lock(&irql); + + if (m_Deleted == FALSE) { + ASSERT(m_PowerState == FxIoQueuePowerOn); + } + + m_PowerState = FxIoQueuePowerStartingTransition; + + // We must wait on the current thread until the queue is actually idle + m_PowerIdle.Clear(); + + // + // Run the event dispatching loop before waiting on the event + // in case this thread actually performs the transition + // + result = DispatchEvents(irql); + if(result) { + // + // This is called from a kernel mode PNP thread, so we do not need + // a KeEnterCriticalRegion() + // + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Waiting for all threads to stop dispatching requests" + " so that WDFQUEUE 0x%p can be powered off", + GetObjectHandle()); + + GetDriverGlobals()->WaitForSignal(m_PowerIdle.GetSelfPointer(), + "waiting for all threads to stop dispatching requests so " + "that queue can be powered off, WDFQUEUE", GetHandle(), + GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + } + + return; +} + +VOID +FxIoQueue::StopProcessingForPower( + __in FxIoStopProcessingForPowerAction Action + ) +/*++ + + Routine Description: + + Stops 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. + + Additional reference is already taken on the object by the caller + to prevent the queue from being deleted. + + +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. + +Return Value: + + NTSTATUS + +--*/ +{ + KIRQL irql; + BOOLEAN result; + + switch (Action) { + case FxIoStopProcessingForPowerPurgeNonManaged: + + // + // If power managed, leave it alone + // + if(m_PowerManaged == TRUE) { + // Should be powered off by now. + ASSERT(m_PowerState == FxIoQueuePowerOff); + return; + } + + // + // Queue is being shut down. This flag prevents the following: + // (1) a race condition where a dispatch queue handler changes the + // state of the queue to accept_requests while we are in the + // middle of a power stopping (purge) operation + + // (2) another thread calling Stop or Start on a queue that is in the + // middle of a power stopping (purge) operation. + // + Lock(&irql); + SetStateForShutdown(); + Unlock(irql); + + QueuePurge(TRUE, TRUE, NULL, NULL); + + Lock(&irql); + // + // Queue must be in PowerOn state. + // + ASSERT(m_PowerState == FxIoQueuePowerOn); + + m_PowerState = FxIoQueuePowerPurge; + + break; + + case FxIoStopProcessingForPowerPurgeManaged: + + // + // If not power managed, leave it alone + // + if(m_PowerManaged == FALSE) { + ASSERT(m_PowerState == FxIoQueuePowerOn); + return; + } + + // + // Queue is being shut down. This flag prevents the following: + // (1) a race condition where a dispatch queue handler changes the + // state of the queue to accept_requests while we are in the + // middle of a power stopping (purge) operation + + // (2) another thread calling Stop or Start on a queue that is in the + // middle of a power stopping (purge) operation. + // + Lock(&irql); + SetStateForShutdown(); + Unlock(irql); + + QueuePurge(TRUE, TRUE, NULL, NULL); + + Lock(&irql); + + m_PowerState = FxIoQueuePowerPurge; + + break; + + case FxIoStopProcessingForPowerHold: + // + // If not power managed, leave it alone + // + if(m_PowerManaged == FALSE) { + ASSERT(m_PowerState == FxIoQueuePowerOn); + return; + } + + Lock(&irql); + + m_PowerState = FxIoQueuePowerStopping; + + break; + + default: + ASSERT(FALSE); + return; + } + + // We must wait on the current thread until the queue is actually idle + m_PowerIdle.Clear(); + + // + // Run the event dispatching loop before waiting on the event + // in case this thread actually performs the transition + // + result = DispatchEvents(irql); + if(result) { + // + // This is called from a kernel mode PNP thread, so we do not need + // a KeEnterCriticalRegion() + // + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Waiting for all inflight requests to be acknowledged " + " on WDFQUEUE 0x%p", + GetObjectHandle()); + + GetDriverGlobals()->WaitForSignal(m_PowerIdle.GetSelfPointer(), + "waiting for all inflight requests " + "to be acknowledged on WDFQUEUE", + GetHandle(), + GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + } + + return; +} + +VOID +FxIoQueue::StartPowerTransitionOn( + VOID + ) +/*++ + Routine Description: Start dispatching I/Os + + Arguments: VOID + + Return Value: VOID +--*/ +{ + KIRQL irql; + + if(m_PowerManaged == FALSE) { + ASSERT(m_PowerState == FxIoQueuePowerOn); + return; + } + + Lock(&irql); + + if (m_Deleted == FALSE) { + ASSERT(m_PowerState == FxIoQueuePowerOn); + } + + // + // If there are requests in the queue when we power up, we + // should set m_TransitionFromEmpty to trigger event-ready notify + // callback on the manual queue to kick start processing of requests. + // If we don't set, there is a posibility for abandoning the requests in the + // the queue if the queue is powered off between the time we call + // ProcessReadNotify and the call to retrieve requests made by the driver + // because the retrieve call will fail and the request will be left in the + // queue with m_TransitionFromEmpty state cleared. + // + if (m_Queue.GetRequestCount() > 0L) { + m_TransitionFromEmpty = TRUE; + m_ForceTransitionFromEmptyWhenAddingNewRequest = FALSE; + } + + DispatchEvents(irql); + + return; +} + +VOID +FxIoQueue::ResumeProcessingForPower( + VOID + ) +/*++ + + Routine Description: + + Resumes a PowerManaged queue for automatic I/O processing due to + a power event that allows I/O to resume. + + Does nothing if its a non-power managed queue. + + Additional reference is already taken on the object by the caller + to prevent the queue from being deleted. + +Arguments: + +Return Value: + + NTSTATUS + +--*/ +{ + KIRQL irql; + + // + // If not power managed, leave it alone + // + if (!m_PowerManaged) { + ASSERT(m_PowerState == FxIoQueuePowerOn); + return; + } + + Lock(&irql); + + if (m_PowerState == FxIoQueuePowerOn) { + Unlock(irql); + return; + } + + ASSERT(m_PowerState == FxIoQueuePowerOff); + + m_PowerState = FxIoQueuePowerRestarting; + + // + // We have transitioned to a status that resumes + // processing, so call dispatch function. + // + + DispatchEvents(irql); + + return; +} + +VOID +FxIoQueue::SetStateForShutdown( + VOID + ) +/*++ + +Routine Description: + The queue is shutting down. Disable WdfQueueStart/Stop from re-enabling + the AcceptRequest bit. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // + // No need to take a lock since caller is responsible for providing the + // required synchronization. + // + + // + // Do not allow request to be queued. + // + SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueSetShutdown | FxIoQueueClearAcceptRequests)); +} + +VOID +FxIoQueue::ResetStateForRestart( + VOID + ) +/*++ + +Routine Description: + This is called on a device (PDO) which has been restarted from the removed + state. It will reset purged queues so that it can accept new requests + when ResumeProcessingForPower is called afterwards. + + Additional reference is already taken on the object by the caller + to prevent the queue from being deleted. + + +Arguments: + None + +Return Value: + None + + --*/ +{ + KIRQL irql; + + Lock(&irql); + + // + // For non power managed queues, let us reset the m_PowerState to On + // + if (!m_PowerManaged) { + m_PowerState = FxIoQueuePowerOn; + } + + // + // Allow requests to be queued. + // + SetState((FX_IO_QUEUE_SET_STATE)(FxIoQueueClearShutdown | FxIoQueueSetAcceptRequests)); + + // + // No need to visit the DispatchEvents because the PowerState + // is still off. + // + Unlock(irql); + + return; +} + +BOOLEAN +FxIoQueue::IsIoEventHandlerRegistered( + __in WDF_REQUEST_TYPE RequestType + ) +/*++ + +Routine Description: + Given a request type, this function checks to see if the appropriate + event handler is registered to receive dispatched requests. + +Return Value: + + TRUE - yes the queue is configured to dispatch requests of given RequestType + FALSE - no, the queue cannot dispatch requests of given RequestType + +--*/ +{ + if(m_Type == WdfIoQueueDispatchManual) { + // + // Manual queues wouldn't have any IoEvent callbacks registered. + // + return TRUE; + } + + // + // Default handler is a catch all handler. + // + if(m_IoDefault.Method != NULL) { + return TRUE; + } + + // + // Default handle is not registered. So check to see if request specific + // handler is registered. + // + switch(RequestType) { + case WdfRequestTypeRead: + if(m_IoRead.Method == NULL) { + return FALSE; + } + break; + case WdfRequestTypeWrite: + if(m_IoWrite.Method == NULL) { + return FALSE; + } + break; + case WdfRequestTypeDeviceControl: + if(m_IoDeviceControl.Method == NULL) { + return FALSE; + } + break; + case WdfRequestTypeDeviceControlInternal: + if(m_IoInternalDeviceControl.Method == NULL) { + return FALSE; + } + break; + case WdfRequestTypeCreate: // Fall through. Must have default handler. + default: + return FALSE; + } + + return TRUE; +} + +VOID +FxIoQueue::_DeferredDispatchThreadThunk( + __in PVOID Parameter + ) +/*++ + +Routine Description: + Thunk used when requests must be posted to a workitem. + +--*/ +{ + FxIoQueue* pQueue = (FxIoQueue*)Parameter; + + PFX_DRIVER_GLOBALS FxDriverGlobals = pQueue->GetDriverGlobals(); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Dispatching requests from worker thread"); + + pQueue->DeferredDispatchRequestsFromWorkerThread(); + + return; +} + + +VOID +FxIoQueue::_DeferredDispatchDpcThunk( + __in PKDPC Dpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ) +/*++ + +Routine Description: + Thunk used when requests must be posted to a DPC. + +--*/ +{ + FxIoQueue* pQueue = (FxIoQueue*)DeferredContext; + + PFX_DRIVER_GLOBALS FxDriverGlobals = pQueue->GetDriverGlobals(); + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Dispatching requests from DPC"); + + pQueue->DeferredDispatchRequestsFromDpc(); + + return; +} + +VOID +FxIoQueue::_PurgeComplete( + __in WDFQUEUE Queue, + __in WDFCONTEXT Context + ) +/*++ + +Routine Description: + Callback function when a queue purge completes + +--*/ +{ + MxEvent* event = (MxEvent*)Context; + + UNREFERENCED_PARAMETER(Queue); + + event->SetWithIncrement(EVENT_INCREMENT); + + return; +} + +VOID +FxIoQueue::_IdleComplete( + __in WDFQUEUE Queue, + __in WDFCONTEXT Context + ) +/*++ + +Routine Description: + Callback function when a stop completes + +--*/ +{ + MxEvent* event = (MxEvent*)Context; + + UNREFERENCED_PARAMETER(Queue); + + event->SetWithIncrement(EVENT_INCREMENT); + + return; +} + +__declspec(noreturn) +VOID +FxIoQueue::FatalError( + __in NTSTATUS Status + ) +{ + WDF_QUEUE_FATAL_ERROR_DATA data; + + RtlZeroMemory(&data, sizeof(data)); + + data.Queue = GetHandle(); + data.Request = NULL; + data.Status = Status; + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_QUEUE_FATAL_ERROR, + (ULONG_PTR) &data); +} + + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::AllocateReservedRequest( + __deref_out FxRequest** Request + ) +/*++ + +Routine Description: + Called by Fxpkgio::Dispatch to allocate a reserved request if one is + avaialble. + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxRequest* pRequest; + PWDF_OBJECT_ATTRIBUTES reqAttribs; + + pFxDriverGlobals = GetDriverGlobals(); + *Request = NULL; + reqAttribs = NULL; + + // + // Get the right context for this request object. + // + if (GetCxDeviceInfo() != NULL) { + reqAttribs = &GetCxDeviceInfo()->RequestAttributes; + } + else { + reqAttribs = m_Device->GetRequestAttributes(); + } + + // + // FxRequest::_Create doesn't create a Request from the Device lookaside + // hence we can't use that as the Request Context doesn't get associated + // if the Request is not created from the lookaside. + // + status = FxRequest::_CreateForPackage(m_Device, reqAttribs, NULL, &pRequest); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Failure to allocate request %!STATUS!", status); + return status; + } + + pRequest->SetReserved(); + pRequest->SetCurrentQueue(this); + + // + // This is used to return the request to the correct queue if it was + // forwarded + // + pRequest->SetForwardProgressQueue(this); + pRequest->SetCompleted(FALSE); + + if (m_FwdProgContext->m_IoReservedResourcesAllocate.Method != NULL) { + + pRequest->SetPresented(); + + status = m_FwdProgContext->m_IoReservedResourcesAllocate.Invoke( + GetHandle(), + pRequest->GetHandle()); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Failure from m_IoReservedResourcesAllocate callback %!STATUS!", + status); + pRequest->FreeRequest(); + } + } + + if (NT_SUCCESS(status)) { + *Request = pRequest; + } + + return status; +} + + +VOID +FxIoQueue::CancelIrps( + __in PLIST_ENTRY IrpListHead + ) +/*++ + +Routine Description: + + This function is called to purge (cancel) the specified list of IRPs. + The IRP's Tail.Overlay.ListEntry field must be used to link these structs together. + +--*/ +{ + MdIrp irp; + FxIrp fxIrp; + PLIST_ENTRY entry; + + while(!IsListEmpty(IrpListHead)) { + + entry = RemoveHeadList(IrpListHead); + + irp = fxIrp.GetIrpFromListEntry(entry); + + fxIrp.SetIrp(irp); + + fxIrp.SetInformation(0); + fxIrp.SetStatus(STATUS_CANCELLED); + fxIrp.CompleteRequest(IO_NO_INCREMENT); + } +} + +VOID +FxIoQueue::PurgeForwardProgressIrps( + __in_opt MdFileObject FileObject + ) +/*++ + +Routine Description: + + This function is called when the queue is purged. + +--*/ +{ + LIST_ENTRY cleanupList; + + InitializeListHead(&cleanupList); + GetForwardProgressIrps(&cleanupList, FileObject); + CancelIrps(&cleanupList); +} + +VOID +FxIoQueue::VerifierVerifyFwdProgListsLocked( + VOID + ) +/*++ + +Routine Description: + Called from dispose to Free all the reserved requests. + +--*/ +{ + ULONG countOfInUseRequests; + ULONG countOfFreeRequests; + PLIST_ENTRY thisEntry, nextEntry, listHead; + + countOfInUseRequests = 0; + + listHead = &m_FwdProgContext->m_ReservedRequestInUseList; + + for(thisEntry = listHead->Flink; + thisEntry != listHead; + thisEntry = nextEntry) + { + nextEntry = thisEntry->Flink; + countOfInUseRequests++; + } + + countOfFreeRequests = 0; + + listHead = &m_FwdProgContext->m_ReservedRequestList; + + for(thisEntry = listHead->Flink; + thisEntry != listHead; + thisEntry = nextEntry) + { + nextEntry = thisEntry->Flink; + countOfFreeRequests++; + } + + ASSERT(countOfFreeRequests + countOfInUseRequests == + m_FwdProgContext->m_NumberOfReservedRequests); + return; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/io/fxioqueueapi.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/io/fxioqueueapi.cpp new file mode 100644 index 00000000000..4dafca90e4f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/io/fxioqueueapi.cpp @@ -0,0 +1,1420 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoQueueApi.cpp + +Abstract: + + This module implements the FxIoQueue object C interfaces + +Author: + + + + +Revision History: + + +--*/ + +#include "ioprivshared.hpp" +#include "FxPkgIo.hpp" +#include "FxIoQueue.hpp" + +extern "C" { +#include "FxIoQueueApi.tmh" +} + +// +// C Accessor methods +// +// These are the "public" API's used by driver writers for both +// C and C++. In the C++ case, a "wrapper" class is placed around these +// methods. This is to avoid exposing any internal details of our +// driver frameworks implementation class, which would cause +// binary coupling with the device driver. +// +// (thus causing drivers to rebuild for even small changes to this C++ object) +// + +// +// extern all functions +// +extern "C" { + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_IO_QUEUE_CONFIG Config, + __in_opt + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + __out_opt + WDFQUEUE* Queue + ) + +/*++ + +Routine Description: + + Creates an IoQueue object and returns its handle to the caller. + + The newly created IoQueue object is associated with the IoPackage + instance for the device. + + The IoQueue object is automatically dereferenced when its + associated device is removed. This driver does not normally have + to manually manage IoQueue object reference counts. + + An IoQueue object is created in the WdfIoQueuePause state, and is + configured for WdfIoQueueDispatchSynchronous; + +Arguments: + + Device - Handle to the Device the I/O Package registered with + at EvtDeviceFileCreate time. + + Config - WDF_IO_QUEUE_CONFIG structure + + pQueue - Pointer to location to store the returned IoQueue handle. + +Return Value: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + CfxDevice* pDevice; + FxPkgIo* pPkgIo; + FxIoQueue* pQueue; + NTSTATUS status; + + // + // Validate the I/O Package handle, and get the FxPkgIo* + // + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + pPkgIo = NULL; + pQueue = NULL; + + FxPointerNotNull(pFxDriverGlobals, Config); + + status = FxValidateObjectAttributes(pFxDriverGlobals, + QueueAttributes, + (FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED | + FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED)); + if (!NT_SUCCESS(status)) { + return status; + } + + // Validate Config structure + if (Config->Size != sizeof(WDF_IO_QUEUE_CONFIG) && + Config->Size != sizeof(WDF_IO_QUEUE_CONFIG_V1_9) && + Config->Size != sizeof(WDF_IO_QUEUE_CONFIG_V1_7)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDF_IO_QUEUE_CONFIG Size 0x%x, " + "expected for v1.7 size 0x%x or v1.9 size 0x%x or " + "current version size 0x%x, %!STATUS!", + Config->Size, sizeof(WDF_IO_QUEUE_CONFIG_V1_7), + sizeof(WDF_IO_QUEUE_CONFIG_V1_9), + sizeof(WDF_IO_QUEUE_CONFIG), status); + return status; + } + + // + // If the queue is not a default queue then the out parameter is not optional + // + if(!Config->DefaultQueue && Queue == NULL) { + status = STATUS_INVALID_PARAMETER_4; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Parameter to receive WDFQUEUE handle is not optional " + "for non default queue %!STATUS!", status); + + return status; + } + + //pPkgIo = (FxPkgIo*)pDevice->m_PkgIo; + pPkgIo = pDevice->m_PkgIo; + + // + // If the queue is a default queue, then we restrict the creation to happen + // a) before the device is started for pnp devices (FDO or PDO) + // b) before the call to WdfControlDeviceFinishInitializing for controldevices. + // This is done to prevent some unknown race conditions and reduce + // the test matrix. + // + if(Config->DefaultQueue) { + + if(pDevice->IsLegacy()) { + // + // This is a controldevice. Make sure the create is called after the device + // is initialized and ready to accept I/O. + // + if((pDevice->GetDeviceObjectFlags() & DO_DEVICE_INITIALIZING) == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Default queue can only be created before WdfControlDeviceFinishInitializing" + "on the WDFDEVICE %p is called %!STATUS!", + Device, + STATUS_INVALID_DEVICE_STATE); + return STATUS_INVALID_DEVICE_STATE; + } + + } else { + // + // This is either FDO or PDO. Make sure it's not started yet. + // + if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Default queue can only be created before the WDFDEVICE 0x%p " + "is started, %!STATUS!", Device, status); + return status; + } + } + } + + // + // Create the Queue for the I/O package + // + status = pPkgIo->CreateQueue(Config, + QueueAttributes, + GetFxDriverGlobals(DriverGlobals)->Driver, + &pQueue); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Queue Creation failed " + "for WDFDEVICE 0x%p, %!STATUS!", Device, status); + return status; + } + + if(Config->DefaultQueue) { + + // + // Make this a default queue. The default queue receives any + // I/O requests that have not been otherwise forwarded to another + // queue by WdfDeviceConfigureRequestDispatching . + // + + status = pPkgIo->InitializeDefaultQueue( + pDevice, + pQueue + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Create failed " + "for FxPkgIo 0x%p, WDFDEVICE 0x%p",pPkgIo, Device); + // + // Delete the queue *without* invoking driver defined callbacks + // + pQueue->DeleteFromFailedCreate(); + + return status; + } + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Created WDFQUEUE 0x%p", pQueue->GetObjectHandle()); + + if(Queue != NULL) { + *Queue = (WDFQUEUE)pQueue->GetObjectHandle(); + } + + return STATUS_SUCCESS; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +WDF_IO_QUEUE_STATE +WDFEXPORT(WdfIoQueueGetState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __out_opt + PULONG QueueCount, + __out_opt + PULONG DriverCount + ) + +/*++ + +Routine Description: + + Return the Queues status + +Arguments: + + Queue - Handle to Queue object + + pQueueCount - Count of requests in the Queue not presented + to the driver. + + pDriverCount - Count of requests the driver is operating + on that are associated with this queue. + +Returns: + + WDF_IO_QUEUE_STATE + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + return pQueue->GetState(QueueCount, DriverCount); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfIoQueueGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue + ) + +/*++ + +Routine Description: + Returns the device handle that the queue is associated with + +Arguments: + Queue - Handle to queue object + +Return Value: + WDFDEVICE handle + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*) &pQueue); + + return (WDFDEVICE) pQueue->GetDevice()->GetHandle(); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoQueueStart)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue + ) + +/*++ + +Routine Description: + + Set the Queues state to start accepting and dispatching new requests. + +Arguments: + + Queue - Handle to Queue object + + A Queue may not go into a specific state right away, since it may have to + wait for requests to be completed or cancelled. This is reflected + in the status returned by WdfIoQueueGetState. + + See the Queue event API's for asynchronous notification of + specific status states. + +Returns: + + NTSTATUS +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + pQueue->QueueStart(); + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoQueueStop)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __drv_when(Context != 0, __in) + __drv_when(Context == 0, __in_opt) + PFN_WDF_IO_QUEUE_STATE StopComplete, + __drv_when(StopComplete != 0, __in) + __drv_when(StopComplete == 0, __in_opt) + WDFCONTEXT Context + ) + +/*++ + +Routine Description: + + Set the Queue state to accept and queue (not dispatch) incoming new requests. + +Arguments: + + Queue - Handle to Queue object + + A Queue may not go into a specific state right away, since it may have to + wait for requests to be completed or cancelled. This is reflected + in the status returned by WdfIoQueueGetState. + + See the Queue event API's for asynchronous notification of + specific status states. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + status = pQueue->QueueIdle(FALSE, StopComplete, Context); + if (!NT_SUCCESS(status)) { + pQueue->FatalError(status); + return; + } + + return; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfIoQueueStopSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue + ) + +/*++ + +Routine Description: + + Set the Queue state to accept and queue (not dispatch) incoming new requests and wait + for 1) all the dispatch callbacks to return and 2) all the driver-owned request to complete. + +Arguments: + + Queue - Handle to Queue object + +Returns: + + NTSTATUS +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + status = pQueue->QueueIdleSynchronously(FALSE); + + if (!NT_SUCCESS(status)) { + pQueue->FatalError(status); + return; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoQueueStopAndPurge)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __drv_when(Context != 0, __in) + __drv_when(Context == 0, __in_opt) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + __drv_when(StopAndPurgeComplete != 0, __in) + __drv_when(StopAndPurgeComplete == 0, __in_opt) + WDFCONTEXT Context + ) + +/*++ + +Routine Description: + + This function does the following: + - sets the queue state to accept and queues (not dispatch) incoming new requests. + - cancels all current (at the time this function is called) queued requests. + - invokes, if present, the cancel callback of cancellable driver requests. + - Asynchronously if complete callback is specified, it waits until + 1) all the dispatch callbacks to return and + 2) all the driver-owned request to complete. + +Arguments: + + Queue - Handle to Queue object + + A Queue may not go into a specific state right away, since it may have to + wait for requests to be completed or cancelled. This is reflected + in the status returned by WdfIoQueueGetState. + + See the Queue event API's for asynchronous notification of + specific status states. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* queue; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&queue); + + status = queue->QueueIdle(TRUE, StopAndPurgeComplete, Context); + if (!NT_SUCCESS(status)) { + queue->FatalError(status); + return; + } + + return; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue + ) + +/*++ + +Routine Description: + + This function does the following: + - sets the queue state to accept and queues (not dispatch) incoming new requests. + - cancels all current (at the time this function is called) queued requests. + - invokes, if present, the cancel callback of cancellable driver requests. + - before returning it waits until + 1) all the dispatch callbacks to return and + 2) all the driver-owned request to complete. + +Arguments: + + Queue - Handle to Queue object + +Returns: + + NTSTATUS +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals; + FxIoQueue* queue; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&queue, + &fxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(fxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + status = queue->QueueIdleSynchronously(TRUE); + + if (!NT_SUCCESS(status)) { + queue->FatalError(status); + return; + } +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveNextRequest)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __out + WDFREQUEST *OutRequest + ) + +/*++ + +WdfIoQueueRetrieveNextRequest: + +Routine Description: + + Returns a request from the head of the queue. + + On successful return the driver owns the request, and must + eventually call WdfRequestComplete. + + The driver does not need to release any extra reference counts, + other than calling WdfRequestComplete. + + +Arguments: + + Queue - Queue handle + + pOutRequest - Pointer to location to return new request handle + +Returns: + + + STATUS_NO_MORE_ENTRIES - The queue is empty + + STATUS_SUCCESS - A request was returned in pOutRequest + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + FxRequest* pOutputRequest = NULL; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + FxPointerNotNull(pQueue->GetDriverGlobals(), OutRequest); + + status = pQueue->GetRequest(NULL, NULL, &pOutputRequest); + + if (NT_SUCCESS(status)) { + *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); + } else { + *OutRequest = NULL; + ASSERT(status != STATUS_NOT_FOUND); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __in + WDFFILEOBJECT FileObject, + __out + WDFREQUEST *OutRequest + ) + +/*++ + +WdfIoQueueRetrieveNextRequest: + +Routine Description: + + Returns a request from the queue that matches the fileobject. + + Requests are dequeued in a first in, first out manner. + + If there are no requests that match the selection criteria, + STATUS_NO_MORE_ENTRIES is returned. + + On successful return the driver owns the request, and must + eventually call WdfRequestComplete. + + The driver does not need to release any extra reference counts, + other than calling WdfRequestComplete. + +Arguments: + + Queue - Queue handle + + FileObject - FileObject to match in the request + + pOutRequest - Pointer to location to return new request handle + +Returns: + + + STATUS_NO_MORE_ENTRIES - The queue is empty, or no more requests + match the selection criteria of TagRequest + and FileObject specified above. + + STATUS_SUCCESS - A request context was returned in + pOutRequest + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + FxRequest* pOutputRequest = NULL; + FxFileObject* pFO = NULL; + MdFileObject pWdmFO = NULL; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, OutRequest); + + FxObjectHandleGetPtr(pFxDriverGlobals, + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + + // Get the real WDM fileobject + pWdmFO = pFO->GetWdmFileObject(); + + status = pQueue->GetRequest(pWdmFO, NULL, &pOutputRequest); + + if (NT_SUCCESS(status)) { + + // Copy out the handle to the new request + *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); + } else { + *OutRequest = NULL; + ASSERT(status != STATUS_NOT_FOUND); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __in + WDFREQUEST TagRequest, + __out + WDFREQUEST * OutRequest + ) + +/*++ + +WdfIoQueueRetrieveNextRequest: + +Routine Description: + + Returns a request from the queue. + + Requests are dequeued in a first in, first out manner. + + The queue is searched for specific peeked + request, and if it is not found, STATUS_NOT_FOUND is + returned. A TagRequest value is returned + from WdfIoQueueFindRequest(). + + If there are no requests that match the selection criteria, + STATUS_NO_MORE_ENTRIES is returned. + + On successful return the driver owns the request, and must + eventually call WdfRequestComplete. + + The driver does not need to release any extra reference counts, + other than calling WdfRequestComplete. + +Arguments: + + Queue - Queue handle + + TagRequest - Request to look for in queue + + pOutRequest - Pointer to location to return new request handle + +Returns: + + STATUS_NOT_FOUND - TagContext was specified, but not + found in the queue. This could be + because the request was cancelled, + or is part of an active queue and + the request was passed to the driver + or forwarded to another queue. + + STATUS_NO_MORE_ENTRIES - The queue is empty, or no more requests + match the selection criteria of TagRequest + specified above. + + STATUS_SUCCESS - A request context was returned in + pOutRequest + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + FxRequest* pTagRequest = NULL; + FxRequest* pOutputRequest = NULL; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, OutRequest); + + FxObjectHandleGetPtr(pFxDriverGlobals, + TagRequest, + FX_TYPE_REQUEST, + (PVOID*)&pTagRequest); + + status = pQueue->GetRequest(NULL, pTagRequest, &pOutputRequest); + + if (NT_SUCCESS(status)) { + // Copy out the handle to the new request + *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); + } else { + *OutRequest = NULL; + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueFindRequest)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __in_opt + WDFREQUEST TagRequest, + __in_opt + WDFFILEOBJECT FileObject, + __inout_opt + PWDF_REQUEST_PARAMETERS Parameters, + __out + WDFREQUEST * OutRequest + ) + +/*++ + +WdfIoQueueFindRequest: + +Routine Description: + + PeekRequest allows a caller to enumerate through requests in + a queue, optionally only returning requests that match a specified + FileObject. + + The first call specifies TagContext == NULL, and the first request + in the queue that matches the FileObject is returned. + + Subsequent requests specify the previous request value as the + TagContext, and searching will continue at the request that follows. + + If the queue is empty, there are no requests after TagContext, or no + requests match the FileObject, NULL is returned. + + If FileObject == NULL, this matches any FileObject in a request. + + If a WDF_REQUEST_PARAMETERS structure is supplied, the information + from the request is returned to allow the driver to further examine + the request to decide whether to service it. + + If a TagRequest is specified, and it is not found, the return + status STATUS_NOT_FOUND means that the queue should + be re-scanned. This is because the TagRequest was cancelled from + the queue, or if the queue was active, delivered to the driver. + There may still be un-examined requests on the queue that match + the drivers search criteria, but the search marker has been lost. + + Re-scanning the queue starting with TagRequest == NULL and + continuing until STATUS_NO_MORE_ENTRIES is returned will ensure + all requests have been examined. + + Enumerating an active queue with this API could result in the + driver frequently having to re-scan. + + If a successful return of a Request object handle occurs, the driver + *must* call WdfObjectDereference when done with it, otherwise an + object leak will result. + + Returned request objects are not owned by the driver, and may not be + used by I/O or completed. The only valid operations are + WdfRequestGetParameters, passing it as the TagRequest parameter to + WdfIoQueueFindRequest, WdfIoQueueRetrieveFoundRequest, or calling + WdfObjectDereference. All other actions are undefined. + + The request could be cancelled without a EvtIoCancel callback while the + driver has the handle. The request then becomes invalid, and + WdfObjectDereference must be called to release its resources. + + The caller should not use any buffer pointers in the returned parameters + structure until it successfully receives ownership of the request by + calling WdfIoQueueRetrieveFoundRequest with the request tag. This is because + the I/O can be cancelled and completed at any time without the driver + being notified until it has received ownership, thus invalidating + the buffer pointers and releasing the memory, even if the request + object itself it still valid due to the reference. + + The driver should hold the reference on the object until after + a call to WdfIoQueueFindRequest using it as the TagRequest + parameter, or WdfIoQueueRetrieveFoundtRequest. Otherwise, a race could + result in which the object is cancelled, its memory re-used for + a new request, and then an attempt to use it as a tag would result + in a different state than intended. The driver verifier will + catch this, but it is a rare race. + + Calling this API on an operating Queue can lead to confusing results. This + is because the request could be presented to EvtIoDefault, causing it to be + invalid as a TagRequest in calls to WdfIoQueueFindRequest, and + WdfIoQueueRetrieveFoundRequest. The extra reference taken on the object by its return + from this call must still be released by WdfObjectDereference. + + The intention of the API is to only hold onto the TagRequest long enough + for the driver to make a decision whether to service the request, or + to continue searching for requests. + +Arguments: + + Queue - Queue handle + + TagRequest - If !NULL, request to begin search at + + FileObject - If !NULL, FileObject to match in the request + + Parameters - If !NULL, pointer to buffer to return the requests + parameters to aid in selection. + + pOutRequest - Pointer to location to return request handle + +Returns: + + STATUS_NOT_FOUND - TagContext was specified, but not + found in the queue. This could be + because the request was cancelled, + or is part of an active queue and + the request was passed to the driver + or forwarded to another queue. + + STATUS_NO_MORE_ENTRIES - The queue is empty, or no more requests + match the selection criteria of TagRequest + and FileObject specified above. + + STATUS_SUCCESS - A request context was returned in + pOutRequest + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + FxRequest* pTagRequest = NULL; + FxRequest* pOutputRequest = NULL; + FxFileObject* pFO = NULL; + MdFileObject pWdmFO = NULL; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, OutRequest); + + // + // Validate tag request handle if supplied + // + if (TagRequest != NULL) { + FxObjectHandleGetPtr(pFxDriverGlobals, + TagRequest, + FX_TYPE_REQUEST, + (PVOID*)&pTagRequest); + } + + // + // If present, validate the FileObject object handle, + // and get its FxFileObject* + // + if (FileObject != NULL) { + FxObjectHandleGetPtr(pFxDriverGlobals, + FileObject, + FX_TYPE_FILEOBJECT, + (PVOID*)&pFO); + // + // Get the real WDM fileobject + // + pWdmFO = pFO->GetWdmFileObject(); + } + + // + // If a parameters buffer is supplied, validate its length + // + if ((Parameters != NULL) && (Parameters->Size < sizeof(WDF_REQUEST_PARAMETERS))) { + status = STATUS_INVALID_PARAMETER_4; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Invalid WDF_REQUEST_PARAMETERS size %d %!STATUS!", + Parameters->Size, status); + return status; + } + + + status = pQueue->PeekRequest(pTagRequest, + pWdmFO, + Parameters, + &pOutputRequest); + + if (NT_SUCCESS(status)) { + // + // Copy out the handle to the new request + // + *OutRequest = (WDFREQUEST)pOutputRequest->GetObjectHandle(); + } else { + *OutRequest = NULL; + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoQueueDrain)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __drv_when(Context != 0, __in) + __drv_when(Context == 0, __in_opt) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + __drv_when(DrainComplete != 0, __in) + __drv_when(DrainComplete == 0, __in_opt) + WDFCONTEXT Context + ) + +/*++ + + Set the Queue to reject new requests, with newly arriving + requests being completed with STATUS_CANCELLED. + + If the optional DrainComplete callback is specified, the + callback will be invoked with the supplied context when + there are no requests owned by the driver and no request pending in the + queue. + + Only one callback registration for WdfIoQueueIdle, WdfIoQueuePurge, + or WdfIoQueueDrain may be outstanding at a time. + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + status = pQueue->QueueDrain(DrainComplete, Context); + + if (!NT_SUCCESS(status)) { + pQueue->FatalError(status); + return; + } + + return; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfIoQueueDrainSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue + ) + +/*++ + + Set the Queue to fail new request with STATUS_CANCELLED, + dispatches pending requests, and waits for the all the pending and + inflight requests to complete before returning. + + Should be called at PASSIVE_LEVEL. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + status = pQueue->QueueDrainSynchronously(); + + if (!NT_SUCCESS(status)) { + pQueue->FatalError(status); + return; + } +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfIoQueuePurgeSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue + ) + +/*++ + + Sets the queue state to fail incoming requests, + cancels all the pending requests, cancels in-flights requests + (if they are marked cancelable), and waits for all the requests + to complete before returning. + + Should be called at PASSIVE_LEVEL. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + status = pQueue->QueuePurgeSynchronously(); + + if (!NT_SUCCESS(status)) { + pQueue->FatalError(status); + return; + } + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoQueuePurge)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __drv_when(Context != 0, __in) + __drv_when(Context == 0, __in_opt) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + __drv_when(PurgeComplete != 0, __in) + __drv_when(PurgeComplete == 0, __in_opt) + WDFCONTEXT Context + ) + +/*++ + + Set the Queue to reject new requests, with newly arriving + requests being completed with STATUS_CANCELLED. + + A Queue may not purge immediately, since the device driver + could be operating on non-cancelable requests. + + + If the optional PurgeComplete callback is specified, the + callback will be invoked with the supplied context when + the Queue is in the WDF_IO_QUEUE_PURGED state. + (Reject new requests, no current requests in Queue or device driver) + + Only one callback registration for WdfIoQueueIdle, WdfIoQueuePurge, + or WdfIoQueueDrain may be outstanding at a time. + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + status = pQueue->QueuePurge( + TRUE, + TRUE, + PurgeComplete, + Context + ); + + if (!NT_SUCCESS(status)) { + pQueue->FatalError(status); + return; + } + + return; +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueReadyNotify)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __in_opt + PFN_WDF_IO_QUEUE_STATE QueueReady, + __in_opt + WDFCONTEXT Context + ) + +/*++ + + This API notifies the device driver when the Queue + has one or more requests that can be processed by + the device driver. + + This event registration continues until cancelled with + by calling with NULL for QueueReady. + + One event is generated for each transition from + not ready, to ready. An event is not generated for each + new request, only request arrival on an empty Queue. + +--*/ + +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue); + + status = pQueue->ReadyNotify( + QueueReady, + Context + ); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoQueueAssignForwardProgressPolicy)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFQUEUE Queue, + __in + PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY ForwardProgressPolicy + ) + +/*++ + + This DDI is used by the driver to configure a queue to have forward + progress. +--*/ +{ + DDI_ENTRY(); + + FxIoQueue* pQueue; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pQueue, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ForwardProgressPolicy); + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pQueue->IsForwardProgressQueue()) { + // + // Queue is already configured for forward progress + // + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Queue is already configured for forward progress %!STATUS!", + status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return status; + } + + // + // Validate Config structure + // + if (ForwardProgressPolicy->Size != sizeof(WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Size 0x%x, " + "expected 0x%x, %!STATUS!", + ForwardProgressPolicy->Size, sizeof(WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY), status); + return status; + } + + // + // Validate policy settings + // + switch (ForwardProgressPolicy->ForwardProgressReservedPolicy) { + case WdfIoForwardProgressReservedPolicyUseExamine: + if (ForwardProgressPolicy->ForwardProgressReservePolicySettings.Policy.ExaminePolicy.EvtIoWdmIrpForForwardProgress == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Examine callback can't be null for WdfIoForwardProgressReservedPolicyUseExamine " + " %!STATUS!", + status); + + return status; + } + break; + + default: + break; + + } + + // + // Validate number of forward progress requests + // + if (ForwardProgressPolicy->TotalForwardProgressRequests == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Need to have more than 0 reserved Requests %!STATUS!", + status); + + return status; + } + + status = pQueue->AssignForwardProgressPolicy( + ForwardProgressPolicy + ); + + return status; +} + + + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/io/fxpkgio.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/io/fxpkgio.cpp new file mode 100644 index 00000000000..5b09c0167b3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/io/fxpkgio.cpp @@ -0,0 +1,1797 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgIo.cpp + +Abstract: + + This module implements the I/O package for the driver frameworks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "ioprivshared.hpp" + +// Tracing support +extern "C" { +#if defined(EVENT_TRACING) +#include "FxPkgIo.tmh" +#endif +} + +// +// This package is initialized by the FxPkgIo::Install virtual method +// being invoked. +// +// A reference is held on it by the FxDevice which owns it. When the +// FxDevice is destroyed, its destructor FxDevice::~FxDevice will release +// its reference to this package, so that FxPkgIo::~FxPkgIo can run. +// +// There is no other package remove, or un-install call. +// + +FxPkgIo::FxPkgIo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ) : + FxPackage(FxDriverGlobals, Device, FX_TYPE_PACKAGE_IO), + m_InCallerContextCallback(FxDriverGlobals) +{ + LARGE_INTEGER tickCount; + + m_Device = Device; + + m_DefaultQueue = NULL; + + RtlZeroMemory(m_DispatchTable, sizeof(m_DispatchTable)); + + m_Filter = FALSE; + + m_PowerStateOn = FALSE; + + m_QueuesAreShuttingDown = FALSE; + + InitializeListHead(&m_IoQueueListHead); + + InitializeListHead(&m_DynamicDispatchInfoListHead); + + Mx::MxQueryTickCount(&tickCount); + + m_RandomSeed = tickCount.LowPart; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIO, + "Constructed FxPkgIo 0x%p",this); +} + +FxPkgIo::~FxPkgIo() +{ + PLIST_ENTRY next; + + m_DefaultQueue = NULL; + + m_Device = NULL; + + while (!IsListEmpty(&m_DynamicDispatchInfoListHead)) { + next = RemoveHeadList(&m_DynamicDispatchInfoListHead); + FxIrpDynamicDispatchInfo* info; + info = CONTAINING_RECORD(next, FxIrpDynamicDispatchInfo, ListEntry); + InitializeListHead(next); + delete info; + } + + ASSERT(IsListEmpty(&m_IoQueueListHead)); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "Destroyed FxPkgIo 0x%p",this); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgIo::Dispatch( + __inout MdIrp Irp + ) +{ + FxIrp fxIrp(Irp); + FX_TRACK_DRIVER(GetDriverGlobals()); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIO, + "WDFDEVICE 0x%p !devobj 0x%p %!IRPMJ!, IRP_MN %x, IRP 0x%p", + m_Device->GetHandle(), m_Device->GetDeviceObject(), + fxIrp.GetMajorFunction(), + fxIrp.GetMinorFunction(), Irp); + + return DispatchStep1(Irp, m_DynamicDispatchInfoListHead.Flink); +} + +_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; +} + +__inline +_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 (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; +} + +__inline +_Must_inspect_result_ +NTSTATUS +__fastcall +FxPkgIo::DispatchStep2( + __inout MdIrp Irp, + __in_opt FxIoInCallerContext* IoInCallerCtx, + __in_opt FxIoQueue* Queue + ) +{ + NTSTATUS status; + FxRequest* request; + BOOLEAN isForwardProgressQueue; + BOOLEAN inCriticalRegion; + PWDF_OBJECT_ATTRIBUTES reqAttribs; + FxIrp fxIrp(Irp); + + request = NULL; + inCriticalRegion = FALSE; + isForwardProgressQueue = Queue != NULL && Queue->IsForwardProgressQueue(); + + ASSERT(fxIrp.GetMajorFunction() <= IRP_MJ_MAXIMUM_FUNCTION); + ASSERT((IoInCallerCtx != NULL && IoInCallerCtx->m_Method != NULL) || + Queue != NULL); + // + // The request inserted into the queue can be retrieved and processed + // by an arbitrary thread. So we need to make sure that such a thread doesn't + // get suspended and deadlock the driver and potentially the system by + // entering critical region.The KeEnterCriticalRegion temporarily disables + // the delivery of normal kernel APCs used to suspend a thread. + // Kernel APCs queued to this thread will get executed when we leave the + // critical region. + // + if (Mx::MxGetCurrentIrql() <= APC_LEVEL) { + Mx::MxEnterCriticalRegion(); + inCriticalRegion = TRUE; + } + + if (Queue != NULL && Queue->GetCxDeviceInfo() != NULL) { + reqAttribs = &Queue->GetCxDeviceInfo()->RequestAttributes; + } + else { + reqAttribs = m_Device->GetRequestAttributes(); + } + + status = FxRequest::_CreateForPackage(m_Device, reqAttribs, Irp, &request); + + // + // Check if it is forward progress queue and the EnhancedVerifierOption for + // testing forward progress are set. + // + if (isForwardProgressQueue && + NT_SUCCESS(status) && + IsFxVerifierTestForwardProgress(GetDriverGlobals())) { + // + // This function returns STATUS_INSUFFICIENT_RESOURCES + // if testing forward progress is enabled and free's the passed in request. + // + status = VerifierFreeRequestToTestForwardProgess(request); + } + + if (!NT_SUCCESS(status)) { + if (m_Filter && Queue == NULL) { + goto CompleteIrp; + } + + if (isForwardProgressQueue) { + status = Queue->GetReservedRequest(Irp, &request); + if (status == STATUS_PENDING) { + goto IrpIsGone; + } + else if (!NT_SUCCESS(status)) { + goto CompleteIrp; + } + } + else { + // + // Fail the request + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIO, + "Could not create WDFREQUEST, %!STATUS!", status); + + goto CompleteIrp; + } + } + else { + if (isForwardProgressQueue) { + status = Queue->InvokeAllocateResourcesCallback(request); + if (!NT_SUCCESS(status)) { + // + // Failure of the callback means the driver wasn't able to + // allocate resources for the request. In that case free the + // request allocated earlier and use the reserved one. + // + request->FreeRequest(); + request = NULL; + + status = Queue->GetReservedRequest(Irp, &request); + if (status == STATUS_PENDING) { + goto IrpIsGone; + } + else if (!NT_SUCCESS(status)) { + goto CompleteIrp; + } + } + } + } + + // + // Since we can't guarantee the callback to be called in the context of the + // caller for reserved requests, we will skip calling InCallerContextCallback + // for reserverd request. + // + if (IoInCallerCtx != NULL && + IoInCallerCtx->m_Method != NULL && + request->IsReserved() == FALSE) { + + request->SetInternalContext(Queue); + status = DispathToInCallerContextCallback(IoInCallerCtx, request, Irp); + + // + // The driver is responsible for calling WdfDeviceEnqueueRequest to + // insert it back into the I/O processing pipeline, or completing it. + // + goto IrpIsGone; + } + + ASSERT(Queue != NULL); + status = Queue->QueueRequest(request); + goto IrpIsGone; + +CompleteIrp: + + fxIrp.SetStatus(status); + fxIrp.SetInformation(0); + fxIrp.CompleteRequest(IO_NO_INCREMENT); + // + // fallthrough + // +IrpIsGone: + + if (inCriticalRegion) { + Mx::MxLeaveCriticalRegion(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgIo::InitializeDefaultQueue( + __in CfxDevice * Device, + __inout FxIoQueue * Queue + ) + +/*++ + + Routine Description: + + Make the input queue as the default queue. There can be + only one queue as the default queue. + + The default queue is the place all requests go to + automatically if a specific queue was not configured + for them. + +Arguments: + + +Return Value: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + ULONG index; + + if (m_DefaultQueue != NULL) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Default Queue Already Configured for " + "FxPkgIo 0x%p, WDFDEVICE 0x%p %!STATUS!",this, + Device->GetHandle(), STATUS_UNSUCCESSFUL); + return STATUS_UNSUCCESSFUL; + } + + for (index=0; index <= IRP_MJ_MAXIMUM_FUNCTION; index++) { + if (m_DispatchTable[index] == NULL) { + m_DispatchTable[index] = Queue; + } + } + + m_DefaultQueue = Queue; + + // + // Default queue can't be deleted. So mark the object to fail WdfObjectDelete on + // the default queue. + // + Queue->MarkNoDeleteDDI(); + return STATUS_SUCCESS; +} + +__inline +FxDriver* +FxPkgIo::GetDriver( + VOID + ) +{ + return m_Device->GetDriver(); +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxPkgIo, VerifyEnqueueRequestUpdateFlags) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* Request, + _Inout_ SHORT* OrigVerifierFlags + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE_LOCKED(); + + KIRQL irql; + + Request->Lock(&irql); + + *OrigVerifierFlags = Request->GetVerifierFlagsLocked(); + + status = Request->VerifyRequestIsInCallerContext(FxDriverGlobals); + if (NT_SUCCESS(status)) { + status = Request->VerifyRequestIsDriverOwned(FxDriverGlobals); + } + + if (NT_SUCCESS(status)) { + Request->ClearVerifierFlagsLocked( + FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT | + FXREQUEST_FLAG_DRIVER_OWNED); + } + + Request->Unlock(irql); + return status; +} + +VOID +FX_VF_METHOD(FxPkgIo, VerifyEnqueueRequestRestoreFlags) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequest* Request, + _In_ SHORT OrigVerifierFlags + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + KIRQL irql; + + PAGED_CODE_LOCKED(); + + Request->Lock(&irql); + Request->ClearVerifierFlagsLocked(~OrigVerifierFlags); + Request->SetVerifierFlagsLocked(OrigVerifierFlags); + Request->Unlock(irql); +} + + +// +// 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; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgIo::ConfigureDynamicDispatching( + __in UCHAR MajorFunction, + __in_opt FxCxDeviceInfo* CxDeviceInfo, + __in PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDispatch, + __in_opt WDFCONTEXT DriverContext + ) +{ + NTSTATUS status; + PFX_DRIVER_GLOBALS fxDriverGlobals; + PLIST_ENTRY next; + FxIrpDynamicDispatchInfo* dispatchInfo; + LONG mjIndex; + CCHAR driverIndex; + BOOLEAN addNew; + + fxDriverGlobals = GetDriverGlobals(); + addNew = TRUE; + + mjIndex = FxIrpDynamicDispatchInfo::Mj2Index(MajorFunction); + + // + // Indirect MajorFunction validation. + // + if (mjIndex >= FxIrpDynamicDispatchInfo::DynamicDispatchMax) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Invalid MajorFunction %!IRPMJ!, %!STATUS!", + MajorFunction, status); + goto Done; + } + + // + // Get driver I/O device path index. + // + driverIndex = FxDevice::GetCxDriverIndex(CxDeviceInfo); + + // + // Insert new info into correct slot in the I/O path. + // Index goes from higher to lower (..., 2, 1, 0) b/c cx's callback is called before + // client's one. + // + for (next = m_DynamicDispatchInfoListHead.Flink; + next != &m_DynamicDispatchInfoListHead; + next = next->Flink) { + + CCHAR curIndex = 0; + + dispatchInfo = CONTAINING_RECORD(next, + FxIrpDynamicDispatchInfo, + ListEntry); + // + // Get current I/O device path index. + // + curIndex = FxDevice::GetCxDriverIndex(dispatchInfo->CxDeviceInfo); + if (driverIndex == curIndex) { + // + // Found it. + // + if (dispatchInfo->Dispatch[mjIndex].EvtDeviceDynamicDispatch != NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Driver %p has already set a dispatch callback for " + "%!IRPMJ!, %!STATUS!", + CxDeviceInfo == NULL ? + GetDriver()->GetHandle() : + CxDeviceInfo->Driver->GetHandle(), + MajorFunction, status); + goto Done; + } + + dispatchInfo->Dispatch[mjIndex].DriverContext = DriverContext; + dispatchInfo->Dispatch[mjIndex].EvtDeviceDynamicDispatch = + EvtDeviceWdmIrpDispatch; + + ASSERT(dispatchInfo->CxDeviceInfo == CxDeviceInfo); + + addNew = FALSE; + break; + } + else if (driverIndex > curIndex) { + // + // Not found (past valid range), add one before current. + // + break; + } + else if (driverIndex < curIndex) { + // + // Keep looking, too high. + // + continue; + } + } + + if (addNew) { + dispatchInfo = new(fxDriverGlobals) FxIrpDynamicDispatchInfo(); + if (dispatchInfo == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Couldn't create object DynamicDispatchInfo, %!STATUS!", + status); + goto Done; + } + + dispatchInfo->CxDeviceInfo = CxDeviceInfo; + dispatchInfo->Dispatch[mjIndex].DriverContext = DriverContext; + dispatchInfo->Dispatch[mjIndex].EvtDeviceDynamicDispatch = + EvtDeviceWdmIrpDispatch; + + // + // We must insert it before 'next' element. + // + InsertTailList(next, &dispatchInfo->ListEntry); + } + + status = STATUS_SUCCESS; + +Done: + return status; +} + +_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; +} + +_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; +} + + +VOID +FxPkgIo::RemoveQueueReferences( + __inout FxIoQueue* pQueue + ) +/*++ + +Routine Description: + + This is called from FxIoQueue::Dispose to remove + the queue from the transaction list. + + Since this acquires the FxPkgIo lock, it assumes that + no calls are made into FxIoQueue while holding the + FxPkgIo lock. + +Arguments: + + None + +Return Value: + None + --*/ +{ + // Remove it from transacation list + RemoveIoQueue(pQueue); + return; +} + +_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; +} + +_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; +} + +_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; +} + +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; + +} + +_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; +} + +static +VOID +GetIoQueueList_ProcessQueueListEntry( + PLIST_ENTRY QueueLE, + PSINGLE_LIST_ENTRY SListHead, + PVOID Tag + ) +{ + FxIoQueueNode* listNode; + FxIoQueue* queue; + + // + // Skip any nodes that are not queues. They can be bookmarks for + // in-progress flush operations. + // + listNode = FxIoQueueNode::_FromListEntry(QueueLE); + if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { + return; + } + + queue = FxIoQueue::_FromIoPkgListEntry(QueueLE); + PushEntryList(SListHead, &queue->m_PowerSListEntry); + + // + // Add a reference since the request will be touched outside of the + // lock being held. We will use the enumerant value as the tag. + // + queue->ADDREF(Tag); +} + +VOID +FxPkgIo::GetIoQueueListLocked( + __in PSINGLE_LIST_ENTRY SListHead, + __inout FxIoIteratorList ListType + ) +/*++ + + Routine Description: + + Called to make a temporary list of queues for iteration purpose. + Function is called with the FxPkg lock held. + +--*/ +{ + PLIST_ENTRY listHead, le; + + listHead = &m_IoQueueListHead; + + if (FxIoQueueIteratorListPowerOn == ListType || + (FxIoQueueIteratorListPowerOff == ListType && // backwards compatibility order. + m_Device->IsCxInIoPath() == FALSE)) { + // + // Power up: first client driver's queues then cx's queues. + // List is already sorted with client driver's queue first. + // Since we are inserting into the head of the single list head, if we walked + // over the list from first to last, we would reverse the entries. By walking + // the list backwards, we build the single list head in the order of m_IoQueueListHead. + // + for (le = listHead->Blink; le != listHead; le = le->Blink) { + GetIoQueueList_ProcessQueueListEntry(le, + SListHead, + IO_ITERATOR_POWER_TAG); + } + } + else if (FxIoQueueIteratorListPowerOff == ListType) { + // + // Power down: first cx's queues then client driver's queues. + // List is already sorted with client driver's queue first. + // Since we are inserting into the head of the single list head, if we walked + // over the list from last to first, we would reverse the entries. By walking + // the list forwards, we build the single list head in the desired order + // + for (le = listHead->Flink; le != listHead; le = le->Flink) { + GetIoQueueList_ProcessQueueListEntry(le, + SListHead, + IO_ITERATOR_POWER_TAG); + } + } + else { + ASSERT(FALSE); + } +} + +VOID +FxPkgIo::AddIoQueue( + __inout FxIoQueue* IoQueue + ) +{ + PLIST_ENTRY listHead, le; + FxIoQueue* queue; + KIRQL irql; + FxIoQueueNode* listNode; + CCHAR queueIndex, curIndex; + + listHead = &m_IoQueueListHead; + queueIndex = FxDevice::GetCxDriverIndex(IoQueue->GetCxDeviceInfo()); + Lock(&irql); + + ASSERT(IoQueue->m_IoPkgListNode.IsNodeType(FxIoQueueNodeTypeQueue)); + + // + // Insert new queue in sorted list; search from last to first. + // + for (le = listHead->Blink; le != listHead; le = le->Blink) { + // + // Skip any nodes that are not queues. They can be bookmarks for + // in-progress flush operations. + // + listNode = FxIoQueueNode::_FromListEntry(le); + if (listNode->IsNodeType(FxIoQueueNodeTypeQueue) == FALSE) { + continue; + } + + // + // Get current queue's driver index. + // + queue = FxIoQueue::_FromIoPkgListEntry(le); + curIndex = FxDevice::GetCxDriverIndex(queue->GetCxDeviceInfo()); + // + // Queues are inserted in order at the end of its allowed range. + // + if (curIndex < queueIndex || curIndex == queueIndex) { + break; + } + } + + InsertHeadList(le, &IoQueue->m_IoPkgListNode.m_ListEntry); + + if (m_PowerStateOn) { + IoQueue->SetPowerState(FxIoQueuePowerOn); + } else { + IoQueue->SetPowerState(FxIoQueuePowerOff); + if (m_QueuesAreShuttingDown) { + // Clear accept requests + IoQueue->SetStateForShutdown(); + } + } + + Unlock(irql); + + return; +} + +VOID +FxPkgIo::RemoveIoQueue( + __inout FxIoQueue* IoQueue + ) +{ + KIRQL irql; + + Lock(&irql); + + RemoveEntryList(&IoQueue->m_IoPkgListNode.m_ListEntry); + ASSERT(IoQueue->m_IoPkgListNode.IsNodeType(FxIoQueueNodeTypeQueue)); + + InitializeListHead(&IoQueue->m_IoPkgListNode.m_ListEntry); + + Unlock(irql); +} + +FxIoQueue* +FxPkgIo::GetFirstIoQueueLocked( + __in FxIoQueueNode* QueueBookmark, + __in PVOID Tag + ) +/*++ + + Routine Description: + + Inserts the provided bookmark (FxIoQueueNode) at the beginning + of the IO Package's queue list, and calls GetNextIoQueueLocked + to retrieve the first queue and to advance the bookmark. + + Function is called with the FxPkg lock held. + + Return Value: + + NULL if there are no queues in list else + FxIoQueue* reference to first queue in list. + +--*/ +{ + ASSERT(QueueBookmark->IsNodeType(FxIoQueueNodeTypeBookmark)); + ASSERT(IsListEmpty(&QueueBookmark->m_ListEntry)); + + InsertHeadList(&m_IoQueueListHead, &QueueBookmark->m_ListEntry); + + return GetNextIoQueueLocked(QueueBookmark, Tag); +} + +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; +} + +NTSTATUS +FxPkgIo::DispathToInCallerContextCallback( + __in FxIoInCallerContext *InCallerContextInfo, + __in FxRequest *Request, + __inout MdIrp Irp + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequestCompletionState oldState; + FxIrp fxIrp(Irp); + + pFxDriverGlobals = GetDriverGlobals(); + + // + // Mark the IRP pending since we are going + // to return STATUS_PENDING regardless of whether + // the driver completes the request right away + // or not + // + fxIrp.MarkIrpPending(); + + if (pFxDriverGlobals->FxVerifierOn) { + Request->SetVerifierFlags(FXREQUEST_FLAG_DRIVER_INPROCESS_CONTEXT | + FXREQUEST_FLAG_DRIVER_OWNED); + } + + // + // Set a completion callback to manage the reference + // count on the request + // + oldState = Request->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 + // + Request->RELEASE(FXREQUEST_STATE_TAG); + + Request->SetPresented(); + + // + // Drivers that use this API are responsible for handling + // all locking, threading, and IRQL level issues... + // + InCallerContextInfo->Invoke(m_Device->GetHandle(), + Request->GetHandle()); + // + // The driver is responsible for calling WdfDeviceEnqueueRequest to insert + // it back into the I/O processing pipeline, or completing it. + // + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgIo::VerifierFreeRequestToTestForwardProgess( + __in FxRequest* Request + ) +{ + BOOLEAN failAllocation; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + failAllocation = FALSE; + // + // forwardProgressTestFailAll takes precedence over forwardProgressTestFailRandom + // + if (IsFxVerifierTestForwardProgressFailAll(pFxDriverGlobals)) { + failAllocation = TRUE; + } + else if (IsFxVerifierTestForwardProgressFailRandom(pFxDriverGlobals)) { + // + // Modulo 17 makes the probability of failure ~6% just like verifier.exe + // + failAllocation = (FxRandom(&m_RandomSeed) % 17 == 0); + } + + if (failAllocation) { + // + // Don't use DeleteObject() here as the Request wasn't presented to the + // driver and the cleanup /dispose callback can be invoked unless + // we use FreeRequest() which clears the cleanup /dispose callbacks + // + Request->FreeRequest(); + + return STATUS_INSUFFICIENT_RESOURCES; + } + else { + return STATUS_SUCCESS; + } +} + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/io/ioprivshared.hpp b/sdk/lib/drivers/wdf/shared/irphandlers/io/ioprivshared.hpp new file mode 100644 index 00000000000..5167f1dd373 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/io/ioprivshared.hpp @@ -0,0 +1,309 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + iopriv.hpp + +Abstract: + + This module defines private interfaces for the I/O package + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef _IOPRIV_H_ +#define _IOPRIV_H_ + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#define FX_IS_USER_MODE (TRUE) +#define FX_IS_KERNEL_MODE (FALSE) +#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#define FX_IS_USER_MODE (FALSE) +#define FX_IS_KERNEL_MODE (TRUE) +#endif + +/*#if defined(MODE_AGNSOTIC_FXPKGIO_NOT_IN_SHARED_FOLDER) +#include +#else +// common header file for all irphandler\* files +#include "irphandlerspriv.hpp" +#endif + +#if FX_IS_USER_MODE +#define PWDF_REQUEST_PARAMETERS PVOID +#define PFN_WDF_REQUEST_CANCEL PVOID +#define PIO_CSQ_IRP_CONTEXT PVOID +#endif*/ + +extern "C" { +#include "mx.h" +} + +#include "FxMin.hpp" + +#include "wdfmemory.h" +#include "wdfrequest.h" +#include "wdfio.h" +#include "wdfdevice.h" +#include "wdfWmi.h" +#include "wdfChildList.h" +#include "wdfpdo.h" +#include "wdffdo.h" +#include "FxIrpQueue.hpp" +#include "FxCallback.hpp" + +// +__drv_functionClass(EVT_SYSTEMWORKITEM) +__drv_maxIRQL(PASSIVE_LEVEL) +__drv_maxFunctionIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +typedef +VOID +EVT_SYSTEMWORKITEM( + __in PVOID Parameter + ); + +typedef EVT_SYSTEMWORKITEM *PFN_WDF_SYSTEMWORKITEM; + +// + +#include "FxSystemThread.hpp" + +#include "FxCallbackSpinlock.hpp" +#include "FxCallbackMutexLock.hpp" +#include "FxTransactionedList.hpp" + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#include "FxIrpKm.hpp" +#else +#include "FxIrpUm.hpp" +#endif + + +#include "FxPackage.hpp" +#include "FxCollection.hpp" +#include "FxDeviceInitShared.hpp" +#include "FxDeviceToMxInterface.hpp" + +#include "IfxMemory.hpp" +#include "FxCallback.hpp" +#include "FxRequestContext.hpp" +#include "FxRequestContextTypes.h" +#include "FxRequestBase.hpp" +#include "FxMemoryObject.hpp" +#include "FxMemoryBufferPreallocated.hpp" +#include "FxRequestMemory.hpp" +#include "FxRequest.hpp" +#include "FxRequestBuffer.hpp" +#include "FxSyncRequest.hpp" + +#include "irphandlerspriv.hpp" +#include "FxPkgPnp.hpp" +#include "FxPkgIo.hpp" +#include "FxIoQueue.hpp" +#include "FxIoQueueCallbacks.hpp" + + +// +// At this time we are unable to include wdf17.h in the share code, thus for +// now we simply cut and paste the needed structures. +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_7 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + +} WDF_IO_QUEUE_CONFIG_V1_7, *PWDF_IO_QUEUE_CONFIG_V1_7; + +// +// At this time we are unable to include wdf19.h in the shared code, thus for +// now we simply cut and paste the needed structures. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_9 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + +} WDF_IO_QUEUE_CONFIG_V1_9, *PWDF_IO_QUEUE_CONFIG_V1_9; + + +// +// public headers +// +/*#include "wdfDevice.h" +#include "wdfChildList.h" +#include "wdfPdo.h" +#include "wdffdo.h" +#include "wdfQueryInterface.h" +#include "wdfMemory.h" +#include "wdfWmi.h" + +#if FX_IS_KERNEL_MODE +#include "wdfrequest.h" +#endif +#include "wdfio.h" + + + +#include "FxCallback.hpp" + + +#include "FxRequestBaseShared.hpp" +#include "FxRequestShared.hpp" + +// FxDevice To Shared interface header +#include "FxDeviceToMxInterface.hpp" +#include "FxRequestToMxInterface.hpp" + +#if defined(MODE_AGNSOTIC_FXPKGIO_NOT_IN_SHARED_FOLDER) +#include "FxRequestToMxInterfaceKM.hpp" +#endif + +// +// private headers +// +#include "FxTransactionedList.hpp" +#include "FxSystemThread.hpp" + +#if FX_IS_KERNEL_MODE +#include "FxFileObject.hpp" +#endif + +#include "Fxirpqueue.hpp" + +#include "FxCallbackSpinLock.hpp" +#include "FxCallbackMutexLock.hpp" + +//#include "FxDeviceInterface.hpp" +//#include "FxQueryInterface.hpp" +//#include "FxPnpCallbacks.hpp" +#include "FxPackage.hpp" + +#include "FxChildList.hpp" +#include "FxPkgPnp.hpp" +#include "FxPkgPdo.hpp" + +#include "FxPkgIo.hpp" +#include "FxIoQueue.hpp" + + +/*#if !defined(MODE_AGNSOTIC_FXPKGIO_NOT_IN_SHARED_FOLDER) + +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V1_7 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + +} WDF_IO_QUEUE_CONFIG_V1_7, *PWDF_IO_QUEUE_CONFIG_V1_7; + +// + +// +// +// +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA, *PWDF_QUEUE_FATAL_ERROR_DATA; + +// + +#endif //MODE_AGNSOTIC_FXPKGIO_NOT_IN_SHARED_FOLDER*/ + +#endif //_IOPRIV_H_ diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/io/km/fxioqueuekm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/io/km/fxioqueuekm.cpp new file mode 100644 index 00000000000..514eaac3355 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/io/km/fxioqueuekm.cpp @@ -0,0 +1,573 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "..\ioprivshared.hpp" + + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoQueueKm.tmh" +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::QueueForwardProgressIrpLocked( + __in PIRP Irp + ) +{ + InsertTailList(&m_FwdProgContext->m_PendedIrpList, + &Irp->Tail.Overlay.ListEntry); + + Irp->Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY] = + m_FwdProgContext; + + IoSetCancelRoutine(Irp, _WdmCancelRoutineForReservedIrp); + + if (Irp->Cancel) { + if (IoSetCancelRoutine(Irp, NULL) != NULL){ + + Irp->Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY] = NULL; + + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + InitializeListHead(&Irp->Tail.Overlay.ListEntry); + + return STATUS_CANCELLED; + } + else { + // + // CancelRoutine will complete the IRP + // + DO_NOTHING(); + } + } + + IoMarkIrpPending(Irp); + + return STATUS_PENDING; +} + + +_Must_inspect_result_ +PIRP +FxIoQueue::GetForwardProgressIrpLocked( + __in_opt PFILE_OBJECT FileObject + ) +/*++ + + Routine Description: + Remove an IRP from the pending irp list if it matches with the input + fileobject. If the fileobject value is NULL, return the first one from + the pending list. + +--*/ +{ + PIRP pIrp; + PLIST_ENTRY thisEntry, nextEntry, listHead; + PIO_STACK_LOCATION pIrpStack; + + pIrp = NULL; + listHead = &m_FwdProgContext->m_PendedIrpList; + + for(thisEntry = listHead->Flink; + thisEntry != listHead; + thisEntry = nextEntry) { + nextEntry = thisEntry->Flink; + + pIrp = CONTAINING_RECORD(thisEntry, IRP, Tail.Overlay.ListEntry); + pIrpStack = IoGetCurrentIrpStackLocation(pIrp); + + if (FileObject == NULL || FileObject == pIrpStack->FileObject) { + + RemoveEntryList(thisEntry); + InitializeListHead(thisEntry); + + if (NULL != IoSetCancelRoutine (pIrp, NULL)) { + pIrp->Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY] = NULL; + break; + } + else { + // + // Irp is canceled and the cancel routines is waiting to run. + // Continue to get the next the irp in the list. + // + DO_NOTHING(); + } + } + + pIrp = NULL; + } + + return pIrp; +} + +VOID +FxIoQueue::FreeAllReservedRequests( + __in BOOLEAN Verify + ) +/*++ + +Routine Description: + Called from dispose to Free all the reserved requests. + + Verify - + TRUE - Make sure the number of request freed matches with the count of + request created. + FALSE - Called when we fail to allocate all the reserved requests + during config at init time. So we don't verify because the + count of request freed wouldn't match with the configured value. +--*/ +{ + ULONG count; + KIRQL oldIrql; + + count = 0; + + // + // Since forward progress request are allocated only for top level + // queues which cant be deleted so we dont need to add a reference on the + // queue for each reserved request since the Queue is guaranteed to be + // around when the request is being freed even if the Request was forwarded + // to another Queue. + // + m_FwdProgContext->m_PendedReserveLock.Acquire(&oldIrql); + + while (!IsListEmpty(&m_FwdProgContext->m_ReservedRequestList)) { + PLIST_ENTRY pEntry; + FxRequest * pRequest; + + pEntry = RemoveHeadList(&m_FwdProgContext->m_ReservedRequestList); + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryForwardProgress, + pEntry); + pRequest->FreeRequest(); + + count++; + } + + if (Verify) { + ASSERT(count == m_FwdProgContext->m_NumberOfReservedRequests); + } + + ASSERT(IsListEmpty(&m_FwdProgContext->m_ReservedRequestInUseList)); + ASSERT(IsListEmpty(&m_FwdProgContext->m_PendedIrpList)); + + m_FwdProgContext->m_PendedReserveLock.Release(oldIrql); + + return; +} + +VOID +FxIoQueue::ReturnReservedRequest( + __in FxRequest *ReservedRequest + ) +/*++ + +Routine Description: + Reuse the ReservedRequest if there are pended IRPs otherwise + add it back to the reserve list. + +--*/ +{ + KIRQL oldIrql; + PIRP pIrp; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + pIrp= NULL; + + ASSERT(ReservedRequest->GetRefCnt() == 1); + + if (pFxDriverGlobals->FxVerifierOn) { + ReservedRequest->ClearVerifierFlags( + FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP); + } + + // + // Reuse the reserved request for dispatching the next pending IRP. + // + m_FwdProgContext->m_PendedReserveLock.Acquire(&oldIrql); + + pIrp = GetForwardProgressIrpLocked(NULL); + + m_FwdProgContext->m_PendedReserveLock.Release(oldIrql); + + ReservedRequest->ClearFieldsForReuse(); + + if (pIrp != NULL) { + // + // Associate the reserved request with the Pended IRP + // + ReservedRequest->m_Irp.SetIrp(pIrp); + ReservedRequest->AssignMemoryBuffers(m_Device->GetIoType()); + + if (pFxDriverGlobals->FxVerifierOn) { + ReservedRequest->SetVerifierFlags( + FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP); + } + + // + // Ignore the return status because QueueRequest will complete the + // request on it own if it fails to queue request. + // + (VOID) QueueRequest(ReservedRequest); + } + else { + PutBackReservedRequest(ReservedRequest); + } +} + +VOID +FxIoQueue::GetForwardProgressIrps( + __in PLIST_ENTRY IrpListHead, + __in_opt MdFileObject FileObject + ) +/*++ + +Routine Description: + + This function is called to retrieve the list of reserved queued IRPs. + The IRP's Tail.Overlay.ListEntry field is used to link these structs together. + +--*/ +{ + PIRP irp; + KIRQL irql; + + m_FwdProgContext->m_PendedReserveLock.Acquire(&irql); + + do { + irp = GetForwardProgressIrpLocked(FileObject); + if (irp != NULL) { + // + // Add it to the cleanupList. We will complete the IRP after + // releasing the lock. + // + InsertTailList(IrpListHead, &irp->Tail.Overlay.ListEntry); + } + } while (irp != NULL); + + m_FwdProgContext->m_PendedReserveLock.Release(irql); +} + +VOID +FxIoQueue::_WdmCancelRoutineForReservedIrp( + __inout struct _DEVICE_OBJECT * DeviceObject, + __in __drv_useCancelIRQL PIRP Irp + ) +/*++ + +Routine Description: + + Cancel routine for forward progress irp. + +--*/ +{ + KIRQL irql; + PFXIO_FORWARD_PROGRESS_CONTEXT m_FwdPrgContext; + + UNREFERENCED_PARAMETER (DeviceObject); + + IoReleaseCancelSpinLock(Irp->CancelIrql); + + m_FwdPrgContext = (PFXIO_FORWARD_PROGRESS_CONTEXT) + Irp->Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY]; + + Irp->Tail.Overlay.DriverContext[FX_IRP_QUEUE_CSQ_CONTEXT_ENTRY] = NULL; + + m_FwdPrgContext->m_PendedReserveLock.Acquire(&irql); + + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); + InitializeListHead(&Irp->Tail.Overlay.ListEntry); + + m_FwdPrgContext->m_PendedReserveLock.Release(irql); + + Irp->IoStatus.Status = STATUS_CANCELLED; + Irp->IoStatus.Information = 0; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return; +} + +VOID +FxIoQueue::FlushQueuedDpcs( + VOID + ) +/*++ + +Routine Description: + + This is the kernel mode routine to flush queued DPCs. + +Arguments: + +Return Value: + +--*/ +{ + KeFlushQueuedDpcs(); +} + + +VOID +FxIoQueue::InsertQueueDpc( + VOID + ) +/*++ + +Routine Description: + + This is the kernel mode routine to insert a dpc. + +Arguments: + +Return Value: + +--*/ +{ + KeInsertQueueDpc(&m_Dpc, NULL, NULL); +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::GetReservedRequest( + __in MdIrp Irp, + __deref_out_opt FxRequest **ReservedRequest + ) +/*++ + +Routine Description: + Use the policy configured on the queue to decide whether to allocate a + reserved request. + +--*/ +{ + WDF_IO_FORWARD_PROGRESS_ACTION action; + FxRequest *pRequest; + KIRQL oldIrql; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + *ReservedRequest = NULL; + action = WdfIoForwardProgressActionInvalid; + + switch (m_FwdProgContext->m_Policy) { + + case WdfIoForwardProgressReservedPolicyPagingIO: + if (IsPagingIo(Irp)) { + action = WdfIoForwardProgressActionUseReservedRequest; + } + else { + action = WdfIoForwardProgressActionFailRequest; + } + + break; + case WdfIoForwardProgressReservedPolicyAlwaysUseReservedRequest: + + action = WdfIoForwardProgressActionUseReservedRequest; + break; + + case WdfIoForwardProgressReservedPolicyUseExamine: + + // + // Call the driver to figure out what action to take. + // + if (m_FwdProgContext->m_IoExamineIrp.Method != NULL) { + + action = m_FwdProgContext->m_IoExamineIrp.Invoke(GetHandle(), Irp); + + // + // Make sure the use has returned a valid action + // + if((action < WdfIoForwardProgressActionFailRequest || + action > WdfIoForwardProgressActionUseReservedRequest)) { + + status = STATUS_UNSUCCESSFUL; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "EvtIoExamineIrp callback on WDFQUEUE %p returned an " + "invalid action %d, %!STATUS!", + GetHandle(), action, status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return status; + } + + } + break; + + default: + ASSERTMSG("Invalid forward progress setting ", FALSE); + break; + } + + if (action == WdfIoForwardProgressActionFailRequest) { + status = STATUS_UNSUCCESSFUL; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Forward action on WDFQUEUE %p says that framework should fail " + "the Irp %p, %!STATUS!", + GetHandle(), Irp, status); + + return status; + } + + pRequest = NULL; + + m_FwdProgContext->m_PendedReserveLock.Acquire(&oldIrql); + + if (!IsListEmpty(&m_FwdProgContext->m_ReservedRequestList)) { + PLIST_ENTRY pEntry; + + pEntry = RemoveHeadList(&m_FwdProgContext->m_ReservedRequestList); + + pRequest = FxRequest::_FromOwnerListEntry(FxListEntryForwardProgress, + pEntry); + ASSERT(pRequest != NULL); + ASSERT(pRequest->GetRefCnt() == 1); + + InsertTailList(&m_FwdProgContext->m_ReservedRequestInUseList, + pRequest->GetListEntry(FxListEntryForwardProgress)); + + pRequest->m_Irp.SetIrp(Irp); + pRequest->AssignMemoryBuffers(m_Device->GetIoType()); + + if (pFxDriverGlobals->FxVerifierOn) { + pRequest->SetVerifierFlags(FXREQUEST_FLAG_RESERVED_REQUEST_ASSOCIATED_WITH_IRP); + } + + // + // if *ReservedRequest is non-null the caller needs to free the + // previous request it allocated. + // + *ReservedRequest = pRequest; + + status = STATUS_SUCCESS; + } + else { + + status = QueueForwardProgressIrpLocked(Irp); + ASSERT(*ReservedRequest == NULL); + } + + m_FwdProgContext->m_PendedReserveLock.Release(oldIrql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoQueue::AssignForwardProgressPolicy( + __in PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY Policy + ) +/*++ + +Routine Description: + Configure the queue for forward Progress. + +--*/ +{ + NTSTATUS status; + FxRequest *pRequest; + ULONG index; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + // + // If the queue is not a top level queue then return an error + // + status = STATUS_SUCCESS; + + // + // From v1.11 any queue can be top level (see WdfDeviceWdmDispatchIrpToIoQueue API). + // + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1, 11) == FALSE) { + if (m_PkgIo->IsTopLevelQueue(this) == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Setting Forward progress policy on non-top level queue %!STATUS!", + status); + + return status; + } + } + + m_FwdProgContext = (PFXIO_FORWARD_PROGRESS_CONTEXT) + FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + sizeof(FXIO_FORWARD_PROGRESS_CONTEXT) + ); + if (m_FwdProgContext == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not allocate memory for forward progress context %!STATUS!", + status); + + return status; + } + + RtlZeroMemory(m_FwdProgContext, sizeof(FXIO_FORWARD_PROGRESS_CONTEXT)); + + // + // Initialize the things which will not fail first + // + m_FwdProgContext->m_Policy = Policy->ForwardProgressReservedPolicy; + + m_FwdProgContext->m_NumberOfReservedRequests = + Policy->TotalForwardProgressRequests; + + m_FwdProgContext->m_IoReservedResourcesAllocate.Method = + Policy->EvtIoAllocateResourcesForReservedRequest; + + m_FwdProgContext->m_IoResourcesAllocate.Method = + Policy->EvtIoAllocateRequestResources; + + m_FwdProgContext->m_IoExamineIrp.Method = + Policy->ForwardProgressReservePolicySettings.Policy.\ + ExaminePolicy.EvtIoWdmIrpForForwardProgress; + + InitializeListHead(&m_FwdProgContext->m_ReservedRequestList); + InitializeListHead(&m_FwdProgContext->m_ReservedRequestInUseList); + InitializeListHead(&m_FwdProgContext->m_PendedIrpList); + + m_FwdProgContext->m_PendedReserveLock.Initialize(); + + for (index = 0; + index < m_FwdProgContext->m_NumberOfReservedRequests; + index++) + { + status = AllocateReservedRequest(&pRequest); + if (!NT_SUCCESS(status)) { + break; + } + + InsertTailList(&m_FwdProgContext->m_ReservedRequestList, + pRequest->GetListEntry(FxListEntryForwardProgress)); + } + + // + // Since we allow forward progress policy to be set even after AddDevice + // when the queue has already started dispatching, we need to make + // sure all checks which determine whether the queue is configured for + // forward progress succeed. Setting Forward progress on the queue as the + // last operation helps with that. + // + if (NT_SUCCESS(status)) { + m_SupportForwardProgress = TRUE; + } + else { + FreeAllReservedRequests(FALSE); + + m_FwdProgContext->m_PendedReserveLock.Uninitialize(); + + FxPoolFree(m_FwdProgContext); + m_FwdProgContext = NULL; + } + + return status; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/irphandlerspriv.hpp b/sdk/lib/drivers/wdf/shared/irphandlers/irphandlerspriv.hpp new file mode 100644 index 00000000000..cc43545aaaa --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/irphandlerspriv.hpp @@ -0,0 +1,38 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + irphandlerspriv.hpp + +Abstract: + + Private header for irphandlers. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +extern "C" { +#include "mx.h" +} + +#include "FxMin.hpp" + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "wdmdefs.h" +#include "FxIrpUm.hpp" +#else +#include "FxIrpKm.hpp" +#endif + +#include "FxIrp.hpp" diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/package/fxpackage.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/package/fxpackage.cpp new file mode 100644 index 00000000000..341be94a690 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/package/fxpackage.cpp @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + package.cpp + +Abstract: + + This module implements the base package class. Other packages will + derive from this base class. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + + +#include "irphandlerspriv.hpp" + +#include "FxPackage.hpp" + +FxPackage::FxPackage( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device, + __in WDFTYPE Type + ) : + // By passing 0, we are indicating we are an internal object which will not + // represented as a WDFHANDLE + FxNonPagedObject(Type, 0, FxDriverGlobals) +{ + m_Device = Device; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/devicepwrreqstatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/devicepwrreqstatemachine.cpp new file mode 100644 index 00000000000..5ce51db4daf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/devicepwrreqstatemachine.cpp @@ -0,0 +1,430 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + DevicePwrReq.cpp + +Abstract: + + This module implements the device power requirement logic in the framework. + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "DevicePwrReqStateMachine.tmh" +#endif +} + +const FxDevicePwrRequirementTargetState +FxDevicePwrRequirementMachine::m_UnregisteredStates[] = +{ + {DprEventRegisteredWithPox, DprDevicePowerRequiredD0 DEBUGGED_EVENT} +}; + +const FxDevicePwrRequirementTargetState +FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States[] = +{ + {DprEventPoxDoesNotRequirePower, DprDevicePowerNotRequiredD0 DEBUGGED_EVENT}, + {DprEventUnregisteredWithPox, DprUnregistered DEBUGGED_EVENT}, + {DprEventDeviceReturnedToD0, DprDevicePowerRequiredD0 DEBUGGED_EVENT} +}; + +const FxDevicePwrRequirementTargetState +FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States[] = +{ + {DprEventDeviceGoingToDx, DprDevicePowerNotRequiredDx DEBUGGED_EVENT}, + {DprEventPoxRequiresPower, DprReportingDevicePowerAvailable DEBUGGED_EVENT}, + {DprEventUnregisteredWithPox, DprUnregistered TRAP_ON_EVENT} +}; + +const FxDevicePwrRequirementTargetState +FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates[] = +{ + {DprEventDeviceReturnedToD0, DprWaitingForDevicePowerRequiredD0 DEBUGGED_EVENT}, + {DprEventPoxRequiresPower, DprDevicePowerRequiredDx DEBUGGED_EVENT} +}; + +const FxDevicePwrRequirementTargetState +FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates[] = +{ + {DprEventDeviceReturnedToD0, DprReportingDevicePowerAvailable DEBUGGED_EVENT} +}; + +const FxDevicePwrRequirementTargetState +FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States[] = +{ + {DprEventPoxRequiresPower, DprReportingDevicePowerAvailable DEBUGGED_EVENT}, + {DprEventDeviceReturnedToD0, DprWaitingForDevicePowerRequiredD0 TRAP_ON_EVENT}, + {DprEventUnregisteredWithPox, DprUnregistered DEBUGGED_EVENT}, +}; + +const FxDevicePwrRequirementStateTable +FxDevicePwrRequirementMachine::m_StateTable[] = +{ + // DprUnregistered + { NULL, + FxDevicePwrRequirementMachine::m_UnregisteredStates, + ARRAY_SIZE(FxDevicePwrRequirementMachine::m_UnregisteredStates), + }, + + // DprDevicePowerRequiredD0 + { NULL, + FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States, + ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerRequiredD0States), + }, + + // DprDevicePowerNotRequiredD0 + { FxDevicePwrRequirementMachine::PowerNotRequiredD0, + FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States, + ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredD0States), + }, + + // DprDevicePowerNotRequiredDx + { NULL, + FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates, + ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerNotRequiredDxStates), + }, + + // DprDevicePowerRequiredDx + { FxDevicePwrRequirementMachine::PowerRequiredDx, + FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates, + ARRAY_SIZE(FxDevicePwrRequirementMachine::m_DevicePowerRequiredDxStates), + }, + + // DprReportingDevicePowerAvailable + { FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable, + NULL, + 0, + }, + + // DprWaitingForDevicePowerRequiredD0 + { NULL, + FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States, + ARRAY_SIZE(FxDevicePwrRequirementMachine::m_WaitingForDevicePowerRequiredD0States), + }, +}; + +FxDevicePwrRequirementMachine::FxDevicePwrRequirementMachine( + __in FxPoxInterface * PoxInterface + ) : FxThreadedEventQueue(FxDevicePwrRequirementEventQueueDepth) +{ + // + // Make sure we can fit the state into a byte + // + C_ASSERT(DprMax <= 0xFF); + + m_CurrentState = DprUnregistered; + + RtlZeroMemory(&m_Queue, sizeof(m_Queue)); + RtlZeroMemory(&m_States, sizeof(m_States)); + + // + // Store the initial state in the state history array + // + m_States.History[IncrementHistoryIndex()] = m_CurrentState; + m_PoxInterface = PoxInterface; +} + +VOID +FxDevicePwrRequirementMachine::ProcessEvent( + __in FxDevicePwrRequirementEvents Event + ) +{ + NTSTATUS status; + KIRQL irql; + LONGLONG timeout = 0; + + // + // Acquire state machine *queue* lock, raising to DISPATCH_LEVEL + // + Lock(&irql); + + if (IsFull()) { + // + // The queue is full. This should never happen. + // + Unlock(irql); + + ASSERTMSG("The device power requirement state machine queue is full\n", + FALSE); + return; + } + + if (IsClosedLocked()) { + // + // The queue is closed. This should never happen. + // + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current device power requirement state" + " %!FxDevicePwrRequirementStates! dropping event " + "%!FxDevicePwrRequirementEvents! because of a closed queue", + m_PoxInterface->m_PkgPnp->GetDevice()->GetHandle(), + m_PoxInterface->m_PkgPnp->GetDevice()->GetDeviceObject(), + m_CurrentState, + Event); + + Unlock(irql); + + ASSERTMSG( + "The device power requirement state machine queue is closed\n", + FALSE + ); + return; + } + + // + // Enqueue the event + // + m_Queue[InsertAtTail()] = Event; + + // + // Drop the state machine *queue* lock + // + Unlock(irql); + + // + // Now, if we are running at PASSIVE_LEVEL, attempt to run the state machine + // on this thread. If we can't do that, then queue a work item. + // + if (irql == PASSIVE_LEVEL) { + // + // Try to acquire the state machine lock + // + status = m_StateMachineLock.AcquireLock( + m_PoxInterface->m_PkgPnp->GetDriverGlobals(), + &timeout + ); + if (FxWaitLockInternal::IsLockAcquired(status)) { + FxPostProcessInfo info; + + // + // We now hold the state machine lock. So call the function that + // dispatches the next state. + // + ProcessEventInner(&info); + + // + // The pnp state machine should be the only one deleting the object + // + ASSERT(info.m_DeleteObject == FALSE); + + // + // Release the state machine lock + // + m_StateMachineLock.ReleaseLock( + m_PoxInterface->m_PkgPnp->GetDriverGlobals() + ); + + info.Evaluate(m_PkgPnp); + + return; + } + } + + // + // For one reason or another, we couldn't run the state machine on this + // thread. So queue a work item to do it. + // + QueueToThread(); + return; +} + +VOID +FxDevicePwrRequirementMachine::_ProcessEventInner( + __inout FxPkgPnp* PkgPnp, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ) +{ + FxDevicePwrRequirementMachine * pThis = NULL; + + UNREFERENCED_PARAMETER(WorkerContext); + + pThis = PkgPnp->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.m_DevicePowerRequirementMachine; + + // + // Take the state machine lock. + // + pThis->m_StateMachineLock.AcquireLock( + pThis->m_PoxInterface->m_PkgPnp->GetDriverGlobals() + ); + + // + // Call the function that will actually run the state machine. + // + pThis->ProcessEventInner(Info); + + // + // We are being called from the work item and m_WorkItemRunning is > 0, so + // we cannot be deleted yet. + // + ASSERT(Info->SomethingToDo() == FALSE); + + // + // Now release the state machine lock + // + pThis->m_StateMachineLock.ReleaseLock( + pThis->m_PoxInterface->m_PkgPnp->GetDriverGlobals() + ); + + return; +} + +VOID +FxDevicePwrRequirementMachine::ProcessEventInner( + __inout FxPostProcessInfo* Info + ) +{ + KIRQL irql; + FxDevicePwrRequirementEvents event; + const FxDevicePwrRequirementStateTable* entry; + FxDevicePwrRequirementStates newState; + + // + // Process as many events as we can + // + for ( ; ; ) { + // + // Acquire state machine *queue* lock + // + Lock(&irql); + + if (IsEmpty()) { + // + // The queue is empty. + // + GetFinishedState(Info); + Unlock(irql); + return; + } + + // + // Get the event from the queue + // + event = m_Queue[GetHead()]; + IncrementHead(); + + // + // Drop the state machine *queue* lock + // + Unlock(irql); + + // + // Get the state table entry for the current state + // + // NOTE: Prefast complains about buffer overflow if (m_CurrentState == + // DprMax), but that should never happen because DprMax is not a real + // state. We just use it to represent the maximum value in the enum that + // defines the states. + // + __analysis_assume(m_CurrentState < DprMax); + entry = &m_StateTable[m_CurrentState - DprUnregistered]; + + // + // Based on the event received, figure out the next state + // + newState = DprMax; + for (ULONG i = 0; i < entry->TargetStatesCount; i++) { + if (entry->TargetStates[i].DprEvent == event) { + DO_EVENT_TRAP(&entry->TargetStates[i]); + newState = entry->TargetStates[i].DprState; + break; + } + } + + if (newState == DprMax) { + // + // Unexpected event for this state + // + DoTraceLevelMessage( + m_PoxInterface->PkgPnp()->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p device power requirement state " + "%!FxDevicePwrRequirementStates! dropping event " + "%!FxDevicePwrRequirementEvents!", + m_PoxInterface->PkgPnp()->GetDevice()->GetHandle(), + m_PoxInterface->PkgPnp()->GetDevice()->GetDeviceObject(), + m_CurrentState, + event + ); + + COVERAGE_TRAP(); + } + + while (newState != DprMax) { + DoTraceLevelMessage( + m_PoxInterface->PkgPnp()->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, + TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering device power requirement " + "state %!FxDevicePwrRequirementStates! from " + "%!FxDevicePwrRequirementStates!", + m_PoxInterface->PkgPnp()->GetDevice()->GetHandle(), + m_PoxInterface->PkgPnp()->GetDevice()->GetDeviceObject(), + newState, + m_CurrentState + ); + + // + // Update the state history array + // + m_States.History[IncrementHistoryIndex()] = (UCHAR) newState; + + // + // Move to the new state + // + m_CurrentState = (BYTE) newState; + entry = &m_StateTable[m_CurrentState-DprUnregistered]; + + // + // Invoke the state entry function (if present) for the new state + // + if (entry->StateFunc != NULL) { + newState = entry->StateFunc(this); + } + else { + newState = DprMax; + } + } + } + + return; +} + +FxDevicePwrRequirementStates +FxDevicePwrRequirementMachine::PowerNotRequiredD0( + __in FxDevicePwrRequirementMachine* This + ) +{ + This->m_PoxInterface->PkgPnp()->PowerPolicyProcessEvent( + PwrPolDevicePowerNotRequired + ); + return DprMax; +} + +FxDevicePwrRequirementStates +FxDevicePwrRequirementMachine::PowerRequiredDx( + __in FxDevicePwrRequirementMachine* This + ) +{ + This->m_PoxInterface->PkgPnp()->PowerPolicyProcessEvent( + PwrPolDevicePowerRequired + ); + return DprMax; +} + +FxDevicePwrRequirementStates +FxDevicePwrRequirementMachine::ReportingDevicePowerAvailable( + __in FxDevicePwrRequirementMachine* This + ) +{ + This->m_PoxInterface->PoxReportDevicePoweredOn(); + return DprDevicePowerRequiredD0; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/eventqueue.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/eventqueue.cpp new file mode 100644 index 00000000000..e437fb38985 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/eventqueue.cpp @@ -0,0 +1,438 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + EventQueue.cpp + +Abstract: + + This module implements a baseline event queue structure which takes care of + 90% of the work requireed to run a state machine + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "EventQueue.tmh" +#endif +} + +FxEventQueue::FxEventQueue( + __in UCHAR QueueDepth + ) +{ + m_PkgPnp = NULL; + m_EventWorker = NULL; + + m_HistoryIndex = 0; + m_QueueHead = 0; + m_QueueTail = 0; + m_QueueDepth = QueueDepth; + + m_WorkItemFinished = NULL; + m_QueueFlags = 0x0; + m_WorkItemRunningCount = 0x0; +} + +_Must_inspect_result_ +NTSTATUS +FxEventQueue::Initialize( + __in PFX_DRIVER_GLOBALS DriverGlobals + ) +{ + NTSTATUS status; + + // + // For KM, lock initialize always succeeds. For UM, it might fail. + // + status = m_StateMachineLock.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, + TRACE_LEVEL_ERROR, TRACINGPNP, + "Initializing state machine lock failed for EventQueue 0x%p, " + "status %!STATUS!", + this, status); + } + + return status; +} + +VOID +FxEventQueue::Configure( + __in FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine, + __in PVOID Context + ) +{ + m_PkgPnp = Pnp; + m_EventWorker = WorkerRoutine; + m_EventWorkerContext = Context; + + return; +} + +BOOLEAN +FxEventQueue::SetFinished( + __in FxCREvent* Event + ) +/*++ + +Routine Description: + Puts the queue into a closed state. If the queue cannot be closed and + finished in this context, the Event is stored and set when it moves into + the finished state + +Arguments: + Event - the event to set when we move into the finished state + +Return Value: + TRUE if the queue is closed in this context, FALSE if the Event should be + waited on. + + --*/ +{ + KIRQL irql; + BOOLEAN result; + + result = TRUE; + + Lock(&irql); + ASSERT((m_QueueFlags & FxEventQueueFlagClosed) == 0x0); + m_QueueFlags |= FxEventQueueFlagClosed; + + result = IsIdleLocked(); + + if (result == FALSE) { + m_WorkItemFinished = Event; + } + + Unlock(irql); + + if (result) { + Event->Set(); + } + + return result; +} + +VOID +FxEventQueue::SetDelayedDeletion( + VOID + ) +{ + KIRQL irql; + + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p delaying deletion to outside state machine", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject()); + + Lock(&irql); + ASSERT((m_QueueFlags & FxEventQueueFlagDelayDeletion) == 0x0); + m_QueueFlags |= FxEventQueueFlagDelayDeletion; + Unlock(irql); +} + +BOOLEAN +FxEventQueue::QueueToThreadWorker( + VOID + ) +/*++ + +Routine Description: + Generic worker function which encapsulates the logic of whether to enqueue + onto a different thread if the thread has not already been queued to. + + NOTE: this function could have been virtual, or call a virtual worker function + once we have determined that we need to queue to a thread. But to save + space on vtable storage (why have one unless you really need one?), + we rearrange the code so that the derived class calls the worker function + and this function indicates in its return value what the caller should + do + +Arguments: + None + +Return Value: + TRUE if the caller should queue to a thread to do the work + FALSE if the caller shoudl not queue to a thread b/c it has already been + queued + + --*/ +{ + KIRQL irql; + BOOLEAN result; + + Lock(&irql); + + // + // For one reason or another, we couldn't run the state machine on this + // thread. So queue a work item to do it. + // + if (IsEmpty()) { + // + // There is no work to do. This means that the caller inserted the + // event into the queue, dropped the lock, and then another thread came + // in and processed the event. + // + // This check also helps in the rundown case when the queue is closing + // and the following happens between 2 thread: + // #1 #2 + // insert event + // drop lock + // process event queue + // queue goes to empty, so event is set + // try to queue work item + // + result = FALSE; + + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p not queueing work item to process " + "event queue", m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject()); + } + else if ((m_QueueFlags & FxEventQueueFlagWorkItemQueued) == 0x00) { + m_QueueFlags |= FxEventQueueFlagWorkItemQueued; + result = TRUE; + } + else { + // + // Somebody is already in the process of enqueuing the work item. + // + result = FALSE; + } + + Unlock(irql); + + return result; +} + +VOID +FxEventQueue::EventQueueWorker( + VOID + ) +/*++ + +Routine Description: + This is the work item that attempts to run the queue state machine on + the special power thread. + + +--*/ +{ + FxPostProcessInfo info; + KIRQL irql; + FxPkgPnp* pPkgPnp; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + FX_TRACK_DRIVER(m_PkgPnp->GetDriverGlobals()); +#endif + + // + // Cache away m_PkgPnp while we know we still have a valid object. Once + // we Unlock() after the worker routine, the object could be gone until + // the worker routine set a flag postponing deletion. + // + pPkgPnp = m_PkgPnp; + + Lock(&irql); + + ASSERT(m_QueueFlags & FxEventQueueFlagWorkItemQueued); + + // + // Clear the queued flag, so that it's clear that the work item can + // be safely re-enqueued. + // + m_QueueFlags &= ~FxEventQueueFlagWorkItemQueued; + + // + // We should only see this count rise to a small number (like 10 or so). + // + ASSERT(m_WorkItemRunningCount < 0xFF); + m_WorkItemRunningCount++; + + Unlock(irql); + + // + // Call the function that will actually run the state machine. + // + m_EventWorker(m_PkgPnp, &info, m_EventWorkerContext); + + Lock(&irql); + m_WorkItemRunningCount--; + GetFinishedState(&info); + Unlock(irql); + + // + // NOTE: There is no need to use a reference count to keep this event queue + // (and the containing state machine) alive. Instead, the thread + // which wants to delete the state machine must wait for this work + // item to exit. If there was a reference to release, we would have + // a race between Unlock()ing and releasing the reference if the state + // machine moved into the finished state and deletes the device after + // we dropped the lock, but before we released the reference. + // + // This is important in that the device deletion can trigger + // DriverUnload to run before the release executes. DriverUnload + // frees the IFR buffer. If this potential release logs something to + // the IFR, you would bugcheck. Since it is impossible to defensively + // prevent all destructors from logging to the IFR, we can't use a + // ref count here to keep the queue alive. + // + + // + // If Evaluate needs to use pPkgPnp, then the call to the worker routine + // above made sure that pPkgPnp has not yet been freed. + // + info.Evaluate(pPkgPnp); +} + +FxWorkItemEventQueue::FxWorkItemEventQueue( + __in UCHAR QueueDepth + ) : FxEventQueue(QueueDepth) +{ +} + +FxWorkItemEventQueue::~FxWorkItemEventQueue() +{ + m_WorkItem.Free(); +} + +_Must_inspect_result_ +NTSTATUS +FxWorkItemEventQueue::Init( + __inout FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine, + __in PVOID WorkerContext + ) +{ + NTSTATUS status; + + Configure(Pnp, WorkerRoutine, WorkerContext); + + + + + + + + + + + + status = m_WorkItem.Allocate( + (MdDeviceObject)(GetIoMgrObjectForWorkItemAllocation()) + ); + + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} + +FxThreadedEventQueue::FxThreadedEventQueue( + __in UCHAR QueueDepth + ) : FxEventQueue(QueueDepth) +{ + ExInitializeWorkItem(&m_EventWorkQueueItem, + (PWORKER_THREAD_ROUTINE) _WorkerThreadRoutine, + this); +} + +FxThreadedEventQueue::~FxThreadedEventQueue( + VOID + ) +{ + m_WorkItem.Free(); +} + +_Must_inspect_result_ +NTSTATUS +FxThreadedEventQueue::Init( + __inout FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine, + __in PVOID WorkerContext + ) +{ + NTSTATUS status; + + Configure(Pnp, WorkerRoutine, WorkerContext); + + + status = m_WorkItem.Allocate(Pnp->GetDevice()->GetDeviceObject()); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} + +VOID +FxThreadedEventQueue::_WorkerThreadRoutine( + __in PVOID Context + ) +{ + FxThreadedEventQueue* This = (FxThreadedEventQueue *)Context; + + This->EventQueueWorker(); +} + +VOID +FxThreadedEventQueue::QueueWorkItem( + VOID + ) +{ + if (m_PkgPnp->HasPowerThread()) { + // + // Use the power thread for the stack + // + m_PkgPnp->QueueToPowerThread(&m_EventWorkQueueItem); + } + else { + // + // Use the work item since the power thread is not available + // + m_WorkItem.Enqueue(_WorkItemCallback, + (FxEventQueue*) this); + } +} + +VOID +FxThreadedEventQueue::_WorkItemCallback( + __in MdDeviceObject DeviceObject, + __in PVOID Context + ) +/*++ + +Routine Description: + This is the work item that attempts to run the machine on a thread + separate from the one the caller was using. + +--*/ +{ + FxThreadedEventQueue* This = (FxThreadedEventQueue *)Context; + + UNREFERENCED_PARAMETER(DeviceObject); + + This->EventQueueWorker(); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fdopower.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fdopower.cpp new file mode 100644 index 00000000000..93420bef7ba --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fdopower.cpp @@ -0,0 +1,586 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FdoPower.cpp + +Abstract: + + This module implements the pnp/power package for the driver + framework. This, specifically, is the power code. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + +--*/ + +#include "pnppriv.hpp" + + + + +#if defined(EVENT_TRACING) +extern "C" { +#include "FdoPower.tmh" +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PowerPassDown( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked when a Power Irp we don't handle comes into the + driver. + +Arguemnts: + + This - the package + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + FxPkgFdo* pThis; + MdDeviceObject pDevObj; + NTSTATUS status; + MdIrp pIrp; + + pIrp = Irp->GetIrp(); + pThis = (FxPkgFdo*) This; + + pDevObj = pThis->m_Device->GetDeviceObject(); + + // + // FDOs don't handle this IRP, so simply pass it down. + // + Irp->StartNextPowerIrp(); + Irp->CopyCurrentIrpStackLocationToNext(); + + status = Irp->PoCallDriver(pThis->m_Device->GetAttachedDevice()); + + Mx::MxReleaseRemoveLock(pThis->m_Device->GetRemoveLock(), + pIrp); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_DispatchSetPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is invoked when a SetPower IRP enters the driver. + +Arguemnts: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + if (Irp->GetParameterPowerType() == SystemPowerState) { + return ((FxPkgFdo*) This)->DispatchSystemSetPower(Irp); + } + else { + return ((FxPkgFdo*) This)->DispatchDeviceSetPower(Irp); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_DispatchQueryPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked when a QueryPower IRP enters the driver. + +Arguemnts: + + This - The package + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + if (Irp->GetParameterPowerType() == SystemPowerState) { + return ((FxPkgFdo*) This)->DispatchSystemQueryPower(Irp); + } + else { + return ((FxPkgFdo*) This)->DispatchDeviceQueryPower(Irp); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_SystemPowerS0Completion( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in PVOID Context + ) +{ + FxPkgPnp* pPkgPnp; + KIRQL irql; + FxIrp irp(OriginalIrp); + + pPkgPnp = (FxPkgPnp*) Context; + + // + // Ideally we would like to complete the S0 irp before we start + // processing the event in the state machine so that the D0 irp + // comes after the S0 is moving up the stack... + // + // ... BUT ... + // + // ... by allowing the S0 irp to go up the stack first, we must then + // handle pnp requests from the current power policy state (because + // the S0 irp could be the last S irp in the system and when completed, + // the pnp lock is released). So, we process the event first so + // that we can move into a state where we can handle pnp events in + // the power policy state machine. + // + // We mitigate the situation a little bit by forcing the processing of the + // event to occur on the power policy thread rather then in the current + // context. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + pPkgPnp->PowerPolicyProcessEvent(PwrPolS0); + Mx::MxLowerIrql(irql); + + irp.StartNextPowerIrp(); + + // + // Let the irp continue on its way + // + if (irp.PendingReturned()) { + irp.MarkIrpPending(); + } + + Mx::MxReleaseRemoveLock((&FxDevice::_GetFxWdmExtension(DeviceObject)->IoRemoveLock), + OriginalIrp); + + return irp.GetStatus(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_SystemPowerSxCompletion( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in PVOID Context + ) +{ + FxPkgFdo *pThis; + FxIrp irp(OriginalIrp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pThis = (FxPkgFdo*) Context; + + ASSERT(pThis->IsPowerPolicyOwner()); + ASSERT(OriginalIrp == pThis->GetPendingSystemPowerIrp()); + + pThis->PowerPolicyProcessEvent(PwrPolSx); + + // + // Power policy will complete the system irp + // + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::DispatchSystemSetPower( + __in FxIrp *Irp + ) +{ + NTSTATUS status; + MxDeviceObject deviceObject(m_Device->GetDeviceObject()); + + m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState(); + deviceObject.SetPowerState(SystemPowerState, + Irp->GetParameterPowerState()); + + if (IsPowerPolicyOwner()) { + // + // If we are going to S0, we just notify the power policy state machine + // and then let the request go (per the fast resume spec). Otherwise, + // send the request down and on the way up, send the Dx request. + // + if (m_SystemPowerState == PowerSystemWorking) { + // + // Post the event into the state machine when the irp is going up + // the stack. See the comment in _SystemPowerS0Completion for more + // detail as to why. + // + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutineEx(deviceObject.GetObject(), + _SystemPowerS0Completion, + this); + + return Irp->PoCallDriver(m_Device->GetAttachedDevice()); + } + else { + // + // Stash away the irp for the power policy state machine. We will + // post the event to the power policy state machine when the S irp + // completes back to this driver. + // + SetPendingSystemPowerIrp(Irp); + + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutineEx(deviceObject.GetObject(), + _SystemPowerSxCompletion, + this); + + Irp->PoCallDriver(m_Device->GetAttachedDevice()); + + status = STATUS_PENDING; + } + } + else { + // + // We don't do anything with S irps if we are not the power policy + // owner. + // + // This will release the remove lock as well. + // + status = _PowerPassDown(this, Irp); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::DispatchDeviceSetPower( + __in FxIrp *Irp + ) + +{ + NTSTATUS status; + + if (IsPowerPolicyOwner()) { + if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE && + m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) { + // + // A power irp arrived, but we did not request it. log and bugcheck + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, " + "but the irp was not requested by the device (the power policy owner)", + Irp->GetIrp(), m_Device->GetHandle(), + m_Device->GetDeviceObject()); + + FxVerifierBugCheck(GetDriverGlobals(), // globals + WDF_POWER_MULTIPLE_PPO, // specific type + (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2 + (ULONG_PTR)Irp->GetIrp()); // parm 3 + + /* NOTREACHED */ + } + + // + // We are no longer requesting a power irp because we received the one + // we requested. + // + if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE; + } else { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE; + } + } + + // + // Determine if we are raising or lowering the device power state. + // + if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) { + status = RaiseDevicePower(Irp); + } + else { + status = LowerDevicePower(Irp); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::RaiseDevicePower( + __in FxIrp *Irp + ) +{ + Irp->MarkIrpPending(); + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), + RaiseDevicePowerCompletion, + this); + + Irp->PoCallDriver(m_Device->GetAttachedDevice()); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::RaiseDevicePowerCompletion( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in PVOID Context + ) +{ + FxPkgFdo* pThis; + FxIrp irp(OriginalIrp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pThis = (FxPkgFdo*) Context; + + // + // We can safely cache away the device power irp in our fdo package + // storage because we know we can only get one device power irp at + // a time. + // + pThis->SetPendingDevicePowerIrp(&irp); + + // + // Kick off the power state machine. + // + pThis->PowerProcessEvent(PowerD0); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::LowerDevicePower( + __in FxIrp *Irp + ) +{ + SetPendingDevicePowerIrp(Irp); + + // + // Kick off the power state machine. + // + PowerProcessEvent(PowerDx); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::DispatchSystemQueryPower( + __in FxIrp *Irp + ) +{ + if (PowerPolicyIsWakeEnabled()) { + NTSTATUS status; + + status = PowerPolicyHandleSystemQueryPower( + Irp->GetParameterPowerStateSystemState() + ); + + Irp->SetStatus(status); + + if (!NT_SUCCESS(status)) { + return CompletePowerRequest(Irp, status); + } + } + + // + // Passing down the irp because one of the following + // a) We don't care b/c we don't control the power policy + // b) we are not enabled for arming for wake from Sx + // c) we can wake from the queried S state + // + return _PowerPassDown(this, Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::DispatchDeviceQueryPower( + __in FxIrp *Irp + ) +{ + // + // Either the framework is the power policy owner and we wouldn't be sending + // a device query power or we are a subordinate will do what the power + // policy owner wants 100% of the time. + // + Irp->SetStatus(STATUS_SUCCESS); + + // + // This will release the remove lock + // + return _PowerPassDown(this, Irp); +} + +VOID +FxPkgFdo::PowerReleasePendingDeviceIrp( + __in BOOLEAN IrpMustBePresent + ) +{ + MdIrp pIrp; + + pIrp = ClearPendingDevicePowerIrp(); + + UNREFERENCED_PARAMETER(IrpMustBePresent); + ASSERT(IrpMustBePresent == FALSE || pIrp != NULL); + + if (pIrp != NULL) { + FxIrp irp(pIrp); + + if (irp.GetParameterPowerStateDeviceState() == PowerDeviceD0) { + // + // We catch D0 irps on the way up, so complete it + // + CompletePowerRequest(&irp, STATUS_SUCCESS); + } + else { + irp.SetStatus(STATUS_SUCCESS); + + // + // We catch Dx irps on the way down, so send it on its way + // + // This will also release the remove lock + // + (void) _PowerPassDown(this, &irp); + } + } +} + +WDF_DEVICE_POWER_STATE +FxPkgFdo::PowerCheckDeviceTypeOverload( + VOID + ) +/*++ + +Routine Description: + This function implements the Check Type state. This is FDO code, + so the answer is reductionistly simple. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + return WdfDevStatePowerWaking; +} + +WDF_DEVICE_POWER_STATE +FxPkgFdo::PowerCheckDeviceTypeNPOverload( + VOID + ) +/*++ + +Routine Description: + This function implements the Check Type state. This is FDO code, + so the answer is reductionistly simple. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + return WdfDevStatePowerWakingNP; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PowerCheckParentOverload( + __out BOOLEAN* ParentOn + ) +/*++ + +Routine Description: + This function implements the CheckParent state. Its + job is to determine which state we should go to next based on whether + the parent is in D0. But since this is the FDO code, we can't know + that. So just assume that the PDO will guarantee it. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + ASSERT(!"This state shouldn't be reachable for an FDO."); + *ParentOn = TRUE; + return STATUS_SUCCESS; +} + +VOID +FxPkgFdo::PowerParentPowerDereference( + VOID + ) +/*++ + +Routine Description: + This virtual function is a nop for an FDO. PDOs implement this function + +Arguments: + None + +Return Value: + None + + --*/ +{ + DO_NOTHING(); +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxinterruptapi.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxinterruptapi.cpp new file mode 100644 index 00000000000..7cade6a0970 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxinterruptapi.cpp @@ -0,0 +1,1385 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxInterruptApi.cpp + +Abstract: + + This implements the WDFINTERRUPT API's + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#include "FxInterruptApi.tmh" +} + +// +// At this time we are unable to include wdf19.h in the share code, thus for +// now we simply cut and paste the needed structures. +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_9 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_9, *PWDF_INTERRUPT_CONFIG_V1_9; + +// +// The interrupt config structure has changed post win8-Beta. This is a +// temporary definition to allow beta drivers to load on post-beta builds. +// Note that size of win8-beta and win8-postbeta structure is different only on +// non-x64 platforms, but the fact that size is same on amd64 is harmless because +// the struture gets zero'out by init macro, and the default value of the new +// field is 0 on amd64. +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_11_BETA { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + +} WDF_INTERRUPT_CONFIG_V1_11_BETA, *PWDF_INTERRUPT_CONFIG_V1_11_BETA; + +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_11 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + + // + // TRUE: Interrupt is reported inactive on explicit power down + // instead of disconnecting it. + // FALSE: Interrupt is disconnected instead of reporting inactive + // on explicit power down. + // DEFAULT: Framework decides the right value. + // + WDF_TRI_STATE ReportInactiveOnPowerDown; + +} WDF_INTERRUPT_CONFIG_V1_11, *PWDF_INTERRUPT_CONFIG_V1_11; + +// +// extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfInterruptCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_INTERRUPT_CONFIG Configuration, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFINTERRUPT* Interrupt + ) + +/*++ + +Routine Description: + + Create an Interrupt object along with its associated DpcForIsr. + +Arguments: + + Object - Handle to a WDFDEVICE or WDFQUEUE to associate the interrupt with. + + pConfiguration - WDF_INTERRUPT_CONFIG structure. + + pAttributes - Optional WDF_OBJECT_ATTRIBUTES to request a context + memory allocation, and a DestroyCallback. + + pInterrupt - Pointer to location to return the resulting WDFINTERRUPT handle. + +Returns: + + STATUS_SUCCESS - A WDFINTERRUPT handle has been created. + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxInterrupt* pFxInterrupt; + FxDevice* pDevice; + FxObject* pParent; + NTSTATUS status; + WDF_DEVICE_PNP_STATE devicePnpState; + ULONG expectedConfigSize; + WDF_INTERRUPT_CONFIG intConfig; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Configuration); + FxPointerNotNull(pFxDriverGlobals, Interrupt); + + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13)) { + expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG); + } else if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG_V1_11); + } else { + expectedConfigSize = sizeof(WDF_INTERRUPT_CONFIG_V1_9); + } + + + // + // We could check if Configuration->Size != expectedConfigSize, but + // logic below allows me to installing old WDF drivers v1.11 on new WDF. + // + if (Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG) && + Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_11) && + Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_11_BETA) && + Configuration->Size != sizeof(WDF_INTERRUPT_CONFIG_V1_9)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDF_INTERRUPT_CONFIG size 0x%x incorrect, expected 0x%x", + Configuration->Size, expectedConfigSize); + + return STATUS_INFO_LENGTH_MISMATCH; + } + + // + // Normalize WDF_INTERRUPT_CONFIG structure. + // + if (Configuration->Size < sizeof(WDF_INTERRUPT_CONFIG)) { + // + // Init new fields to default values. + // + WDF_INTERRUPT_CONFIG_INIT(&intConfig, + Configuration->EvtInterruptIsr, + Configuration->EvtInterruptDpc); + // + // Copy over existing fields and readjust the struct size. + // + RtlCopyMemory(&intConfig, Configuration, Configuration->Size); + intConfig.Size = sizeof(intConfig); + + // + // Use new config structure from now on. + // + Configuration = &intConfig; + } + + // + // Parameter validation. + // + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // Ensure access to interrupts is allowed + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED, + (pDevice->IsInterruptAccessAllowed() == TRUE)), + DriverGlobals->DriverName); + + // + // PassiveHandling member must be set to TRUE. INIT macro does that for + // UMDF. This check ensures the field is not overriden by caller. + // + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("PassiveHandling not set to TRUE in WDF_INTERRUPT_CONFIG structure", + (Configuration->PassiveHandling == TRUE)), + DriverGlobals->DriverName); +#endif + + if (Configuration->EvtInterruptIsr == NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "NULL EvtInterruptIsr in WDF_INTERRUPT_CONFIG structure 0x%p" + " passed", Configuration); + return STATUS_INVALID_PARAMETER; + } + + // + // Driver can specify a parent only in the AutomaticSerialization case. + // + status = FxValidateObjectAttributes( + pFxDriverGlobals, + Attributes, + Configuration->AutomaticSerialization ? + FX_VALIDATE_OPTION_NONE_SPECIFIED : + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Attributes != NULL && Attributes->ParentObject != NULL) { + FxObjectHandleGetPtr(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent); + } + else { + pParent = (FxObject*)pDevice; + } + + devicePnpState = pDevice->GetDevicePnpState(); + + if (devicePnpState != WdfDevStatePnpInit && + 0x0 == (pDevice->GetCallbackFlags() & + FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE)) { + + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFINTERRUPTs can only be created during: " + "(1) EvtDriverDeviceAdd when the WDFDEVICE %p is initially created, or " + "(2) EvtDevicePrepareHardware, %!STATUS!", Device, status); + + return status; + } + + // + // Interrupts created in EvtDriverDeviceAdd must not specify any + // CM resources b/c driver doesn't known them yet. + // + if (devicePnpState == WdfDevStatePnpInit) { + + if (Configuration->InterruptRaw != NULL || + Configuration->InterruptTranslated != NULL) { + + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Not NULL InterruptRaw or InterruptTranslated in " + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + + // + // Wake Interrupts can not be created in AddDevice as it is + // not known if they are actually marked as wake capable + // + if (Configuration->CanWakeDevice) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "CanWakeDevice set in WDF_INTERRUPT_CONFIG structure 0x%p" + "during EvtDriverDeviceAdd, %!STATUS!", + Configuration, status); + + return status; + } + } + + // + // Checks for interrupt created in EvtDevicePrepareHardware. + // + if (devicePnpState != WdfDevStatePnpInit) { + // + // CM resources must be specified. + // + if (Configuration->InterruptRaw == NULL || + Configuration->InterruptTranslated == NULL) { + + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "NULL InterruptRaw or InterruptTranslated in " + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + + // + // Share vector must be default. + // + if (Configuration->ShareVector != WdfUseDefault) { + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify ShareVector different from " + "WdfUseDefault in EvtDevicePrepareHardware callback," + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + + } + + if (Configuration->CanWakeDevice) { + if (FxInterrupt::_IsWakeHintedInterrupt( + Configuration->InterruptTranslated->Flags) == FALSE) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify an interrupt as CanWakeDevice if " + "the CM_RESOURCE_INTERRUPT_WAKE_HINT is not present." + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + + // + // Driver is allowed to create wake interrupt only if it + // is the power policy owner so that the we can wake the + // stack when the interrupt fires + // + if (pDevice->m_PkgPnp->IsPowerPolicyOwner() == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify an interrupt as CanWakeDevice if " + "it is not power policy powner. WDF_INTERRUPT_CONFIG " + "structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + + // + // Declaring an interrupt as wake capable allows it to + // take ownership of interrupt from ACPI. It does not + // make sense for a PDO + // + if (pDevice->IsPdo()) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify an interrupt as CanWakeDevice for a PDO " + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + } + + if (Configuration->EvtInterruptDpc != NULL && + Configuration->EvtInterruptWorkItem != NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver can provide either EvtInterruptDpc or " + "EvtInterruptWorkItem callback but not both. " + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + + if (Configuration->PassiveHandling == FALSE) { + // + // DIRQL handling validations. + // + if (Configuration->WaitLock) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify WaitLock when handling interrupts at " + "DIRQL, WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } + // + // Wake interrupts should be passive level so that the stack + // can be sychronously bring the device back to D0 form within + // the ISR + // + if (Configuration->CanWakeDevice) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "CanWakeDevice set in WDF_INTERRUPT_CONFIG structure for an" + "interrupt not marked as passive 0x%p, %!STATUS!", + Configuration, status); + + return status; + } + } + else { + // + // Passive-level handling validations. + // + if (FxIsPassiveLevelInterruptSupported() == FALSE) { + status = STATUS_NOT_SUPPORTED; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The current version of Windows does not support the handling " + "of interrupts at passive-level, WDF_INTERRUPT_CONFIG " + "structure 0x%p passed, %!STATUS!", Configuration, status); + + return status; + } + + if (Configuration->SpinLock) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify SpinLock when handling interrupts at " + "passive-level, WDF_INTERRUPT_CONFIG structure 0x%p passed, " + "%!STATUS!", Configuration, status); + + return status; + } + + + // + // For UMDF reflector decides whether to handle the interrupt + // at passive or DIRQL. Driver has no choice. Therefore this check + // is applicable only for KMDF. + // +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (Configuration->InterruptTranslated != NULL && + FxInterrupt::_IsMessageInterrupt( + Configuration->InterruptTranslated->Flags)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify PassiveHandling for MSI interrupts, " + "WDF_INTERRUPT_CONFIG structure 0x%p passed, %!STATUS!", + Configuration, status); + + return status; + } +#endif + } + + // + // Make sure the specified resources are valid. + // Do this check only under verifier b/c if the driver has a lot of + // interrupts/resources, this verification can slow down power up. + // Note that if InterruptRaw is != NULL, it implies that + // InterruptTranslated is != NULL from the checks above. + // + if (pFxDriverGlobals->FxVerifierOn) { + if (Configuration->InterruptRaw != NULL ) { + status = pDevice->m_PkgPnp->ValidateInterruptResourceCm( + Configuration->InterruptRaw, + Configuration->InterruptTranslated, + Configuration); + if (!NT_SUCCESS(status)) { + return status; + } + } + } + + status = FxInterrupt::_CreateAndInit( + pFxDriverGlobals, + pDevice, + pParent, + Attributes, + Configuration, + &pFxInterrupt); + + if (NT_SUCCESS(status)) { + *Interrupt = (WDFINTERRUPT) pFxInterrupt->GetObjectHandle(); + } + + return status; +} + +BOOLEAN +WDFEXPORT(WdfInterruptQueueDpcForIsr)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Queue the DPC for the ISR + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + TRUE - If the DPC has been enqueued. + + FALSE - If the DPC has already been enqueued. + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + return pFxInterrupt->QueueDeferredRoutineForIsr(); +} + +BOOLEAN +WDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Queue the interrupt's work-item for the ISR. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + TRUE - If the work-item has been enqueued. + + FALSE - If the work-item has already been enqueued. + + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + return pFxInterrupt->QueueWorkItemForIsr(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFEXPORT(WdfInterruptSynchronize)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt, + __in + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + __in + WDFCONTEXT Context + ) + +/*++ + +Routine Description: + + Synchronize execution with the interrupt handler + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + + Callback - PWDF_INTERRUPT_SYNCHRONIZE callback function to invoke + + Context - Context to pass to the PFN_WDF_INTERRUPT_SYNCHRONIZE callback + +Returns: + + BOOLEAN result from user PFN_WDF_INTERRUPT_SYNCHRONIZE callback + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + if (pFxInterrupt->IsPassiveHandling()) { + status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return FALSE; + } + } + + FxPointerNotNull(pFxInterrupt->GetDriverGlobals(), Callback); + + return pFxInterrupt->Synchronize(Callback, Context); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfInterruptAcquireLock)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Begin synchronization to the interrupts IRQL level + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + if (pFxInterrupt->IsPassiveHandling()) { + status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + } + + pFxInterrupt->AcquireLock(); +} + +__drv_maxIRQL(DISPATCH_LEVEL + 1) +VOID +WDFEXPORT(WdfInterruptReleaseLock)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + End synchronization to the interrupts IRQL level + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + if (pFxInterrupt->IsPassiveHandling()) { + status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + } + + pFxInterrupt->ReleaseLock(); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfInterruptEnable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Request that the interrupt be enabled in the hardware. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + // + // Okay to ignore error status. Called function prints error messages. + // + (VOID) pFxInterrupt->ForceReconnect(); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfInterruptDisable)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Request that the interrupt be disabled in the hardware. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + // + // Okay to ignore error status. Called function prints error messages. + // + (VOID) pFxInterrupt->ForceDisconnect(); +} + +_Must_inspect_result_ +struct _KINTERRUPT* +WDFEXPORT(WdfInterruptWdmGetInterrupt)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Return the WDM _KINTERRUPT* + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + return pFxInterrupt->GetInterruptPtr(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfInterruptGetInfo)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt, + __out + PWDF_INTERRUPT_INFO Info + ) + +/*++ + +Routine Description: + + Return the WDF_INTERRUPT_INFO that describes this + particular Message Signaled Interrupt MessageID. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + Nothing + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; + FxInterrupt* pFxInterrupt = NULL; + ULONG size = 0; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Info); + + if (sizeof(WDF_INTERRUPT_INFO_V1_7) == Info->Size) { + size = sizeof(WDF_INTERRUPT_INFO_V1_7); + } + else if (sizeof(WDF_INTERRUPT_INFO) == Info->Size) { + size = sizeof(WDF_INTERRUPT_INFO); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDF_INTERRUPT_INFO %p Size %d invalid, expected %d", + Interrupt, Info->Size, sizeof(WDF_INTERRUPT_INFO)); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + RtlCopyMemory(Info, pFxInterrupt->GetInfo(), size); + + Info->Size = size; +} + +WDFDEVICE +WDFEXPORT(WdfInterruptGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Get the device that the interrupt is related to. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + WDFDEVICE + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + return pFxInterrupt->GetDevice()->GetHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfInterruptSetPolicy)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt, + __in + WDF_INTERRUPT_POLICY Policy, + __in + WDF_INTERRUPT_PRIORITY Priority, + __in + KAFFINITY TargetProcessorSet + ) + +/*++ + +Routine Description: + + Interrupts have attributes that a driver might want to influence. This + routine tells the Framework to tell the PnP manager what the driver would + prefer. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; + FxInterrupt* pFxInterrupt = NULL; + GROUP_AFFINITY processorSet; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt, + &pFxDriverGlobals); + + if (Policy < WdfIrqPolicyMachineDefault || + Policy > WdfIrqPolicySpreadMessagesAcrossAllProcessors) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Policy %d is out of range", Policy); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (Priority < WdfIrqPriorityLow || Priority > WdfIrqPriorityHigh) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Priority %d is out of range", Priority); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + RtlZeroMemory(&processorSet, sizeof(processorSet)); + processorSet.Mask = TargetProcessorSet; + + pFxInterrupt->SetPolicy(Policy, Priority, &processorSet); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfInterruptSetExtendedPolicy)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFINTERRUPT Interrupt, + __in + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ) + +/*++ + +Routine Description: + + Interrupts have attributes that a driver might want to influence. This + routine tells the Framework to tell the PnP manager what the driver would + prefer. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + + PolicyAndGroup - Driver preference for policy, priority and group affinity. + +Returns: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; + FxInterrupt* pFxInterrupt = NULL; + PGROUP_AFFINITY processorSet = NULL; + WDF_INTERRUPT_POLICY policy; + WDF_INTERRUPT_PRIORITY priority; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt, + &pFxDriverGlobals); + + if (PolicyAndGroup->Size != sizeof(WDF_INTERRUPT_EXTENDED_POLICY)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDF_INTERRUPT_EXTENDED_POLICY %p Size %d invalid, expected %d", + PolicyAndGroup, + PolicyAndGroup->Size, + sizeof(WDF_INTERRUPT_EXTENDED_POLICY)); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + policy = PolicyAndGroup->Policy; + priority = PolicyAndGroup->Priority; + processorSet = &PolicyAndGroup->TargetProcessorSetAndGroup; + + if (policy < WdfIrqPolicyMachineDefault || + policy > WdfIrqPolicySpreadMessagesAcrossAllProcessors) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Policy %d is out of range", policy); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (priority < WdfIrqPriorityLow || priority > WdfIrqPriorityHigh) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Priority %d is out of range", priority); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (processorSet->Reserved[0] != 0 || processorSet->Reserved[1] != 0 || + processorSet->Reserved[2] != 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "TargetProcessorSet's reserved fields are not zero"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pFxInterrupt->SetPolicy(policy, priority, processorSet); +} + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +_Post_satisfies_(return == 1 || return == 0) +BOOLEAN +WDFEXPORT(WdfInterruptTryToAcquireLock)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + Try to acquire the interrupt's passive-lock. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + TRUE: function was able to successfully acquire the lock. + + FALSE: function was unable to acquire the lock. + +--*/ + +{ + DDI_ENTRY(); + + FxInterrupt* pFxInterrupt; + NTSTATUS status; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt); + + if (pFxInterrupt->GetDriverGlobals()->FxVerifierOn) { + if (pFxInterrupt->IsPassiveHandling() == FALSE) { + DoTraceLevelMessage( + pFxInterrupt->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFINTERRUPT %p is handled at DIRQL. This API is not " + "available for DIQRL interrupt handling.", + Interrupt); + FxVerifierDbgBreakPoint(pFxInterrupt->GetDriverGlobals()); + return FALSE; + } + + status = FxVerifierCheckIrqlLevel(pFxInterrupt->GetDriverGlobals(), + PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return FALSE; + } + } + + return pFxInterrupt->TryToAcquireLock(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfInterruptReportActive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + This DDI informs the system that the interrupt is active and expecting + interrupt requests on the associated lines. This is typically called after + having reported the lines as inactive via WdfInterruptReportInactive. + The DDI doesn't do anything if this DDI is called before + WdfInterruptReportInactive while the interrupt is connected. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + VOID + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; + FxInterrupt* pFxInterrupt = NULL; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt, + &pFxDriverGlobals); + + pFxInterrupt->ReportActive(); + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfInterruptReportInactive)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ) + +/*++ + +Routine Description: + + This DDI informs the system that the the interrupt is no longer active + and is not expecting interrupt requests on the associated lines. + +Arguments: + + Interrupt - Handle to WDFINTERUPT object created with WdfInterruptCreate. + +Returns: + + VOID + +--*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals = NULL; + FxInterrupt* pFxInterrupt = NULL; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Interrupt, + FX_TYPE_INTERRUPT, + (PVOID*)&pFxInterrupt, + &pFxDriverGlobals); + + pFxInterrupt->ReportInactive(); + + return; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgfdo.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgfdo.cpp new file mode 100644 index 00000000000..8a51eb63832 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgfdo.cpp @@ -0,0 +1,1569 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgFdo.cpp + +Abstract: + + This module implements the pnp/power package for the driver + framework. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + +--*/ + +#include "pnppriv.hpp" + + +//#include + +#include +#include + +#if defined(EVENT_TRACING) +// Tracing support +extern "C" { +#include "FxPkgFdo.tmh" +} +#endif + +struct FxFilteredStartContext : public FxStump { + FxFilteredStartContext( + VOID + ) + { + ResourcesRaw = NULL; + ResourcesTranslated = NULL; + } + + ~FxFilteredStartContext() + { + if (ResourcesRaw != NULL) { + MxMemory::MxFreePool(ResourcesRaw); + } + if (ResourcesTranslated != NULL) { + MxMemory::MxFreePool(ResourcesTranslated); + } + } + + FxPkgFdo* PkgFdo; + + PCM_RESOURCE_LIST ResourcesRaw; + + PCM_RESOURCE_LIST ResourcesTranslated; +}; + +const PFN_PNP_POWER_CALLBACK FxPkgFdo::m_FdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1] = +{ + _PnpStartDevice, // IRP_MN_START_DEVICE + _PnpQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE + _PnpRemoveDevice, // IRP_MN_REMOVE_DEVICE + _PnpCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE + _PnpStopDevice, // IRP_MN_STOP_DEVICE + _PnpQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE + _PnpCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE + + _PnpQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS + _PnpQueryInterface, // IRP_MN_QUERY_INTERFACE + _PnpQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES + _PnpPassDown, // IRP_MN_QUERY_RESOURCES + _PnpPassDown, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS + _PnpPassDown, // IRP_MN_QUERY_DEVICE_TEXT + _PnpFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS + + _PnpPassDown, // 0x0E + + _PnpPassDown, // IRP_MN_READ_CONFIG + _PnpPassDown, // IRP_MN_WRITE_CONFIG + _PnpPassDown, // IRP_MN_EJECT + _PnpPassDown, // IRP_MN_SET_LOCK + _PnpPassDown, // IRP_MN_QUERY_ID + _PnpQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE + _PnpPassDown, // IRP_MN_QUERY_BUS_INFORMATION + _PnpDeviceUsageNotification, // IRP_MN_DEVICE_USAGE_NOTIFICATION + _PnpSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL + +}; + +const PFN_PNP_POWER_CALLBACK FxPkgFdo::m_FdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1] = +{ + _DispatchWaitWake, // IRP_MN_WAIT_WAKE + _PowerPassDown, // IRP_MN_POWER_SEQUENCE + _DispatchSetPower, // IRP_MN_SET_POWER + _DispatchQueryPower, // IRP_MN_QUERY_POWER +}; + +//#if defined(ALLOC_PRAGMA) +//#pragma code_seg("PAGE") +//#endif + +FxPkgFdo::FxPkgFdo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ) : + FxPkgPnp(FxDriverGlobals, Device, FX_TYPE_PACKAGE_FDO) +/*++ + +Routine Description: + + This is the constructor for the FxPkgFdo. Don't do any initialization + that might fail here. + +Arguments: + + none + +Returns: + + none + +--*/ + +{ + m_DefaultDeviceList = NULL; + m_StaticDeviceList = NULL; + + m_DefaultTarget = NULL; + m_SelfTarget = NULL; + + m_BusEnumRetries = 0; + + // + // Since we will always have a valid PDO when we are the FDO, we can do + // any device interface related activity at any time + // + m_DeviceInterfacesCanBeEnabled = TRUE; + + m_Filter = FALSE; + + RtlZeroMemory(&m_BusInformation, sizeof(m_BusInformation)); + + RtlZeroMemory(&m_SurpriseRemoveAndReenumerateSelfInterface, + sizeof(m_SurpriseRemoveAndReenumerateSelfInterface)); +} + +FxPkgFdo::~FxPkgFdo( + VOID + ) +/*++ + +Routine Description: + + This is the destructor for the FxPkgFdo + +Arguments: + + none + +Returns: + + none + +--*/ + +{ + if (m_DefaultDeviceList != NULL) { + m_DefaultDeviceList->RELEASE(this); + } + if (m_StaticDeviceList != NULL) { + m_StaticDeviceList->RELEASE(this); + } + if (m_SelfTarget != NULL) { + m_SelfTarget->RELEASE(this); + } + if (m_DefaultTarget != NULL) { + m_DefaultTarget->RELEASE(this); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_Create( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in CfxDevice * Device, + __deref_out FxPkgFdo ** PkgFdo + ) +{ + NTSTATUS status; + FxPkgFdo * fxPkgFdo; + FxEventQueue *eventQueue; + + fxPkgFdo = new(DriverGlobals) FxPkgFdo(DriverGlobals, Device); + + if (NULL == fxPkgFdo) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Memory allocation failed: %!STATUS!", status); + return status; + } + + // + // Initialize the event queues in the PnP, power and power policy state + // machines + // + eventQueue = static_cast (&(fxPkgFdo->m_PnpMachine)); + status = eventQueue->Initialize(DriverGlobals); + if (!NT_SUCCESS(status)) { + goto exit; + } + + eventQueue = static_cast (&(fxPkgFdo->m_PowerMachine)); + status = eventQueue->Initialize(DriverGlobals); + if (!NT_SUCCESS(status)) { + goto exit; + } + + eventQueue = static_cast (&(fxPkgFdo->m_PowerPolicyMachine)); + status = eventQueue->Initialize(DriverGlobals); + if (!NT_SUCCESS(status)) { + goto exit; + } + + *PkgFdo = fxPkgFdo; + +exit: + if (!NT_SUCCESS(status)) { + fxPkgFdo->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::SendIrpSynchronously( + __inout FxIrp* Irp + ) + +/*++ + +Routine Description: + + Helper function that makes it easy to handle events which need to be + done as an IRP comes back up the stack. + +Arguments: + + Irp - The request + +Returns: + + results from IoCallDriver + +--*/ + +{ + Irp->CopyCurrentIrpStackLocationToNext(); + return Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::FireAndForgetIrp( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + Virtual override which sends the request down the stack and forgets about it. + +Arguments: + + Irp - The request + +Returns: + + results from IoCallDriver + +--*/ + +{ + if (Irp->GetMajorFunction() == IRP_MJ_POWER) { + return _PowerPassDown(this, Irp); + } + else { + return _PnpPassDown(this, Irp); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpPassDown( + __in FxPkgPnp* This, + __inout FxIrp* Irp + ) +/*++ + +Routine Description: + Functionally equivalent to FireAndForgetIrp except this isn't a virtual + call + +Arguments: + Irp - The request + +Return Value: + result from IoCallDriver + + --*/ +{ + NTSTATUS status; + FxDevice* device; + MdIrp pIrp; + + device = ((FxPkgFdo*)This)->m_Device; + pIrp = Irp->GetIrp(); + + Irp->CopyCurrentIrpStackLocationToNext(); + status = Irp->CallDriver( + ((FxPkgFdo*)This)->m_Device->GetAttachedDevice()); + + Mx::MxReleaseRemoveLock(device->GetRemoveLock(), + pIrp + ); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpSurpriseRemoval( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is called in response to a PnP SurpriseRemoval IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + return ((FxPkgFdo*) This)->PnpSurpriseRemoval(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryDeviceRelations( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is called in response to a PnP QDR. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + return ((FxPkgFdo*) This)->PnpQueryDeviceRelations(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PnpQueryDeviceRelations( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This routine is called in response to a QueryDeviceRelations IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NSTATUS + +--*/ + +{ + NTSTATUS status; + DEVICE_RELATION_TYPE type; + + type = Irp->GetParameterQDRType(); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering QueryDeviceRelations handler, " + "type %!DEVICE_RELATION_TYPE!", + type); + + status = STATUS_SUCCESS; + + + // + // Set up the type of relations. + // + switch (type) { + case BusRelations: + status = HandleQueryBusRelations(Irp); + + // + // STATUS_NOT_SUPPORTED is a special value. It means that + // HandleQueryBusRelations did not modify the irp at all and it should + // be sent off as is. + // + if (status == STATUS_NOT_SUPPORTED) { + // + // We set status to STATUS_SUCCESS so that we send the requqest down + // the stack in the comparison below. + // + status = STATUS_SUCCESS; + } + break; + + case RemovalRelations: + status = HandleQueryDeviceRelations(Irp, m_RemovalDeviceList); + + // + // STATUS_NOT_SUPPORTED is a special value. It means that + // HandleQueryDeviceRelations did not modify the irp at all and it should + // be sent off as is. + // + if (status == STATUS_NOT_SUPPORTED) { + // + // We set status to STATUS_SUCCESS so that we send the requqest down + // the stack in the comparison below. + // + status = STATUS_SUCCESS; + } + break; + } + + if (NT_SUCCESS(status)) { + status = _PnpPassDown(this, Irp); + } + else { + CompletePnpRequest(Irp, status); + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting QueryDeviceRelations handler, status %!STATUS!", + status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryInterface( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryInterface IRP. + +Arguments: + + This - The package + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + FxPkgFdo* pThis; + NTSTATUS status; + BOOLEAN completeIrp; + + pThis = (FxPkgFdo*) This; + + DoTraceLevelMessage(pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering QueryInterface handler"); + + status = pThis->HandleQueryInterface(Irp, &completeIrp); + + DoTraceLevelMessage(pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting QueryInterface handler, %!STATUS!", + status); + // + // If we understand the irp, we'll complete it. Otherwise we + // pass it down. + // + if (completeIrp == FALSE) { + status = _PnpPassDown(pThis, Irp); + } + else { + Irp->SetInformation(NULL); + pThis->CompletePnpRequest(Irp, status); + } + + // + // Remlock is released in _PnpPassDown and CompletePnpRequest. If this + // irp is racing with remove on another thread, it's possible for the device + // to get deleted right after the lock is released and before anything + // after this point is executed. So make sure to not touch any memory in + // the return path. + // + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryCapabilities( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + + + + + + + + + + + + + return ((FxPkgFdo*) This)->PnpQueryCapabilities(Irp); +} + +VOID +FxPkgFdo::HandleQueryCapabilities( + __inout FxIrp *Irp + ) +{ + PDEVICE_CAPABILITIES pCaps; + LONG pnpCaps; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering QueryCapabilities handler"); + + pCaps = Irp->GetParameterDeviceCapabilities(); + + pnpCaps = GetPnpCapsInternal(); + + // + // Add Capabilities. These need to be done as the IRP goes down, since + // lower drivers need to see them. + // + if ((pCaps->Size >= sizeof(DEVICE_CAPABILITIES)) && (pCaps->Version == 1)) { + SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, LockSupported); + SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, EjectSupported); + SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, Removable); + SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, DockDevice); + SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, SurpriseRemovalOK); + SET_PNP_CAP_IF_TRUE(pnpCaps, pCaps, NoDisplayInUI); + // + // If the driver has declared a wake capable interrupt, + // we need to set this bit in the capabilities so that + // ACPI will relinquish control of wake responsiblity + // + if (SupportsWakeInterrupt()) { + pCaps->WakeFromInterrupt = TRUE; + } + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting QueryCapabilities handler"); + return; +} + +VOID +FxPkgFdo::HandleQueryCapabilitiesCompletion( + __inout FxIrp *Irp + ) +{ + PDEVICE_CAPABILITIES pCaps; + LONG pnpCaps; + ULONG i; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering QueryCapabilities completion handler"); + + pCaps = Irp->GetParameterDeviceCapabilities(); + + pnpCaps = GetPnpCapsInternal(); + + // + // Confirm this is a valid DeviceCapabilities structure. + // + ASSERT(pCaps->Size >= sizeof(DEVICE_CAPABILITIES)); + ASSERT(pCaps->Version >= 1); + + if ((pCaps->Size >= sizeof(DEVICE_CAPABILITIES)) && + (pCaps->Version == 1)) { + ULONG states; + + // + // Remove Capabilities + // + + // + // Re-add SOME capibilties that the bus driver may have accidentally + // stomped. + + + + + + SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, LockSupported); + SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, EjectSupported); + SET_PNP_CAP_IF_FALSE(pnpCaps, pCaps, DockDevice); + + SET_PNP_CAP(pnpCaps, pCaps, Removable); + SET_PNP_CAP(pnpCaps, pCaps, SurpriseRemovalOK); + + // + // The DeviceState array contains a table of D states that correspond + // to a given S state. If the driver writer initialized entries of the + // array, and if the new value is a deeper sleep state than the + // original, we will use the new driver supplied value. + // + states = m_PowerCaps.States; + + for (i = PowerSystemWorking; i < PowerSystemMaximum; i++) { + DEVICE_POWER_STATE state; + + // + // PowerDeviceMaximum indicates to use the default value + // + // We are only allowed to deepen the D states, not lighten them, + // hence the > compare. + // + state = _GetPowerCapState(i, states); + + if (state != PowerDeviceMaximum && state > pCaps->DeviceState[i]) { + pCaps->DeviceState[i] = state; + } + } + + // + // If the driver supplied SystemWake value is lighter than the current + // value, then use the driver supplied value. + // + // PowerSystemMaximum indicates to use the default value + // + // We are only allowed to lighten the S state, not deepen it, hence + // the < compare. + // + if (m_PowerCaps.SystemWake != PowerSystemMaximum && + m_PowerCaps.SystemWake < pCaps->SystemWake) { + pCaps->SystemWake = (SYSTEM_POWER_STATE) m_PowerCaps.SystemWake; + } + + // + // Same for DeviceWake + // + if (m_PowerCaps.DeviceWake != PowerDeviceMaximum && + m_PowerCaps.DeviceWake < pCaps->DeviceWake) { + pCaps->DeviceWake = (DEVICE_POWER_STATE) m_PowerCaps.DeviceWake; + } + + // + // Set the Device wake up latencies. A value of -1 indicates to + // use the default values provided by the lower stack. + // + if (m_PowerCaps.D1Latency != (ULONG) -1 && + m_PowerCaps.D1Latency > pCaps->D1Latency) { + pCaps->D1Latency = m_PowerCaps.D1Latency; + } + + if (m_PowerCaps.D2Latency != (ULONG) -1 && + m_PowerCaps.D2Latency > pCaps->D2Latency) { + pCaps->D2Latency = m_PowerCaps.D2Latency; + } + + if (m_PowerCaps.D3Latency != (ULONG) -1 && + m_PowerCaps.D3Latency > pCaps->D3Latency) { + pCaps->D3Latency = m_PowerCaps.D3Latency; + } + + // + // Set the Address and the UI number values. A value of -1 indicates + // to use the default values provided by the lower stack. + // + if (m_PnpCapsAddress != (ULONG) -1) { + pCaps->Address = m_PnpCapsAddress; + } + + if (m_PnpCapsUINumber != (ULONG) -1) { + pCaps->UINumber= m_PnpCapsUINumber; + } + } + + // + // CompletePnpRequest is called after return from this function + // so it is safe to log here + // + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting QueryCapabilities completion handler"); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpFilterResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgFdo*) This)->PnpFilterResourceRequirements(Irp); +} + + + + + + + +VOID +FxPkgFdo::HandleQueryPnpDeviceStateCompletion( + __inout FxIrp *Irp + ) +{ + PNP_DEVICE_STATE pnpDeviceState; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering QueryPnpDeviceState completion handler"); + + pnpDeviceState = HandleQueryPnpDeviceState( + (PNP_DEVICE_STATE) Irp->GetInformation() + ); + + Irp->SetInformation((ULONG_PTR) pnpDeviceState); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p returning PNP_DEVICE_STATE 0x%d IRP 0x%p", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + pnpDeviceState, + Irp->GetIrp()); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting QueryPnpDeviceState completion handler"); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::RegisterCallbacks( + __in PWDF_FDO_EVENT_CALLBACKS DispatchTable + ) +{ + // + // Walk the table, and only update the pkg table *if* the dispatch + // table has a non-null entry. + // + m_DeviceFilterAddResourceRequirements.m_Method = + DispatchTable->EvtDeviceFilterAddResourceRequirements; + m_DeviceFilterRemoveResourceRequirements.m_Method = + DispatchTable->EvtDeviceFilterRemoveResourceRequirements; + m_DeviceRemoveAddedResources.m_Method = + DispatchTable->EvtDeviceRemoveAddedResources; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::CreateDefaultDeviceList( + __in PWDF_CHILD_LIST_CONFIG ListConfig, + __in PWDF_OBJECT_ATTRIBUTES ListAttributes + ) + +/*++ + +Routine Description: + + + +Arguments: + + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFCHILDLIST hList; + size_t totalDescriptionSize = 0; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + + ASSERT(m_EnumInfo != NULL); + + // + // This should not fail, we already validated the total size when we + // validated the config (we just had no place to store the total size, so + // we recompute it again). + // + status = FxChildList::_ComputeTotalDescriptionSize( + pFxDriverGlobals, + ListConfig, + &totalDescriptionSize + ); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxChildList::_CreateAndInit(&m_DefaultDeviceList, + pFxDriverGlobals, + ListAttributes, + totalDescriptionSize, + m_Device, + ListConfig); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_DefaultDeviceList->Commit(ListAttributes, + (WDFOBJECT*)&hList, + m_Device); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not convert object to handle"); + m_DefaultDeviceList->DeleteFromFailedCreate(); + m_DefaultDeviceList = NULL; + return status; + } + + // + // This will be released in the destructor + // + m_DefaultDeviceList->ADDREF(this); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::SetFilter( + __in BOOLEAN Value + ) + +/*++ + +Routine Description: + + The Framework behaves differently depending on whether this device is a + filter in the stack. This method is the way we keep track. + +Arguments: + + Value - Filter or not + +Returns: + + NTSTATUS + +--*/ + +{ + m_Filter = Value; + return STATUS_SUCCESS; +} + +BOOLEAN +FxPkgFdo::PnpSendStartDeviceDownTheStackOverload( + VOID + ) +/*++ + +Routine Description: + Send the start irp down the stack. + +Arguments: + None + +Return Value: + FALSE, the transition will occur in the irp's completion routine. + + --*/ +{ + // + // We will re-set the pending pnp irp when the start irp returns + // + FxIrp irp(ClearPendingPnpIrp()); + PCM_RESOURCE_LIST pWdmRaw, pWdmTranslated; + NTSTATUS status; + BOOLEAN setFilteredCompletion = FALSE; + FxFilteredStartContext* pContext = NULL; + + pWdmRaw = irp.GetParameterAllocatedResources(); + pWdmTranslated = irp.GetParameterAllocatedResourcesTranslated(); + + // + // Always setup the irp to be sent down the stack. In case of an error, + // this does no harm and it keeps everything simple. + // + irp.CopyCurrentIrpStackLocationToNext(); + + // + // If the driver registered for a callback to remove its added resources + // and there are resources to remove, call the driver and set the next + // stack location to the filtered resources lists + // + if (m_DeviceRemoveAddedResources.m_Method != NULL && + pWdmRaw != NULL && pWdmTranslated != NULL) { + + // + // Since we reuse these 2 fields for both the removal and the normal + // reporting (and can then be subsequently reused on a restart), we + // set the changed status back to FALSE. + // + m_ResourcesRaw->m_Changed = FALSE; + m_Resources->m_Changed = FALSE; + + status = m_ResourcesRaw->BuildFromWdmList(pWdmRaw, + FxResourceAllAccessAllowed); + + if (NT_SUCCESS(status)) { + status = m_Resources->BuildFromWdmList(pWdmTranslated, + FxResourceAllAccessAllowed); + } + + if (NT_SUCCESS(status)) { + status = m_DeviceRemoveAddedResources.Invoke( + m_Device->GetHandle(), + m_ResourcesRaw->GetHandle(), + m_Resources->GetHandle() + ); + } + + if (NT_SUCCESS(status) && + (m_ResourcesRaw->IsChanged() || m_Resources->IsChanged())) { + + pContext = new(GetDriverGlobals()) FxFilteredStartContext(); + + if (pContext != NULL) { + pContext->PkgFdo = this; + + // + // Allocate the raw and translated resources. Upon failure for + // either, fail the start irp. We allocate from NonPagedPool + // because we are going to free the list in a completion routine + // which maybe running at an IRQL > PASSIVE_LEVEL. + // + if (m_ResourcesRaw->Count() > 0) { + pContext->ResourcesRaw = + m_ResourcesRaw->CreateWdmList(NonPagedPool); + + if (pContext->ResourcesRaw == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status) && m_Resources->Count() > 0) { + pContext->ResourcesTranslated = + m_Resources->CreateWdmList(NonPagedPool); + + if (pContext->ResourcesTranslated == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) { + // + // We copied to the next stack location at the start + // + irp.SetParameterAllocatedResources( + pContext->ResourcesRaw); + irp.SetParameterAllocatedResourcesTranslated( + pContext->ResourcesTranslated); + + // + // Completion routine will free the resource list + // allocations. + // + setFilteredCompletion = TRUE; + } + else { + // + // Allocation failure. The destructor will free any + // outstanding allocations. + // + delete pContext; + } + } + } + } + else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + // + // The completion of the start irp will move the state machine into a new + // state. + // + // After calling IoSetCompletionRoutineEx the driver must call + // IoCallDriver, otherwise a memory leak would occur. So call this API + // as close to IoCallDriver as possible to avoid failure paths. + // + if (setFilteredCompletion) { + ASSERT(pContext != NULL); + irp.SetCompletionRoutineEx( + m_Device->GetDeviceObject(), + _PnpFilteredStartDeviceCompletionRoutine, + pContext); + } + else { + irp.SetCompletionRoutineEx( + m_Device->GetDeviceObject(), + _PnpStartDeviceCompletionRoutine, + this); + } + + irp.CallDriver(m_Device->GetAttachedDevice()); + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "PNP start preprocessing failed with %!STATUS!", + status); + + // + // Move the state machine to the failed state. + // + // Process the event *before* completing the irp so that this even is in + // the queue before the device remove event which will be be processed + // right after the start irp has been completed. + // + PnpProcessEvent(PnpEventStartDeviceFailed); + + // + // All states which handle the PnpEventStartDeviceFailed event + // transition do not expect a pended start irp. + // + CompletePnpRequest(&irp, status); + } + + // + // Indicate to the caller that the transition is asynchronous. + // + return FALSE; +} + +WDF_DEVICE_PNP_STATE +FxPkgFdo::PnpEventEjectHardwareOverload( + VOID + ) + +/*++ + +Routine Description: + + This method implements the Eject Hardware state in the PnP State Machine. + Since FDO and PDO behavior is different, this is overloaded. In fact, + this state shouldn't be reachable for FDOs, as the FDO should have been + torn off the stack before the device was cleanly ejected. + +Arguments: + + none + +Returns: + + WdfDevStatePnpEjectedWaitingForRemove + +--*/ + +{ + ASSERT(!"This should only be reachable for PDOs."); + + // + // Do something safe. Act like the device got + // ejected. + // + return WdfDevStatePnpEjectedWaitingForRemove; +} + +WDF_DEVICE_PNP_STATE +FxPkgFdo::PnpEventCheckForDevicePresenceOverload( + VOID + ) + +/*++ + +Routine Description: + + This method implements the Check For Device Presence state in the PnP State + Machine. Since FDO and PDO behavior is different, this is overloaded. In + fact, this state shouldn't be reachable for FDOs, as the FDO should have + been torn off the stack before the device was cleanly ejected. + +Arguments: + + none + +Returns: + + WdfDevStatePnpFinal + +--*/ + +{ + ASSERT(!"This should only be implemented for PDOs."); + + // + // Do something safe. Act like the device is not + // present. + // + return WdfDevStatePnpFinal; +} + +WDF_DEVICE_PNP_STATE +FxPkgFdo::PnpEventPdoRemovedOverload( + VOID + ) + +/*++ + +Routine Description: + + This method implements the PDO Removed state in the PnP State Machine. + Since FDO and PDO behavior is different, this is overloaded. In fact, + this state shouldn't be reachable for FDOs, as the FDO should have been + torn off the stack before the PDO is removed. + +Arguments: + + none + +Returns: + + none + +--*/ + +{ + ASSERT(!"This should only be implemented for PDOs."); + + return WdfDevStatePnpFinal; +} + +WDF_DEVICE_PNP_STATE +FxPkgFdo::PnpGetPostRemoveState( + VOID + ) + +/*++ + +Routine Description: + + This method implements the Removed state in the PnP State Machine. + Since FDO and PDO behavior is different, this is overloaded. This state + just moves us toward the FDO-specific removal states. + +Arguments: + + none + +Returns: + + none + +--*/ + +{ + return WdfDevStatePnpFdoRemoved; +} + +WDF_DEVICE_PNP_STATE +FxPkgFdo::PnpEventFdoRemovedOverload( + VOID + ) +/*++ + +Routine Description: + FDO is being removed, see if there are any children that need to be removed + +Arguments: + None + +Return Value: + New device pnp state + + --*/ +{ + // + // Do that which all device stacks need to do upon removal. + // + PnpEventRemovedCommonCode(); + + return WdfDevStatePnpFinal; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::ProcessRemoveDeviceOverload( + __inout FxIrp* Irp + ) +{ + NTSTATUS status; + + // + // After this is called, any irp dispatched to FxDevice::DispatchWithLock + // will fail with STATUS_INVALID_DEVICE_REQUEST. + // + Mx::MxReleaseRemoveLockAndWait(m_Device->GetRemoveLock(), + Irp->GetIrp()); + + // + // Cleanup the state machines and release the power thread. + // + CleanupStateMachines(TRUE); + + Irp->CopyCurrentIrpStackLocationToNext(); + status = Irp->CallDriver(m_Device->GetAttachedDevice()); + + // + // Detach and delete the device object. + // + DeleteDevice(); + + return status; +} + +VOID +FxPkgFdo::DeleteSymbolicLinkOverload( + __in BOOLEAN GracefulRemove + ) +/*++ + +Routine Description: + Role specific virtual function which determines if the symbolic link for a + device should be deleted. + +Arguments: + None + +Return Value: + None + + --*/ +{ + UNREFERENCED_PARAMETER(GracefulRemove); + + // + // We always remove the symbolic link for an FDO since there is no presence + // state to check. + // + m_Device->DeleteSymbolicLink(); +} + +VOID +FxPkgFdo::QueryForReenumerationInterface( + VOID + ) +{ + PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; + NTSTATUS status; + + pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface; + + if (pInterface->SurpriseRemoveAndReenumerateSelf != NULL) { + // + // Already got it, just return. This function can be called again during + // stop -> start, so we must check. + // + return; + } + + RtlZeroMemory(pInterface, sizeof(*pInterface)); + pInterface->Size = sizeof(*pInterface); + pInterface->Version = 1; + + // + // Since there are some stacks that are not PnP re-entrant + + // we specify that the QI goes only to our attached device and + // not to the top of the stack as a normal QI irp would. For the + // reenumerate self interface, having someone on top of us filter the + // IRP makes no sense anyways. + // + // We also do this as a preventative measure for other stacks we don't know + // about internally and do not have access to when testing. + // + status = m_Device->QueryForInterface(&GUID_REENUMERATE_SELF_INTERFACE_STANDARD, + (PINTERFACE) pInterface, + sizeof(*pInterface), + 1, + NULL, + m_Device->GetAttachedDevice() + ); + + // + // Failure to get this interface is not fatal. + // Note that an implicit reference has been taken on the interface. We + // must release the reference when we are done with the interface. + // + UNREFERENCED_PARAMETER(status); // for analyis tools. +} + +VOID +FxPkgFdo::ReleaseReenumerationInterface( + VOID + ) +/*++ + +Routine Description: + + Releases the implicit reference taken on REENUMERATE_SELF interface. + NOOP for PDO. + +Arguments: + None + +Return Value: + VOID + + --*/ +{ + PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; + + pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface; + + pInterface->SurpriseRemoveAndReenumerateSelf = NULL; + + if (pInterface->InterfaceDereference != NULL) { + pInterface->InterfaceDereference(pInterface->Context); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::QueryForPowerThread( + VOID + ) +/*++ + +Routine Description: + Sends a query for a power thread down the stack. If it can't query for one, + it attempts to create one on its own. + +Arguments: + None + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + + // + // Query down the stack to see if a lower device already created a thread. + // Do NOT send this to the top of the stack, it is sent to the attached + // device b/c we need the thread from a device below us b/c its lifetime + // will outlast this device's. + // + status = m_Device->QueryForInterface(&GUID_POWER_THREAD_INTERFACE, + &m_PowerThreadInterface.Interface, + sizeof(m_PowerThreadInterface), + 1, + NULL, + m_Device->GetAttachedDevice()); + + if (NT_SUCCESS(status)) { + // + // A lower thread exists, use it + // + m_HasPowerThread = TRUE; + } + else { + // + // No thread exists yet, attempt to create our own + // + status = CreatePowerThread(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpFilteredStartDeviceCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ) +{ + FxFilteredStartContext *pContext; + FxPkgFdo* pPkgFdo; + + pContext = (FxFilteredStartContext*) Context; + + // + // Save off the package so we can use it after we free the context + // + pPkgFdo = pContext->PkgFdo; + + delete pContext; + + return _PnpStartDeviceCompletionRoutine(DeviceObject, Irp, pPkgFdo); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpStartDeviceCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ) +{ + FxPkgFdo* pThis; + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pThis = (FxPkgFdo*) Context; + + if (NT_SUCCESS(irp.GetStatus())) { + pThis->SetPendingPnpIrp(&irp); + + // + // Only raise irql if we are the power policy owner. Only the p.p.o. + // does this so that we only have one driver in the device stack moving + // to another thread. + // + if (pThis->IsPowerPolicyOwner()) { + KIRQL irql; + + // + // By raising to dispatch level we are forcing the pnp state machine + // to move to another thread. On NT 6.0 PnP supports asynchronous + // starts, so this will other starts to proceed while WDF processes + // this device starting. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + pThis->PnpProcessEvent(PnpEventStartDeviceComplete); + Mx::MxLowerIrql(irql); + } + else { + pThis->PnpProcessEvent(PnpEventStartDeviceComplete); + } + } + else { + // + // Just complete the request, the current pnp state can handle the remove + // which will be sent b/c of the failed start. + // + DoTraceLevelMessage( + pThis->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "PNP start failed with %!STATUS!", irp.GetStatus()); + + // + // Process the event *before* completing the irp so that this even is in + // the queue before the device remove event which will be be processed + // right after the start irp has been completed. + // + pThis->PnpProcessEvent(PnpEventStartDeviceFailed); + + pThis->CompletePnpRequest(&irp, irp.GetStatus()); + } + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PostCreateDeviceInitialize( + VOID + ) +{ + NTSTATUS status; + + status = __super::PostCreateDeviceInitialize(); + if (!NT_SUCCESS(status)) { + return status; + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // Allow device simulation framework to hook interrupt routines. + // + if (GetDriverGlobals()->FxDsfOn) { + status = QueryForDsfInterface(); + if (!NT_SUCCESS(status)) { + return status; + } + } + +#endif + + status = m_Device->AllocateTarget(&m_DefaultTarget, + FALSE /*SelfTarget=FALSE*/); + if (NT_SUCCESS(status)) { + // + // This will be released in the destructor + // + m_DefaultTarget->ADDREF(this); + } + + if (m_Device->m_SelfIoTargetNeeded) { + status = m_Device->AllocateTarget((FxIoTarget**)&m_SelfTarget, + TRUE /*SelfTarget*/); + if (NT_SUCCESS(status)) { + // + // This will be released in the destructor + // + m_SelfTarget->ADDREF(this); + } + } + + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgpdo.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgpdo.cpp new file mode 100644 index 00000000000..71bf5ef7f21 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgpdo.cpp @@ -0,0 +1,1926 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgPdo.cpp + +Abstract: + + This module implements the Pnp package for Pdo devices. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + +--*/ + +#include "pnppriv.hpp" +#include + +// Tracing support +#if defined(EVENT_TRACING) +extern "C" { +#include "FxPkgPdo.tmh" +} +#endif + +const PFN_PNP_POWER_CALLBACK FxPkgPdo::m_PdoPnpFunctionTable[IRP_MN_SURPRISE_REMOVAL + 1] = +{ + _PnpStartDevice, // IRP_MN_START_DEVICE + _PnpQueryRemoveDevice, // IRP_MN_QUERY_REMOVE_DEVICE + _PnpRemoveDevice, // IRP_MN_REMOVE_DEVICE + _PnpCancelRemoveDevice, // IRP_MN_CANCEL_REMOVE_DEVICE + _PnpStopDevice, // IRP_MN_STOP_DEVICE + _PnpQueryStopDevice, // IRP_MN_QUERY_STOP_DEVICE + _PnpCancelStopDevice, // IRP_MN_CANCEL_STOP_DEVICE + + _PnpQueryDeviceRelations, // IRP_MN_QUERY_DEVICE_RELATIONS + _PnpQueryInterface, // IRP_MN_QUERY_INTERFACE + _PnpQueryCapabilities, // IRP_MN_QUERY_CAPABILITIES + _PnpQueryResources, // IRP_MN_QUERY_RESOURCES + _PnpQueryResourceRequirements, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS + _PnpQueryDeviceText, // IRP_MN_QUERY_DEVICE_TEXT + _PnpFilterResourceRequirements, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS + + _PnpCompleteIrp, // 0x0E + + _PnpCompleteIrp, // IRP_MN_READ_CONFIG + _PnpCompleteIrp, // IRP_MN_WRITE_CONFIG + _PnpEject, // IRP_MN_EJECT + _PnpSetLock, // IRP_MN_SET_LOCK + _PnpQueryId, // IRP_MN_QUERY_ID + _PnpQueryPnpDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE + _PnpQueryBusInformation, // IRP_MN_QUERY_BUS_INFORMATION + _PnpDeviceUsageNotification, // IRP_MN_DEVICE_USAGE_NOTIFICATION + _PnpSurpriseRemoval, // IRP_MN_SURPRISE_REMOVAL +}; + +const PFN_PNP_POWER_CALLBACK FxPkgPdo::m_PdoPowerFunctionTable[IRP_MN_QUERY_POWER + 1] = +{ + _DispatchWaitWake, // IRP_MN_WAIT_WAKE + _DispatchPowerSequence, // IRP_MN_POWER_SEQUENCE + _DispatchSetPower, // IRP_MN_SET_POWER + _DispatchQueryPower, // IRP_MN_QUERY_POWER +}; + +//#if defined(ALLOC_PRAGMA) +//#pragma code_seg("PAGE") +//#endif + +FxPkgPdo::FxPkgPdo( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice *Device + ) : + FxPkgPnp(FxDriverGlobals, Device, FX_TYPE_PACKAGE_PDO) +/*++ + +Routine Description: + + This is the constructor for the FxPkgPdo. Don't do any initialization + that might fail here. + +Arguments: + + none + +Returns: + + none + +--*/ + +{ + m_DeviceTextHead.Next = NULL; + + m_DeviceID = NULL; + m_InstanceID = NULL; + m_HardwareIDs = NULL; + m_CompatibleIDs = NULL; + m_ContainerID = NULL; + m_IDsAllocation = NULL; + + m_RawOK = FALSE; + m_Static = FALSE; + m_AddedToStaticList = FALSE; + + // + // By default the PDO is the owner of wait wake irps (only case where this + // wouldn't be the case is for a bus filter to be sitting above us). + // + m_SharedPower.m_WaitWakeOwner = TRUE; + + m_Description = NULL; + m_OwningChildList = NULL; + + m_EjectionDeviceList = NULL; + m_DeviceEjectProcessed = NULL; + + m_CanBeDeleted = FALSE; + m_EnableWakeAtBusInvoked = FALSE; +} + +FxPkgPdo::~FxPkgPdo( + VOID + ) +/*++ + +Routine Description: + + This is the destructor for the FxPkgPdo + +Arguments: + + none + +Returns: + + none + +--*/ +{ + // + // If IoCreateDevice fails on a dynamically created PDO, m_Description will + // be != NULL b/c we will not go through the pnp state machine in its entirety + // for cleanup. FxChildList will need a valid m_Description to cleanup upon + // failure from EvtChildListDeviceCrate, so we just leave m_Description alone + // here if != NULL. + // + // ASSERT(m_Description == NULL); + + FxDeviceText::_CleanupList(&m_DeviceTextHead); + + // + // This will free the underlying memory for m_DeviceID, m_InstanceID, + // m_HardwareIDs, m_CompatibleIDs and m_ContainerID + // + if (m_IDsAllocation != NULL) { + FxPoolFree(m_IDsAllocation); + m_IDsAllocation = NULL; + } + + if (m_OwningChildList != NULL) { + m_OwningChildList->RELEASE(this); + } + + if (m_EjectionDeviceList != NULL) { + delete m_EjectionDeviceList; + m_EjectionDeviceList = NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::Initialize( + __in PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + + Do initialization that might fail here. + +Arguemnts: + + DeviceInit - the structure the driver passed in with initialization data + +Returns: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + size_t cbLength, cbStrLength; + PWSTR pCur; + PdoInit* pPdo; + + status = FxPkgPnp::Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + cbLength = 0; + + // + // Compute the total number of bytes required for all strings and then + // make one allocation and remember pointers w/in the string so we can + // retrieve them individually later. + // + pPdo = &DeviceInit->Pdo; + cbLength += FxCalculateTotalStringSize(&pPdo->HardwareIDs); + cbLength += FxCalculateTotalStringSize(&pPdo->CompatibleIDs); + + if (pPdo->DeviceID != NULL) { + cbLength += pPdo->DeviceID->ByteLength(TRUE); + } + if (pPdo->InstanceID != NULL) { + cbLength += pPdo->InstanceID->ByteLength(TRUE); + } + if (pPdo->ContainerID != NULL) { + cbLength += pPdo->ContainerID->ByteLength(TRUE); + } + + m_IDsAllocation = (PWSTR) FxPoolAllocate(GetDriverGlobals(), + PagedPool, + cbLength); + + if (m_IDsAllocation == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "DeviceInit %p could not allocate string for device IDs " + "(length %I64d), %!STATUS!", DeviceInit, cbLength, status); + + return status; + } + + pCur = m_IDsAllocation; + + m_HardwareIDs = pCur; + pCur = FxCopyMultiSz(m_HardwareIDs, &pPdo->HardwareIDs); + + m_CompatibleIDs = pCur; + pCur = FxCopyMultiSz(m_CompatibleIDs, &pPdo->CompatibleIDs); + + if (pPdo->DeviceID != NULL) { + m_DeviceID = pCur; + + // + // Copy the bytes and then null terminate the buffer + // + cbStrLength = pPdo->DeviceID->ByteLength(FALSE); + + RtlCopyMemory(m_DeviceID, + pPdo->DeviceID->Buffer(), + cbStrLength); + + m_DeviceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL; + + pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_DeviceID, + cbStrLength + sizeof(UNICODE_NULL)); + } + + if (pPdo->InstanceID != NULL) { + m_InstanceID = pCur; + + // + // Copy the bytes and then null terminate the buffer + // + cbStrLength = pPdo->InstanceID->ByteLength(FALSE); + + RtlCopyMemory(m_InstanceID, + pPdo->InstanceID->Buffer(), + cbStrLength); + + m_InstanceID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL; + + pCur = (PWSTR) WDF_PTR_ADD_OFFSET(m_InstanceID, + cbStrLength + sizeof(UNICODE_NULL)); + } + + if (pPdo->ContainerID != NULL) { + m_ContainerID = pCur; + + // + // Copy the bytes and then null terminate the buffer + // + cbStrLength = pPdo->ContainerID->ByteLength(FALSE); + + RtlCopyMemory(m_ContainerID, + pPdo->ContainerID->Buffer(), + cbStrLength); + + m_ContainerID[cbStrLength / sizeof(WCHAR)] = UNICODE_NULL; + } + + m_Static = pPdo->Static; + + if (m_Static) { + // + // Statically enumerated children do not support reenumeration requests + // from the stack on top of them. + // + + // + // The only way we can have static children is if an FDO enumerates them. + // + + + + + + Mx::MxAssert(m_Device->m_ParentDevice->IsFdo()); + m_OwningChildList = m_Device->m_ParentDevice->GetFdoPkg()->m_StaticDeviceList; + + m_OwningChildList->ADDREF(this); + } + else { + m_Description = pPdo->DescriptionEntry; + + m_OwningChildList = m_Description->GetParentList(); + m_OwningChildList->ADDREF(this); + } + + return STATUS_SUCCESS; +} + +VOID +FxPkgPdo::FinishInitialize( + __in PWDFDEVICE_INIT DeviceInit + ) +{ + PdoInit* pdoInit; + + pdoInit = &DeviceInit->Pdo; + + m_DefaultLocale = pdoInit->DefaultLocale; + m_DeviceTextHead.Next = pdoInit->DeviceText.Next; + pdoInit->DeviceText.Next = NULL; + + // + // Important to do this last since this will cause a pnp state machine + // transition + // + __super::FinishInitialize(DeviceInit); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::SendIrpSynchronously( + __in FxIrp* Irp + ) +/*++ + +Routine Description: + Virtual override for synchronously sending a request down the stack and + catching it on the way back up. For PDOs, we are the bottom, so this is a + no-op. + +Arguments: + Irp - The request + +Return Value: + Status in the Irp + + --*/ +{ + return Irp->GetStatus(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::FireAndForgetIrp( + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + Virtual override for sending a request down the stack and forgetting about + it. Since we are the bottom of the stack, just complete the request. + +Arguments: + +Return Value: + +--*/ +{ + NTSTATUS status; + + status = Irp->GetStatus(); + + if (Irp->GetMajorFunction() == IRP_MJ_POWER) { + return CompletePowerRequest(Irp, status); + } + else { + return CompletePnpRequest(Irp, status); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpCompleteIrp( + __in FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, Irp->GetStatus()); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryDeviceRelations( + __in FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->PnpQueryDeviceRelations(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PnpQueryDeviceRelations( + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is called in response to a PnP QDR. PDOs handle Ejection + Relations and Target Relations. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + PDEVICE_RELATIONS pDeviceRelations; + NTSTATUS status; + DEVICE_RELATION_TYPE type; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + status = Irp->GetStatus(); + pFxDriverGlobals = GetDriverGlobals(); + + type = Irp->GetParameterQDRType(); + switch (type) { + case BusRelations: + status = HandleQueryBusRelations(Irp); + break; + + case EjectionRelations: + case RemovalRelations: + status = HandleQueryDeviceRelations( + Irp, + (type == RemovalRelations) ? m_RemovalDeviceList + : m_EjectionDeviceList); + + // + // STATUS_NOT_SUPPORTED is a special value. It means that + // HandleQueryDeviceRelations did not modify the irp at all and it + // should be sent off as is. + // + if (status == STATUS_NOT_SUPPORTED) { + // + // Complete the request with the status it was received with + // + status = Irp->GetStatus(); + } + break; + + case TargetDeviceRelation: + pDeviceRelations = (PDEVICE_RELATIONS) MxMemory::MxAllocatePoolWithTag( + PagedPool, sizeof(DEVICE_RELATIONS), pFxDriverGlobals->Tag); + + if (pDeviceRelations != NULL) { + PDEVICE_OBJECT pDeviceObject; + + pDeviceObject = reinterpret_cast (m_Device->GetDeviceObject()); + + Mx::MxReferenceObject(pDeviceObject); + + pDeviceRelations->Count = 1; + pDeviceRelations->Objects[0] = pDeviceObject; + + Irp->SetInformation((ULONG_PTR) pDeviceRelations); + status = STATUS_SUCCESS; + } + else { + Irp->SetInformation(NULL); + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p failing TargetDeviceRelations, %!STATUS!", + m_Device->GetHandle(), status); + } + break; + } + + return CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryInterface( + IN FxPkgPnp* This, + IN FxIrp *Irp + ) +/*++ + +Routine Description: + Query interface handler for the PDO + +Arguments: + This - the package + + Irp - the QI request + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + BOOLEAN completeIrp; + + status = ((FxPkgPdo*) This)->HandleQueryInterface(Irp, &completeIrp); + + return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryCapabilities( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->PnpQueryCapabilities(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PnpQueryCapabilities( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryCapabilities IRP. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + PDEVICE_CAPABILITIES pDeviceCapabilities; + STACK_DEVICE_CAPABILITIES parentStackCapabilities = {0}; + NTSTATUS status; + + status = STATUS_UNSUCCESSFUL; + + pDeviceCapabilities = Irp->GetParameterDeviceCapabilities(); + + // + // Confirm this is a valid DeviceCapabilities structure. + // + ASSERT(pDeviceCapabilities->Size >= sizeof(DEVICE_CAPABILITIES)); + ASSERT(pDeviceCapabilities->Version == 1); + + if ((pDeviceCapabilities->Version == 1) && + (pDeviceCapabilities->Size >= sizeof(DEVICE_CAPABILITIES))) { + + // + // Since query caps must be sent to the parent stack until it reaches + // the root, we can quickly run out of stack space. If that happens, + // then move to a work item to get a fresh stack with plenty of stack + // space. + // + if (Mx::MxHasEnoughRemainingThreadStack() == FALSE) { + MxWorkItem workItem; + + status = workItem.Allocate(m_Device->GetDeviceObject()); + + if (NT_SUCCESS(status)) { + // + // Store off the work item so we can free it in the worker routine + // + Irp->SetContext(0, (PVOID)workItem.GetWorkItem()); + + // + // Mark the irp as pending because it will be completed in + // another thread + // + Irp->MarkIrpPending(); + + // + // Kick off to another thread + // + workItem.Enqueue(_QueryCapsWorkItem, Irp->GetIrp()); + + return STATUS_PENDING; + } + else { + // + // Not enough for a work item, return error + // + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else { + MxDeviceObject parentDeviceObject; + + parentDeviceObject.SetObject( + m_Device->m_ParentDevice->GetDeviceObject()); + status = GetStackCapabilities( + GetDriverGlobals(), + &parentDeviceObject, + NULL, // D3ColdInterface + &parentStackCapabilities); + + if (NT_SUCCESS(status)) { +#pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "prefast is confused") + HandleQueryCapabilities(pDeviceCapabilities, + &parentStackCapabilities.DeviceCaps); + + // + // The check above does not guarantee STATUS_SUCCESS explicitly + // (ie the verifier can change the value to something other then + // STATUS_SUCCESS) so set it here + // + status = STATUS_SUCCESS; + } + } + } + + return CompletePnpRequest(Irp, status); +} + +VOID +FxPkgPdo::HandleQueryCapabilities( + __inout PDEVICE_CAPABILITIES ReportedCaps, + __in_bcount(ParentCaps->size) PDEVICE_CAPABILITIES ParentCaps + ) +{ + LONG pnpCaps; + ULONG i; + + // + // PowerSystemUnspecified is reserved for system use as per the DDK + // + for (i = PowerSystemWorking; i < PowerSystemMaximum; i++) { + DEVICE_POWER_STATE state; + + state = _GetPowerCapState(i, m_PowerCaps.States); + + if (state == PowerDeviceMaximum) { + // + // PDO did not specify any value, use parent's cap + // +#pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "Esp:675") + ReportedCaps->DeviceState[i] = ParentCaps->DeviceState[i]; + } + else { + // + // Use PDO's reported value + // + ReportedCaps->DeviceState[i] = state; + } + } + + pnpCaps = GetPnpCapsInternal(); + + // + // Appropriately fill the DeviceCapabilities structure. + // + SET_PNP_CAP(pnpCaps, ReportedCaps, LockSupported); + SET_PNP_CAP(pnpCaps, ReportedCaps, EjectSupported); + SET_PNP_CAP(pnpCaps, ReportedCaps, Removable); + SET_PNP_CAP(pnpCaps, ReportedCaps, DockDevice); + SET_PNP_CAP(pnpCaps, ReportedCaps, UniqueID); + + if ((pnpCaps & FxPnpCapSilentInstallMask) != FxPnpCapSilentInstallUseDefault) { + SET_PNP_CAP(pnpCaps, ReportedCaps, SilentInstall); + } + else if (m_RawOK) { + // + // By default, we report raw devices as silent install devices + // because if they are raw, they don't need any further + // installation. + // + ReportedCaps->SilentInstall = TRUE; + } + + SET_PNP_CAP(pnpCaps, ReportedCaps, SurpriseRemovalOK); + SET_PNP_CAP(pnpCaps, ReportedCaps, HardwareDisabled); + SET_PNP_CAP(pnpCaps, ReportedCaps, NoDisplayInUI); + + SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD0); + SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD1); + SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD2); + SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, WakeFromD3); + SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, DeviceD1); + SET_POWER_CAP(m_PowerCaps.Caps , ReportedCaps, DeviceD2); + + if (m_RawOK) { + ReportedCaps->RawDeviceOK = TRUE; + } + + ReportedCaps->UINumber = m_PnpCapsUINumber; + ReportedCaps->Address = m_PnpCapsAddress; + + if (m_PowerCaps.SystemWake != PowerSystemMaximum) { + ReportedCaps->SystemWake = (SYSTEM_POWER_STATE) m_PowerCaps.SystemWake; + } + else { + ReportedCaps->SystemWake = ParentCaps->SystemWake; + } + + // + // Set the least-powered device state from which the device can + // wake the system. + // + if (m_PowerCaps.DeviceWake != PowerDeviceMaximum) { + ReportedCaps->DeviceWake = (DEVICE_POWER_STATE) m_PowerCaps.DeviceWake; + } + else { + ReportedCaps->DeviceWake = ParentCaps->DeviceWake; + } + + // + // Set the Device wake up latencies. + // + if (m_PowerCaps.D1Latency != (ULONG) -1) { + ReportedCaps->D1Latency = m_PowerCaps.D1Latency; + } + else { + ReportedCaps->D1Latency = 0; + } + + if (m_PowerCaps.D2Latency != (ULONG) -1) { + ReportedCaps->D2Latency = m_PowerCaps.D2Latency; + } + else { + ReportedCaps->D2Latency = 0; + } + + if (m_PowerCaps.D3Latency != (ULONG) -1) { + ReportedCaps->D3Latency = m_PowerCaps.D3Latency; + } +} + +VOID +FxPkgPdo::_QueryCapsWorkItem( + __in MdDeviceObject DeviceObject, + __in PVOID Context + ) +{ + STACK_DEVICE_CAPABILITIES parentCapabilities; + MdWorkItem pItem; + FxPkgPdo* pPkgPdo; + FxIrp irp; + NTSTATUS status; + MxDeviceObject parentDeviceObject; + + irp.SetIrp((MdIrp)Context); + pItem = (MdWorkItem) irp.GetContext(0); + + pPkgPdo = FxDevice::GetFxDevice(DeviceObject)->GetPdoPkg(); + + parentDeviceObject.SetObject( + pPkgPdo->m_Device->m_ParentDevice->GetDeviceObject()); + + status = GetStackCapabilities( + pPkgPdo->m_Device->GetDriverGlobals(), + &parentDeviceObject, + NULL, // D3ColdInterface + &parentCapabilities); + + if (NT_SUCCESS(status)) { +#pragma prefast(suppress:__WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY, "prefast is confused") + pPkgPdo->HandleQueryCapabilities( + irp.GetParameterDeviceCapabilities(), + &parentCapabilities.DeviceCaps + ); + status = STATUS_SUCCESS; + } + + pPkgPdo->CompletePnpRequest(&irp, status); + + MxWorkItem::_Free(pItem); +} + +FxDeviceText * +FindObjectForGivenLocale( + __in PSINGLE_LIST_ENTRY Head, + __in LCID LocaleId + ) + +/*++ + +Routine Description: + + + +Arguments: + +Returns: + +--*/ + +{ + PSINGLE_LIST_ENTRY ple; + + for (ple = Head->Next; ple != NULL; ple = ple->Next) { + FxDeviceText *pDeviceText; + + pDeviceText= FxDeviceText::_FromEntry(ple); + + if (pDeviceText->m_LocaleId == LocaleId) { + // + // We found our object! + // + return pDeviceText; + } + } + + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryDeviceText( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryDeviceText IRP. + We return the decription or the location. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + FxPkgPdo* pThis; + LCID localeId; + FxDeviceText *pDeviceTextObject; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pThis = (FxPkgPdo*) This; + pFxDriverGlobals = pThis->GetDriverGlobals(); + + localeId = Irp->GetParameterQueryDeviceTextLocaleId(); + status = Irp->GetStatus(); + + // + // The PDO package maintains a collection of "DeviceText" objects. We + // will look up the item in the collection with the "appropriate" locale. + // + // If no entries are found in the collection for the given locale, then + // we will use the "default locale" property of the PDO and use the + // entry for the "default locale". + // + + // + // Try to find the FxDeviceText object for the given locale. + // + pDeviceTextObject = FindObjectForGivenLocale( + &pThis->m_DeviceTextHead, localeId); + + if (pDeviceTextObject == NULL) { + pDeviceTextObject = FindObjectForGivenLocale( + &pThis->m_DeviceTextHead, pThis->m_DefaultLocale); + } + + if (pDeviceTextObject != NULL) { + PWCHAR pInformation; + + pInformation = NULL; + + switch (Irp->GetParameterQueryDeviceTextType()) { + case DeviceTextDescription: + pInformation = pDeviceTextObject->m_Description; + break; + + case DeviceTextLocationInformation: + pInformation = pDeviceTextObject->m_LocationInformation; + break; + } + + // + // Information should now point to a valid unicode string. + // + if (pInformation != NULL) { + PWCHAR pBuffer; + size_t length; + + length = (wcslen(pInformation) + 1) * sizeof(WCHAR); + + // + // Make sure the information field of the IRP isn't already set. + // + ASSERT(Irp->GetInformation() == NULL); + + pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag( + PagedPool, length, pFxDriverGlobals->Tag); + + if (pBuffer != NULL) { + RtlCopyMemory(pBuffer, pInformation, length); + Irp->SetInformation((ULONG_PTR) pBuffer); + + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p failing Query Device Text, type %d, %!STATUS!", + pThis->m_Device->GetHandle(), + Irp->GetParameterQueryDeviceTextType(), status); + } + } + } + + return pThis->CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpEject( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + Ejection is handled by the PnP state machine. Handle it synchronously. + Don't pend it since PnP manager does not serilaize it with other state + changing pnp irps if handled asynchronously. + +Arguments: + + This - the package + + Irp - the request + +Return Value: + + NTSTATUS + + --*/ +{ + MxEvent event; + FxPkgPdo* pdoPkg; + NTSTATUS status; + + pdoPkg = (FxPkgPdo*)This; + + // + // This will make sure no new state changing pnp irps arrive while + // we are still processing this one. Also, note that irp is not being + // marked pending. + // + pdoPkg->SetPendingPnpIrp(Irp, FALSE); + + status = event.Initialize(SynchronizationEvent, FALSE); + if (!NT_SUCCESS(status)) { + + DoTraceLevelMessage( + pdoPkg->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Event allocation failed while processing eject for WDFDEVICE %p," + " %!STATUS!", + pdoPkg->m_Device->GetHandle(), status); + } + else { + ASSERT(pdoPkg->m_DeviceEjectProcessed == NULL); + pdoPkg->m_DeviceEjectProcessed = event.GetSelfPointer(); + + // + // let state machine process eject + // + pdoPkg->PnpProcessEvent(PnpEventEject); + + // + // No need to wait in a critical region because we are in the context of a + // pnp request which is in the system context. + // + event.WaitFor(Executive, KernelMode, FALSE, NULL); + + pdoPkg->m_DeviceEjectProcessed = NULL; + + status = Irp->GetStatus(); + } + + // + // complete request + // + + pdoPkg->ClearPendingPnpIrp(); + pdoPkg->CompletePnpRequest(Irp, status); + + return status; +} + +WDF_DEVICE_PNP_STATE +FxPkgPdo::PnpEventEjectHardwareOverload( + VOID + ) +/*++ + +Routine Description: + + This function implements the EjectHardware state. This + function overloads the base PnP State machine handler. Its + job is to call EvtDeviceEject. If that succeeds, then we + transition immediately to EjectedWaitingForRemove. If not, + then to EjectFailed. + +Arguments: + + none + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + WDF_DEVICE_PNP_STATE state; + + status = m_DeviceEject.Invoke(m_Device->GetHandle()); + + if (NT_SUCCESS(status)) { + + // + // Upon a successful eject, mark the child as missing so that when we + // get another QDR, it is not re-reported. + // + FxChildList* pList; + MxEvent* event; + + pList = m_Description->GetParentList(); + + status = pList->UpdateAsMissing(m_Description->GetId()); + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "PDO WDFDEVICE %p !devobj %p marked missing as a result of eject", + m_Device->GetHandle(), m_Device->GetDeviceObject()); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to mark PDO WDFDEVICE %p !devobj %p missing after eject %!STATUS!", + m_Device->GetHandle(), m_Device->GetDeviceObject(), + status); + } + + // + // We must wait for any pending scans to finish so that the previous + // update as missing is enacted into the list and reported to the + // OS. Otherwise, if we don't wait we could be in the middle of a + // scan, complete the eject, report the child again and it will be + // reenumerated. + // + event = pList->GetScanEvent(); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "waiting on event %p for device to finish scanning", + &event); + + // + // No need to wait in a crtical region because we are in the context of a + // pnp request which is in the system context. + // + event->WaitFor(Executive, KernelMode, FALSE, NULL); + + // + // Change the state. + // + state = WdfDevStatePnpEjectedWaitingForRemove; + } + else { + state = WdfDevStatePnpEjectFailed; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Eject failed since driver's EvtDeviceEject returned %!STATUS!", status); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "EvtDeviceEject returned an invalid status STATUS_NOT_SUPPORTED"); + + if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + } + + // + // set irp status + // + SetPendingPnpIrpStatus(status); + + // + // Pnp dispatch routine is waiting on this event, and it will complete + // the Eject irp + // + m_DeviceEjectProcessed->Set(); + + return state; +} + +WDF_DEVICE_PNP_STATE +FxPkgPdo::PnpEventCheckForDevicePresenceOverload( + VOID + ) +/*++ + +Routine Description: + + This function implements the CheckForDevicePresence state. This + function overloads the base PnP State machine handler. It's + job is to figure out whether the removed device is actually + still attached. It then changes state based on that result. + +Arguments: + + none + +Return Value: + + NTSTATUS + +--*/ + +{ + if (m_Description != NULL) { + if (m_Description->IsDeviceRemoved()) { + // + // The description freed itself now that the device has been reported + // missing. + // + return WdfDevStatePnpPdoRemoved; + } + else { + // + // Device was not reported as missing, keep it alive + // + return WdfDevStatePnpRemovedPdoWait; + } + } + else { + // + // Only static children can get this far without having an m_Description + // + ASSERT(m_Static); + + // + // The description freed itself now that the device has been reported + // missing. + // + return WdfDevStatePnpPdoRemoved; + } +} + +WDF_DEVICE_PNP_STATE +FxPkgPdo::PnpEventPdoRemovedOverload( + VOID + ) +/*++ + +Routine Description: + + This function implements the Removed state. This + function overloads the base PnP State machine handler. + +Arguments: + + none + +Return Value: + + NTSTATUS + +--*/ +{ + m_CanBeDeleted = TRUE; + + // + // Unconditionally delete the symbolic link now (vs calling + // DeleteSymbolicLinkOverload()) because we know that the device has been + // reported as missing. + // + m_Device->DeleteSymbolicLink(); + + // + // Do that which all device stacks need to do upon removal. + // + PnpEventRemovedCommonCode(); + + // + // m_Device is Release()'ed in FxPkgPnp::PnpEventFinal + // + if (m_Description != NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Removing entry reference %p on FxPkgPnp %p", + m_Description, this); + + m_Description->ProcessDeviceRemoved(); + m_Description = NULL; + } + + return WdfDevStatePnpFinal; +} + +WDF_DEVICE_PNP_STATE +FxPkgPdo::PnpGetPostRemoveState( + VOID + ) +{ + // + // Transition to the check for device presence state. + // + return WdfDevStatePnpCheckForDevicePresence; +} + +WDF_DEVICE_PNP_STATE +FxPkgPdo::PnpEventFdoRemovedOverload( + VOID + ) +{ + ASSERT(!"This should only be implemented for FDOs."); + + // + // Do something safe. Act like the device is not present. + // + return WdfDevStatePnpFinal; +} + +VOID +FxPkgPdo::PnpEventSurpriseRemovePendingOverload( + VOID + ) +{ + if (m_Description != NULL) { + m_Description->DeviceSurpriseRemoved(); + } + + FxPkgPnp::PnpEventSurpriseRemovePendingOverload(); +} + +BOOLEAN +FxPkgPdo::PnpSendStartDeviceDownTheStackOverload( + VOID + ) +/*++ + +Routine Description: + Process the start irp on the way down the stack during a start. + + Since the PDO is the bottom, just move to the new state where we + are processing the irp up the stack. + +Arguments: + None + +Return Value: + TRUE, the completion of the start irp down the stack was synchronous + + --*/ +{ + // + // We are successful so far, indicate this in the irp. + // + SetPendingPnpIrpStatus(STATUS_SUCCESS); + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpSetLock( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + Set lock + +Arguments: + This - the package + + Irp - the irp + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + BOOLEAN lock; + + lock = Irp->GetParameterSetLockLock(); + + status = ((FxPkgPdo*) This)->m_DeviceSetLock.Invoke( + ((FxPkgPdo*) This)->m_Device->GetHandle(), lock); + + if (NT_SUCCESS(status)) { + Irp->SetInformation(NULL); + } + + return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryId( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + FxPkgPdo* pThis; + NTSTATUS status; + PWCHAR pBuffer; + PCWSTR pSrc; + size_t cbLength; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + BUS_QUERY_ID_TYPE queryIdType; + + pThis = (FxPkgPdo*) This; + pFxDriverGlobals = pThis->GetDriverGlobals(); + status = Irp->GetStatus(); + cbLength = 0; + + queryIdType = Irp->GetParameterQueryIdType(); + + switch (queryIdType) { + case BusQueryDeviceID: + case BusQueryInstanceID: + case BusQueryContainerID: + if (queryIdType == BusQueryDeviceID) { + pSrc = pThis->m_DeviceID; + } + else if (queryIdType == BusQueryInstanceID) { + pSrc = pThis->m_InstanceID; + } + else { + pSrc = pThis->m_ContainerID; + } + + if (pSrc != NULL) { + cbLength = (wcslen(pSrc) + 1) * sizeof(WCHAR); + + pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag( + PagedPool, cbLength, pFxDriverGlobals->Tag); + } + else { + status = Irp->GetStatus(); + break; + } + + if (pBuffer != NULL) { + + // + // This will copy the NULL terminator too + // + RtlCopyMemory(pBuffer, pSrc, cbLength); + Irp->SetInformation((ULONG_PTR) pBuffer); + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + + case BusQueryHardwareIDs: + case BusQueryCompatibleIDs: + if (queryIdType == BusQueryHardwareIDs) { + pSrc = pThis->m_HardwareIDs; + } + else { + pSrc = pThis->m_CompatibleIDs; + } + + if (pSrc != NULL) { + cbLength = FxCalculateTotalMultiSzStringSize(pSrc); + } + else { + // + // Must return an empty list + // + cbLength = 2 * sizeof(UNICODE_NULL); + } + + pBuffer = (PWCHAR) MxMemory::MxAllocatePoolWithTag( + PagedPool, cbLength, pFxDriverGlobals->Tag); + + if (pBuffer != NULL) { + if (pSrc != NULL) { + RtlCopyMemory(pBuffer, pSrc, cbLength); + } + else { + RtlZeroMemory(pBuffer, cbLength); + } + + Irp->SetInformation((ULONG_PTR) pBuffer); + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + break; + } + + if (!NT_SUCCESS(status)) { + Irp->SetInformation(NULL); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p does not have a string for PnP query IdType " + "%!BUS_QUERY_ID_TYPE!, %!STATUS!", + pThis->m_Device->GetHandle(), + queryIdType, status); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p could not alloc string for PnP query IdType " + "%!BUS_QUERY_ID_TYPE!, %!STATUS!", + pThis->m_Device->GetHandle(), + queryIdType, status); + } + } + + return ((FxPkgPdo*) pThis)->CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryPnpDeviceState( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + indicates the current device state + +Arguments: + This - the package + + Irp - the request + +Return Value: + NTSTATUS + + --*/ +{ + PNP_DEVICE_STATE pnpDeviceState; + PFX_DRIVER_GLOBALS FxDriverGlobals = This->GetDriverGlobals(); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering QueryPnpDeviceState handler"); + + pnpDeviceState = ((FxPkgPdo*) This)->HandleQueryPnpDeviceState( + (PNP_DEVICE_STATE) Irp->GetInformation()); + + Irp->SetInformation((ULONG_PTR) pnpDeviceState); + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p returning PNP_DEVICE_STATE 0x%d IRP 0x%p", + This->GetDevice()->GetHandle(), + This->GetDevice()->GetDeviceObject(), + pnpDeviceState, + Irp->GetIrp()); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting QueryPnpDeviceState handler"); + + return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, STATUS_SUCCESS); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryBusInformation( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + Returns the bus information for this child + +Arguments: + This - the package + + Irp - the request + +Return Value: + NTSTATUS + + --*/ +{ + FxPkgPdo* pThis; + NTSTATUS status; + + pThis = (FxPkgPdo*) This; + + status = pThis->m_Device->m_ParentDevice->m_PkgPnp-> + HandleQueryBusInformation(Irp); + + return pThis->CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpSurpriseRemoval( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + FxPkgPdo* pThis; + + pThis = (FxPkgPdo*) This; + + pThis->m_Description->DeviceSurpriseRemoved(); + + return pThis->PnpSurpriseRemoval(Irp); +} + +VOID +FxPkgPdo::RegisterCallbacks( + __in PWDF_PDO_EVENT_CALLBACKS DispatchTable + ) +{ + m_DeviceResourcesQuery.m_Method = DispatchTable->EvtDeviceResourcesQuery; + m_DeviceResourceRequirementsQuery.m_Method = DispatchTable->EvtDeviceResourceRequirementsQuery; + m_DeviceEject.m_Method = DispatchTable->EvtDeviceEject; + m_DeviceSetLock.m_Method = DispatchTable->EvtDeviceSetLock; + + m_DeviceEnableWakeAtBus.m_Method = DispatchTable->EvtDeviceEnableWakeAtBus; + m_DeviceDisableWakeAtBus.m_Method = DispatchTable->EvtDeviceDisableWakeAtBus; + + // + // this callback was added in V1.11 + // + if (DispatchTable->Size > sizeof(WDF_PDO_EVENT_CALLBACKS_V1_9)) { + m_DeviceReportedMissing.m_Method = DispatchTable->EvtDeviceReportedMissing; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::AskParentToRemoveAndReenumerate( + VOID + ) +/*++ + +Routine Description: + This routine asks the PDO to ask its parent bus driver to Surprise-Remove + and re-enumerate the PDO. This will be done only at the point of + catastrophic software failure, and occasionally after catastrophic hardware + failure. + +Arguments: + None + +Return Value: + status + + --*/ +{ + // + // Static children do not support reenumeration. + // + if (m_Description != NULL && m_Static == FALSE) { + m_Description->GetParentList()->ReenumerateEntry(m_Description); + return STATUS_SUCCESS; + } + + return STATUS_NOT_FOUND; +} + + +VOID +FxPkgPdo::DeleteSymbolicLinkOverload( + __in BOOLEAN GracefulRemove + ) +/*++ + +Routine Description: + Role specific virtual function which determines if the symbolic link for a + device should be deleted. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (GracefulRemove) { + // + // We will remove the symbolic link when we determine if the PDO was + // reported missing or not. + // + return; + } + else if (m_Description->IsDeviceReportedMissing()) { + // + // Surprise removed and we have reported the PDO as missing + // + + m_Device->DeleteSymbolicLink(); + } +} + + +VOID +FxPkgPdo::_RemoveAndReenumerateSelf( + __in PVOID Context + ) +/*++ + +Routine Description: + This routine is passed out to higher-level drivers as part of the + re-enumeration interface. + +Arguments: + This + +Return Value: + void + + --*/ +{ + ((FxPkgPdo*) Context)->AskParentToRemoveAndReenumerate(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::HandleQueryInterfaceForReenumerate( + __in FxIrp* Irp, + __out PBOOLEAN CompleteRequest + ) +/*++ + +Routine Description: + Handles a query interface on the PDO for the self reenumeration interface. + +Arguments: + Irp - the request containing the QI + + CompleteRequest - whether the caller should complete the request when this + call returns + +Return Value: + status to complete the irp with + + --*/ +{ + PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; + NTSTATUS status; + + *CompleteRequest = TRUE; + + if (m_Static) { + // + // Return the embedded status in the irp since this is a statically + // enumerated child. Only dynamically enuemrated child support self + // reenumeration. + // + return Irp->GetStatus(); + } + + if (Irp->GetParameterQueryInterfaceVersion() == 1 && + Irp->GetParameterQueryInterfaceSize() >= sizeof(*pInterface)) { + + pInterface = (PREENUMERATE_SELF_INTERFACE_STANDARD) + Irp->GetParameterQueryInterfaceInterface(); + + // + // Expose the interface to the requesting driver. + // + pInterface->Version = 1; + pInterface->Size = sizeof(*pInterface); + pInterface->Context = this; + pInterface->InterfaceReference = FxDevice::_InterfaceReferenceNoOp; + pInterface->InterfaceDereference = FxDevice::_InterfaceDereferenceNoOp; + pInterface->SurpriseRemoveAndReenumerateSelf = &FxPkgPdo::_RemoveAndReenumerateSelf; + + status = STATUS_SUCCESS; + + // + // Caller assumes a reference has been taken. + // + pInterface->InterfaceReference(pInterface->Context); + } + else { + status = STATUS_INVALID_BUFFER_SIZE; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::ProcessRemoveDeviceOverload( + __inout FxIrp* Irp + ) +{ + if (m_CanBeDeleted) { + // + // After this is called, any irp dispatched to FxDevice::DispatchWithLock + // will fail with STATUS_INVALID_DEVICE_REQUEST. + // + + + + + + + + Mx::MxReleaseRemoveLockAndWait( + m_Device->GetRemoveLock(), + Irp->GetIrp() + ); + + // + // Cleanup the state machines and release the power thread. + // + CleanupStateMachines(TRUE); + + // + // Detach and delete the device object. + // + DeleteDevice(); + + // + // Can't call CompletePnpRequest because we just released the tag in + // IoReleaseRemoveLockAndWait above. + // + Irp->CompleteRequest(IO_NO_INCREMENT); + + return STATUS_SUCCESS; + } + else { + // + // This was a PDO which was not reported missing, so do not free the + // memory and clear out our stack local address. + // + m_DeviceRemoveProcessed = NULL; + return CompletePnpRequest(Irp, Irp->GetStatus()); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::QueryForPowerThread( + VOID + ) +/*++ + +Routine Description: + Since the PDO is the lowest device in the stack, it does not have to send + a query down the stack. Rather, it just creates the thread and returns. + +Arguments: + None + +Return Value: + NTSTATUS + + --*/ +{ + return CreatePowerThread(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::AddEjectionDevice( + __in MdDeviceObject DependentDevice + ) +{ + FxRelatedDevice* pRelated; + NTSTATUS status; + + if (m_EjectionDeviceList == NULL) { + KIRQL irql; + + Lock(&irql); + if (m_EjectionDeviceList == NULL) { + m_EjectionDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList(); + + if (m_EjectionDeviceList != NULL) { + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate ejection device list for PDO WDFDEVICE %p", + + m_Device->GetHandle()); + } + } + else { + // + // another thread allocated the list already + // + status = STATUS_SUCCESS; + } + Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + pRelated = new(GetDriverGlobals()) + FxRelatedDevice(DependentDevice, GetDriverGlobals()); + + if (pRelated == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = m_EjectionDeviceList->Add(GetDriverGlobals(), pRelated); + + if (NT_SUCCESS(status)) { + // + // EjectRelations are queried automatically by PnP when the device is + // going to be ejected. No need to tell pnp that the list changed + // until it needs to query for it. + // + DO_NOTHING(); + } + else { + pRelated->DeleteFromFailedCreate(); + } + + return status; +} + +VOID +FxPkgPdo::RemoveEjectionDevice( + __in MdDeviceObject DependentDevice + ) +{ + if (m_EjectionDeviceList != NULL) { + m_EjectionDeviceList->Remove(GetDriverGlobals(), DependentDevice); + } + + // + // EjectRelations are queried automatically by PnP when the device is + // going to be ejected. No need to tell pnp that the list changed + // until it needs to query for it. + // +} + +VOID +FxPkgPdo::ClearEjectionDevicesList( + VOID + ) +{ + FxRelatedDevice* pEntry; + + if (m_EjectionDeviceList != NULL) { + m_EjectionDeviceList->LockForEnum(GetDriverGlobals()); + while ((pEntry = m_EjectionDeviceList->GetNextEntry(NULL)) != NULL) { + m_EjectionDeviceList->Remove(GetDriverGlobals(), + pEntry->GetDevice()); + } + m_EjectionDeviceList->UnlockFromEnum(GetDriverGlobals()); + } + + // + // EjectRelations are queried automatically by PnP when the device is + // going to be ejected. No need to tell pnp that the list changed + // until it needs to query for it. + // +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgpnp.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgpnp.cpp new file mode 100644 index 00000000000..8df92503d37 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/fxpkgpnp.cpp @@ -0,0 +1,6487 @@ +/*++ + + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxPkgPnp.cpp + +Abstract: + + This module implements the pnp IRP handlers for the driver framework. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + +--*/ + +#include "pnppriv.hpp" + +#include +#include + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxPkgPnp.tmh" +#endif + +} + +/* dc7a8e51-49b3-4a3a-9e81-625205e7d729 */ +const GUID FxPkgPnp::GUID_POWER_THREAD_INTERFACE = { + 0xdc7a8e51, 0x49b3, 0x4a3a, { 0x9e, 0x81, 0x62, 0x52, 0x05, 0xe7, 0xd7, 0x29 } +}; + +FxPkgPnp::FxPkgPnp( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice* Device, + __in WDFTYPE Type + ) : + FxPackage(FxDriverGlobals, Device, Type) +{ + ULONG i; + + m_DmaEnablerList = NULL; + m_RemovalDeviceList = NULL; + m_UsageDependentDeviceList = NULL; + + // + // Initialize the structures to the default state and then override the + // non WDF std default values to the unsupported / off values. + // + m_PnpStateAndCaps.Value = + FxPnpStateDisabledUseDefault | + FxPnpStateDontDisplayInUIUseDefault | + FxPnpStateFailedUseDefault | + FxPnpStateNotDisableableUseDefault | + FxPnpStateRemovedUseDefault | + FxPnpStateResourcesChangedUseDefault | + + FxPnpCapLockSupportedUseDefault | + FxPnpCapEjectSupportedUseDefault | + FxPnpCapRemovableUseDefault | + FxPnpCapDockDeviceUseDefault | + FxPnpCapUniqueIDUseDefault | + FxPnpCapSilentInstallUseDefault | + FxPnpCapSurpriseRemovalOKUseDefault | + FxPnpCapHardwareDisabledUseDefault | + FxPnpCapNoDisplayInUIUseDefault + ; + + m_PnpCapsAddress = (ULONG) -1; + m_PnpCapsUINumber = (ULONG) -1; + + RtlZeroMemory(&m_PowerCaps, sizeof(m_PowerCaps)); + m_PowerCaps.Caps = + FxPowerCapDeviceD1UseDefault | + FxPowerCapDeviceD2UseDefault | + FxPowerCapWakeFromD0UseDefault | + FxPowerCapWakeFromD1UseDefault | + FxPowerCapWakeFromD2UseDefault | + FxPowerCapWakeFromD3UseDefault + ; + + m_PowerCaps.DeviceWake = PowerDeviceMaximum; + m_PowerCaps.SystemWake = PowerSystemMaximum; + + m_PowerCaps.D1Latency = (ULONG) -1; + m_PowerCaps.D2Latency = (ULONG) -1; + m_PowerCaps.D3Latency = (ULONG) -1; + + m_PowerCaps.States = 0; + for (i = 0; i < PowerSystemMaximum; i++) { + _SetPowerCapState(i, PowerDeviceMaximum, &m_PowerCaps.States); + } + + RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface)); + RtlZeroMemory(&m_SpecialSupport[0], sizeof(m_SpecialSupport)); + RtlZeroMemory(&m_SpecialFileCount[0], sizeof(m_SpecialFileCount)); + + m_PowerThreadInterface.Interface.Size = sizeof(m_PowerThreadInterface); + m_PowerThreadInterface.Interface.Version = 1; + m_PowerThreadInterface.Interface.Context = this; + m_PowerThreadInterface.Interface.InterfaceReference = &FxPkgPnp::_PowerThreadInterfaceReference; + m_PowerThreadInterface.Interface.InterfaceDereference = &FxPkgPnp::_PowerThreadInterfaceDereference; + m_PowerThreadInterface.PowerThreadEnqueue = &FxPkgPnp::_PowerThreadEnqueue; + m_PowerThread = NULL; + m_HasPowerThread = FALSE; + m_PowerThreadInterfaceReferenceCount = 1; + m_PowerThreadEvent = NULL; + + m_DeviceStopCount = 0; + m_CapsQueried = FALSE; + m_InternalFailure = FALSE; + m_FailedAction = WdfDeviceFailedUndefined; + + // + // We only set the pending child count to 1 once we know we have successfully + // created an FxDevice and initialized it fully. If we delete an FxDevice + // which is half baked, it cannot have any FxChildLists which have any + // pending children on them. + // + m_PendingChildCount = 0; + + m_QueryInterfaceHead.Next = NULL; + + m_DeviceInterfaceHead.Next = NULL; + m_DeviceInterfacesCanBeEnabled = FALSE; + + m_Failed = FALSE; + m_SetDeviceRemoveProcessed = FALSE; + + m_SystemPowerState = PowerSystemWorking; + m_DevicePowerState = WdfPowerDeviceD3Final; + m_DevicePowerStateOld = WdfPowerDeviceD3Final; + + m_PendingPnPIrp = NULL; + m_PendingSystemPowerIrp = NULL; + m_PendingDevicePowerIrp = NULL; + m_SystemPowerAction = (UCHAR) PowerActionNone; + + m_PnpStateCallbacks = NULL; + m_PowerStateCallbacks = NULL; + m_PowerPolicyStateCallbacks = NULL; + + m_SelfManagedIoMachine = NULL; + + m_EnumInfo = NULL; + + m_Resources = NULL; + m_ResourcesRaw = NULL; + + InitializeListHead(&m_InterruptListHead); + m_InterruptObjectCount = 0; + m_WakeInterruptCount = 0; + m_WakeInterruptPendingAckCount = 0; + m_SystemWokenByWakeInterrupt = FALSE; + m_WakeInterruptsKeepConnected = FALSE; + m_AchievedStart = FALSE; + + m_SharedPower.m_WaitWakeIrp = NULL; + m_SharedPower.m_WaitWakeOwner = FALSE; + m_SharedPower.m_ExtendWatchDogTimer = FALSE; + + m_DeviceRemoveProcessed = NULL; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // Interrupt APIs for Vista and forward + // + m_IoConnectInterruptEx = FxLibraryGlobals.IoConnectInterruptEx; + m_IoDisconnectInterruptEx = FxLibraryGlobals.IoDisconnectInterruptEx; + + // + // Interrupt APIs for Windows 8 and forward + // + m_IoReportInterruptActive = FxLibraryGlobals.IoReportInterruptActive; + m_IoReportInterruptInactive = FxLibraryGlobals.IoReportInterruptInactive; + +#endif + + m_ReleaseHardwareAfterDescendantsOnFailure = FALSE; + + MarkDisposeOverride(ObjectDoNotLock); +} + +FxPkgPnp::~FxPkgPnp() +{ + PSINGLE_LIST_ENTRY ple; + + Mx::MxAssert(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + // + // We should either have zero pending children or we never made it out of + // the init state during a failed WDFDEVICE create or failed EvtDriverDeviceAdd + // + Mx::MxAssert(m_PendingChildCount == 0 || + m_Device->GetDevicePnpState() == WdfDevStatePnpInit); + + + ple = m_DeviceInterfaceHead.Next; + while (ple != NULL) { + FxDeviceInterface* pDI; + + pDI = FxDeviceInterface::_FromEntry(ple); + + // + // Advance to the next before deleting the current + // + ple = ple->Next; + + // + // No longer in the list + // + pDI->m_Entry.Next = NULL; + + delete pDI; + } + m_DeviceInterfaceHead.Next = NULL; + + if (m_DmaEnablerList != NULL) { + delete m_DmaEnablerList; + m_DmaEnablerList = NULL; + } + + if (m_RemovalDeviceList != NULL) { + delete m_RemovalDeviceList; + m_RemovalDeviceList = NULL; + } + + if (m_UsageDependentDeviceList != NULL) { + delete m_UsageDependentDeviceList; + m_UsageDependentDeviceList = NULL; + } + + if (m_PnpStateCallbacks != NULL) { + delete m_PnpStateCallbacks; + } + + if (m_PowerStateCallbacks != NULL) { + delete m_PowerStateCallbacks; + } + + if (m_PowerPolicyStateCallbacks != NULL) { + delete m_PowerPolicyStateCallbacks; + } + + if (m_SelfManagedIoMachine != NULL) { + delete m_SelfManagedIoMachine; + m_SelfManagedIoMachine = NULL; + } + + if (m_EnumInfo != NULL) { + delete m_EnumInfo; + m_EnumInfo = NULL; + } + + if (m_Resources != NULL) { + m_Resources->RELEASE(this); + m_Resources = NULL; + } + + if (m_ResourcesRaw != NULL) { + m_ResourcesRaw->RELEASE(this); + m_ResourcesRaw = NULL; + } + + ASSERT(IsListEmpty(&m_InterruptListHead)); +} + +BOOLEAN +FxPkgPnp::Dispose( + VOID + ) +{ + PSINGLE_LIST_ENTRY ple; + + // + // All of the interrupts were freed during this object's dispose path. This + // is because all of the interrupts were attached as children to this object. + // + // It is safe to just reinitialize the list head. + // + InitializeListHead(&m_InterruptListHead); + + m_QueryInterfaceLock.AcquireLock(GetDriverGlobals()); + + // + // A derived class can insert an embedded FxQueryInterface into the QI list, + // so clear out the list before the destructor chain runs. (The derived + // class will be destructed first, as such, the embedded FxQueryInterface + // will also destruct first and complain it is still in a list. + // + ple = m_QueryInterfaceHead.Next; + + // + // Clear out the head while holding the lock so that we synchronize against + // processing a QI while deleting the list. + // + m_QueryInterfaceHead.Next = NULL; + + m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals()); + + while (ple != NULL) { + FxQueryInterface* pQI; + + pQI = FxQueryInterface::_FromEntry(ple); + + // + // Advance before we potentiall free the structure + // + ple = ple->Next; + + // + // FxQueryInterface's destructor requires Next be NULL + // + pQI->m_Entry.Next = NULL; + + if (pQI->m_EmbeddedInterface == FALSE) { + delete pQI; + } + } + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + DropD3ColdInterface(); +#endif + + // + // Call up the hierarchy + // + return __super::Dispose(); +} + + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::Initialize( + __in PWDFDEVICE_INIT DeviceInit + ) + +/*++ + +Routine Description: + + This function initializes state associated with an instance of FxPkgPnp. + This differs from the constructor because it can do operations which + will fail, and can return failure. (Constructors can't fail, they can + only throw exceptions, which we can't deal with in this kernel mode + environment.) + +Arguments: + + DeviceInit - Struct that the driver initialized that contains defaults. + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + + m_ReleaseHardwareAfterDescendantsOnFailure = (DeviceInit->ReleaseHardwareOrderOnFailure == + WdfReleaseHardwareOrderOnFailureAfterDescendants); + + status = m_QueryInterfaceLock.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGPNP, + "Could not initialize QueryInterfaceLock for " + "WDFDEVICE %p, %!STATUS!", + m_Device->GetHandle(), status); + return status; + } + + status = m_DeviceInterfaceLock.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGPNP, + "Could not initialize DeviceInterfaceLock for " + "WDFDEVICE %p, %!STATUS!", + m_Device->GetHandle(), status); + return status; + } + + // + // Initialize preallocated events for UM + // (For KM, events allocated on stack are used since event initialization + // doesn't fail in KM) + // +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + + status = m_CleanupEventUm.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGPNP, + "Could not initialize cleanup event for " + "WDFDEVICE %p, %!STATUS!", + m_Device->GetHandle(), status); + return status; + } + + status = m_RemoveEventUm.Initialize(SynchronizationEvent, FALSE); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGPNP, + "Could not initialize remove event for " + "WDFDEVICE %p, %!STATUS!", + m_Device->GetHandle(), status); + return status; + } +#endif + + if (DeviceInit->IsPwrPolOwner()) { + m_PowerPolicyMachine.m_Owner = new (pFxDriverGlobals) + FxPowerPolicyOwnerSettings(this); + + if (m_PowerPolicyMachine.m_Owner == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = m_PowerPolicyMachine.m_Owner->Init(); + if (!NT_SUCCESS(status)) { + return status; + } + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + QueryForD3ColdInterface(); +#endif + } + + // + // we will change the access flags on the object later on when we build up + // the list from the wdm resources + // + status = FxCmResList::_CreateAndInit(&m_Resources, + pFxDriverGlobals, + m_Device, + WDF_NO_OBJECT_ATTRIBUTES, + FxResourceNoAccess); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_Resources->Commit(WDF_NO_OBJECT_ATTRIBUTES, + WDF_NO_HANDLE, + m_Device); + + // + // This should never fail + // + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) { + m_Resources->DeleteFromFailedCreate(); + m_Resources = NULL; + return status; + } + + m_Resources->ADDREF(this); + + // + // we will change the access flags on the object later on when we build up + // the list from the wdm resources + // + status = FxCmResList::_CreateAndInit(&m_ResourcesRaw, + pFxDriverGlobals, + m_Device, + WDF_NO_OBJECT_ATTRIBUTES, + FxResourceNoAccess); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_ResourcesRaw->Commit(WDF_NO_OBJECT_ATTRIBUTES, + WDF_NO_HANDLE, + m_Device); + + // + // This should never fail + // + ASSERT(NT_SUCCESS(status)); + if (!NT_SUCCESS(status)) { + m_ResourcesRaw->DeleteFromFailedCreate(); + m_ResourcesRaw = NULL; + return status; + } + + m_ResourcesRaw->ADDREF(this); + + status = RegisterCallbacks(&DeviceInit->PnpPower.PnpPowerEventCallbacks); + if (!NT_SUCCESS(status)) { + return status; + } + + if (IsPowerPolicyOwner()) { + RegisterPowerPolicyCallbacks(&DeviceInit->PnpPower.PolicyEventCallbacks); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::Dispatch( + __in MdIrp Irp + ) + +/*++ + +Routine Description: + + This is the main dispatch handler for the pnp package. This method is + called by the framework manager when a PNP or Power IRP enters the driver. + This function will dispatch the IRP to a function designed to handle the + specific IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + FxIrp irp(Irp); + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + FX_TRACK_DRIVER(GetDriverGlobals()); +#endif + + if (irp.GetMajorFunction() == IRP_MJ_PNP) { + + switch (irp.GetMinorFunction()) { + case IRP_MN_START_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_REMOVE_DEVICE: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_STOP_DEVICE: + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_CANCEL_STOP_DEVICE: + case IRP_MN_SURPRISE_REMOVAL: + case IRP_MN_EJECT: + case IRP_MN_QUERY_PNP_DEVICE_STATE: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + irp.GetMinorFunction(), irp.GetIrp()); + break; + + case IRP_MN_QUERY_DEVICE_RELATIONS: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! " + "type %!DEVICE_RELATION_TYPE! IRP 0x%p", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + irp.GetMinorFunction(), + irp.GetParameterQDRType(), irp.GetIrp()); + break; + + default: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p, IRP_MJ_PNP, %!pnpmn! IRP 0x%p", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + irp.GetMinorFunction(), irp.GetIrp()); + break; + } + + if (irp.GetMinorFunction() <= IRP_MN_SURPRISE_REMOVAL) { + status = (*GetDispatchPnp()[irp.GetMinorFunction()])(this, &irp); + } + else { + // + // For Pnp IRPs we don't understand, just forget about them + // + status = FireAndForgetIrp(&irp); + } + } + else { + // + // If this isn't a PnP Irp, it must be a power irp. + // + switch (irp.GetMinorFunction()) { + case IRP_MN_WAIT_WAKE: + case IRP_MN_SET_POWER: + if (irp.GetParameterPowerType() == SystemPowerState) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! " + "IRP 0x%p for %!SYSTEM_POWER_STATE! (S%d)", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + irp.GetMinorFunction(), irp.GetIrp(), + irp.GetParameterPowerStateSystemState(), + irp.GetParameterPowerStateSystemState() - 1); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! " + "IRP 0x%p for %!DEVICE_POWER_STATE!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + irp.GetMinorFunction(), irp.GetIrp(), + irp.GetParameterPowerStateDeviceState()); + } + break; + + default: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p IRP_MJ_POWER, %!pwrmn! IRP 0x%p", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + irp.GetMinorFunction(), irp.GetIrp()); + break; + } + + Mx::MxAssert(irp.GetMajorFunction() == IRP_MJ_POWER); + + if (irp.GetMinorFunction() <= IRP_MN_QUERY_POWER) { + status = (*GetDispatchPower()[irp.GetMinorFunction()])(this, &irp); + } + else { + // + // For Power IRPs we don't understand, just forget about them + // + status = FireAndForgetIrp(&irp); + } + } + + return status; +} + +PNP_DEVICE_STATE +FxPkgPnp::HandleQueryPnpDeviceState( + __in PNP_DEVICE_STATE PnpDeviceState + ) + +/*++ + +Routine Description: + + This function handled IRP_MN_QUERY_DEVICE_STATE. Most of the bits are + just copied from internal Framework state. + +Arguments: + + PnpDeviceState - Bitfield that will be returned to the sender of the IRP. + +Returns: + + NTSTATUS + +--*/ + +{ + LONG state; + + state = GetPnpStateInternal(); + + // + // Return device state set by driver. + // + SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, + PNP_DEVICE_DISABLED, + state, + Disabled); + SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, + PNP_DEVICE_DONT_DISPLAY_IN_UI, + state, + DontDisplayInUI); + SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, + PNP_DEVICE_FAILED, + state, + Failed); + SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, + PNP_DEVICE_NOT_DISABLEABLE, + state, + NotDisableable); + SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, + PNP_DEVICE_REMOVED, + state, + Removed); + SET_PNP_DEVICE_STATE_BIT(&PnpDeviceState, + PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED, + state, + ResourcesChanged); + + if ((state & FxPnpStateDontDisplayInUIMask) == FxPnpStateDontDisplayInUIUseDefault) { + LONG caps; + + // + // Mask off all caps except for NoDispalyInUI + // + caps = GetPnpCapsInternal() & FxPnpCapNoDisplayInUIMask; + + // + // If the driver didn't specify pnp state, see if they specified no + // display as a capability. For raw PDOs and just usability, it is not + // always clear to the driver writer that they must set both the pnp cap + // and the pnp state for the no display in UI property to stick after + // the device has been started. + // + if (caps == FxPnpCapNoDisplayInUITrue) { + PnpDeviceState |= PNP_DEVICE_DONT_DISPLAY_IN_UI; + } + else if (caps == FxPnpCapNoDisplayInUIFalse) { + PnpDeviceState &= ~PNP_DEVICE_DONT_DISPLAY_IN_UI; + } + } + + // + // Return device state maintained by frameworks. + // + if (IsInSpecialUse()) { + PnpDeviceState |= PNP_DEVICE_NOT_DISABLEABLE; + } + + // + // If there is an internal failure, then indicate that up to pnp. + // + if (m_InternalFailure || m_Failed) { + PnpDeviceState |= PNP_DEVICE_FAILED; + } + + return PnpDeviceState; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::HandleQueryBusRelations( + __inout FxIrp* Irp + ) +/*++ + +Routine Description: + Handles a query device relations for the bus relations type (all other types + are handled by HandleQueryDeviceRelations). This function will call into + each of the device's FxChildList objects to process the request. + +Arguments: + Irp - the request contain the query device relations + +Return Value: + NTSTATUS + + --*/ +{ + FxWaitLockTransactionedList* pList; + PDEVICE_RELATIONS pRelations; + FxTransactionedEntry* ple; + NTSTATUS status, listStatus; + BOOLEAN changed; + + // + // Before we do anything, callback into the driver + // + m_DeviceRelationsQuery.Invoke(m_Device->GetHandle(), BusRelations); + + // + // Default to success unless list processing fails + // + status = STATUS_SUCCESS; + + // + // Keep track of changes made by any list object. If anything changes, + // remember it for post-processing. + // + changed = FALSE; + + pRelations = (PDEVICE_RELATIONS) Irp->GetInformation(); + + if (m_EnumInfo != NULL) { + pList = &m_EnumInfo->m_ChildListList; + + pList->LockForEnum(GetDriverGlobals()); + } + else { + pList = NULL; + } + + ple = NULL; + while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) { + FxChildList* pChildList; + + pChildList = FxChildList::_FromEntry(ple); + + // + // ProcessBusRelations will free and reallocate pRelations if necessary + // + listStatus = pChildList->ProcessBusRelations(&pRelations); + + // + // STATUS_NOT_SUPPORTED is a special value. It indicates that the call + // to ProcessBusRelations did not modify pRelations in any way. + // + if (listStatus == STATUS_NOT_SUPPORTED) { + continue; + } + + + if (!NT_SUCCESS(listStatus)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p, WDFCHILDLIST %p returned %!STATUS! from " + "processing bus relations", + m_Device->GetHandle(), pChildList->GetHandle(), listStatus); + status = listStatus; + break; + } + + // + // We updated pRelations, change the status later + // + changed = TRUE; + } + + // + // By checking for NT_SUCCESS(status) below we account for + // both the cases - list changed, as well as list unchanged but possibly + // children being reported missing (that doesn't involve list change). + // + if (NT_SUCCESS(status)) { + + ple = NULL; + while (pList != NULL && (ple = pList->GetNextEntry(ple)) != NULL) { + FxChildList* pChildList; + + pChildList = FxChildList::_FromEntry(ple); + + // + // invoke the ReportedMissing callback for for children that are + // being reporte missing + // + pChildList->InvokeReportedMissingCallback(); + } + } + + if (pList != NULL) { + pList->UnlockFromEnum(GetDriverGlobals()); + } + + if (NT_SUCCESS(status) && changed == FALSE) { + // + // Went through the entire list of FxChildList objects, but no object + // modified the pRelations, so restore the caller's NTSTATUS. + // + status = Irp->GetStatus(); + } + + // + // Re-set the relations into the structure so that any changes that any call + // to FxChildList::ProcessBusRelations takes effect and is reported. + // + Irp->SetInformation((ULONG_PTR) pRelations); + Irp->SetStatus(status); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE %p, returning %!STATUS! from processing bus relations", + m_Device->GetHandle(), status + ); + + if (NT_SUCCESS(status) && pRelations != NULL) { + ULONG i; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p returning %d devices in relations %p", + m_Device->GetHandle(), pRelations->Count, pRelations + ); + + // + // Try to not consume an IFR entry per DO reported. Instead, report up + // to 4 at a time. + // + for (i = 0; i < pRelations->Count && GetDriverGlobals()->FxVerboseOn; i += 4) { + if (i + 3 < pRelations->Count) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "PDO %p PDO %p PDO %p PDO %p", + pRelations->Objects[i], + pRelations->Objects[i+1], + pRelations->Objects[i+2], + pRelations->Objects[i+3] + ); + } + else if (i + 2 < pRelations->Count) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "PDO %p PDO %p PDO %p", + pRelations->Objects[i], + pRelations->Objects[i+1], + pRelations->Objects[i+2] + ); + } + else if (i + 1 < pRelations->Count) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "PDO %p PDO %p", + pRelations->Objects[i], + pRelations->Objects[i+1] + ); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "PDO %p", + pRelations->Objects[i] + ); + } + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::HandleQueryBusInformation( + __inout FxIrp* Irp + ) +{ + NTSTATUS status; + + // + // Probably is a better check then this to see if the driver set the bus + // information + // + if (m_BusInformation.BusTypeGuid.Data1 != 0x0) { + PPNP_BUS_INFORMATION pBusInformation; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + pBusInformation = (PPNP_BUS_INFORMATION) MxMemory::MxAllocatePoolWithTag( + PagedPool, sizeof(PNP_BUS_INFORMATION), pFxDriverGlobals->Tag); + + if (pBusInformation != NULL) { + // + // Initialize the PNP_BUS_INFORMATION structure with the data + // from PDO properties. + // + RtlCopyMemory(pBusInformation, + &m_BusInformation, + sizeof(PNP_BUS_INFORMATION)); + + Irp->SetInformation((ULONG_PTR) pBusInformation); + status = STATUS_SUCCESS; + } + else { + Irp->SetInformation(NULL); + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p could not allocate PNP_BUS_INFORMATION string, " + " %!STATUS!", m_Device->GetHandle(), status); + } + } + else { + status = Irp->GetStatus(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::HandleQueryDeviceRelations( + __inout FxIrp* Irp, + __inout FxRelatedDeviceList* List + ) +/*++ + +Routine Description: + Handles the query device relations request for all relation types *except* + for bus relations (HandleQueryBusRelations handles that type exclusively). + + This function will allocate a PDEVICE_RELATIONS structure if the passed in + FxRelatedDeviceList contains any devices to add to the relations list. + +Arguments: + Irp - the request + + List - list containing devices to report in the relations + +Return Value: + NTSTATUS + + --*/ +{ + PDEVICE_RELATIONS pPriorRelations, pNewRelations; + FxRelatedDevice* entry; + DEVICE_RELATION_TYPE type; + ULONG count; + size_t size; + NTSTATUS status; + BOOLEAN retry; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + if (List == NULL) { + // + // Indicate that we didn't modify the irp at all since we have no list + // + return STATUS_NOT_SUPPORTED; + } + + pFxDriverGlobals = GetDriverGlobals(); + type = Irp->GetParameterQDRType(); + status = STATUS_SUCCESS; + + // + // Notify driver that he should re-scan for device relations. + // + m_DeviceRelationsQuery.Invoke(m_Device->GetHandle(), type); + + pPriorRelations = (PDEVICE_RELATIONS) Irp->GetInformation(); + retry = FALSE; + + count = 0; + + List->LockForEnum(pFxDriverGlobals); + + // + // Count how many entries there are in the list + // + for (entry = NULL; (entry = List->GetNextEntry(entry)) != NULL; count++) { + DO_NOTHING(); + } + + // + // If we have + // 1) no devices in the list AND + // a) we have nothing to report OR + // b) we have something to report and there are previous relations (which + // if left unchanged will be used to report our missing devices) + // + // THEN we have nothing else to do, just return + // + if (count == 0 && + (List->m_NeedReportMissing == 0 || pPriorRelations != NULL)) { + List->UnlockFromEnum(pFxDriverGlobals); + return STATUS_NOT_SUPPORTED; + } + + if (pPriorRelations != NULL) { + // + // Looks like another driver in the stack has already added some + // entries. Make sure we allocate space for these additional entries. + // + count += pPriorRelations->Count; + } + + // + // Allocate space for the device relations structure (which includes + // space for one PDEVICE_OBJECT, and then allocate enough additional + // space for the extra PDEVICE_OBJECTS we need. + // + // (While no FxChildList objects are used in this function, this static + // function from the class computes what we need.) + // + size = FxChildList::_ComputeRelationsSize(count); + + pNewRelations = (PDEVICE_RELATIONS) MxMemory::MxAllocatePoolWithTag( + PagedPool, size, pFxDriverGlobals->Tag); + + if (pNewRelations == NULL) { + // + // Dereference any previously reported relations before exiting. They + // are dereferenced here because the PNP manager will see error and not + // do anything while the driver which added these objects expects the + // pnp manager to do the dereference. Since this device is changing the + // status, it must act like the pnp manager. + // + if (pPriorRelations != NULL) { + ULONG i; + + for (i = 0; i < pPriorRelations->Count; i++) { + Mx::MxDereferenceObject(pPriorRelations->Objects[i]); + } + } + + if (List->IncrementRetries() < 3) { + retry = TRUE; + } + + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p could not allocate device relations for type %d string, " + " %!STATUS!", m_Device->GetHandle(), type, status); + + goto Done; + } + + RtlZeroMemory(pNewRelations, size); + + // + // If there was an existing device relations structure, copy + // the entries to the new structure. + // + if (pPriorRelations != NULL && pPriorRelations->Count > 0) { + RtlCopyMemory( + pNewRelations, + pPriorRelations, + FxChildList::_ComputeRelationsSize(pPriorRelations->Count) + ); + } + + // + // Walk the list and return the relations here + // + for (entry = NULL; + (entry = List->GetNextEntry(entry)) != NULL; + pNewRelations->Count++) { + MdDeviceObject pdo; + + pdo = entry->GetDevice(); + + if (entry->m_State == RelatedDeviceStateNeedsReportPresent) { + entry->m_State = RelatedDeviceStateReportedPresent; + } + + // + // Add it to the DEVICE_RELATIONS structure. Pnp dictates that each + // PDO in the list be referenced. + // + pNewRelations->Objects[pNewRelations->Count] = reinterpret_cast(pdo); + Mx::MxReferenceObject(pdo); + } + +Done: + if (NT_SUCCESS(status)) { + List->ZeroRetries(); + } + + List->UnlockFromEnum(GetDriverGlobals()); + + if (pPriorRelations != NULL) { + MxMemory::MxFreePool(pPriorRelations); + } + + if (retry) { + MxDeviceObject physicalDeviceObject( + m_Device->GetPhysicalDevice() + ); + + physicalDeviceObject.InvalidateDeviceRelations(type); + } + + Irp->SetStatus(status); + Irp->SetInformation((ULONG_PTR) pNewRelations); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PostCreateDeviceInitialize( + VOID + ) + +/*++ + +Routine Description: + + This function does any initialization to this object which must be done + after the underlying device object has been attached to the device stack, + i.e. you can send IRPs down this stack now. + +Arguments: + + none + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + + status = m_PnpMachine.Init(this, &FxPkgPnp::_PnpProcessEventInner); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "PnP State Machine init failed, %!STATUS!", + status); + return status; + } + + status = m_PowerMachine.Init(this, &FxPkgPnp::_PowerProcessEventInner); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Power State Machine init failed, %!STATUS!", + status); + return status; + } + + status = m_PowerPolicyMachine.Init(this, &FxPkgPnp::_PowerPolicyProcessEventInner); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Power Policy State Machine init failed, %!STATUS!", + status); + return status; + } + + return status; +} + +VOID +FxPkgPnp::FinishInitialize( + __inout PWDFDEVICE_INIT DeviceInit + ) +/*++ + +Routine Description: + Finish initializing the object. All initialization up until this point + could fail. This function cannot fail, so all it can do is assign field + values and take allocations from DeviceInit. + +Arguments: + DeviceInit - device initialization structure that the driver writer has + initialized + +Return Value: + None + + --*/ + +{ + // + // Reassign the state callback arrays away from the init struct. + // Set the init field to NULL so that it does not attempt to free the array + // when it is destroyed. + // + m_PnpStateCallbacks = DeviceInit->PnpPower.PnpStateCallbacks; + DeviceInit->PnpPower.PnpStateCallbacks = NULL; + + m_PowerStateCallbacks = DeviceInit->PnpPower.PowerStateCallbacks; + DeviceInit->PnpPower.PowerStateCallbacks = NULL; + + m_PowerPolicyStateCallbacks = DeviceInit->PnpPower.PowerPolicyStateCallbacks; + DeviceInit->PnpPower.PowerPolicyStateCallbacks = NULL; + + // + // Bias the count towards one so that we can optimize the synchronous + // cleanup case when the device is being destroyed. + // + m_PendingChildCount = 1; + + // + // Now "Add" this device in the terms that the PnP state machine uses. This + // will be in the context of an actual AddDevice function for FDOs, and + // something very much like it for PDOs. + // + // Important that the posting of the event is after setting of the state + // callback arrays so that we can guarantee that any state transition + // callback will be made. + // + PnpProcessEvent(PnpEventAddDevice); +} + +VOID +FxPkgPnp::ProcessDelayedDeletion( + VOID + ) +{ + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p processing delayed deletion from pnp state " + "machine", m_Device->GetHandle(), m_Device->GetDeviceObject()); + + CleanupStateMachines(FALSE); + DeleteDevice(); +} + +VOID +FxPkgPnp::SetSpecialFileSupport( + __in WDF_SPECIAL_FILE_TYPE FileType, + __in BOOLEAN Supported + ) + +/*++ + +Routine Description: + + This function marks the device as capable of handling the paging path, + hibernation or crashdumps. Any device that is necessary for one of these + three things will get notification. It is then responsible for forwarding + the notification to its parent. The Framework handles that. This + function just allows a driver to tell the Framework how to respond. + + +Arguments: + + FileType - identifies which of the special paths the device is in + Supported - Yes or No + +Returns: + + void + +--*/ + +{ + switch (FileType) { + case WdfSpecialFilePaging: + case WdfSpecialFileHibernation: + case WdfSpecialFileDump: + case WdfSpecialFileBoot: + SetUsageSupport(_SpecialTypeToUsage(FileType), Supported); + break; + + default: + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid special file type %x", FileType); + } +} + +_Must_inspect_result_ +NTSTATUS +PnpPassThroughQI( + __in CfxDevice* Device, + __inout FxIrp* Irp + ) + +/*++ + +Routine Description: + + This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting + a direct-call table from some driver in a device stack. In some cases, the + right response is to turn around and send a similar query to the device's + parent. This function does that. + + +Arguments: + + Device - This WDFDEVICE. + Irp - The IRP that was sent to us. + +Returns: + + NTSTATUS + +--*/ + +{ + MdIrp pFwdIrp; + NTSTATUS status; + NTSTATUS prevStatus; + MxDeviceObject pTopOfStack; + + prevStatus = Irp->GetStatus(); + + + + + + + + + + + + + pTopOfStack.SetObject(Device->m_ParentDevice->GetAttachedDeviceReference()); + + pFwdIrp = FxIrp::AllocateIrp(pTopOfStack.GetStackSize()); + + if (pFwdIrp != NULL) { + FxAutoIrp fxFwdIrp(pFwdIrp); + + // + // The worker routine copies stack parameters to forward-Irp, sends it + // down the stack synchronously, then copies back the stack parameters + // from forward-irp to original-irp + // + PnpPassThroughQIWorker(&pTopOfStack, Irp, &fxFwdIrp); + + if (fxFwdIrp.GetStatus() != STATUS_NOT_SUPPORTED) { + status = fxFwdIrp.GetStatus(); + } + else { + status = prevStatus; + } + + Irp->SetStatus(status); + Irp->SetInformation(fxFwdIrp.GetInformation()); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + Device->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p could not allocate IRP to send QI to parent !devobj " + "%p, %!STATUS!", Device->GetHandle(), pTopOfStack.GetObject(), + status); + } + + pTopOfStack.DereferenceObject(); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::HandleQueryInterfaceForPowerThread( + __inout FxIrp* Irp, + __out PBOOLEAN CompleteRequest + ) +{ + NTSTATUS status; + + *CompleteRequest = TRUE; + + // + // Send the request down the stack first. If someone lower handles it + // or failed trying to, just return their status + // + status = SendIrpSynchronously(Irp); + + if (NT_SUCCESS(status) || status != STATUS_NOT_SUPPORTED) { + // + // Success or failure trying to handle it + // + return status; + } + + // + // The semantic of this QI is that it sent down while processing start or + // a device usage notification on the way *up* the stack. That means that + // by the time the QI gets to the lower part of the stack, the power thread + // will have already been allocated and exported. + // + ASSERT(HasPowerThread()); + + if (Irp->GetParameterQueryInterfaceVersion() == 1 && + Irp->GetParameterQueryInterfaceSize() >= + m_PowerThreadInterface.Interface.Size) { + // + // Expose the interface to the requesting driver. + // + CopyQueryInterfaceToIrpStack(&m_PowerThreadInterface, Irp); + + status = STATUS_SUCCESS; + + // + // Caller assumes a reference has been taken. + // + m_PowerThreadInterface.Interface.InterfaceReference( + m_PowerThreadInterface.Interface.Context + ); + } + else { + status = STATUS_INVALID_BUFFER_SIZE; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::HandleQueryInterface( + __inout FxIrp* Irp, + __out PBOOLEAN CompleteRequest + ) + +/*++ + +Routine Description: + + This driver may be sent IRP_MN_QUERY_INTERFACE, which is a way of getting + a direct-call table from some driver in a device stack. This function + looks into a list of interfaces that the driver has registered and, if + the interface that is being sought is present, it answers the IRP. + +Arguments: + + Irp - The IRP that was sent to us. + CompleteRequest - tells the caller whether the IRP should be completed + +Returns: + + NTSTATUS + +--*/ + +{ + FxDeviceProcessQueryInterfaceRequest callback; + const GUID* pInterfaceType; + PSINGLE_LIST_ENTRY ple; + FxQueryInterface *pQI; + PVOID pFound; + PINTERFACE pExposedInterface; + PVOID pExposedInterfaceSpecificData; + BOOLEAN sendToParent; + + NTSTATUS status; + + *CompleteRequest = FALSE; + + pFound = NULL; + pQI = NULL; + pExposedInterface = NULL; + pExposedInterfaceSpecificData = NULL; + sendToParent = FALSE; + + pInterfaceType = Irp->GetParameterQueryInterfaceType(); + // + // The power thread is special cased because it has a different semantic + // then the usual QI irp that we expose to the driver writer. In this case, + // we want to fill in the interface if the lower stack does not support it. + // + if (FxIsEqualGuid(pInterfaceType, &GUID_POWER_THREAD_INTERFACE)) { + return HandleQueryInterfaceForPowerThread(Irp, CompleteRequest); + } + else if (FxIsEqualGuid(pInterfaceType, &GUID_REENUMERATE_SELF_INTERFACE_STANDARD)) { + if (m_Device->IsPdo()) { + return ((FxPkgPdo*) this)->HandleQueryInterfaceForReenumerate( + Irp, CompleteRequest); + } + } + + status = Irp->GetStatus(); + + // + // Walk the interface collection and return the appropriate interface. + // + m_QueryInterfaceLock.AcquireLock(GetDriverGlobals()); + + for (ple = m_QueryInterfaceHead.Next; ple != NULL; ple = ple->Next) { + pQI = FxQueryInterface::_FromEntry(ple); + + if (FxIsEqualGuid(Irp->GetParameterQueryInterfaceType(), + &pQI->m_InterfaceType)) { + + pExposedInterface = Irp->GetParameterQueryInterfaceInterface(); + pExposedInterfaceSpecificData = + Irp->GetParameterQueryInterfaceInterfaceSpecificData(); + + if (pQI->m_Interface != NULL) { + // + // NOTE: If a driver has exposed the same interface GUID with + // different sizes as a ways of versioning, then the driver + // writer can specify the minimum size and version number + // and then fill in the remaining fields in the callback + // below. + // + if (pQI->m_Interface->Size <= Irp->GetParameterQueryInterfaceSize() && + pQI->m_Interface->Version <= Irp->GetParameterQueryInterfaceVersion()) { + + if (pQI->m_ImportInterface == FALSE) { + // + // Expose the interface to the requesting driver. + // + RtlCopyMemory(pExposedInterface, + pQI->m_Interface, + pQI->m_Interface->Size); + } + else { + // + // The interface contains data which the driver wants + // before copying over its information, so don't do a + // copy and let the event callback do the copy + // + DO_NOTHING(); + } + } + else { + status = STATUS_INVALID_BUFFER_SIZE; + break; + } + } + + callback.m_Method = pQI->m_ProcessRequest.m_Method; + sendToParent = pQI->m_SendQueryToParentStack; + pFound = pQI; + + status = STATUS_SUCCESS; + break; + } + } + + m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals()); + + if (!NT_SUCCESS(status) || pFound == NULL) { + goto Done; + } + + // + // Let the driver see the interface before it is handed out. + // + status = callback.Invoke(m_Device->GetHandle(), + (LPGUID) Irp->GetParameterQueryInterfaceType(), + pExposedInterface, + pExposedInterfaceSpecificData); + + // + // STATUS_NOT_SUPPORTED is a special cased error code which indicates that + // the QI should travel down the rest of the stack. + // + if (!NT_SUCCESS(status) && status != STATUS_NOT_SUPPORTED) { + goto Done; + } + + // + // If it is meant for the parent, send it down the parent stack + // + if (sendToParent) { + status = PnpPassThroughQI(m_Device, Irp); + goto Done; + } + + // + // Reference the interface before returning it to the requesting driver. + // If this is an import interface, the event callback is free to not fill + // in the InterfaceReference function pointer. + // + if (pExposedInterface->InterfaceReference != NULL) { + pExposedInterface->InterfaceReference(pExposedInterface->Context); + } + + // + // If we are not a PDO in the stack, then send the fully formatted QI request + // down the stack to allow others to filter the interface. + // + if (m_Device->IsPdo() == FALSE) { + ASSERT(NT_SUCCESS(status) || status == STATUS_NOT_SUPPORTED); + + Irp->SetStatus(status); + Irp->CopyCurrentIrpStackLocationToNext(); + status = Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); + } + +Done: + if (pFound != NULL) { + *CompleteRequest = TRUE; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::QueryForCapabilities( + VOID + ) +{ + STACK_DEVICE_CAPABILITIES caps; + NTSTATUS status; + + MxDeviceObject deviceObject; + + deviceObject.SetObject(m_Device->GetDeviceObject()); + + status = GetStackCapabilities(GetDriverGlobals(), + &deviceObject, + &m_D3ColdInterface, + &caps); + + if (NT_SUCCESS(status)) { + ULONG states, i; + + ASSERT(caps.DeviceCaps.DeviceWake <= 0xFF && caps.DeviceCaps.SystemWake <= 0xFF); + + m_SystemWake = (BYTE) caps.DeviceCaps.SystemWake; + + // + // Initialize the array of wakeable D-states to say that all system + // states down to the one identified in the caps can generate wake. + // This will be overridden below if the BIOS supplied more information. + // + // Compatibility Note: Non-ACPI bus drivers (root-enumerated drivers) + // or other bus drivers that haven't set the power settings correctly + // for their PDO may end up with a valid value for DeviceWake in the + // device capabilities but a value of PowerSystemUnspecified for + // SystemWake, in which case a call to WdfDeviceAssignS0IdleSettings or + // WdfDeviceAssignSxWakeSettings DDIs will fail on 1.11+ resulting in + // device compat issues. The failure is expected and right thing to do + // but has compatibility implications - drivers that worked earlier now + // fail on 1.11. Note that earlier versions of WDF did not have + // m_DeviceWake as an array and stored just the capabilities->DeviceWake + // value without regard to the SystemWake but the current implementation + // introduces dependency on systemWake value). So for compat reasons, + // for pre-1.11 compiled drivers we initilaize the array with DeviceWake + // value ignoring SystemWake, removing any dependency of DeviceWake + // on SystemWake value and thus preserving previous behavior for + // pre-1.11 compiled drivers. + // + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) { + + RtlFillMemory(m_DeviceWake, DeviceWakeStates, DeviceWakeDepthNotWakeable); + + for (i = PowerSystemWorking; i <= m_SystemWake; i++) { + + // + // Note that this cast is hiding a conversion between two slightly + // incompatible types. DeviceWake is in terms of DEVICE_POWER_STATE + // which is defined this way: + // + // typedef enum _DEVICE_POWER_STATE { + // PowerDeviceUnspecified = 0, + // PowerDeviceD0, + // PowerDeviceD1, + // PowerDeviceD2, + // PowerDeviceD3, + // PowerDeviceMaximum + // } DEVICE_POWER_STATE, *PDEVICE_POWER_STATE; + // + // m_DeviceWake is defined in terms of DEVICE_WAKE_DEPTH which is + // defined this way: + // + // typedef enum _DEVICE_WAKE_DEPTH { + // DeviceWakeDepthNotWakeable = 0, + // DeviceWakeDepthD0, + // DeviceWakeDepthD1, + // DeviceWakeDepthD2, + // DeviceWakeDepthD3hot, + // DeviceWakeDepthD3cold, + // DeviceWakeDepthMaximum + // } DEVICE_WAKE_DEPTH, *PDEVICE_WAKE_DEPTH; + // + // The result is that the conversion below will map D3 onto D3hot, + // which is a safe assumption to start with, one which may be + // overridden later. + // + C_ASSERT(PowerDeviceD0 == DeviceWakeDepthD0); + m_DeviceWake[i - PowerSystemWorking] = (BYTE) caps.DeviceCaps.DeviceWake; + } + } + else { + // + // See comments above for information on mapping of device power + // state to device wake depth. + // + RtlFillMemory(m_DeviceWake, + DeviceWakeStates, + (BYTE) caps.DeviceCaps.DeviceWake); + } + + // + // Capture the S -> D state mapping table as a ULONG for use in the + // power policy owner state machine when the machine moves into Sx and + // the device is not armed for wake and has set an IdealDxStateForSx + // value + // + states = 0x0; + + for (i = 0; i < ARRAY_SIZE(caps.DeviceCaps.DeviceState); i++) { + _SetPowerCapState(i, caps.DeviceCaps.DeviceState[i], &states); + } + + m_PowerPolicyMachine.m_Owner->m_SystemToDeviceStateMap = states; + + // + // Query for the D3cold support interface. If present, it will tell + // us specifically which D-states will work for generating wake signals + // from specific S-states. + // + // Earlier versions of WDF didn't make this query, so for compatibility, + // we only make it now if the driver was built against WDF 1.11 or + // later. In truth, this just shifts the failure from initialization + // time to run time, because the information that we're presumably + // getting from the BIOS with this interrogation is saying that the + // code in earlier verisions of WDF would have blindly enabled a device + // for wake which simply wasn't capable of generating its wake signal + // from the chosen D-state. Thus the device would have been put into + // a low power state and then failed to resume in response to its wake + // signal. + // + + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) { + + // + // Cycle through all the system states that this device can wake + // from. There's no need to look at deeper sleep states than + // m_SystemWake because the driver will not arm for wake in + // those states. + // + for (i = PowerSystemWorking; i <= m_SystemWake; i++) { + if (caps.DeepestWakeableDstate[i] != DeviceWakeDepthMaximum) { + m_DeviceWake[i - PowerSystemWorking] = (BYTE)caps.DeepestWakeableDstate[i]; + } + } + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpStartDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + This method is called in response to a PnP StartDevice IRP coming down the + stack. + +Arguments: + This - device instance + Irp - a pointer to the FxIrp + +Returns: + STATUS_PENDING + +--*/ +{ + This->SetPendingPnpIrp(Irp); + This->PnpProcessEvent(PnpEventStartDevice); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpQueryStopDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + Pnp callback querying to see if the device can be stopped. + + The Framework philosophy surrounding Query Stop (and Query Remove) is that + it's impossible to really know if you can stop unless you've tried to stop. + This may not always be true, but it's hard to find a general strategy that + works that is less conservative. Furthermore, I couldn't find good examples + of drivers that would really benefit from continuing to handle requests + until the actual Stop IRP arrived, particularly when you consider that + most QueryStops are followed immediately by Stops. + + So this function sends an event to the PnP State machine that begins the + stopping process. If it is successful, then ultimately the QueryStop IRP + will be successfully completed. + +Arguments: + + This - a pointer to the PnP package + + Irp - a pointer to the FxIrp + +Return Value: + + STATUS_PENDING + + --*/ + +{ + // + // Keep this IRP around, since we're going to deal with it later. + // + This->SetPendingPnpIrp(Irp); + + // + // Now run the state machine on this thread. + // + This->PnpProcessEvent(PnpEventQueryStop); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpCancelStopDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + This routine is invoked in response to a query stop failing, somewhere in + the stack. Note that we can receive a cancel stop without being in the + query stop state if a driver above us in the stack failed the query stop. + + Again, this function just exists to bridge the gap between the WDM IRPs + and the PnP state machine. This function does little more than send an + event to the machine. + +Arguments: + + This - the package + + Irp - a pointer to the FxIrp + +Returns: + + STATUS_PENDING + +--*/ +{ + // + // Seed the irp with success + // + Irp->SetStatus(STATUS_SUCCESS); + + // + // Pend it and transition the state machine + // + This->SetPendingPnpIrp(Irp); + This->PnpProcessEvent(PnpEventCancelStop); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpStopDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is invoked in response to a Pnp StopDevice IRP. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + STATUS_PENDING + +--*/ +{ + // + // Seed the irp with success + // + Irp->SetStatus(STATUS_SUCCESS); + + // + // Pend and transition the state machine + // + This->SetPendingPnpIrp(Irp); + This->PnpProcessEvent(PnpEventStop); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpQueryRemoveDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + Again, the Framework handles QueryRemove by stopping everything going on + related to the device and then asking the driver whether it can be + removed. This function just kicks the state machine. Final completion + of the IRP will come (much) later. + +Arguments: + + This - the package + + Irp - a pointer to the FxIrp + +Returns: + + STATUS_PENDING + +--*/ +{ + // + // By default we handle this state. + // + Irp->SetStatus(STATUS_SUCCESS); + + // + // Keep this IRP around, since we're going to deal with it later. + // + This->SetPendingPnpIrp(Irp); + + // + // Now run the state machine on this thread. + // + This->PnpProcessEvent(PnpEventQueryRemove); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpCancelRemoveDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + Notification of a previous remove being canceled. Kick the state machine. + +Arguments: + + This - the package + + Irp - FxIrp representing the notification + +Return Value: + + STATUS_PENDING + + --*/ + +{ + // + // Seed the irp with success + // + Irp->SetStatus(STATUS_SUCCESS); + + // + // Pend it and transition the state machine + // + + This->SetPendingPnpIrp(Irp); + This->PnpProcessEvent(PnpEventCancelRemove); + + return STATUS_PENDING; +} + +VOID +FxPkgPnp::CleanupStateMachines( + __in BOOLEAN CleanupPnp + ) +{ +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + FxCREvent * event = m_CleanupEventUm.GetSelfPointer(); +#else + FxCREvent eventOnStack; + eventOnStack.Initialize(); + FxCREvent * event = eventOnStack.GetSelfPointer(); +#endif + + // + // Order of shutdown is important here. + // o Pnp initiates events to power policy. + // o Power policy initiates events to power and device-power-requirement + // o Power does not initiate any events + // o Device-power-requirement does not initiate any events + // + // By shutting them down in the order in which they send events, we can + // guarantee that no new events will be posted into the subsidiary state + // machines. + // + + // + // This will shut off the pnp state machine and synchronize any outstanding + // threads of execution. + // + if (CleanupPnp && m_PnpMachine.SetFinished( + event + ) == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p waiting for pnp state machine to finish", + m_Device->GetHandle(), m_Device->GetDeviceObject()); + + // + // Process the event *before* completing the irp so that this event is in + // the queue before the device remove event which will be processed + // right after the start irp has been completed. + // + event->EnterCRAndWaitAndLeave(); + } + + // + // Even though event is a SynchronizationEvent, so we need to reset it for + // the next wait because SetFinished will set it if even if the transition + // to the finished state is immediate + // + event->Clear(); + + if (m_PowerPolicyMachine.SetFinished(event) == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p waiting for pwr pol state machine to finish", + m_Device->GetHandle(), m_Device->GetDeviceObject()); + + event->EnterCRAndWaitAndLeave(); + } + + // + // See previous comment about why we Clear() + // + event->Clear(); + + if (m_PowerMachine.SetFinished(event) == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p waiting for pwr state machine to finish", + m_Device->GetHandle(), m_Device->GetDeviceObject()); + + event->EnterCRAndWaitAndLeave(); + } + + if (IsPowerPolicyOwner()) { + // + // See previous comment about why we Clear() + // + event->Clear(); + + if (NULL != m_PowerPolicyMachine.m_Owner->m_PoxInterface. + m_DevicePowerRequirementMachine) { + + if (FALSE == m_PowerPolicyMachine.m_Owner->m_PoxInterface. + m_DevicePowerRequirementMachine->SetFinished(event)) { + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p waiting for device power " + "requirement state machine to finish", + m_Device->GetHandle(), + m_Device->GetDeviceObject()); + + event->EnterCRAndWaitAndLeave(); + } + } + + m_PowerPolicyMachine.m_Owner->CleanupPowerCallback(); + } + + // + // Release the power thread if we have one either through creation or query. + // Since the power policy state machine is off, we should no longer need + // a dedicated thread. + // + // *** NOTE *** + // The power thread must be released *BEFORE* sending the irp down the stack + // because this can happen + // 1) this driver is not the power thread owner, but the last client + // 2) we send the pnp irp first + // 3) the power thread owner waits on this thread for all the clients to go + // away, but this device still has a reference on it + // 4) this device will not release the reference b/c the owner is waiting + // in the same thread. + // + ReleasePowerThread(); + + // + // Deref the reenumeration interface + // + ReleaseReenumerationInterface(); +} + +VOID +FxPkgPnp::CleanupDeviceFromFailedCreate( + __in MxEvent * WaitEvent + ) +/*++ + +Routine Description: + The device failed creation in some stage. It is assumed that the device has + enough state that it can survive a transition through the pnp state machine + (which means that pointers like m_PkgIo are valid and != NULL). When this + function returns, it will have deleted the owning FxDevice. + +Arguments: + WaitEvent - Event on which RemoveProcessed wait will be performed + + We can't initialize this event on stack as the initialization + can fail in user-mode. We can't have Initialize method + preinitailize this event either as this function may get called + before initialize (or in case of initialization failure). + + Hence the caller preallocates the event and passes to this + function. + + Caller must initialize this event as SynchronizationEvent + and it must be unsignalled. +Return Value: + None + + --*/ +{ + Mx::MxAssert(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + // + // Caller must initialize the event as Synchronization event and it should + // be passed as non-signalled. But we Clear it just to be sure. + // + WaitEvent->Clear(); + + ADDREF(WaitEvent); + + ASSERT(m_DeviceRemoveProcessed == NULL); + m_DeviceRemoveProcessed = WaitEvent; + + // + // Simulate a remove event coming to the device. After this call returns + // m_Device is still valid and must be deleted. + // + PnpProcessEvent(PnpEventRemove); + + // + // No need to wait in a critical region because we are in the context of a + // pnp request which is in the system context. + // + WaitEvent->WaitFor(Executive, KernelMode, FALSE, NULL); + m_DeviceRemoveProcessed = NULL; + + RELEASE(WaitEvent); +} + +VOID +FxPkgPnp::DeleteDevice( + VOID + ) +/*++ + +Routine Description: + This routine will detach and delete the device object and free the memory + for the device if there are no other references to it. Before calling this + routine, the state machines should have been cleaned up and the power thread + released. + +--*/ +{ + // + // This will detach and delete the device object + // + m_Device->Destroy(); + + // + // If this is the last reference, this will free the memory for the device + // + m_Device->DeleteObject(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpRemoveDevice( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + Notification of a remove. Kick the state machine. + +Arguments: + + This - the package + + Irp - FxIrp representing the notification + +Return Value: + + status + + --*/ + +{ +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + MxEvent * event = This->m_RemoveEventUm.GetSelfPointer(); +#else + MxEvent eventOnStack; + eventOnStack.Initialize(SynchronizationEvent, FALSE); + MxEvent * event = eventOnStack.GetSelfPointer(); +#endif + + NTSTATUS status; + + status = Mx::MxAcquireRemoveLock( + This->m_Device->GetRemoveLock(), + Irp->GetIrp()); + +#if DBG + ASSERT(NT_SUCCESS(status)); +#else + UNREFERENCED_PARAMETER(status); +#endif + + // + // Keep this object around after m_Device has RELEASE'ed its reference to + // this package. + // + This->ADDREF(Irp); + + // + // Removes are always success + // + Irp->SetStatus(STATUS_SUCCESS); + + ASSERT(This->m_DeviceRemoveProcessed == NULL); + This->m_DeviceRemoveProcessed = event; + + // + // Post the event and wait for the FxDevice to destroy itself or determine + // it has not been reported missing yet (for PDOs and bus filters). + // + This->PnpProcessEvent(PnpEventRemove); + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p waiting for remove event to finish processing", + This->m_Device->GetHandle(), This->m_Device->GetDeviceObject()); + + // + // No need to wait in a critical region because we are in the context of a + // pnp request which is in the system context. + // + event->WaitFor(Executive, KernelMode, FALSE, NULL); + + This->m_DeviceRemoveProcessed = NULL; + + status = This->ProcessRemoveDeviceOverload(Irp); + + // + // Release the reference added at the top. This is most likely going to be + // the last reference on the package for KMDF. For UMDF, host manages the + // lifetime of FxDevice so this may not be the last release for UMDF. + // + This->RELEASE(Irp); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpSurpriseRemoval( + __inout FxIrp* Irp + ) + +/*++ + +Routine Description: + + Notification that the device has been surprise removed. Kick the state + machine. + +Arguments: + + Irp - pointer to FxIrp representing this notification + +Return Value: + + STATUS_PENDING + +--*/ + +{ + // + // Package specific handling + // + Irp->SetStatus(STATUS_SUCCESS); + SetPendingPnpIrp(Irp); + PnpProcessEvent(PnpEventSurpriseRemove); + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_DispatchWaitWake( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This the first-level dispatch routine for IRP_MN_WAIT_WAKE. What one + does with a WaitWake IRP depends very much on whether one is an FDO, a PDO + or a filter. So dispatch immediately to a subclassable function. + +Arguments: + + This - the package + + Irp - pointer to FxIrp representing this notification + +Return Value: + + status + +--*/ + +{ + return This->DispatchWaitWake(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::DispatchWaitWake( + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + + Handles wait wake requests in a generic fashion + +Arguments: + + +Return Value: + + --*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + NTSTATUS status; + PIRP oldIrp; + KIRQL irql; + + if (IsPowerPolicyOwner()) { + if (m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp == FALSE) { + // + // A power irp arrived, but we did not request it. log and bugcheck + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Received wait wake power irp %p on device %p, but the irp was " + "not requested by the device (the power policy owner)", + Irp->GetIrp(), m_Device->GetDeviceObject()); + + FxVerifierBugCheck(GetDriverGlobals(), // globals + WDF_POWER_MULTIPLE_PPO, // specific type + (ULONG_PTR)m_Device->GetDeviceObject(), //parm 2 + (ULONG_PTR)Irp->GetIrp()); // parm 3 + + /* NOTREACHED */ + } + + // + // We are no longer requesting a power irp because we received the one + // we requested. + // + m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = FALSE; + } + + // + // The Framework has the concept of a "Wait/Wake Owner." This is the layer + // in the stack that is enabling and disabling wake at the bus level. This + // is probably the PDO or a bus filter like ACPI.sys. This is distinct + // from being the "Power Policy Owner," which would mean that this driver + // is deciding what D-state is appropriate for the device, and also + // sending Wait/Wake IRPs. + // + + if (m_SharedPower.m_WaitWakeOwner) { + m_PowerMachine.m_WaitWakeLock.Acquire(&irql); + + if (m_SharedPower.m_WaitWakeIrp != NULL) { + // + // We only allow one pended wait wake irp in the stack at a time. + // Fail this secondary wait wake request. + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failing wait wake irp %p with %!STATUS! because wait wake irp " + "%p already pended", + Irp->GetIrp(), status, m_SharedPower.m_WaitWakeIrp); + } + else { + MdCancelRoutine pRoutine; + + // + // No wait wake irp is currently in the stack, so attempt to set + // a cancel routine and transition the power state machine into a + // a state where it can arm the device at the bus level for this + // child. + // + // The power state machine expects the wait wake irp to have a cancel + // routine set in all states. For those states which require a + // non cancelable irp, those states clear the cancel routine as + // appropriate. + // + pRoutine = Irp->SetCancelRoutine(_PowerWaitWakeCancelRoutine); +#if DBG + ASSERT(pRoutine == NULL); +#else + UNREFERENCED_PARAMETER(pRoutine); +#endif + status = STATUS_PENDING; + + if (Irp->IsCanceled()) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "wait wake irp %p already canceled", Irp->GetIrp()); + + // + // This IRP has already been cancelled, we must clear the cancel + // routine before completing the IRP. + // + pRoutine = Irp->SetCancelRoutine(NULL); + + if (pRoutine != NULL) { + // + // Our cancel routine will not be called + // +#if DBG + ASSERT(pRoutine == _PowerWaitWakeCancelRoutine); +#else + UNREFERENCED_PARAMETER(pRoutine); +#endif + Irp->SetStatus(STATUS_CANCELLED); + status = STATUS_CANCELLED; + } + } + + if (status == STATUS_PENDING) { + // + // Either we successfully set the cancel routine or the irp + // was canceled and the cancel routine is about to run when + // we drop the lock. If the routine is about to run, we still + // need to setup m_SharedPower to values that it expects. + // + Irp->MarkIrpPending(); + m_SharedPower.m_WaitWakeIrp = Irp->GetIrp(); + } + } + m_PowerMachine.m_WaitWakeLock.Release(irql); + + if (NT_SUCCESS(status)) { + // + // Post to the appropriate matchines + // + PowerProcessEvent(PowerWakeArrival); + + if (IsPowerPolicyOwner()) { + PowerPolicyProcessEvent(PwrPolWakeArrived); + } + } + else { + CompletePowerRequest(Irp, status); + } + + return status; + } + else if (IsPowerPolicyOwner()) { + // + // Try to set m_WaitWakeIrp to the new IRP value only if the current + // value of m_WaitWakeIrp is NULL because there can only be one + // active wait wake irp in the stack at a time. Since the power policy + // state machine never sends more then one, this is really a guard + // against some other device in the stack sending a wait wake irp to + // this device in the wrong state. + // + oldIrp = (PIRP) InterlockedCompareExchangePointer( + (PVOID*) &m_SharedPower.m_WaitWakeIrp, + Irp->GetIrp(), + NULL + ); + + // + // If oldIrp is NULL then there was no previous irp and we successfully + // exchanged the new PIRP value into m_WaitWakeIrp + // + if (oldIrp == NULL) { + m_PowerPolicyMachine.SetWaitWakeUnclaimed(); + + // + // NOTE: There is a built in race condition here that WDF cannot + // solve with the given WDM primitives. After arming the + // device for wake, there is a window where the wait wake irp + // has not yet been processed by the wait wake owner. Until + // the wake request is processed, wake events could be generated + // and lost. There is nothing we can do about this until we + // have synchronous "goto Dx and arm" command available. + // + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutineEx(m_Device->GetDeviceObject(), + _PowerPolicyWaitWakeCompletionRoutine, + this); + + // + // Technically, there should be a PDO vs FDO overload here which + // does the right thing w/regard to this request and if it is at the + // bottom of the stack or not. But, by design, we check for + // m_WaitWakeOwner first which has the direct side affect of making + // it impossible for a PDO to get to this point. + // + ASSERT(m_Device->IsFdo()); + + status = Irp->PoCallDriver(m_Device->GetAttachedDevice()); + + // + // Send the wake arrived after sending the request as commented above. + // This window between sending the request and sending the event to + // the state machine allows the wait owner to complete the request + // immediately. When completed synchronously, it has an effect on + // both wake scenarios: + // + // 1) wake from S0: the device never transitions to Dx and the idle + // timer is resumed if no i/o is present + // + // 2) wake from sx: the device is disarmed for wake from Sx and + // put into Dx with being armed for wake. + // + PowerPolicyProcessEvent(PwrPolWakeArrived); + } + else { + status = STATUS_POWER_STATE_INVALID; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "already have a ww irp %p, failing new ww irp %p with %!STATUS!", + oldIrp, Irp->GetIrp(), status); + + CompletePowerRequest(Irp, status); + } + } + else { + // + // Not the power policy owner, not the wait wake irp owner, ignore the + // irp + // + // This will release the remove lock. + // + status = FireAndForgetIrp(Irp); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::RegisterCallbacks( + __in PWDF_PNPPOWER_EVENT_CALLBACKS DispatchTable + ) +{ + NTSTATUS status; + + // + // Update the callback table. + // + m_DeviceD0Entry.m_Method = DispatchTable->EvtDeviceD0Entry; + m_DeviceD0EntryPostInterruptsEnabled.m_Method = + DispatchTable->EvtDeviceD0EntryPostInterruptsEnabled; + m_DeviceD0ExitPreInterruptsDisabled.m_Method = + DispatchTable->EvtDeviceD0ExitPreInterruptsDisabled; + m_DeviceD0Exit.m_Method = DispatchTable->EvtDeviceD0Exit; + + m_DevicePrepareHardware.m_Method = DispatchTable->EvtDevicePrepareHardware; + m_DeviceReleaseHardware.m_Method = DispatchTable->EvtDeviceReleaseHardware; + + m_DeviceQueryStop.m_Method = DispatchTable->EvtDeviceQueryStop; + m_DeviceQueryRemove.m_Method = DispatchTable->EvtDeviceQueryRemove; + + m_DeviceSurpriseRemoval.m_Method = DispatchTable->EvtDeviceSurpriseRemoval; + + m_DeviceUsageNotification.m_Method = DispatchTable->EvtDeviceUsageNotification; + m_DeviceUsageNotificationEx.m_Method = DispatchTable->EvtDeviceUsageNotificationEx; + m_DeviceRelationsQuery.m_Method = DispatchTable->EvtDeviceRelationsQuery; + + if (DispatchTable->EvtDeviceSelfManagedIoCleanup != NULL || + DispatchTable->EvtDeviceSelfManagedIoFlush != NULL || + DispatchTable->EvtDeviceSelfManagedIoInit != NULL || + DispatchTable->EvtDeviceSelfManagedIoSuspend != NULL || + DispatchTable->EvtDeviceSelfManagedIoRestart != NULL) { + + status = FxSelfManagedIoMachine::_CreateAndInit(&m_SelfManagedIoMachine, + this); + + if (!NT_SUCCESS(status)) { + return status; + } + + m_SelfManagedIoMachine->InitializeMachine(DispatchTable); + } + + return STATUS_SUCCESS; +} + +VOID +FxPkgPnp::RegisterPowerPolicyCallbacks( + __in PWDF_POWER_POLICY_EVENT_CALLBACKS Callbacks + ) +{ + m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromS0.m_Method = + Callbacks->EvtDeviceArmWakeFromS0; + m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.m_Method = + Callbacks->EvtDeviceArmWakeFromSx; + m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.m_MethodWithReason = + Callbacks->EvtDeviceArmWakeFromSxWithReason; + + m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.m_Method = + Callbacks->EvtDeviceDisarmWakeFromS0; + m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromSx.m_Method = + Callbacks->EvtDeviceDisarmWakeFromSx; + + m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.m_Method = + Callbacks->EvtDeviceWakeFromS0Triggered; + m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.m_Method = + Callbacks->EvtDeviceWakeFromSxTriggered; +} + +NTSTATUS +FxPkgPnp::RegisterPowerPolicyWmiInstance( + __in const GUID* Guid, + __in FxWmiInstanceInternalCallbacks* Callbacks, + __out FxWmiInstanceInternal** Instance + ) +{ + WDF_WMI_PROVIDER_CONFIG config; + NTSTATUS status; + + WDF_WMI_PROVIDER_CONFIG_INIT(&config, Guid); + + // + // We are assuming we are registering either for the wait wake or device + // timeout GUIDs which both operate on BOOLEANs. If we expand this API in + // the future, have the caller pass in a config structure for the provider + // GUID. + // + config.MinInstanceBufferSize = sizeof(BOOLEAN); + + status = m_Device->m_PkgWmi->AddPowerPolicyProviderAndInstance( + &config, + Callbacks, + Instance); + + if (status == STATUS_OBJECT_NAME_COLLISION) { + status = STATUS_SUCCESS; + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to register WMI power GUID %!STATUS!", status); + } + + return status; +} + +NTSTATUS +FxPkgPnp::PowerPolicySetS0IdleSettings( + __in PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ) +/*++ + +Routine Description: + + Updates the S0 Idle settings for the device and then posts an update event + to the power policy state machine. The first this function is called, the + ability to allow the user to control this setting is set. + +Arguments: + + Settings - The settings to apply. + +Return Value: + + NTSTATUS + + --*/ +{ + DEVICE_POWER_STATE dxState; + ULONG idleTimeout; + NTSTATUS status; + BOOLEAN enabled, s0Capable, overridable, firstTime; + WDF_TRI_STATE powerUpOnSystemWake; + const LONGLONG negliblySmallIdleTimeout = -1; // 100 nanoseconds + + s0Capable = FALSE; + dxState = PowerDeviceD3; + overridable = FALSE; + firstTime = TRUE; + + if (Settings->Enabled == WdfTrue) { + enabled = TRUE; + + } else if (Settings->Enabled == WdfUseDefault) { + enabled = TRUE; + + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + DECLARE_CONST_UNICODE_STRING(valueName, WDF_S0_IDLE_DEFAULT_VALUE_NAME); + + // + // Read registry. If registry value is not found, the value of "enabled" + // remains unchanged + // + ReadRegistryS0Idle(&valueName, &enabled); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "If registry value WdfDefaultIdleInWorkingState was present, " + "it was not read because DDI WdfDeviceAssignS0IdleSettings " + "was not called at PASSIVE_LEVEL"); + } + } + else { + enabled = FALSE; + } + + if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Set) { + firstTime = FALSE; + } + + if (m_CapsQueried == FALSE && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + status = QueryForCapabilities(); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Do not set m_CapsQueried to TRUE yet because we will do that once we + // know the entire stack has been built we will do the query again. + // + } + + switch (Settings->IdleCaps) { + case IdleUsbSelectiveSuspend: + case IdleCanWakeFromS0: + s0Capable = TRUE; + + if (Settings->DxState == PowerDeviceMaximum) { + dxState = PowerPolicyGetDeviceDeepestDeviceWakeState(PowerSystemWorking); + + // + // Some bus drivers + + // incorrectly report DeviceWake=D0 to + // indicate that it does not support wake instead of specifying + // PowerDeviceUnspecified and KMDF ends up requesting + // a D0 irp when going to Dx. The check prevents this bug. + // + if (dxState < PowerDeviceD1 || + dxState > PowerDeviceD3 || + (dxState > PowerDeviceD2 && Settings->IdleCaps == IdleUsbSelectiveSuspend) + ) { + status = STATUS_POWER_STATE_INVALID; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "DeviceWake power state reported in device capabilities " + "%!DEVICE_POWER_STATE! indicates that device can not signal" + " a wake event, %!STATUS!", + dxState, status); + return status; + } + } + else { + DEVICE_POWER_STATE dxDeepest; + + dxState = Settings->DxState; + dxDeepest = PowerPolicyGetDeviceDeepestDeviceWakeState(PowerSystemWorking); + + if (dxState > dxDeepest) { + status = STATUS_POWER_STATE_INVALID; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "DxState specified by driver %!DEVICE_POWER_STATE! cannot " + "be lighter than lightest available device wake state" + " %!DEVICE_POWER_STATE!, %!STATUS!", dxState, + dxDeepest, status); + return status; + } + + // + // Can only perform wait wake from D2 on a USB device + // + if (dxState > PowerDeviceD2 && + Settings->IdleCaps == IdleUsbSelectiveSuspend) { + status = STATUS_POWER_STATE_INVALID; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "DxState specified by driver %!DEVICE_POWER_STATE! cannot " + "be lighter than PowerDeviceD2 for USB selective suspend " + "%!STATUS!", + dxState, status); + return status; + } + } + + if (Settings->IdleCaps == IdleUsbSelectiveSuspend) { + status = m_PowerPolicyMachine.InitUsbSS(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to initialize USB selective suspend %!STATUS!", + status); + return status; + } + } + + break; + + case IdleCannotWakeFromS0: + s0Capable = FALSE; + + if (Settings->DxState == PowerDeviceMaximum) { + dxState = PowerDeviceD3; + } + else { + dxState = Settings->DxState; + } + + break; + + default: + ASSERT(FALSE); + break; + } + + if (Settings->IdleTimeout == IdleTimeoutDefaultValue) { + idleTimeout = FxPowerPolicyDefaultTimeout; + } + else { + idleTimeout = Settings->IdleTimeout; + } + + if (Settings->UserControlOfIdleSettings == IdleAllowUserControl) { + + status = UpdateWmiInstanceForS0Idle(AddInstance); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Settings->Enabled == WdfUseDefault) { + // + // Read the registry entry for idle enabled if it's the first time. + // + if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + DECLARE_CONST_UNICODE_STRING(valueName, WDF_S0_IDLE_ENABLED_VALUE_NAME); + + // + // Read registry. If registry value is not found, the value of + // "enabled" remains unchanged + // + ReadRegistryS0Idle(&valueName, &enabled); + } + else { + // + // Use the saved value for idle enabled. + // + enabled = m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; + } + } + + overridable = TRUE; + } + else if (Settings->UserControlOfIdleSettings == IdleDoNotAllowUserControl) { + // + // No user control + // + overridable = FALSE; + + (void) UpdateWmiInstanceForS0Idle(RemoveInstance); + } + + // + // !!!! DO NOT INTRODUCE FAILURES BEYOND THIS POINT !!!! + // + // We should not introduce any failures that are not due to driver errors + // beyond this point. This is because we are going to commit the driver's + // S0-idle settings now and any failure in the midst of that could leave us + // in a bad state. Therefore, all failable code where the failure is beyond + // the driver's control should be placed above this point. + // + // For example, a driver may want wake-from-S0 support, but the device may + // not support it. We already checked for that failure above, before we + // started committing any of the driver's S0-idle settings. + // + // Any failures below this point should only be due to driver errors, i.e. + // the driver incorrectly calling the AssignS0IdleSettings DDI. + // + + if (firstTime) { + m_PowerPolicyMachine.m_Owner->m_IdleSettings.Set = TRUE; + m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable = overridable; + } + + // + // IdleTimeoutType is available only on > 1.9 + // + if (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) { + if (firstTime) { + if ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) || + (SystemManagedIdleTimeoutWithHint == + Settings->IdleTimeoutType)) { + // + // This is the first time S0-idle policy is being specified and + // the caller has asked for the idle timeout to be determined + // by the power manager. + // + status = m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UseSystemManagedIdleTimeout( + GetDriverGlobals() + ); + if (!NT_SUCCESS(status)) { + return status; + } + } + } else { + // + // This is not the first time S0-idle policy is being specified. + // Verify that the caller is not trying to change their mind about + // whether the idle timeout is determined by the power manager. + // + BOOLEAN currentlyUsingSystemManagedIdleTimeout; + BOOLEAN callerWantsSystemManagedIdleTimeout; + + currentlyUsingSystemManagedIdleTimeout = + m_PowerPolicyMachine.m_Owner->m_IdleSettings.m_TimeoutMgmt. + UsingSystemManagedIdleTimeout(); + callerWantsSystemManagedIdleTimeout = + ((SystemManagedIdleTimeout == Settings->IdleTimeoutType) || + (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType)); + + // + // UMDF currently does not implement + // IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable. So + // that method must be called only as part of the second check in + // the "if" statement below. Since UMDF currently does not support + // system managed idle timeout, the first check will always evaluate + // to 'FALSE', so the second check never gets executed for UMDF. + // + if ((callerWantsSystemManagedIdleTimeout != + currentlyUsingSystemManagedIdleTimeout) + && + (IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable()) + ) { + + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "A previous call to assign S0-idle policy specified that " + "the idle timeout %s be determined by the power manager. " + "This decision cannot be changed. %!STATUS!", + currentlyUsingSystemManagedIdleTimeout ? + "should" : + "should not", + status); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return status; + } + } + } + + if (Settings->IdleCaps == IdleCannotWakeFromS0) { + // + // PowerUpIdleDeviceOnSystemWake field added after v1.7. + // By default KMDF uses an optimization where the device is not powered + // up when resuming from Sx if it is idle. The field + // PowerUpIdleDeviceOnSystemWake is used to turn off this optimization and allow + // device to power up when resuming from Sx. Note that this optimization + // is applicable only for IdleCannotWakeFromS0. In other cases the + // device is always powered up in order to arm for wake. + // + powerUpOnSystemWake = + (Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7)) ? + Settings->PowerUpIdleDeviceOnSystemWake : + WdfUseDefault; + + switch(powerUpOnSystemWake) { + case WdfTrue: + m_PowerPolicyMachine.m_Owner->m_IdleSettings.PowerUpIdleDeviceOnSystemWake = TRUE; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Driver turned off S0Idle optimization. Device will be " + "powered up on resume from Sx even when it is idle"); + break; + case WdfFalse: + m_PowerPolicyMachine.m_Owner->m_IdleSettings.PowerUpIdleDeviceOnSystemWake = FALSE; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Driver turned on S0Idle optimization. Device will remain " + "powered off if idle when resuming from Sx"); + break; + case WdfUseDefault: + DO_NOTHING(); + break; + default: + break; + } + } + + if (FALSE == + m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapabilityKnown) + { + if (Settings->IdleCaps == IdleUsbSelectiveSuspend) { + m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable = TRUE; + m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.UsbSSCapabilityKnown = TRUE; + + } else if (Settings->IdleCaps == IdleCanWakeFromS0) { + + m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.UsbSSCapabilityKnown = TRUE; + } + } + + // + // Wake FromS0Capable is set every time because we want to allow the driver + // to swap between idle wake capable and idle not wake capable. This should + // be allowed so that a scenario similar to the following can be implemented: + // + // a) when the device has an outstanding open, the device should arm itself + // for wake when idle + // + // b) when the device does not have an outstanding open, the device should + // be off and not armed. + // + // The only way to be off is to assign S0 wake settings, so the + // WakeFromS0Capable field must change on each DDI call. This is not a + // problem for the power policy state machine because it evaluates + // WakeFromS0Capable state before enabling of idle. If we are not + // WakeFromS0Capable and USB SS capable (ie a have a torn/unsynchronized + // state) in m_IdleSettings, we will recover from it when processing + // PwrPolS0IdlePolicyChanged in the state machine (b/c this event causes + // both fields to be reevaluated). + // + m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable = s0Capable; + + m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState = dxState; + + if (m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // With system managed idle timeout, we don't want to apply an idle + // timeout of our own on top of that. Effectively, our idle timeout is + // 0. + // But we apply a negligibly small timeout value as this allows us to + // keep the same logic in the idle state machine, regardless of whether + // we're using system-managed idle timeout or driver-managed idle + // timeout. + // + if (firstTime) { + m_PowerPolicyMachine.m_Owner-> + m_PowerIdleMachine.m_PowerTimeout.QuadPart = + negliblySmallIdleTimeout; + } + + if (SystemManagedIdleTimeoutWithHint == Settings->IdleTimeoutType) { + // + // We save the idle timeout hint, but we don't provide the hint to + // the power framework immediately. This is because currently we may + // or may not be registered with the power framework. Note that + // WdfDeviceAssignS0IdleSettings might get called even when we are + // not registered with the power framework. + // + // Therefore, we provide the hint to the power framework only when + // we get to the WdfDevStatePwrPolStartingDecideS0Wake state. This + // state is a good choice for providing the hint because: + // 1. We know we would be registered with the power framework when + // we are in this state. + // 2. Any change in S0-idle settings causes us to go through this + // state. + // + m_PowerPolicyMachine.m_Owner->m_PoxInterface.m_NextIdleTimeoutHint = + idleTimeout; + } + + } else { + m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.m_PowerTimeout.QuadPart + = WDF_REL_TIMEOUT_IN_MS(idleTimeout); + } + + // + // If the driver is 1.11 or later, update the bus drivers with the client's + // choice on the topic of D3hot or D3cold. + // + if ((Settings->Size > sizeof(WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9)) && + (Settings->ExcludeD3Cold != WdfUseDefault)) { + MxDeviceObject deviceObject; + BOOLEAN enableD3Cold; + + deviceObject.SetObject(m_Device->GetDeviceObject()); + + switch (Settings->ExcludeD3Cold) { + case WdfFalse: + enableD3Cold = TRUE; + break; + default: + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Invalid tri-state value for ExcludeD3Cold %d", + Settings->ExcludeD3Cold); + __fallthrough; + case WdfTrue: + enableD3Cold = FALSE; + break; + } + + SetD3ColdSupport(GetDriverGlobals(), + &deviceObject, + &m_D3ColdInterface, + enableD3Cold); + } + + PowerPolicySetS0IdleState(enabled); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::PowerPolicySetSxWakeSettings( + __in PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings, + __in BOOLEAN ArmForWakeIfChildrenAreArmedForWake, + __in BOOLEAN IndicateChildWakeOnParentWake + ) +/*++ + +Routine Description: + + Updates the Sx wake settings for the device. No event is posted to the + state machine because this setting is statically checked when the machine + is entering an Sx state (unlike S0 idle which can be checked at any time). + + The first this function is called, the ability to allow the user to control + this setting is set. + +Arguments: + + Settings - the new settings to apply + + ArmForWakeIfChildrenAreArmedForWake - Inidicates whether the device + should arm for wake when one or more children are armed for wake + + IndicateChildWakeOnParentWake - Indicates whether the device should + propagate the wake status to its children + +Return Value: + + NTSTATUS + + --*/ +{ + DEVICE_POWER_STATE dxState; + NTSTATUS status; + BOOLEAN overridable, firstTime, enabled; + + dxState = PowerDeviceD3; + overridable = FALSE; + firstTime = TRUE; + + if (Settings->Enabled == WdfTrue) { + enabled = TRUE; + + } + else if (Settings->Enabled == WdfUseDefault) { + enabled = TRUE; + + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + DECLARE_CONST_UNICODE_STRING(valueName, WDF_SX_WAKE_DEFAULT_VALUE_NAME); + + // + // Read registry. If registry value is not found, the value of "enabled" + // remains unchanged + // + ReadRegistrySxWake(&valueName, &enabled); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "If registry value WdfDefaultWakeFromSleepState was present, " + "it was not read because DDI WdfDeviceAssignSxWakeSettings " + "was not called at PASSIVE_LEVEL"); + } + } + else { + enabled = FALSE; + } + + if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Set) { + firstTime = FALSE; + } + + if (m_CapsQueried == FALSE && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + status = QueryForCapabilities(); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Do not set m_CapsQueried to TRUE yet because we will do that once we + // know the entire stack has been built we will do the query again. + // + } + + if (Settings->DxState == PowerDeviceMaximum) { + dxState = PowerPolicyGetDeviceDeepestDeviceWakeState((SYSTEM_POWER_STATE)m_SystemWake); + + // + // Some bus drivers + + // incorrectly report DeviceWake=D0 to + // indicate that it does not support wake instead of specifying + // PowerDeviceUnspecified and KMDF ends up requesting + // a D0 irp when going to Dx. The check prevents this bug. + // + if (dxState < PowerDeviceD1 || dxState > PowerDeviceD3) { + status = STATUS_POWER_STATE_INVALID; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "DeviceWake power state reported in device capabilities " + "%!DEVICE_POWER_STATE! indicates that device can not signal a " + "wake event, %!STATUS!", + dxState, status); + return status; + } + } + else { + DEVICE_POWER_STATE dxDeepest; + + dxState = Settings->DxState; + dxDeepest = PowerPolicyGetDeviceDeepestDeviceWakeState((SYSTEM_POWER_STATE)m_SystemWake); + + if (dxState > dxDeepest) { + status = STATUS_POWER_STATE_INVALID; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "DxState specified by driver %!DEVICE_POWER_STATE! cannot be" + " lighter than lightest available device wake state " + "%!DEVICE_POWER_STATE!, %!STATUS!", dxState, + dxDeepest, status); + return status; + } + } + + if (Settings->UserControlOfWakeSettings == WakeAllowUserControl) { + + status = UpdateWmiInstanceForSxWake(AddInstance); + + if (!NT_SUCCESS(status)) { + return status; + } + + if (Settings->Enabled == WdfUseDefault) { + // + // Read the registry entry for wake enabled if it's the first time. + // + if (firstTime && Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + DECLARE_CONST_UNICODE_STRING(valueName, WDF_SX_WAKE_ENABLED_VALUE_NAME); + + // + // Read registry. If registry value is not found, the value of + // "enabled" remains unchanged + // + ReadRegistrySxWake(&valueName, &enabled); + } + else { + // + // Use the saved value for wake enabled. + // + enabled = m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; + } + } + + overridable = TRUE; + } + else if (Settings->UserControlOfWakeSettings == WakeDoNotAllowUserControl) { + // + // No user control, just set to enabled + // + overridable = FALSE; + + (void) UpdateWmiInstanceForSxWake(RemoveInstance); + } + + if (firstTime) { + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Set = TRUE; + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable = overridable; + + // + // If ArmForWakeIfChildrenAreArmedForWake setting is set to FALSE, + // then we use the legacy framework behavior which did not depend + // on the child device being capable of arming for wake or not. + // + m_PowerPolicyMachine.m_Owner->m_WakeSettings.ArmForWakeIfChildrenAreArmedForWake = + ArmForWakeIfChildrenAreArmedForWake; + + // + // If IndicateChildWakeOnParentWake setting is set to FALSE, then + // we use the legacy framework behavior wherein the wake status + // is not propagated from the parent device to the child device. + // + m_PowerPolicyMachine.m_Owner->m_WakeSettings.IndicateChildWakeOnParentWake = + IndicateChildWakeOnParentWake; + } + + m_PowerPolicyMachine.m_Owner->m_WakeSettings.DxState = dxState; + + PowerPolicySetSxWakeState(enabled); + + return STATUS_SUCCESS; +} + + + + + + + + + + + + + + + + + +NTSTATUS +FxPkgPnp::_S0IdleQueryInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* /* Instance */, + __in ULONG /* OutBufferSize */, + __out PVOID OutBuffer, + __out PULONG BufferUsed + ) +{ + *((BOOLEAN*) OutBuffer) = + (Device->m_PkgPnp)->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; + *BufferUsed = sizeof(BOOLEAN); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::_S0IdleSetInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* /* Instance */, + __in ULONG /* InBufferSize */, + __in PVOID InBuffer + ) +{ + BOOLEAN value; + + + // + // FxWmiIrpHandler makes sure the buffer is at least one byte big, so we + // don't check the buffer size. + // + + value = *(PBOOLEAN) InBuffer; + + (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::_S0IdleSetItem( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* /* Instance */, + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in PVOID InBuffer + ) +{ + BOOLEAN value; + + if (DataItemId != 0) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (InBufferSize < sizeof(BOOLEAN)) { + return STATUS_BUFFER_TOO_SMALL; + } + + value = *(BOOLEAN*) InBuffer; + (Device->m_PkgPnp)->PowerPolicySetS0IdleState(value); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::_SxWakeQueryInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* /* Instance */, + __in ULONG /* OutBufferSize */, + __out PVOID OutBuffer, + __out PULONG BufferUsed + ) +{ + *((BOOLEAN*) OutBuffer) = + (Device->m_PkgPnp)->m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; + *BufferUsed = sizeof(BOOLEAN); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::_SxWakeSetInstance( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* /* Instance */, + __in ULONG /* InBufferSize */, + __in PVOID InBuffer + ) +{ + BOOLEAN value; + + // + // FxWmiIrpHandler makes sure that the buffer is at least one byte big, so + // we don't check the buffer size + // + value = *(PBOOLEAN) InBuffer; + + (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::_SxWakeSetItem( + __in CfxDevice* Device, + __in FxWmiInstanceInternal* /* Instance */, + __in ULONG DataItemId, + __in ULONG InBufferSize, + __in PVOID InBuffer + ) +{ + BOOLEAN value; + + if (DataItemId != 0) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (InBufferSize < sizeof(BOOLEAN)) { + return STATUS_BUFFER_TOO_SMALL; + } + + value = *(BOOLEAN*) InBuffer; + (Device->m_PkgPnp)->PowerPolicySetSxWakeState(value); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PowerPolicyHandleSystemQueryPower( + __in SYSTEM_POWER_STATE QueryState + ) +/*++ + +Framework Philosophy Discussion: + + WDM sends IRP_MN_QUERY_POWER for system power states (where system power + states are S0-working, S1-light-sleep, S2-deeper-sleep, S3-deepest-sleep, + S4-hibernation, S5-soft-off.) The idea is that, if a driver can't support + a particular state, it fails the query. The problem is that this idea is + horribly broken. + + The first problem is that WDM doesn't always send these IRPs. In some + situations, (very low battery, system getting critically hot) WDM will + attempt to preserve user data by sleeping or hibernating, rather than just + crashing. This is good, but it makes a driver writer's life very difficult, + since it means that you have to deal with being told to go to a particular + state even if you think that your device won't be able to deal well with + that state. + + The second problem is that, by the time the system is going to sleep, the + user probably isn't still looking at the screen. This is especially true + for laptop computers, as the system is very likely sleeping because the + user closed the clamshell lid. So any attempt to ask the user how to + resolve a situation where a driver doesn't want to go to a low power state + is futile. Furthermore, even when the screen is still available, users + dislike it when they push the sleep button or the power button on their + machines and the machines don't do what they were told to do. + + The third problem is related to the second. While there may be completely + legitimate reasons for the driver to want to delay or even to veto a + transition into a sleep state, (an example of a valid scenario would be one + in which the driver was involved in burning a CD, an operation which can't + be interrupted,) there isn't any good way for a driver to interact with a + user anyhow. (Which desktop is the right one to send messages to? What + should the UI for problem resolution look like? How does a driver put up + UI anyhow?) + + All the driver really knows is that it will or won't be able to maintain + device state, and it will or won't be able to get enough power to arm + any wake events that it might want to deliver (like PME#.) + + Consequently, the designers of the PnP/Power model in the Framework have + decided that all QueryPower-Sx IRPs will be completed successfully + except if the device cannot maintain enough power to trigger its wake + signal *AND* if the system supports lighter sleep states than the + one that is currently being queried. (If it does, then the kernel's power + manager will turn right around and query for those, next.) + + This story usually brings up a few objections: + + 1) My device is important! When it's operating, I don't want + the machine to just fall asleep. I need to fail QueryPower-Sx to + prevent that. + + This objection is an unfortunate consequence of the existing DDK. There + is a perfectly good API that allows a driver to say that the machine + shouldn't just fall asleep. (See PoSetSystemState.) If a user presses + a button telling the machine to go to sleep, then the driver has a + responsibility to do that. + + 2) There are certain operations that just can't be interrupted! + + While that's true, those operations started somewhere, probably in user- + mode. Those same user-mode components would be much, much better suited + toward negotiating with the user or with other components to figure out + what to do when the uninterruptable must be interrupted. User-mode + components get notification that the system is going to sleep and they + can delay or veto the transition. Get over the idea that your driver + needs to be involved, too. + +Routine Description: + + Determines if for the passed in System state, if we can wake the machine + from it. If the query state is the machine's minimum system state, then + we always succeed it because we want the machine to go to at least some + sleeping state. We always succeed hibernate and system off requests as well. + +Arguments: + + QueryState - The proposed system state + +Return Value: + + NT_SUCCESS if the queried state should be allowed, !NT_SUCCESS otherwise + + --*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + NTSTATUS status; + + if (QueryState >= PowerSystemHibernate || + PowerPolicyCanWakeFromSystemState(QueryState)) { + // + // If the query is for the machine's minimum S state or we going into + // hibernate or off, always succeed it. + // + status = STATUS_SUCCESS; + } + else { + + // + // On Windows Vista and above, its OK to return a failure status code + // if the system is going into an S state at which the device cannot + // wake the system. + // + ASSERT(FxLibraryGlobals.OsVersionInfo.dwMajorVersion >= 6); + + // + // The S state the machine is going into is one where we can't + // wake it up because our D state is too low for this S state. + // Since this isn't the minimum S state the machine is capable + // of, reject the current query. + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP, + "failing system query power because the device cannot wake the " + "machine from S%d", + QueryState - 1); + + status = STATUS_POWER_STATE_INVALID; + } + + return status; +} + +VOID +FxPkgPnp::PowerPolicySetS0IdleState( + __in BOOLEAN State + ) +{ + m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled = State ? TRUE : FALSE; + m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty = TRUE; + PowerPolicyProcessEvent(PwrPolS0IdlePolicyChanged); +} + +VOID +FxPkgPnp::PowerPolicySetSxWakeState( + __in BOOLEAN State + ) +/*++ + +Routine Description: + Sets the wake from Sx state + + No need to post an event to the power policy state machine because we + will not change any active due to a change in this setting. We only + evaluate this state when going into Sx and once in this state we will not + change our behavior until the next Sx, which will then evaluate this state. + +Arguments: + State - New state + +Return Value: + VOID + + --*/ +{ + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled = State ? TRUE : FALSE; + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty = TRUE; + + // + // Since we are not posting an event to the power policy state machine, try + // to write out the value now, otherwise it will be written when we + // transition + // + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + NTSTATUS status; + LONGLONG timeout; + + timeout = 0; + + // + // If the lock is already acquired on this thread, this will fail, which + // is OK. + // + status = m_PowerPolicyMachine.m_StateMachineLock.AcquireLock( + GetDriverGlobals(), + &timeout + ); + + if (FxWaitLockInternal::IsLockAcquired(status)) { + SaveState(TRUE); + + m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock( + GetDriverGlobals() + ); + } + } +} + +VOID +FxPkgPnp::SetDeviceFailed( + __in WDF_DEVICE_FAILED_ACTION FailedAction + ) +/*++ + +Routine Description: + Marks the device as a victim of catastrophic failure, either in software + or in hardware. + + If AttemptToRestart is TRUE, then we should try to get the stack re-built + after it has been torn down. This would typically be the case the failure + was in the software, and possibly not be the case if the failure was in + the hardware. + +Arguments: + FailedAction - action to take once the stack has been removed + +Return Value: + None + + --*/ +{ + NTSTATUS status; + MdDeviceObject pdo; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(2, 15) == FALSE && + FailedAction == WdfDeviceFailedAttemptRestart) { + + FailedAction = WdfDeviceFailedNoRestart; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGDEVICE, + "WdfDeviceFailedAttemptRestart is only available for UMDF 2.15 " + "and later drivers. Reverting to WdfDeviceFailedNoRestart."); + } +#endif + + m_FailedAction = (BYTE) FailedAction; + + // + // This will cause the PnP manager to tear down this stack, even if + // the PDO can't be surprise-removed. + // + m_Failed = TRUE; + + if (FailedAction == WdfDeviceFailedAttemptRestart) { + // + // Attempt to get the PDO surprise-removed. + // + status = AskParentToRemoveAndReenumerate(); + + if (NT_SUCCESS(status)) { + return; + } + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // In between creating a PDO WDFDEVICE and it starting, if this DDI is called, + // we will not have a valid PDO. Make sure it is valid before we proceed. + // + pdo = m_Device->GetSafePhysicalDevice(); + + if (pdo != NULL) { + // + // Now tell the PnP manager to re-query us for our state. + // + MxDeviceObject physicalDeviceObject(pdo); + + physicalDeviceObject.InvalidateDeviceState( + m_Device->GetDeviceObject() + ); + } +#else // USER_MODE + m_Device->GetMxDeviceObject()->InvalidateDeviceState( + m_Device->GetDeviceObject()); + UNREFERENCED_PARAMETER(pdo); +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::_PnpDeviceUsageNotification( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return This->PnpDeviceUsageNotification(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpDeviceUsageNotification( + __inout FxIrp* Irp + ) +{ + FxRelatedDeviceList* pList; + FxRelatedDevice *pDependent; + FxAutoIrp relatedIrp(NULL), parentIrp(NULL); + MxDeviceObject topOfParentStack; + DEVICE_USAGE_NOTIFICATION_TYPE type; + NTSTATUS status; + MxDeviceObject pAttached; + MdIrp pNewIrp; + CCHAR maxStack; + BOOLEAN inPath, supported; + ULONG oldFlags; + MxAutoWorkItem workItem; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering DeviceUsageNotification handler"); + + status = STATUS_SUCCESS; + + type = Irp->GetParameterUsageNotificationType(); + inPath = Irp->GetParameterUsageNotificationInPath(); + supported = FALSE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "type %x, in path %x, can support paging %x, dump file %x, " + "hiber file %x, boot file %x", + type, inPath, + IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFilePaging)), + IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileDump)), + IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileHibernation)), + IsUsageSupported(_SpecialTypeToUsage(WdfSpecialFileBoot))); + + + if (type >= WdfSpecialFilePaging && type < WdfSpecialFileMax) { + if (inPath) { + if (m_Device->IsFilter()) { + // + // Filters always support usage notifications + // + supported = TRUE; + } + else { + supported = IsUsageSupported(type); + } + } + else { + // + // We always handle notifications where we are out of the path + // + supported = TRUE; + } + } + + if (supported == FALSE) { + status = STATUS_NOT_IMPLEMENTED; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Usage type %x not supported, %!STATUS!", type, status); + + return CompletePnpRequest(Irp, status); + } + + // + // Usage notification IRP gets forwarded to parent stack or to + // dependent stack. Since in such cases (with deep device tree) the stack + // may run out quickly, ensure there is enough stack, otherwise use a + // workitem. + // + if (Mx::MxHasEnoughRemainingThreadStack() == FALSE && + (m_Device->IsPdo() || + m_UsageDependentDeviceList != NULL)) { + + status = workItem.Allocate(m_Device->GetDeviceObject()); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p could not allocate workitem " + "to send usage notification type %d, inpath %d, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + type, inPath, status); + + return CompletePnpRequest(Irp, status); + } + } + + // + // Usage notification is supported. Set the flags on the device object + // before processing this any further and save the current flags on the + // device object. + // + oldFlags = SetUsageNotificationFlags(type, inPath); + + if (m_Device->IsPdo()) { + + + + + + + + + + + + + topOfParentStack.SetObject( + m_Device->m_ParentDevice->GetAttachedDeviceReference()); + + pNewIrp = FxIrp::AllocateIrp(topOfParentStack.GetStackSize()); + if (pNewIrp != NULL) { + parentIrp.SetIrp(pNewIrp); + + // + // parentIrp now owns the irp + // + pNewIrp = NULL; + + status = SendDeviceUsageNotification(&topOfParentStack, + &parentIrp, + &workItem, + Irp, + FALSE); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p could not allocate PIRP for parent !devobj %p to " + "send usage notification type %d, inpath %d, %!STATUS!", + m_Device->GetHandle(), topOfParentStack.GetObject(), + type, inPath, status); + } + topOfParentStack.DereferenceObject(); + topOfParentStack.SetObject(NULL); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit %!STATUS!", status); + + RevertUsageNotificationFlags(type, inPath, oldFlags); + return CompletePnpRequest(Irp, status); + } + } + + maxStack = 0; + pDependent = NULL; + + // + // If the driver supports the given special file, lets notify dependent + // stacks. + // + + // + // LockForEnum will lock out new changes to the list until we unlock the list. + // We remain at passive level once we are locked. + // + if (m_UsageDependentDeviceList != NULL) { + // + // We capture the m_UsageDependentDeviceList pointer value so that we + // always use the same pointer value and that we have matched actions + // (lock for enum / unlock from enum). What we are trying to avoid is + // this: + // 1) we do not lock for enum because m_UsageDependentDeviceList == NULL + // 2) in the middle of this function, m_UsageDependentDeviceList is + // assigned a pointer value + // 3) we try to unlock from enum later (or iterate, thinking the enum + // lock is held) by checking m_UsageDependentDeviceList for NULL, and + // now that is != NULL, use it. + // + // By capturing the pointer now, we either have a list or not and we don't + // hit situations 2 or 3. So, the rule is every subseqeunt time we need + // to check if there is valid m_UsageDependentDeviceList pointer, we + // use pList, but when we use the list, we can use m_UsageDependentDeviceList + // directly. + // + pList = m_UsageDependentDeviceList; + + m_UsageDependentDeviceList->LockForEnum(GetDriverGlobals()); + + while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { + + MxDeviceObject deviceObject(pDependent->GetDevice()); + + + + + + + + + + + + + + pAttached.SetObject(deviceObject.GetAttachedDeviceReference()); + + if (pAttached.GetStackSize() > maxStack) { + maxStack = pAttached.GetStackSize(); + } + + pAttached.DereferenceObject(); + } + } + else { + pList = NULL; + } + + if (maxStack > 0) { + // + // If we have a maxStack size, we have a list as well + // + ASSERT(m_UsageDependentDeviceList != NULL); + + // + // Allocate one irp for all the stacks so that we don't have an + // allocation later. This way, once we have the irp, we can send the + // usage notification to all stacks reliably, as well as the reverting + // of the notification if we encounter failure. + // + pNewIrp = FxIrp::AllocateIrp(maxStack); + if (pNewIrp == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p could not allocate IRP to send usage notifications" + " to related stacks, type %d, inpath %d, status %!STATUS!", + m_Device->GetHandle(), type, inPath, status); + } + else { + MxDeviceObject dependentDevice; + + // + // relatedIrp will free the irp when it goes out of scope + // + relatedIrp.SetIrp(pNewIrp); + + // + // Walk our collection of dependent device stacks, and notify + // each stack of the device notification. If any fail, notify + // the stacks who already were told of the reverted behavior. + // + pDependent = NULL; + while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { + dependentDevice.SetObject(pDependent->GetDevice()); + status = SendDeviceUsageNotification(&dependentDevice, + &relatedIrp, + &workItem, + Irp, + FALSE); + + if (!NT_SUCCESS(status)) { + FxRelatedDevice* pDependent2; + + pDependent2 = NULL; + + // + // A device failed the device usage notification request. + // Notify the stacks that didn't fail, so they can unwind + // the operation. + // + while ((pDependent2 = m_UsageDependentDeviceList->GetNextEntry(pDependent2)) != NULL && + pDependent2 != pDependent) { + dependentDevice.SetObject(pDependent2->GetDevice()); + + // + // We're already in a failure path. We can't do anything + // about yet another failure. So we ignore the return + // value. + // + (void) SendDeviceUsageNotification(&dependentDevice, + &relatedIrp, + &workItem, + Irp, + TRUE); + } + + // + // Now break out of our outter loop. + // + break; + } + } + } + } + + // + // If we are successful to this point, then send the IRP down the + // stack. + // + if (NT_SUCCESS(status)) { + BOOLEAN referenceSucceeded, sendDown; + + referenceSucceeded = FALSE; + sendDown = TRUE; + + // + // Make sure the stack is in D0 before sending down the request. This + // will at least guarantee that all devices below this one are in D0 + // when the make the transition from power pageable to non or vice versa. + // + if (IsPowerPolicyOwner()) { + status = PowerReference(TRUE); + + if (NT_SUCCESS(status)) { + referenceSucceeded = TRUE; + } + else { + Irp->SetStatus(status); + sendDown = FALSE; + } + } + + if (sendDown) { + // + // If we supported the usage, set the status to success, otherwise we + // keep the status in the irp as it arrived to this device + // + if (supported) { + Irp->SetStatus(status); + } + status = SendIrpSynchronously(Irp); + } + + // + // Transitioning from a thread which was power pagable to non power + // pagable. We now need a power thread for the stack, ask for it. + // Note that there is no need for power thread in case of "boot" + // notification since boot notification doesn't require clearing device's + // DO_POWER_PAGABLE flag (power thread is required when handling power + // irp at dispatch level which can happen if the DO_POWER_PAGABLE flag + // is cleared). + // + // NOTE: Once we have a power thread, we never go back to using work + // items even though the stack may revert to power pagable. + // This is an acceptable tradeoff between resource usage and + // WDF complexity. + // + // + if (NT_SUCCESS(status) && + inPath && + (HasPowerThread() == FALSE) && + type != WdfSpecialFileBoot + ) { + status = QueryForPowerThread(); + + if (!NT_SUCCESS(status)) { + // + // Keep status the same through out so we can set it back in + // the irp when we are done. + // + if (m_Device->IsPdo()) { + // + // need to revert our parent's stack + // + + + + + + + + + + + + + topOfParentStack.SetObject( + m_Device->m_ParentDevice->GetAttachedDeviceReference()); + + // + // Ignore the status because we can't do anything on failure + // + (void) SendDeviceUsageNotification(&topOfParentStack, + &parentIrp, + &workItem, + Irp, + TRUE); + + topOfParentStack.DereferenceObject(); + } + else { + // + // Notify the stack below us + // + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetParameterUsageNotificationInPath(FALSE); + + // + // Required for pnp irps + // + Irp->SetStatus(STATUS_NOT_SUPPORTED); + + // + // Ignore the status because we can't do anything on failure + // + (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); + } + + Irp->SetStatus(status); + } + } + + // + // Now check whether the lower devices succeeded or failed. If they + // failed, back out our changes and propogate the failure. + // + if (!NT_SUCCESS(status)) { + // + // Revert the flags set on the device object. + // + RevertUsageNotificationFlags(type, inPath, oldFlags); + + // + // Notify dependent stacks of the failure. + // + pDependent = NULL; + + // + // See pList initiatilazation as to why we compare pList for != NULL + // and not m_UsageDependentDeviceList. + // + if (pList != NULL) { + MxDeviceObject dependentDevice; + + while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { + dependentDevice.SetObject(pDependent->GetDevice()); + + // + // We're already in a failure path. We can't do anything + // about yet another failure. So we ignore the return value. + // + (void) SendDeviceUsageNotification(&dependentDevice, + &relatedIrp, + &workItem, + Irp, + TRUE); + } + } + } + + // + // By this point, we have propagated the notification to dependent devices + // and lower stack, and if anyone failed during that time, we also + // propagated failure to dependent stacks and lower stack. + // If status is success at this point, invoke the driver's callback. + // + if (NT_SUCCESS(status)) { + // + // Invoke callback. Note that only one of the callbacks + // DeviceUsageNotification or DeviceUsgeNotificationEx will get + // invoked since only one of the callbacks at a time is supported. + // We ensured that during registration of the callback. + // Note that Ex callback will return success if driver did not + // supply any callback. + // + m_DeviceUsageNotification.Invoke(m_Device->GetHandle(), + _UsageToSpecialType(type), + inPath); + + status = m_DeviceUsageNotificationEx.Invoke( + m_Device->GetHandle(), + _UsageToSpecialType(type), + inPath + ); + + if (!NT_SUCCESS(status)) { + // + // Driver's callback returned failure. We need to propagate + // failure to lower stack and dependent stacks. + // + // + // Keep status the same through out so we can set it back in + // the irp when we are done. + // + if (m_Device->IsPdo()) { + // + // need to revert our parent's stack + // + + + + + + + + + + + + + topOfParentStack.SetObject( + m_Device->m_ParentDevice->GetAttachedDeviceReference()); + + // + // Ignore the status because we can't do anything on failure + // + (void) SendDeviceUsageNotification(&topOfParentStack, + &parentIrp, + &workItem, + Irp, + TRUE); + + topOfParentStack.DereferenceObject(); + } + else { + // + // Notify the stack below us + // + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetParameterUsageNotificationInPath(FALSE); + + // + // Required for pnp irps + // + Irp->SetStatus(STATUS_NOT_SUPPORTED); + + // + // Ignore the status because we can't do anything on failure + // + (void) Irp->SendIrpSynchronously(m_Device->GetAttachedDevice()); + } + + Irp->SetStatus(status); + + // + // Revert the flags set on the device object. + // + RevertUsageNotificationFlags(type, inPath, oldFlags); + + // + // Notify dependent stacks of the failure. + // + pDependent = NULL; + + // + // See pList initiatilazation as to why we compare pList for != NULL + // and not m_UsageDependentDeviceList. + // + if (pList != NULL) { + MxDeviceObject dependentDevice; + + while ((pDependent = m_UsageDependentDeviceList->GetNextEntry(pDependent)) != NULL) { + dependentDevice.SetObject(pDependent->GetDevice()); + + // + // We're already in a failure path. We can't do anything + // about yet another failure. So we ignore the return value. + // + (void) SendDeviceUsageNotification(&dependentDevice, + &relatedIrp, + &workItem, + Irp, + TRUE); + } + } + } + + if (NT_SUCCESS(status)) { + + CommitUsageNotification(type, oldFlags); + + // + // If we are in the dump file path, we cannot idle out because we + // can experience a crash dump at any time. + // + if (IsPowerPolicyOwner() && type == DeviceUsageTypeDumpFile) { + // + // Add a reference everytime we are notified of being in the + // path, no need to match the first inPath notification and the + // last !inPath notification. + // + if (inPath) { + NTSTATUS refStatus; + + ASSERT(GetUsageCount(type) > 0); + + // + // Since our previous synchronous power reference succeeded, + // an addtional reference while we are powered up should + // never fail. + // + refStatus = PowerReference(FALSE); +#if DBG + ASSERT(NT_SUCCESS(refStatus)); +#else + UNREFERENCED_PARAMETER(refStatus); +#endif + } + else { + ASSERT(GetUsageCount(type) >= 0); + PowerDereference(); + } + } + } + } + + // + // We no longer need to be in D0 if we don't have to be. + // + if (referenceSucceeded) { + ASSERT(IsPowerPolicyOwner()); + PowerDereference(); + } + } + + // + // See pList initiatilazation as to why we compare pList for != NULL + // and not m_UsageDependentDeviceList. + // + if (pList != NULL) { + m_UsageDependentDeviceList->UnlockFromEnum(GetDriverGlobals()); + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exit %!STATUS!", status); + + return CompletePnpRequest(Irp, status); +} + +ULONG +FxPkgPnp::SetUsageNotificationFlags( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type, + __in BOOLEAN InPath + ) +/*++ + +Routine Description: + + This routine sets the usage notification flags on the device object (for + non-boot usages) and updates the special file usage count . + +Arguments: + + Type - the special file type - paging, hibernate, dump or boot file. + + InPath - indicates whether the system is creating or removing the special + file on the device. + +Return Value: + + Returns the old flags on the device object. + +--*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + ULONG oldFlags, newFlags; + + oldFlags = m_Device->GetDeviceObjectFlags(); + + // + + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Before: type %d, in path %d, special count %d, flags 0x%x, " + "device %p (WDFDEVICE %p), is pageable capable %d", + Type, InPath, GetUsageCount(Type), oldFlags, + m_Device->GetDeviceObject(), m_Device->GetHandle(), + m_Device->IsPowerPageableCapable()); + + // + // Adjust our "special file count". + // + AdjustUsageCount(Type, InPath); + + // + // Boot notification doesn't require updating device flags. + // + if (Type == WdfSpecialFileBoot) { + return oldFlags; + } + + if (m_Device->IsFilter()) { + // + // Clear the previous flags and reset them to the attached + // device's flags + // + newFlags = oldFlags & ~(DO_POWER_PAGABLE | DO_POWER_INRUSH); + newFlags |= m_Device->GetAttachedDeviceObjectFlags() & + (DO_POWER_PAGABLE | DO_POWER_INRUSH); + m_Device->SetDeviceObjectFlags(newFlags); + } + else { + if (InPath) { + m_Device->SetDeviceObjectFlags( + m_Device->GetDeviceObjectFlags() & ~DO_POWER_PAGABLE + ); + } + else { + if (m_Device->IsPowerPageableCapable() && IsInSpecialUse() == FALSE) { + m_Device->SetDeviceObjectFlags( + m_Device->GetDeviceObjectFlags() | DO_POWER_PAGABLE + ); + } + } + } + + return oldFlags; +} + +VOID +FxPkgPnp::RevertUsageNotificationFlags( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type, + __in BOOLEAN InPath, + __in ULONG OldFlags + ) +/*++ + +Routine Description: + + This routine reverts the usage notification flags to the old flags on + the device object and updates the special file usage count. + +Arguments: + + Type - the special file type - paging, hibernate or dump file. + + InPath - indicates whether the system is creating or removing the special + file on the device. + + OldFlags - the previous flags on the device object. + +--*/ +{ + // + // Re-adjust our "special file count". + // + InPath = !InPath; + AdjustUsageCount(Type, InPath); + + // + // Restore the flags on the device object. + // + m_Device->SetDeviceObjectFlags(OldFlags); +} + +VOID +FxPkgPnp::CommitUsageNotification( + __in DEVICE_USAGE_NOTIFICATION_TYPE Type, + __in ULONG OldFlags + ) +/*++ + +Routine Description: + + This routine commits the usage notification flags on the device object + and invokes the usage notification callbacks. If the current flags on + the device object indicates that there was a transition from power-pagable + to non power-pagable, or vice-versa, then an event is posted to the power + state machine to notify it of the change. After this routine is called + the PNP manager will no longer be able to disable the device. + +Arguments: + + Type - the special file type - paging, hibernation or crash dump file. + + InPath - indicates whether the system is creating or removing the special + file on the device. + + OldFlags - the previous flags on the device object. + +--*/ +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + ULONG newFlags; + + newFlags = m_Device->GetDeviceObjectFlags(); + + if ((OldFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE && + (newFlags & DO_POWER_PAGABLE) == 0) { + // + // We transitioned from a power pageable to a non power pageable + // device. Move the power state machine to the appropriate + // state. + // + PowerProcessEvent(PowerMarkNonpageable); + } + + if ((OldFlags & DO_POWER_PAGABLE) == 0 && + (newFlags & DO_POWER_PAGABLE) == DO_POWER_PAGABLE) { + // + // We transitioned from a non power pageable to a power pageable + // device. Move the power state machine to the appropriate + // state. + // + PowerProcessEvent(PowerMarkPageable); + } + + // + // Notify PNP that it should no longer be able + // to disable this device. + // + MxDeviceObject physicalDeviceObject( + m_Device->GetPhysicalDevice() + ); + physicalDeviceObject.InvalidateDeviceState( + m_Device->GetDeviceObject() + ); + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, + "After: special count %d, flags 0x%x, device %p (WDFDEVICE %p)", + GetUsageCount(Type), newFlags, + m_Device->GetDeviceObject(), m_Device->GetHandle()); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::AddUsageDevice( + __in MdDeviceObject DependentDevice + ) +{ + FxRelatedDevice* pRelated; + NTSTATUS status; + + if (m_UsageDependentDeviceList == NULL) { + KIRQL irql; + + Lock(&irql); + if (m_UsageDependentDeviceList == NULL) { + m_UsageDependentDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList(); + + if (m_UsageDependentDeviceList != NULL) { + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate usage device list for WDFDEVICE %p, " + "%!STATUS!", m_Device->GetHandle(), status); + } + + } + else { + // + // another thread allocated the list already + // + status = STATUS_SUCCESS; + } + Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + pRelated = new(GetDriverGlobals()) + FxRelatedDevice(DependentDevice, GetDriverGlobals()); + + if (pRelated == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = m_UsageDependentDeviceList->Add(GetDriverGlobals(), pRelated); + + if (!NT_SUCCESS(status)) { + pRelated->DeleteFromFailedCreate(); + } + + return status; +} + +VOID +FxPkgPnp::RemoveUsageDevice( + __in MdDeviceObject DependentDevice + ) +{ + if (m_UsageDependentDeviceList != NULL) { + m_UsageDependentDeviceList->Remove(GetDriverGlobals(), DependentDevice); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::AddRemovalDevice( + __in MdDeviceObject DependentDevice + ) +{ + FxRelatedDevice* pRelated; + NTSTATUS status; + + if (m_RemovalDeviceList == NULL) { + KIRQL irql; + + Lock(&irql); + if (m_RemovalDeviceList == NULL) { + m_RemovalDeviceList = new (GetDriverGlobals()) FxRelatedDeviceList(); + + if (m_RemovalDeviceList != NULL) { + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate removal device list for WDFDEVICE %p, " + "%!STATUS!", m_Device->GetHandle(), status); + } + } + else { + // + // another thread allocated the list already + // + status = STATUS_SUCCESS; + } + Unlock(irql); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + pRelated = new(GetDriverGlobals()) + FxRelatedDevice(DependentDevice, GetDriverGlobals()); + if (pRelated == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = m_RemovalDeviceList->Add(GetDriverGlobals(), pRelated); + + if (NT_SUCCESS(status)) { + // + // RemovalRelations are queried automatically by PnP when the device is + // going to be query removed. No need to tell pnp that the list changed + // until it needs to query for it. + // + DO_NOTHING(); + } + else { + pRelated->DeleteFromFailedCreate(); + } + + return status; +} + +VOID +FxPkgPnp::RemoveRemovalDevice( + __in MdDeviceObject DependentDevice + ) +{ + if (m_RemovalDeviceList != NULL) { + m_RemovalDeviceList->Remove(GetDriverGlobals(), DependentDevice); + } + + // + // RemovalRelations are queried automatically by PnP when the device is + // going to be query removed. No need to tell pnp that the list changed + // until it needs to query for it. + // +} + +VOID +FxPkgPnp::ClearRemovalDevicesList( + VOID + ) +{ + FxRelatedDevice* pEntry; + + if (m_RemovalDeviceList == NULL) { + return; + } + + m_RemovalDeviceList->LockForEnum(GetDriverGlobals()); + while ((pEntry = m_RemovalDeviceList->GetNextEntry(NULL)) != NULL) { + m_RemovalDeviceList->Remove(GetDriverGlobals(), pEntry->GetDevice()); + } + m_RemovalDeviceList->UnlockFromEnum(GetDriverGlobals()); + + // + // RemovalRelations are queried automatically by PnP when the device is + // going to be query removed. No need to tell pnp that the list changed + // until it needs to query for it. + // +} + +VOID +FxPkgPnp::SetInternalFailure( + VOID + ) +/*++ + +Routine Description: + Sets the failure field and then optionally invalidates the device state. + +Arguments: + InvalidateState - If TRUE, the state is invalidated + +Return Value: + None + + --*/ +{ + m_InternalFailure = TRUE; + + MxDeviceObject physicalDeviceObject( + m_Device->GetPhysicalDevice() + ); + physicalDeviceObject.InvalidateDeviceState( + m_Device->GetDeviceObject() + ); +} + +VOID +FxPkgPnp::SetPendingPnpIrp( + __inout FxIrp* Irp, + __in BOOLEAN MarkIrpPending + ) +{ + if (m_PendingPnPIrp != NULL ) { + FxIrp pendingIrp(m_PendingPnPIrp); + + // + // A state changing pnp irp is already pended. If we don't bugcheck + // the pended pnp irp will be overwritten with new pnp irp and the old + // one may never get completed, which may have drastic implications ( + // unresponsive system, power manager not sending Sx Irp etc.) + // + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "A new state changing pnp irp %!pnpmn! IRP %p arrived while another " + "pnp irp %!pnpmn! IRP %p is still pending WDFDEVICE %p\n", + Irp->GetMinorFunction(), Irp->GetIrp(), + pendingIrp.GetMinorFunction(),pendingIrp.GetIrp(), + m_Device->GetHandle()); + + FxVerifierBugCheck(GetDriverGlobals(), // globals + WDF_PNP_FATAL_ERROR, // specific type + (ULONG_PTR)m_Device->GetHandle(), //parm 2 + (ULONG_PTR)Irp->GetIrp()); // parm 3 + + /* NOTREACHED */ + return; + } + if (MarkIrpPending) { + Irp->MarkIrpPending(); + } + m_PendingPnPIrp = Irp->GetIrp(); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::AllocateEnumInfo( + VOID + ) +{ + KIRQL irql; + NTSTATUS status; + + if (m_EnumInfo != NULL) { + return STATUS_SUCCESS; + } + + Lock(&irql); + if (m_EnumInfo == NULL) { + m_EnumInfo = new (GetDriverGlobals()) FxEnumerationInfo(GetDriverGlobals()); + + if (m_EnumInfo != NULL) { + status = m_EnumInfo->Initialize(); + + if (!NT_SUCCESS(status)) { + delete m_EnumInfo; + m_EnumInfo = NULL; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGPNP, + "Could not initialize enum info for " + "WDFDEVICE %p, %!STATUS!", + m_Device->GetHandle(), status); + } + + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate enum info for WDFDEVICE %p, " + "%!STATUS!", m_Device->GetHandle(), status); + } + } + else { + // + // another thread allocated the list already + // + status = STATUS_SUCCESS; + } + Unlock(irql); + + return status; +} + +VOID +FxPkgPnp::AddChildList( + __in FxChildList* List + ) +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Adding FxChildList %p, WDFCHILDLIST %p", List, + List->GetHandle()); + + m_EnumInfo->m_ChildListList.Add(GetDriverGlobals(), + &List->m_TransactionLink); +} + +VOID +FxPkgPnp::RemoveChildList( + __in FxChildList* List + ) +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Removing FxChildList %p, WDFCHILDLIST %p", List, + List->GetHandle()); + + m_EnumInfo->m_ChildListList.Remove(GetDriverGlobals(), &List->m_TransactionLink); + + // + + // +} + +VOID +FxPkgPnp::ChildListNotifyRemove( + __inout PLONG PendingCount + ) +{ + FxTransactionedEntry* ple; + + ple = NULL; + + if (m_EnumInfo != NULL) { + m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); + while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { + FxChildList::_FromEntry(ple)->NotifyDeviceRemove(PendingCount); + } + m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); + } +} + +VOID +FxPkgPnp::AddQueryInterface( + __in FxQueryInterface* QI, + __in BOOLEAN Lock + ) +/*++ + +Routine Description: + Add a query interface structure to the list of interfaces supported + +Arguments: + QI - the interface to add + + Lock - indication of the list lock should be acquired or not + +Return Value: + None + + --*/ +{ + SINGLE_LIST_ENTRY **ppPrev, *pCur; + + if (Lock) { + m_QueryInterfaceLock.AcquireLock(GetDriverGlobals()); + } + + ASSERT(QI->m_Entry.Next == NULL); + + // + // Iterate until we find the end of the list and then append the new + // structure. ppPrev is the pointer to the Next pointer value. When we + // get to the end, ppPrev will be equal to the Next field which points to NULL. + // + ppPrev = &m_QueryInterfaceHead.Next; + pCur = m_QueryInterfaceHead.Next; + + while (pCur != NULL) { + ppPrev = &pCur->Next; + pCur = pCur->Next; + } + + *ppPrev = &QI->m_Entry; + + if (Lock) { + m_QueryInterfaceLock.ReleaseLock(GetDriverGlobals()); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +__drv_minIRQL(DISPATCH_LEVEL) +__drv_requiresIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +VOID +FxWatchdog::_WatchdogDpc( + __in PKDPC Dpc, + __in_opt PVOID Context, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) +/*++ + +Routine Description: + + This routine's job is to crash the machine, attempting to get some data + into the crashdump file (or minidump) about why the machine stopped + responding during an attempt to put the machine to sleep. + +Arguments: + + This - the instance of FxPkgPnp + +Return Value: + + this routine never returns + +--*/ +{ + WDF_POWER_ROUTINE_TIMED_OUT_DATA data; + FxWatchdog* pThis; + CfxDevice* pDevice; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + pThis = (FxWatchdog*) Context; + pDevice = pThis->m_PkgPnp->GetDevice(); + + DoTraceLevelMessage(pDevice->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "The driver failed to return from a callback routine " + "in a reasonable period of time. This prevented the " + "machine from going to sleep or from hibernating. The " + "machine crashed because that was the best way to get " + "data about the cause of the crash into a minidump file."); + + data.PowerState = pDevice->GetDevicePowerState(); + data.PowerPolicyState = pDevice->GetDevicePowerPolicyState(); + data.DeviceObject = reinterpret_cast(pDevice->GetDeviceObject()); + data.Device = pDevice->GetHandle(); + data.TimedOutThread = reinterpret_cast(pThis->m_CallingThread); + + FxVerifierBugCheck(pDevice->GetDriverGlobals(), + WDF_POWER_ROUTINE_TIMED_OUT, + (ULONG_PTR) &data); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::CreatePowerThread( + VOID + ) +/*++ + +Routine Description: + Creates a power thread for the device node. This thread is share among all + the devices in the stack through the POWER_THREAD_INTERFACE structure and + PnP query interface. + +Arguments: + None + +Return Value: + NTSTATUS + + --*/ +{ + FxSystemThread *pThread, *pOld; + NTSTATUS status; + + status = FxSystemThread::_CreateAndInit( + &pThread, + GetDriverGlobals(), + m_Device->GetHandle(), + m_Device->GetDeviceObject()); + + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Simple locking logic in case N requests are conncurrent. (The requests + // never should be concurrent, but in the case that there are 2 usage + // notifications coming in from two different sources, it could + // theoritically happen.) + // + pOld = (FxSystemThread*) InterlockedCompareExchangePointer( + (PVOID*) &m_PowerThread, pThread, NULL); + + if (pOld != NULL) { + // + // Someone also set the thread pointer value at the same time, free + // our new one here. + // + pThread->ExitThread(); + pThread->DeleteObject(); + } + + m_HasPowerThread = TRUE; + + return STATUS_SUCCESS; +} + +VOID +FxPkgPnp::ReleasePowerThread( + VOID + ) +/*++ + +Routine Description: + If this device is the owner of the power thread, it kills the thread. + Otherwise, if this device has acquired the thread from a lower device, + release the reference now. + +Arguments: + None + +Return Value: + None + + --*/ +{ + BOOLEAN hadThread; + + hadThread = m_HasPowerThread; + + // + // Set to FALSE before cleaning up the reference or thread itself in case + // there is some other context trying to enqueue. The only way that could + // be happening is if the power policy owner is not WDF and sends power irps + // after query remove or surprise remove. + // + m_HasPowerThread = FALSE; + + // + // Check for ownership + // + if (m_PowerThread != NULL) { + + FxCREvent event; + + // + // Event on stack is used, which is fine since this code is invoked + // only in KM. Verify this assumption. + // + // If this code is ever needed for UM, m_PowerThreadEvent should be + // pre-initialized (simlar to the way m_RemoveEventUm is used) + // + WDF_VERIFY_KM_ONLY_CODE(); + + ASSERT(m_PowerThreadEvent == NULL); + m_PowerThreadEvent = event.GetSelfPointer(); + + if (InterlockedDecrement(&m_PowerThreadInterfaceReferenceCount) > 0) { + // + // Wait for all references to go away before exitting the thread. + // A reference will be taken for every device in the stack above this + // one which queried for the interface. + // + event.EnterCRAndWaitAndLeave(); + } + + m_PowerThreadEvent = NULL; + + // + // Wait for the thread to exit and then delete it. Since we have + // turned off the power policy state machine, we can safely do this here. + // Any upper level clients will have also turned off their power policy + // state machines. + // + m_PowerThread->ExitThread(); + m_PowerThread->DeleteObject(); + + m_PowerThread = NULL; + } + else if (hadThread) { + // + // Release our reference + // + m_PowerThreadInterface.Interface.InterfaceDereference( + m_PowerThreadInterface.Interface.Context + ); + } +} + +VOID +FxPkgPnp::_PowerThreadInterfaceReference( + __inout PVOID Context + ) +/*++ + +Routine Description: + Increments the ref count on the thread interface. + +Arguments: + Context - FxPkgPnp* + +Return Value: + None + + --*/ +{ + LONG count; + + count = InterlockedIncrement( + &((FxPkgPnp*) Context)->m_PowerThreadInterfaceReferenceCount + ); + +#if DBG + ASSERT(count >= 2); +#else + UNREFERENCED_PARAMETER(count); +#endif +} + +VOID +FxPkgPnp::_PowerThreadInterfaceDereference( + __inout PVOID Context + ) +/*++ + +Routine Description: + Interface deref for the thread interface. If this is the last reference + released, an event is set so that the thread which waiting for the last ref + to go away can unblock. + +Arguments: + Context - FxPkgPnp* + +Return Value: + None + + --*/ + +{ + FxPkgPnp* pThis; + + pThis = (FxPkgPnp*) Context; + + if (InterlockedDecrement(&pThis->m_PowerThreadInterfaceReferenceCount) == 0) { + pThis->m_PowerThreadEvent->Set(); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpPowerReferenceSelf( + VOID + ) +/*++ + +Routine Description: + Take a power reference during a query pnp transition. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (IsPowerPolicyOwner()) { + // + // We want to synchronously wait to move into D0 + // + return PowerReference(TRUE); + } + else { + return STATUS_SUCCESS; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpPowerReferenceDuringQueryPnp( + VOID + ) +/*++ + +Routine Description: + Take a power reference during a query pnp transition. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (IsPowerPolicyOwner()) { + // + // We want to synchronously wait to move into D0 + // + return m_PowerPolicyMachine.m_Owner-> + m_PowerIdleMachine.PowerReferenceWithFlags( + FxPowerReferenceSendPnpPowerUpEvent + ); + } + else { + return STATUS_SUCCESS; + } +} + +VOID +FxPkgPnp::PnpPowerDereferenceSelf( + VOID + ) +/*++ + +Routine Description: + Release the power reference taken during a query pnp transition + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (IsPowerPolicyOwner()) { + PowerDereference(); + } +} + +NTSTATUS +FxPkgPnp::CompletePowerRequest( + __inout FxIrp* Irp, + __in NTSTATUS Status + ) +{ + MdIrp irp; + + // + // Once we call CompleteRequest, 2 things happen + // 1) this object may go away + // 2) Irp->m_Irp will be cleared + // + // As such, we capture the underlying WDM objects so that we can use them + // to release the remove lock and use the PIRP *value* as a tag to release + // the remlock. + // + irp = Irp->GetIrp(); + + Irp->SetStatus(Status); + Irp->StartNextPowerIrp(); + Irp->CompleteRequest(IO_NO_INCREMENT); + + Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), + irp); + + return Status; +} + +LONG +FxPkgPnp::GetPnpStateInternal( + VOID + ) +/*++ + +Routine Description: + Returns the pnp device state encoded into a ULONG. This state is the state + that is reported to PNp via IRP_MN_QUERY_PNP_DEVICE_STATE after it has been + decoded into the bits pnp expects + +Arguments: + None + +Return Value: + the current state bits + + --*/ +{ + LONG state; + KIRQL irql; + + // + // State is shared with the caps bits. Use a lock to guard against + // corruption of the value between these 2 values + // + Lock(&irql); + state = m_PnpStateAndCaps.Value & FxPnpStateMask; + Unlock(irql); + + return state; +} + +LONG +FxPkgPnp::GetPnpCapsInternal( + VOID + ) +/*++ + +Routine Description: + Returns the pnp device capabilities encoded into a LONG. This state is used + in reporting device capabilities via IRP_MN_QUERY_CAPABILITIES and filling + in the PDEVICE_CAPABILITIES structure. + +Arguments: + None + +Return Value: + the current pnp cap bits + + --*/ +{ + LONG caps; + KIRQL irql; + + Lock(&irql); + caps = m_PnpStateAndCaps.Value & FxPnpCapMask; + Unlock(irql); + + return caps; +} + + +VOID +FxPkgPnp::SetPnpCaps( + __in PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ) +/*++ + +Routine Description: + Encode the driver provided pnp capabilities into our internal capabilities + bit field and store the result. + +Arguments: + PnpCapabilities - capabilities as reported by the driver writer + +Return Value: + None + + --*/ +{ + LONG pnpCaps; + KIRQL irql; + + pnpCaps = 0; + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, LockSupported); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, EjectSupported); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, Removable); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, DockDevice); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, UniqueID); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, SilentInstall); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, SurpriseRemovalOK); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, HardwareDisabled); + pnpCaps |= GET_PNP_CAP_BITS_FROM_STRUCT(PnpCapabilities, NoDisplayInUI); + + // + // Since the caller of IRP_MN_QUERY_CAPABILITIES sets these 2 values to -1, + // we can reuse the -1 as the default/no override value since the associated + // PDEVICE_CAPAPBILITIES structure will have been predisposed to these values + // + if (PnpCapabilities->Address != (ULONG) -1) { + m_PnpCapsAddress = PnpCapabilities->Address; + } + if (PnpCapabilities->UINumber != (ULONG) -1) { + m_PnpCapsUINumber = PnpCapabilities->UINumber; + } + + // + // Use the FxPnpStateMask to keep the state mask while applying the new + // pnp capabilities. + // + Lock(&irql); + m_PnpStateAndCaps.Value = (m_PnpStateAndCaps.Value & FxPnpStateMask) | pnpCaps; + Unlock(irql); +} + +VOID +FxPkgPnp::GetPnpState( + __out PWDF_DEVICE_STATE State + ) +/*++ + +Routine Description: + Decodes our internal pnp state bitfield into the external WDF_DEVICE_STATE + structure + +Arguments: + State - the structure to decode into + +Return Value: + None + + --*/ +{ + LONG state; + + state = GetPnpStateInternal(); + + SET_TRI_STATE_FROM_STATE_BITS(state, State, Disabled); + SET_TRI_STATE_FROM_STATE_BITS(state, State, DontDisplayInUI); + SET_TRI_STATE_FROM_STATE_BITS(state, State, Failed); + SET_TRI_STATE_FROM_STATE_BITS(state, State, NotDisableable); + SET_TRI_STATE_FROM_STATE_BITS(state, State, Removed); + SET_TRI_STATE_FROM_STATE_BITS(state, State, ResourcesChanged); +} + +VOID +FxPkgPnp::SetPnpState( + __in PWDF_DEVICE_STATE State + ) +/*++ + +Routine Description: + Encodes the driver writer provided state into our internal bit field. + +Arguments: + State - the states to encode + +Return Value: + None + + --*/ +{ + LONG pnpState; + KIRQL irql; + + pnpState = 0x0; + pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Disabled); + pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, DontDisplayInUI); + pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Failed); + pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, NotDisableable); + pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, Removed); + pnpState |= GET_PNP_STATE_BITS_FROM_STRUCT(State, ResourcesChanged); + + // + // Mask off FxPnpCapMask to keep the capabilities part of the bitfield + // the same while change the pnp state. + // + Lock(&irql); + m_PnpStateAndCaps.Value = (m_PnpStateAndCaps.Value & FxPnpCapMask) | pnpState; + Unlock(irql); +} + +VOID +FxPkgPnp::_SetPowerCapState( + __in ULONG Index, + __in DEVICE_POWER_STATE State, + __out PULONG Result + ) +/*++ + +Routine Description: + Encodes the given device power state (State) into Result at the given Index. + States are encoded in nibbles (4 bit chunks), starting at the bottom of the + result and moving upward + +Arguments: + Index - zero based index into the number of nibbles to encode the value + + State - State to encode + + Result - pointer to where the encoding will take place + +Return Value: + None + + --*/ +{ + // + // We store off state in 4 bits, starting at the lowest byte + // + ASSERT(Index < 8); + + // + // Erase the old value + // + *Result &= ~(0xF << (Index * 4)); + + // + // Write in the new one + // + *Result |= (0xF & State) << (Index * 4); +} + +DEVICE_POWER_STATE +FxPkgPnp::_GetPowerCapState( + __in ULONG Index, + __in ULONG State + ) +/*++ + +Routine Description: + Decodes our internal device state encoding and returns a normalized device + power state for the given index. + +Arguments: + Index - nibble (4 bit chunk) index into the State + + State - value which has the device states encoded into it + +Return Value: + device power state for the given Index + + --*/ +{ + ASSERT(Index < 8); + // isolate the value and normalize it + return (DEVICE_POWER_STATE) ((State & (0xF << (Index * 4))) >> (Index * 4)); +} + +VOID +FxPkgPnp::SetPowerCaps( + __in PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ) +/*++ + +Routine Description: + Encodes the driver provided power capabilities into the object. The device + power states are encoded into one ULONG while the other power caps are + encoded into their own distinct fields. + +Arguments: + PowerCapabilities - the power caps reported by the driver writer + +Return Value: + None + + --*/ +{ + ULONG states, i; + USHORT powerCaps; + + states = 0x0; + + // + // Build up the device power state encoding into a temp var so that if we are + // retrieving the encoding in another thread, we don't get a partial view + // + for (i = 0; i < ARRAY_SIZE(PowerCapabilities->DeviceState); i++) { + _SetPowerCapState(i, PowerCapabilities->DeviceState[i], &states); + } + + m_PowerCaps.States = states; + + // + // Same idea. Build up the caps locally first so that when we assign them + // into the object, it is assigned as a whole. + // + powerCaps = 0x0; + powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, DeviceD1); + powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, DeviceD2); + powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD0); + powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD1); + powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD2); + powerCaps |= GET_POWER_CAP_BITS_FROM_STRUCT(PowerCapabilities, WakeFromD3); + + m_PowerCaps.Caps = powerCaps; + + if (PowerCapabilities->DeviceWake != PowerDeviceMaximum) { + m_PowerCaps.DeviceWake = (BYTE) PowerCapabilities->DeviceWake; + } + if (PowerCapabilities->SystemWake != PowerSystemMaximum) { + m_PowerCaps.SystemWake = (BYTE) PowerCapabilities->SystemWake; + } + + m_PowerCaps.D1Latency = PowerCapabilities->D1Latency; + m_PowerCaps.D2Latency = PowerCapabilities->D2Latency; + m_PowerCaps.D3Latency = PowerCapabilities->D3Latency; + + if (PowerCapabilities->IdealDxStateForSx != PowerDeviceMaximum) { + // + // Caller has already validated that IdealDxStateForSx is only set if + // they device is the power policy owner. + // + m_PowerPolicyMachine.m_Owner->m_IdealDxStateForSx = (BYTE) + PowerCapabilities->IdealDxStateForSx; + } +} + +NTSTATUS +FxPkgPnp::CompletePnpRequest( + __inout FxIrp* Irp, + __in NTSTATUS Status + ) +{ + MdIrp pIrp = Irp->GetIrp(); + + Irp->SetStatus(Status); + Irp->CompleteRequest(IO_NO_INCREMENT); + + Mx::MxReleaseRemoveLock(m_Device->GetRemoveLock(), + pIrp); + + return Status; +} + +BOOLEAN +FxPkgPnp::PowerPolicyIsWakeEnabled( + VOID + ) +{ + if (IsPowerPolicyOwner() && PowerPolicyGetCurrentWakeReason() != 0x0) { + return TRUE; + } + else { + return FALSE; + } +} + +ULONG +FxPkgPnp::PowerPolicyGetCurrentWakeReason( + VOID + ) +/*++ + +Routine Description: + This routine determines the reasons for whether wake should be enabled or + not. Wake could be enabled because it is explicitly enabled for the device + in the wake policy settings or, because the device opted to depend on its + children being armed for wake. + +Arguments: + None + +Return Value: + Returns a combination of FxPowerPolicySxWakeChildrenArmedFlag, to indicate + that wake can be enabled because of more than one children being armed for + wake, and FxPowerPolicySxWakeDeviceEnabledFlag, to indicate that wake can + be enabled because the device was explicitly enabled in the wake policy + settings. + + Returns Zero to indicate that wake is currently disabled for the device. + +--*/ +{ + ULONG wakeReason; + + wakeReason = 0x0; + + if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.ArmForWakeIfChildrenAreArmedForWake && + m_PowerPolicyMachine.m_Owner->m_ChildrenArmedCount > 0) { + // + // Wake settings depends on children and one or more children are + // armed for wake. + // + wakeReason |= FxPowerPolicySxWakeChildrenArmedFlag; + } + + if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled) { + // + // Wake settings is explicitly enabled. + // + wakeReason |= FxPowerPolicySxWakeDeviceEnabledFlag; + } + + return wakeReason; +} + +VOID +FxPkgPnp::SaveState( + __in BOOLEAN UseCanSaveState + ) +/*++ + +Routine Description: + Saves any permanent state of the device out to the registry + +Arguments: + None + +Return Value: + None + + --*/ + +{ + UNICODE_STRING name; + FxAutoRegKey hKey; + NTSTATUS status; + ULONG value; + + // + // We only have settings to save if we are the power policy owner + // + if (IsPowerPolicyOwner() == FALSE) { + return; + } + + if (UseCanSaveState && + m_PowerPolicyMachine.m_Owner->m_CanSaveState == FALSE) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Not saving wake settings for WDFDEVICE %p due to system power " + "transition", m_Device->GetHandle()); + return; + } + + // + // Check to see if there is anything to write out + // + if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty == FALSE && + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty == FALSE) { + return; + } + + // + // No need to write out if user control is not enabled + // + if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable == FALSE && + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable == FALSE) { + return; + } + + // + // If the device is in paging path we should not be touching registry during + // power up because it may incur page fault which won't be satisfied if the + // device is still not powered up, blocking power Irp. User control state + // change will not get written if any at this time but will be flushed out + // to registry during device disable/remove in the remove path. + // + if (IsUsageSupported(DeviceUsageTypePaging) && IsDevicePowerUpIrpPending()) { + return; + } + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + + status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_WRITE); + if (!NT_SUCCESS(status)) { + return; + } +#else + status = STATUS_SUCCESS; +#endif + + if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.Overridable && + m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty) { + RtlInitUnicodeString(&name, WDF_S0_IDLE_ENABLED_VALUE_NAME); + value = m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled; + + WriteStateToRegistry(hKey.m_Key, &name, value); + + m_PowerPolicyMachine.m_Owner->m_IdleSettings.Dirty = FALSE; + } + + if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.Overridable && + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty) { + RtlInitUnicodeString(&name, WDF_SX_WAKE_ENABLED_VALUE_NAME); + value = m_PowerPolicyMachine.m_Owner->m_WakeSettings.Enabled; + + WriteStateToRegistry(hKey.m_Key, &name, value); + + m_PowerPolicyMachine.m_Owner->m_WakeSettings.Dirty = FALSE; + } +} + +VOID +FxPkgPnp::AddInterruptObject( + __in FxInterrupt* Interrupt + ) +/*++ + +Routine Description: + + This routine adds a WDFINTERRUPT object onto the list of interrupts + which are attached to this device. This list is used in response to + several IRPs. + +Note: + + It shouldn't be necessary to lock this list, since the driver will add or + remove interrupt objects only in callbacks that are effectively serialized + by the PnP manager. + +Further note: + + This list must remain sorted by order of interrupt object creation. E.g. + the first interrupt object created must be first in this list. + +Arguments: + + Interrupt - a Framework interrupt object + +Return Value: + + VOID + +--*/ +{ + m_InterruptObjectCount++; + InsertTailList(&m_InterruptListHead, &Interrupt->m_PnpList); +} + +VOID +FxPkgPnp::RemoveInterruptObject( + __in FxInterrupt* Interrupt + ) +/*++ + +Routine Description: + This routine removes a WDFINTERRUPT object onto the list of interrupts + which are attached to this device. This list is used in response to + several IRPs. + +Arguments: + + Interrupt - a Framework interrupt object + +Return Value: + + VOID + +--*/ +{ + m_InterruptObjectCount--; + RemoveEntryList(&Interrupt->m_PnpList); +} + +VOID +FxPkgPnp::NotifyResourceobjectsToReleaseResources( + VOID + ) +/*++ + +Routine Description: + + This routine traverses all resource objects and tells them that their + resources are no longer valid. + +Arguments: + + none + +Return Value: + + VOID + +--*/ +{ + FxInterrupt* interruptInstance; + PLIST_ENTRY intListEntry; + + // + // Revoke each of the interrupts. + // + + intListEntry = m_InterruptListHead.Flink; + + while (intListEntry != &m_InterruptListHead) { + + // + // Disconnect interrupts and then tell them that they no longer + // own their resources. + // + + interruptInstance = CONTAINING_RECORD(intListEntry, FxInterrupt, m_PnpList); + interruptInstance->RevokeResources(); + intListEntry = intListEntry->Flink; + } + + // + // Now revoke each of the DMA enablers (only system-mode enablers + // will be affected by this) + // + + if (m_DmaEnablerList != NULL) { + FxTransactionedEntry* listEntry; + + m_DmaEnablerList->LockForEnum(GetDriverGlobals()); + + for (listEntry = m_DmaEnablerList->GetNextEntry(NULL); + listEntry != NULL; + listEntry = m_DmaEnablerList->GetNextEntry(listEntry)) { + RevokeDmaEnablerResources( + (FxDmaEnabler *) listEntry->GetTransactionedObject() + ); + } + + m_DmaEnablerList->UnlockFromEnum(GetDriverGlobals()); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::NotifyResourceObjectsD0( + __in ULONG NotifyFlags + ) +/*++ + +Routine Description: + + This routine traverses all resource objects and tells them that the device + is entering D0. If an error is encountered, the walking of the list is + halted. + +Arguments: + + none + +Return Value: + + VOID + +--*/ +{ + FxInterrupt* pInterrupt; + PLIST_ENTRY ple; + NTSTATUS status; + + for (ple = m_InterruptListHead.Flink; + ple != &m_InterruptListHead; + ple = ple->Flink) { + + // + // Connect the interrupts + // + pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + + status = pInterrupt->Connect(NotifyFlags); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFINTERRUPT %p failed to connect, %!STATUS!", + pInterrupt->GetHandle(), status); + + return status; + } + } + + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::NotifyResourceObjectsDx( + __in ULONG NotifyFlags + ) +/*++ + +Routine Description: + This routine traverses all resource objects and tells them that the device + is leaving D0. If there is an error, the remaining resources in the list + are still notified of exitting D0. + +Arguments: + NotifyFlags - combination of values from the enum NotifyResourcesFlags + +Return Value: + None + +--*/ +{ + FxInterrupt* pInterrupt; + PLIST_ENTRY ple; + NTSTATUS status, finalStatus; + + finalStatus = STATUS_SUCCESS; + + // + // Disconect in the reverse order in which we connected the interrupts + // + for (ple = m_InterruptListHead.Blink; + ple != &m_InterruptListHead; + ple = ple->Blink) { + + // + // Disconnect interrupts and then tell them that they no longer + // own their resources. + // + pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + + status = pInterrupt->Disconnect(NotifyFlags); + + if (!NT_SUCCESS(status)) { + // + // When we encounter an error we still disconnect the remaining + // interrupts b/c we would just do it later during device tear down + // (might as well do it now). + // + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFINTERRUPT %p failed to disconnect, %!STATUS!", + pInterrupt->GetHandle(), status); + // + // Overwriting a previous finalStatus is OK, we'll just report the + // last one + // + finalStatus = status; + } + } + + return finalStatus; +} + +VOID +FxPkgPnp::SendEventToAllWakeInterrupts( + __in FxWakeInterruptEvents WakeInterruptEvent + ) +/*++ + +Routine Description: + This routine traverses all interrupt objects and queues the + given event into those interrupts that are marked as wake + capable and have a state machine + +Arguments: + WakeInterruptEvent - Event to be queued in the wake interrupt + state machines + +Return Value: + None + +--*/ +{ + FxInterrupt* pInterrupt; + PLIST_ENTRY ple; + + if (m_WakeInterruptCount == 0) { + return; + } + + // + // Initialize the pending count to the wake interrupt count + // If the event needs an acknowledgement, this variable will + // be decremented as the interrupt machines ack. + // + m_WakeInterruptPendingAckCount = m_WakeInterruptCount; + + for (ple = m_InterruptListHead.Flink; + ple != &m_InterruptListHead; + ple = ple->Flink) { + + pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + + if (pInterrupt->IsWakeCapable()) { + pInterrupt->ProcessWakeInterruptEvent(WakeInterruptEvent); + } + + } +} + +VOID +FxPkgPnp::AckPendingWakeInterruptOperation( + __in BOOLEAN ProcessPowerEventOnDifferentThread + ) +/*++ + +Routine Description: + This routine is invoked by the interrupt wake machine to acknowledge + back an event that was queued into it. When the last interrupt machine + acknowledges, an event is queued back into the Pnp/power state machine + +Arguments: + + ProcessPowerEventOnDifferentThread - Once all wake interrupts for the device + have acknowledged the operation, if this is TRUE, the power state + machine will process the PowerWakeInterruptCompleteTransition event on a + seperate thread. + +Return Value: + None + +--*/ +{ + if (InterlockedDecrement((LONG *)&m_WakeInterruptPendingAckCount) == 0) { + PowerProcessEvent( + PowerWakeInterruptCompleteTransition, + ProcessPowerEventOnDifferentThread + ); + } +} + + +NTSTATUS +FxPkgPnp::AssignPowerFrameworkSettings( + __in PWDF_POWER_FRAMEWORK_SETTINGS PowerFrameworkSettings + ) +{ + NTSTATUS status; + PPO_FX_COMPONENT_IDLE_STATE idleStates = NULL; + ULONG idleStatesSize = 0; + PPO_FX_COMPONENT component = NULL; + ULONG componentSize = 0; + PPOX_SETTINGS poxSettings = NULL; + ULONG poxSettingsSize = 0; + BYTE * buffer = NULL; + + if (FALSE==(IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable())) { + // + // If system-managed idle timeout is not available on this OS, then + // there is nothing to do. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p !devobj %p Power framework is not supported on the " + "current OS. Therefore, the power framework settings will not take " + "effect.", + m_Device->GetHandle(), + m_Device->GetDeviceObject() + ); + return STATUS_SUCCESS; + } + + if (NULL != PowerFrameworkSettings->Component) { + // + // Caller should ensure that IdleStateCount is not zero + // + ASSERT(0 != PowerFrameworkSettings->Component->IdleStateCount); + + // + // Compute buffer size needed for storing F-states + // + status = RtlULongMult( + PowerFrameworkSettings->Component->IdleStateCount, + sizeof(*(PowerFrameworkSettings->Component->IdleStates)), + &idleStatesSize + ); + if (FALSE == NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Unable to compute length of buffer " + "required to store F-states. RtlULongMult failed with " + "%!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + status + ); + goto exit; + } + + // + // Compute buffer size needed for storing component information + // (including F-states) + // + status = RtlULongAdd(idleStatesSize, + sizeof(*component), + &componentSize); + if (FALSE == NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Unable to compute length of buffer " + "required to store driver's component information. RtlULongAdd " + "failed with %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + status + ); + goto exit; + } + } + + // + // Compute total buffer size needed for power framework settings + // + status = RtlULongAdd(componentSize, + sizeof(*poxSettings), + &poxSettingsSize); + if (FALSE == NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Unable to compute length of buffer " + "required to store driver's power framework settings. RtlULongAdd " + "failed with %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + status + ); + goto exit; + } + + // + // Allocate memory to copy the settings + // + buffer = (BYTE *) MxMemory::MxAllocatePoolWithTag(NonPagedPool, + poxSettingsSize, + GetDriverGlobals()->Tag); + if (NULL == buffer) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Unable to allocate buffer required to " + "store F-states. %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + status + ); + goto exit; + } + + // + // Set our pointers to point to appropriate locations in the buffer. + // + // NOTES: + // - The array of F-states comes first because it has ULONGLONG members + // because of which it has the biggest alignment requirement. + // - The logic below works even if the client driver did not specify any + // component information. In that case idleStatesSize and componentSize + // are both 0 and 'poxSettings' points to the beginning of the allocated + // buffer + // + idleStates = (PPO_FX_COMPONENT_IDLE_STATE) buffer; + component = (PPO_FX_COMPONENT) (buffer + idleStatesSize); + poxSettings = (PPOX_SETTINGS) (buffer + componentSize); + + // + // Copy the relevant parts of the settings buffer + // + poxSettings->EvtDeviceWdmPostPoFxRegisterDevice = + PowerFrameworkSettings->EvtDeviceWdmPostPoFxRegisterDevice; + poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice = + PowerFrameworkSettings->EvtDeviceWdmPrePoFxUnregisterDevice; + poxSettings->Component = PowerFrameworkSettings->Component; + poxSettings->ComponentActiveConditionCallback = + PowerFrameworkSettings->ComponentActiveConditionCallback; + poxSettings->ComponentIdleConditionCallback = + PowerFrameworkSettings->ComponentIdleConditionCallback; + poxSettings->ComponentIdleStateCallback = + PowerFrameworkSettings->ComponentIdleStateCallback; + poxSettings->PowerControlCallback = + PowerFrameworkSettings->PowerControlCallback; + poxSettings->PoFxDeviceContext = PowerFrameworkSettings->PoFxDeviceContext; + + if (NULL != PowerFrameworkSettings->Component) { + // + // Copy the component information + // + poxSettings->Component = component; + RtlCopyMemory(poxSettings->Component, + PowerFrameworkSettings->Component, + sizeof(*component)); + + // + // Caller should ensure that IdleStates is not NULL + // + ASSERT(NULL != PowerFrameworkSettings->Component->IdleStates); + + // + // Copy the F-states + // + poxSettings->Component->IdleStates = idleStates; + RtlCopyMemory(poxSettings->Component->IdleStates, + PowerFrameworkSettings->Component->IdleStates, + idleStatesSize); + } + + // + // Commit these settings + // + status = m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.CommitPowerFrameworkSettings( + GetDriverGlobals(), + poxSettings + ); + if (FALSE == NT_SUCCESS(status)) { + goto exit; + } + + status = STATUS_SUCCESS; + +exit: + if (FALSE == NT_SUCCESS(status)) { + if (NULL != buffer) { + MxMemory::MxFreePool(buffer); + } + } + return status; +} + +DEVICE_POWER_STATE +FxPkgPnp::PowerPolicyGetDeviceDeepestDeviceWakeState( + __in SYSTEM_POWER_STATE SystemState + ) +{ + DEVICE_POWER_STATE dxState; + + // + // Earlier versions of WDF (pre-1.11) did not take into account SystemState + // in figuring out the deepest wake state. So for compatibility we restrict + // this to drivers compiled for 1.11 or newer. See comments in the + // FxPkgPnp::QueryForCapabilities function for more information on + // compatibility risk. + // + if (GetDriverGlobals()->IsVersionGreaterThanOrEqualTo(1,11)) { + if ((SystemState < PowerSystemWorking) || + (SystemState > PowerSystemHibernate)) { + dxState = PowerDeviceD0; + } else { + dxState = MapWakeDepthToDstate( + (DEVICE_WAKE_DEPTH)m_DeviceWake[SystemState - PowerSystemWorking] + ); + } + } + else { + // + // For pre-1.11 drivers, all of m_DeviceWake array is populated with + // the same DeviceWake value obtained from device capabilities so we + // just use the first one (index 0). + // + dxState = MapWakeDepthToDstate((DEVICE_WAKE_DEPTH)m_DeviceWake[0]); + } + + // + // Per WDM docs DeviceWake and SystemWake must be non-zero to support + // wake. We warn about the violation. Ideally, a verifier check would have + // been better but we want to avoid that because some drivers may + // intentionally call this DDI and do not treat the DDI failure as fatal ( + // because they are aware that DDI may succeed in some cases), and a verifier + // breakpoint would force them to avoid the verifier failure by not enabling + // verifier. + // + if (dxState == PowerDeviceUnspecified || + m_SystemWake == PowerSystemUnspecified) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "SystemWake %!SYSTEM_POWER_STATE! and DeviceWake " + "%!DEVICE_POWER_STATE! power state reported in device " + "capabilities do not support wake. Both the SystemWake and " + "DeviceWake members should be nonzero to support wake-up on " + "this system.", m_SystemWake, dxState); + } + + return dxState; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/interruptobject.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/interruptobject.cpp new file mode 100644 index 00000000000..2929008a7a3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/interruptobject.cpp @@ -0,0 +1,2013 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + InterruptObject.cpp + +Abstract: + + This module implements a frameworks managed interrupt object + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + +--*/ + +#include "pnppriv.hpp" + +// Tracing support +extern "C" { +#if defined(EVENT_TRACING) +#include "InterruptObject.tmh" +#endif +} + +// +// We need three parameters for KeSynchronizeExecution so we use this +// structure on the stack since its a synchronous call +// +struct FxInterruptSyncParameters { + FxInterrupt* Interrupt; + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback; + WDFCONTEXT Context; +}; + +// +// At this time we are unable to include wdf19.h in the share code, thus for +// now we simply cut and paste the needed structures. +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_9 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // Automatic Serialization of the DpcForIsr + // + BOOLEAN AutomaticSerialization; + + // Event Callbacks + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + +} WDF_INTERRUPT_CONFIG_V1_9, *PWDF_INTERRUPT_CONFIG_V1_9; + +// +// The interrupt config structure has changed post win8-Beta. This is a +// temporary definition to allow beta drivers to load on post-beta builds. +// Note that size of win8-beta and win8-postbeta structure is different only on +// non-x64 platforms, but the fact that size is same on amd64 is harmless because +// the struture gets zero'out by init macro, and the default value of the new +// field is 0 on amd64. +// +typedef struct _WDF_INTERRUPT_CONFIG_V1_11_BETA { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + +} WDF_INTERRUPT_CONFIG_V1_11_BETA, *PWDF_INTERRUPT_CONFIG_V1_11_BETA; + +// +// Public constructors +// +FxInterrupt::FxInterrupt( + __in PFX_DRIVER_GLOBALS Globals + ) : + FxNonPagedObject(FX_TYPE_INTERRUPT, sizeof(FxInterrupt), Globals) +{ + + m_Interrupt = NULL; + + m_OldIrql = PASSIVE_LEVEL; + + m_EvtInterruptEnable = NULL; + m_EvtInterruptDisable = NULL; + + m_PassiveHandling = FALSE; + + m_EvtInterruptIsr = NULL; + m_EvtInterruptDpc = NULL; + m_EvtInterruptWorkItem = NULL; + + m_CallbackLock = NULL; + m_WaitLock = NULL; + m_SystemWorkItem = NULL; + + m_DisposeWaitLock = FALSE; + + // + // We want platform specific behavior for soft disconnect to avoid any + // compat issues on existing platforms. In later versions (after 1.11) the + // platform differenciation could be removed. + // +#if defined(_ARM_) + m_UseSoftDisconnect = TRUE; +#else + m_UseSoftDisconnect = FALSE; +#endif + +#if FX_IS_KERNEL_MODE + KeInitializeDpc(&m_Dpc, _InterruptDpcThunk, this); + + m_Active = FALSE; + m_InterruptCaptured = NULL; + +#elif FX_IS_USER_MODE + + m_RdInterruptContext = NULL; + m_InterruptWaitblock = NULL; + m_CanQueue = FALSE; + m_PassiveHandlingByRedirector = FALSE; +#endif + + m_Disconnecting = FALSE; + m_IsEdgeTriggeredNonMsiInterrupt = FALSE; + + m_ShareVector = WdfUseDefault; + + m_AddedToList = FALSE; + m_Connected = FALSE; + m_ForceDisconnected = FALSE; + m_Enabled = FALSE; + m_FloatingSave = FALSE; + + m_WakeInterruptMachine = NULL; + + // This field is init later on. + m_CreatedInPrepareHardware = FALSE; + + WDF_INTERRUPT_INFO_INIT(&m_InterruptInfo); + m_CmTranslatedResource = NULL; + + Reset(); + + // This is set up by Initialize + m_SpinLock = NULL; + + // + // MSI Support + // + m_InterruptInfo.MessageNumber = 0; + + // + // WdfIrqPolicyOneCloseProcessor is a safe policy to use. It ensures that + // old devices continue to work without any change in their functionality. + // + m_Policy = WdfIrqPolicyOneCloseProcessor; + m_Priority = WdfIrqPriorityUndefined; + RtlZeroMemory(&m_Processors, sizeof(m_Processors)); + m_SetPolicy = FALSE; + + InitializeListHead(&m_PnpList); + + // + // Driver writer can only create WDFINTERRUPTs, not delete them + // + MarkNoDeleteDDI(ObjectDoNotLock); + MarkPassiveDispose(ObjectDoNotLock); + MarkDisposeOverride(ObjectDoNotLock); +} + +FxInterrupt::~FxInterrupt() +{ + + // + // If this hits, its because someone destroyed the INTERRUPT by + // removing too many references by mistake without calling WdfObjectDelete + // + if( m_Interrupt != NULL ) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Destroy Interrupt destroyed without calling WdfObjectDelete, or " + "by Framework processing DeviceRemove. Possible reference count problem?"); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + if (m_Device != NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Destroy Interrupt destroyed without calling WdfObjectDelete, or " + "by Framework processing DeviceRemove. Possible reference count problem?"); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::CreateWakeInterruptMachine( + VOID + ) +/*++ + +Routine Description: + This routine is used to create a state machine that + is used to manage a wake capable interrupt machine + +Arguments: + +Return Value: + None + +--*/ +{ + NTSTATUS status; + FxWakeInterruptMachine * fxWakeInterruptMachine = NULL; + + ASSERT(NULL == m_WakeInterruptMachine); + + fxWakeInterruptMachine = new (m_Device->m_PkgPnp->GetDriverGlobals()) + FxWakeInterruptMachine(this); + + if (NULL == fxWakeInterruptMachine) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p failed to allocate FxWakeInterruptMachine. %!STATUS!.", + m_Device, status); + goto exit; + } + + status = fxWakeInterruptMachine->Initialize(m_Device->m_PkgPnp->GetDriverGlobals()); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p failed to initialize FxWakeInterruptMachine. %!STATUS!.", + m_Device, status); + goto exit; + } + + status = fxWakeInterruptMachine->Init( + m_Device->m_PkgPnp, + FxWakeInterruptMachine::_ProcessEventInner, + fxWakeInterruptMachine + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p failed to init FxWakeInterruptMachine. %!STATUS!.", + m_Device, status); + goto exit; + } + + m_WakeInterruptMachine = fxWakeInterruptMachine; + + fxWakeInterruptMachine->m_IsrEvent.Initialize(SynchronizationEvent,FALSE); + + m_Device->m_PkgPnp->WakeInterruptCreated(); + + DoTraceLevelMessage( + GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE 0x%p created wake interrupt", + m_Device); + +exit: + if (!NT_SUCCESS(status)) { + if (NULL != fxWakeInterruptMachine) { + delete fxWakeInterruptMachine; + } + } + return status; +} + +VOID +FxInterrupt::InvokeWakeInterruptEvtIsr( + VOID +/*++ + +Routine Description: + This routine is called by the interrupt wake machine to invoke + the Evt for the ISR + +Arguments: + +Return Value: + None + +--*/ + ) +{ + ASSERT(m_PassiveHandling); + ASSERT(m_WakeInterruptMachine != NULL); + + // + // Acquire our internal passive-lock after the kernel acquired its own + // passive-lock and before invoking the callback. + // + AcquireLock(); + + m_WakeInterruptMachine->m_Claimed = m_EvtInterruptIsr( + GetHandle(), + m_InterruptInfo.MessageNumber); + ReleaseLock(); +} + +BOOLEAN +FxInterrupt::WakeInterruptIsr( + VOID + ) +/*++ + +Routine Description: + This is the ISR for a wake interrupt. This queues an event into the + state machine. State machine will take care of waking the device if + the device is in Dx and then invoking the driver callback for the + interrupt. + +Arguments: + +Return Value: + None + +--*/ +{ + ASSERT(m_WakeInterruptMachine != NULL); + + // + // Queue an event in the state machine + // + m_WakeInterruptMachine->ProcessEvent(WakeInterruptEventIsr); + + GetDriverGlobals()->WaitForSignal(m_WakeInterruptMachine->m_IsrEvent.GetSelfPointer(), + "Wake Interrupt ISR is stuck waiting for the device" + "to power back up and driver calllback to be processed", + GetHandle(), + GetDriverGlobals()->DbgWaitForWakeInterruptIsrTimeoutInSec, + WaitSignalBreakUnderVerifier|WaitSignalBreakUnderDebugger); + + // + // State machine stores the return value of the callback in the + // m_Claimed member variable + // + return m_WakeInterruptMachine->m_Claimed; +} + + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::_CreateAndInit( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CfxDevice * Device, + __in_opt FxObject * Parent, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in PWDF_INTERRUPT_CONFIG Configuration, + __out FxInterrupt ** Interrupt + ) +{ + FxInterrupt * pFxInterrupt; + NTSTATUS status; + + pFxInterrupt = new (FxDriverGlobals, Attributes) + FxInterrupt(FxDriverGlobals); + + if (pFxInterrupt == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "not enough memory to allocate WDFINTERRUPT for WDFDEVICE %p, " + "%!STATUS!", Device, status); + + return status; + } + + if (NULL == Parent) { + Parent = Device; + } + + status = pFxInterrupt->Initialize(Device, Parent, Configuration); + + if (NT_SUCCESS(status)) { + status = pFxInterrupt->Commit(Attributes, NULL, Parent); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "FxInterrupt Commit failed %!STATUS!", status); + } + } + + if (NT_SUCCESS(status)) { + *Interrupt = pFxInterrupt; + } + else { + pFxInterrupt->DeleteFromFailedCreate(); + return status; + } + + if (Configuration->CanWakeDevice) { + status = pFxInterrupt->CreateWakeInterruptMachine(); + } + + if (!NT_SUCCESS(status)) { + pFxInterrupt->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::Initialize( + __in CfxDevice* Device, + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ) +{ + NTSTATUS status; + FxPkgPnp* pkgPnp; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescRaw; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDescTrans; + + // + // DIRQL handling: FxInterrupt can be parented by, and optionally + // serialize its DpcForIsr or WorItemForIsr with an FxDevice or + // FxIoQueue. + // + // Passive handling: FxInterrupt can be parented by, and optionally + // serialize its WorItemForIsr with an FxDevice or FxIoQueue. + + // + // Add a reference to the device object we are associated with. We will be + // notified in Dispose to release this reference. + // + Device->ADDREF(this); + + // + // It is important to store the Device only after taking the reference + // because Dispose checks for m_Device != NULL to release the reference. If + // assign it here and then take the reference later, we can return failure + // in between the assignment and reference and then release a reference that + // was not taken in Dispose. + // + m_Device = Device; + pkgPnp = m_Device->m_PkgPnp; + + // + // NOTE: Since Dispose always releases this reference, we *must* take this + // reference, so that even if we return error, the reference is + // still there to be removed on cleanup. + // + ADDREF(_InterruptThunk); + + // + // Values always supplied by the caller + // + m_ShareVector = Configuration->ShareVector; + m_FloatingSave = Configuration->FloatingSave; + + m_EvtInterruptEnable = Configuration->EvtInterruptEnable; + m_EvtInterruptDisable = Configuration->EvtInterruptDisable; + + // + // Do further initialization + // + status = InitializeWorker(Parent, Configuration); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Update the message number used for MSI support + // + m_InterruptInfo.MessageNumber = pkgPnp->m_InterruptObjectCount; + + // + // This logic is executed when the driver creates interrupts in its + // EvtDevicePrepareHardware callback. + // + if (Configuration->InterruptRaw != NULL) { + + ASSERT(Configuration->InterruptTranslated != NULL); + ASSERT(m_Device->GetDevicePnpState() != WdfDevStatePnpInit); + + m_CreatedInPrepareHardware = TRUE; + + // + // Get the real resource descriptors not the copies. + // + cmDescRaw = &(CONTAINING_RECORD(Configuration->InterruptRaw, + FxResourceCm, + m_DescriptorClone))->m_Descriptor; + + cmDescTrans = &(CONTAINING_RECORD(Configuration->InterruptTranslated, + FxResourceCm, + m_DescriptorClone))->m_Descriptor; + // + // Assign resources to this interrupt. + // + FxInterrupt::AssignResources(cmDescRaw, cmDescTrans); + } + + // Add this interrupt to the list of them being kept in the PnP package. + pkgPnp->AddInterruptObject(this); + + m_AddedToList = TRUE; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::InitializeWorker( + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ) +{ + FxObject* tmpObject; + IFxHasCallbacks* callbacks; + NTSTATUS status; + CfxDeviceBase* deviceBase; + BOOLEAN passiveCallbacks; + + const PFX_DRIVER_GLOBALS fxDriverGlobals = GetDriverGlobals(); + const WDFTYPE parentType = Parent->GetType(); + + // + // Init interrupt's callbacks. + // + m_EvtInterruptIsr = Configuration->EvtInterruptIsr; + m_EvtInterruptDpc = Configuration->EvtInterruptDpc; + m_EvtInterruptWorkItem = Configuration->EvtInterruptWorkItem; + + // + // Init soft disconnect configuration + // + switch (Configuration->ReportInactiveOnPowerDown) { + case WdfTrue: + m_UseSoftDisconnect = TRUE; + break; + + case WdfFalse: + m_UseSoftDisconnect = FALSE; + break; + + case WdfUseDefault: + default: + // + // Leave the driver's value alone. + // + break; + } + + // + // TRUE if passive-level interrupt handling is enabled for this interrupt. + // + m_PassiveHandling = Configuration->PassiveHandling; + + // + // If the caller specified a spinlock we use it. + // + if (Configuration->SpinLock != NULL) { + FxSpinLock* pFxSpinLock; + + FxObjectHandleGetPtr(GetDriverGlobals(), + Configuration->SpinLock, + FX_TYPE_SPIN_LOCK, + (PVOID*)&pFxSpinLock); + + pFxSpinLock->SetInterruptSpinLock(); + + m_SpinLock = pFxSpinLock->GetLock(); + } + else if (m_PassiveHandling == FALSE) { + // + // If the caller does not specify a spinlock, and this is + // a DIRQL interrupt we use a built in one. + // Originally this logic was added to allow Acquire/Release Lock + // to work on W2K platforms that does not support + // KeAcquireInterruptSpinLock. + // + m_SpinLock = &m_BuiltInSpinLock.Get(); + } + + // + // Automatic serialization: the DPC or work-item is synchronized with + // the parent's callback lock. + // + + // + // Get the first ancestor that implements callbacks. + // + deviceBase = FxDeviceBase::_SearchForDevice(Parent, &callbacks); + + // + // Validate parent: + // - the specified device (from API) must be one of the ancestors. + // - the parent can only be a queue or a device. + // + if (m_DeviceBase == NULL || deviceBase != m_DeviceBase || + (parentType != FX_TYPE_QUEUE && parentType != FX_TYPE_DEVICE)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The specified object 0x%p is not a valid parent for a " + "WDFINTERRUPT, WDF_INTERRUPT_CONFIG structure 0x%p passed, " + "%!STATUS!", Parent->GetObjectHandle(), Configuration, status); + + return status; + } + + // + // If automatic-serialization is off, m_CallbackLock is NULL. + // else if parent doesn't use locking, m_CallbackLock is NULL. + // else if work-item ISR callback set, m_CallbackLock is a passive lock. + // else m_CallbackLock is a spin-lock. + // + // Note: logic retrieves the parent's callback lock when automatic + // serialization is on even if work-item or DPC callbacks are not set, + // this is not to break the existing behavior/validation. + // + if (Configuration->EvtInterruptWorkItem != NULL) { + passiveCallbacks = TRUE; + } + else if (Configuration->EvtInterruptDpc != NULL) { + passiveCallbacks = FALSE; + } + else if (m_PassiveHandling) { + passiveCallbacks = TRUE; + } + else { + passiveCallbacks = FALSE; + } + + status = _GetEffectiveLock( Parent, + callbacks, // IFxHasCallbacks* + Configuration->AutomaticSerialization, + passiveCallbacks, + &m_CallbackLock, + &tmpObject // No reference count is taken. + ); + if (!NT_SUCCESS(status)) { + // + // We should never incur this error. + // + ASSERT(status != STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL); + return status; + } + + // + // If the parent is a queue, the queue inherits the deletion constraints of the + // interrupt object, i.e., driver cannot manually delete the queue. + // + if (FX_TYPE_QUEUE == parentType) { + ((FxIoQueue*)Parent)->SetInterruptQueue(); + } + + // + // Passive-level handling: init wait-lock. + // + if (m_PassiveHandling) { + ASSERT(NULL == m_SpinLock); + + // + //If the caller specified a waitlock, we use it. + // + if (Configuration->WaitLock != NULL) { + ASSERT(m_PassiveHandling); + FxObjectHandleGetPtr(GetDriverGlobals(), + Configuration->WaitLock, + FX_TYPE_WAIT_LOCK, + (PVOID*)&m_WaitLock); + } + + // + // Use a default lock if none was specified. + // + if (NULL == m_WaitLock) { + WDFWAITLOCK waitLock = NULL; + WDF_OBJECT_ATTRIBUTES attributes; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + status = FxWaitLock::_Create( + fxDriverGlobals, + &attributes, + NULL, + FALSE, + &waitLock); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate waitlock, %!STATUS!", + status); + return status; + } + + FxObjectHandleGetPtr(fxDriverGlobals, + waitLock, + FX_TYPE_WAIT_LOCK, + (PVOID*)&m_WaitLock); + // + // Explicitly dispose this wait-lock object. + // + m_DisposeWaitLock = TRUE; + } + } + + // + // If needed, initialize the interrupt's workitem. + // Alloacte workitem if driver specified EvtInterruptWorkitem. + // In addition, for Umdf, allocate workitem if driver alternatively + // specified EvtInterruptDpc. Note that driver is not allwed to specify both. + // + if (m_EvtInterruptWorkItem != NULL || + (FxLibraryGlobals.IsUserModeFramework && m_EvtInterruptDpc != NULL)) { + status = FxSystemWorkItem::_Create( + fxDriverGlobals, + m_Device->GetDeviceObject(), + &m_SystemWorkItem); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate workitem, %!STATUS!", + status); + return status; + } + } + + // + // Do mode-apecific initialization + // + status = InitializeInternal(Parent, Configuration); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} + +VOID +FxInterrupt::Reset( + VOID + ) +/*++ + +Routine Description: + Resets the interrupt info and synchronize irql for the interrupt. The pnp + state machine will call this function every time new resources are assigned + to the device. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // + // Other values in m_InterruptInfo survive a reset, so RtlZeroMemory is not + // an option. Manually set the fields that need resetting. + // + m_InterruptInfo.TargetProcessorSet = 0; + m_InterruptInfo.Group = 0; + m_InterruptInfo.Irql = PASSIVE_LEVEL; + m_InterruptInfo.ShareDisposition = 0; + m_InterruptInfo.Mode = LevelSensitive; + m_InterruptInfo.Vector = 0; + + m_SynchronizeIrql = PASSIVE_LEVEL; + + // + // Do mode-specific reset. + // For KMDF, it's a no-op. + // For UMDF, a message is sent to reflector to reset the interrupt info. + // + ResetInternal(); +} + +// +// This is an API call from the device driver to delete this INTERRUPT. +// +VOID +FxInterrupt::DeleteObject( + VOID + ) +{ + if (m_AddedToList) { + // + // Pop this off of PnP's list of interrupts. + // + m_Device->m_PkgPnp->RemoveInterruptObject(this); + } + + if (m_CmTranslatedResource != NULL) { + // + // This can happen if driver explicitly deletes the interrupt in its + // release hardware callback. + // + RevokeResources(); + } + + if (m_WakeInterruptMachine) { + delete m_WakeInterruptMachine; + m_WakeInterruptMachine = NULL; + } + + // + // Use the base FxObject's DeleteObject implementation which will Dispose us + // + __super::DeleteObject(); +} + +// +// Called by the PnP package after the driver's release hardware callback. +// +VOID +FxInterrupt::OnPostReleaseHardware( + VOID + ) +{ + if (m_CreatedInPrepareHardware) { + // Delete this interrupt. + DeleteObject(); + } +} + +PWDF_INTERRUPT_INFO +FxInterrupt::GetInfo( + VOID + ) +{ + return &m_InterruptInfo; +} + +// +// Called from the parent when the parent is being removed. +// +// Must ensure that any races with Delete are handled properly +// +BOOLEAN +FxInterrupt::Dispose( + VOID + ) +{ + // MarkPassiveDispose() in Initialize ensures this + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + FlushAndRundown(); + + return TRUE; +} + +VOID +FxInterrupt::AssignResources( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans + ) +/*++ + +Routine Description: + + This function allows an interrupt object to know what resources have been + assigned to it. It will be called as part of IRP_MN_START_DEVICE. + +Arguments: + + CmDescRaw - A CmResourceDescriptor that describes raw interrupt resources + + CmDescTrans - A CmResourceDescriptor that describes translated interrupt + resources + +Return Value: + + VOID + +--*/ +{ + if (CmDescTrans->u.Interrupt.Group > 0 && + FxIsProcessorGroupSupported() == FALSE) { + // + // This should never happen. + // + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + +#if FX_IS_USER_MODE + // + // For UMDF, see if this is level-triggered interrupt in which case we need + // reflector to handle it at passive level. Also, level-triggered + // support is present only on Win8 and newer. Note that, for KMDF, driver + // would have provided the choice of handling at passive level so we know + // that early on for KMDF, however for UMDF, driver can't specify the choice + // and UMDF figures out whether to handle at passive or not by looking at + // the interrupt type in resources. + // + if (IsLevelTriggered(CmDescTrans->Flags) && + FxIsPassiveLevelInterruptSupported()) { + m_PassiveHandlingByRedirector = TRUE; + } +#endif + + if (IsPassiveConnect() && _IsMessageInterrupt(CmDescTrans->Flags)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Driver cannot specify PassiveHandling for MSI interrupts."); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + // IoConnectInterruptEx will fail later on. + } + + m_InterruptInfo.Group = CmDescTrans->u.Interrupt.Group; + m_InterruptInfo.TargetProcessorSet = CmDescTrans->u.Interrupt.Affinity; + m_InterruptInfo.ShareDisposition = CmDescTrans->ShareDisposition; + m_InterruptInfo.Mode = + CmDescTrans->Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive; + + // + // Interrupt's IRQL. + // + m_InterruptInfo.Irql = (KIRQL)CmDescTrans->u.Interrupt.Level; + + if (IsPassiveConnect()) { + m_InterruptInfo.Irql = PASSIVE_LEVEL; + } + + // + // Note if this is an MSI interrupt + // + m_InterruptInfo.MessageSignaled = _IsMessageInterrupt(CmDescTrans->Flags); + + // + // Edge-triggered interrupts that are ActiveBoth are made stateful by the OS + // (GPIO buttons driver) to track buttons' press/release state. This is because + // the driver may not have the ability to read the state directly from the hardware. + // + // There is no way to identify ActiveBoth interrupts since KINTERRUPT_POLARITY is + // not exposed to client drivers, so we decided to apply this logic to all + // edge-triggered non-MSI interrupts. + // + m_IsEdgeTriggeredNonMsiInterrupt = (m_InterruptInfo.Mode == Latched && + m_InterruptInfo.MessageSignaled == FALSE); + + if (m_InterruptInfo.MessageSignaled && + CmDescRaw->u.MessageInterrupt.Raw.MessageCount > 1) { + // + // This is an assignment for a multi-message PCI 2.2-style resource. + // Thus the vector and message data have to be deduced. + // + m_InterruptInfo.Vector = CmDescTrans->u.Interrupt.Vector + m_InterruptInfo.MessageNumber; + + m_Device->SetDeviceTelemetryInfoFlags(DeviceInfoMsi22MultiMessageInterrupt); + } + else { + // + // This is an assignment for a single interrupt, either line-based or + // PCI 2.2 single-message MSI, or PCI 3.0 MSI-X-style resource. + // + m_InterruptInfo.Vector = CmDescTrans->u.Interrupt.Vector; + + if (m_InterruptInfo.MessageSignaled) { + m_Device->SetDeviceTelemetryInfoFlags(DeviceInfoMsiXOrSingleMsi22Interrupt); + } + else { + if (IsLevelTriggered(CmDescTrans->Flags)) { + m_Device->SetDeviceTelemetryInfoFlags(DeviceInfoLineBasedLevelTriggeredInterrupt); + } + else { + m_Device->SetDeviceTelemetryInfoFlags(DeviceInfoLineBasedEdgeTriggeredInterrupt); + } + } + } + + if (IsPassiveConnect()) { + m_Device->SetDeviceTelemetryInfoFlags(DeviceInfoPassiveLevelInterrupt); + } + + // + // Do mode-specific work. For KMDF, it's a no-op. + // For UMDF, send a sync message to Reflector to assign resources. + // + AssignResourcesInternal(CmDescRaw, CmDescTrans, &m_InterruptInfo); + + // + // Weak ref to the translated resource interrupt descriptor. + // It is valid from prepare hardware callback to release hardware callback. + // + m_CmTranslatedResource = CmDescTrans; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Is MSI? %d, MSI-ID %d, AffinityPolicy %!WDF_INTERRUPT_POLICY!, " + "Priority %!WDF_INTERRUPT_PRIORITY!, Group %d, Affinity 0x%I64x, " + "Irql 0x%x, Vector 0x%x\n", + m_InterruptInfo.MessageSignaled, + m_InterruptInfo.MessageNumber, + m_Policy, + m_Priority, + m_InterruptInfo.Group, + (ULONGLONG)m_InterruptInfo.TargetProcessorSet, + m_InterruptInfo.Irql, + m_InterruptInfo.Vector); + +} + +VOID +FxInterrupt::RevokeResources( + VOID + ) +/*++ + +Routine Description: + + This function tells an interrupt object that it no longer owns any resources. + +Arguments: + + none + +Return Value: + + VOID + +--*/ +{ + ULONG messageNumber; + + // + // The message # doesn't change, so we must preserve it. + // + messageNumber = m_InterruptInfo.MessageNumber; + + // + // This will zero out all the fields and init the size (as the structure + // can be resued again say after a rebalance). + // + WDF_INTERRUPT_INFO_INIT(&m_InterruptInfo); + + m_InterruptInfo.MessageNumber = messageNumber; + + // + // Used by interrupts created during 'EvtDevicePrepareHardware' callback. + // + m_CmTranslatedResource = NULL; + + // + // Do mode-specific work. For KMDF, it's a no-op. + // For UMDF, send a sync message to Reflector. + // + RevokeResourcesInternal(); +} + +VOID +FxInterrupt::SetPolicy( + __in WDF_INTERRUPT_POLICY Policy, + __in WDF_INTERRUPT_PRIORITY Priority, + __in PGROUP_AFFINITY TargetProcessorSet + ) +/*++ + +Routine Description: + + This function fills in the policy member variables. These values will be + used in IRP_MN_FILTER_RESOURCE_REQUIREMENTS. + +Arguments: + + Policy - Strategy for assigning target processors + + Priority - DIRQL preference + + TargetProcessorSet - Processors which should receive this interrupt, if + the policy is "SpecifyProcessors." + +Return Value: + + VOID + +--*/ +{ + // + // We cannot apply policy for interrupts created during prepare hardware. + // + if (m_CreatedInPrepareHardware) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "You cannot apply policy at this stage for WDFINTERRUPT 0x%p " + "For interrupts created in EvtDevicePrepareHardware you must use " + "EvtDeviceFilter APIs or use a pre-process routine to handle the " + "IRP_MN_FILTER_RESOURCE_REQUIREMENT, %!STATUS!", + GetHandle(), STATUS_INVALID_DEVICE_REQUEST); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + + m_Policy = Policy; + m_Priority = Priority; + m_Processors = *TargetProcessorSet; + + // + // Make sure OS supports processor groups, default to group 0 otherwise. + // + if (FxIsProcessorGroupSupported() == FALSE) { + m_Processors.Group = 0; + } + + m_SetPolicy = TRUE; + + // + // Do mode-specific work. This function does nothing for KMDF. + // It sends a message to reflector for UMDF. + // + SetPolicyInternal(Policy, Priority, TargetProcessorSet); +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::Connect( + __in ULONG NotifyFlags + ) +/*++ + +Routine Description: + + This function is the external interface for connecting the interrupt. It + calls the PnP manager to connect the interrupt (only if the operation is + not occurring in a non power pageable state). Then it calls + EvtInterruptEnable at DIRQL and EvtInterruptPostEnable at PASSIVE_LEVEL. + +Arguments: + NotifyFlags - combination of values from the enum NotifyResourcesFlags + +Return Value: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + + pFxDriverGlobals = GetDriverGlobals(); + + if ((NotifyFlags & NotifyResourcesExplicitPowerup) && + IsActiveForWake()) { + // + // If an interrupt is marked as wakeable and the device has been set to + // wake via a driver-owned ISR, leave the interrupt connected. + // + SetActiveForWake(FALSE); + + return STATUS_SUCCESS; + } + + // + // See if we need to just do soft connect. We do soft connect on explicit + // power up if driver opted-in for that. + // + if (IsSoftDisconnectCapable() && + (NotifyFlags & NotifyResourcesExplicitPowerup)){ + + ReportActive(TRUE); + + status = STATUS_SUCCESS; + goto Enable; + } + + // + // We should either be disconnected or being asked to connect in the NP path + // + ASSERT(m_Connected == FALSE || (NotifyFlags & NotifyResourcesNP)); + + if (m_ForceDisconnected) { + return STATUS_SUCCESS; + } + + // + // Check to see if this interrupt object was actually assigned any + // resources. If it wasn't, then don't attempt to connect. A WDFINTERRUPT + // object won't be assigned any resources if the underlying device wasn't + // granted any by the PnP manager. + // + if (m_InterruptInfo.Vector == 0) { + return STATUS_SUCCESS; + } + + // + // If we are in an NP path, the interrupt remained connected while the device + // went into Dx so there is no need to reconnect it. + // + if ((NotifyFlags & NotifyResourcesNP) == 0) { + + ASSERT(m_Interrupt == NULL); + ASSERT(m_SynchronizeIrql != PASSIVE_LEVEL || m_PassiveHandling); + + // + // Call pnp manager to connect the interrupt. For KMDF, we call + // kernel DDI, whereas for UMDF, we send a sync message to redirector. + // + status = ConnectInternal(); + + if (!NT_SUCCESS(status)) { + m_Interrupt = NULL; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "IoConnectInterrupt(Ex) Failed," + " SpinLock 0x%p," + " Vector 0x%x," + " IRQL 0x%x," + " Synchronize IRQL 0x%x," + " Mode 0x%x," + " ShareVector %s," + " ProcessorGroup %d," + " ProcessorEnableMask 0x%I64x," + " FloatingSave %s," + " %!STATUS!", + m_SpinLock, + m_InterruptInfo.Vector, + m_InterruptInfo.Irql, + m_SynchronizeIrql, + m_InterruptInfo.Mode, + m_InterruptInfo.ShareDisposition == + CmResourceShareShared ? "True" : "False", + m_InterruptInfo.Group, + (ULONGLONG)m_InterruptInfo.TargetProcessorSet, + m_FloatingSave ? "True" : "False", + status + ); + + return status; + } + + m_Connected = TRUE; + +#if FX_IS_KERNEL_MODE + m_Active = TRUE; +#endif + + } + else { + ASSERT(m_Connected); + ASSERT(m_Interrupt != NULL); + } + +Enable: + + // + // Enable the interrupt at the hardware. + // + status = InterruptEnable(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtInterruptEnable WDFDEVICE %p, WDFINTERRUPT %p, PKINTERRUPT %p " + "returned %!STATUS!", m_Device->GetHandle(), GetHandle(), + m_Interrupt, status); + + return status; + } + + m_Enabled = TRUE; + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::Disconnect( + __in ULONG NotifyFlags + ) +/*++ + +Routine Description: + + This function is the external interface for disconnecting the interrupt. It + calls the Io manager to disconnect. Then it calls EvtInterruptPreDisable at + PASSIVE_LEVEL and EvtInterruptDisable at DIRQL. + +Arguments: + + Surprise - Indicates that we are disconnecting due to a surprise-remove, + which means that we shouldn't do anything that touches hardware. + +Return Value: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status, finalStatus; + + finalStatus = STATUS_SUCCESS; + pFxDriverGlobals = GetDriverGlobals(); + + // + // Check to see if this interrupt object was actually assigned any + // resources. If it wasn't, then don't attempt to disconnect. A + // WDFINTERRUPT object won't be assigned any resources if the underlying + // device wasn't granted any by the PnP manager. + // + + if (m_InterruptInfo.Vector == 0) { + return STATUS_SUCCESS; + } + + if (IsWakeCapable() && + (NotifyFlags & NotifyResourcesArmedForWake)) { + // + // If an interrupt is marked as wakeable and the device has been set to + // wake via a driver-owned ISR, leave the interrupt connected. + // + ASSERT(NotifyFlags & NotifyResourcesExplicitPowerDown); + + SetActiveForWake(TRUE); + + return STATUS_SUCCESS; + } + + // + // This takes care of the power-up failure path for interrupt that doesnt + // support soft disconnect. The interrupt has already been hard + // disconnected in power-up failure path. + // + if ((NotifyFlags & NotifyResourcesDisconnectInactive) && + (IsSoftDisconnectCapable() == FALSE) && + (IsActiveForWake() == FALSE)) { + // + // We got here to disconnect an inactive interrupt. But if + // this interrupt is not Soft Disconnect capable then it was + // never made inactive in the first place so nothing to do here. + // It should already be hard disconnected by now. + // + ASSERT(NotifyFlags & NotifyResourcesForceDisconnect); + + return STATUS_SUCCESS; + } + + + if (m_Connected == FALSE) { + // + // No way we can be not connect and enabled + // + ASSERT(m_Enabled == FALSE); + + // + // if m_Connected is FALSE because the driver forcefully disconnected + // the interrupt we still want to disconnect the actual interrupt object + // if the caller wants to force disconnect (e.g., the device is being + // removed) + // + if (m_Interrupt != NULL && + (NotifyFlags & NotifyResourcesForceDisconnect)) { + // + // If the driver lets the state machine handle the interrupt state + // we should never get here so make sure the driver forced the issue. + // + ASSERT(m_ForceDisconnected); + + goto Disconnect; + } + + return STATUS_SUCCESS; + } + + if (m_Enabled && ((NotifyFlags & NotifyResourcesSurpriseRemoved) == 0)) { + + // + // + // For wake capable interrupts it is possible to enter this path + // with NotifyResourcesDisconnectInactive flag if the device fails + // to power up after the interrupt was left connected during Dx + // + if (IsWakeCapable() == FALSE) { + ASSERT((NotifyFlags & NotifyResourcesDisconnectInactive) == 0); + } + + // + // Disable the interrupt at the hardware. + // + status = InterruptDisable(); + + m_Enabled = FALSE; + + if (!NT_SUCCESS(status)) { + // + // Even upon failure we continue because we don't want to leave + // the interrupt connected when we tear down the stack. + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtInterruptDisable WDFDEVICE %p, WDFINTERRUPT %p, " + "PKINTERRUPT %p returned %!STATUS!", + m_Device->GetHandle(), + GetHandle(), m_Interrupt, status); + + // + // Overwrite the previous value. Not a big deal since both are + // errors. + // + finalStatus = status; + } + } + +#if FX_IS_KERNEL_MODE + // + // Some edge-triggered interrupts may fire before the connection process is + // finished and m_Interrupt is set. To accomodate them, we save the KINTERRUPT + // in _InterruptThunk to m_InterruptCaptured which serves as a backup for + // m_Interrupt. Now we need to NULL m_InterruptCaptured and ensure that + // _InterruptThunk will not re-capture it. + // + if (m_IsEdgeTriggeredNonMsiInterrupt == TRUE) { + // + // Synchronize the setting of m_Disconnecting with any running ISRs. + // No new ISR callbacks will run after _SynchronizeExecution returns, + // until m_Disconnecting is set to FALSE again. + // + if (m_Interrupt != NULL) { + _SynchronizeExecution(m_Interrupt, _InterruptMarkDisconnecting, this); + } + + // + // Because m_Disconnecting was set, we know the ISR + // will not re-capture the KINTERRUPT again. + // + m_InterruptCaptured = NULL; + } +#endif + + // + // Now flush queued callbacks so that we know that nobody is still trying to + // synchronize against this interrupt. For KMDF this will flush DPCs and + // for UMDF this will send a message to reflector to flush queued DPCs. + // + FlushQueuedDpcs(); + +#if FX_IS_KERNEL_MODE + // + // Rundown the workitem if present (passive-level interrupt support or KMDF). + // Not needed for UMDF since reflector doesn't use workitem for isr. + // + FlushQueuedWorkitem(); + +#endif + + // + // See if we need to just do soft disconnect. Soft disconnect is done only + // during explicit power down. + // + if (IsSoftDisconnectCapable() && + (NotifyFlags & NotifyResourcesExplicitPowerDown)) { + ReportInactive(TRUE); + + goto Exit; + } + + // + // In the NP path we disable the interrupt but do not disconnect the + // interrupt. (That is b/c IoDisconnectInterrupt is a pagable function and + // calling it could cause paging I/O on this device which will be unserviceable + // because it is in Dx. + // + if (NotifyFlags & NotifyResourcesNP) { + // + // If we are in the NP path, force disconnect should not be set. Force + // disconnect is setup during a query remove/stop power down. + // + ASSERT((NotifyFlags & NotifyResourcesForceDisconnect) == 0); + + goto Exit; + } + +Disconnect: + // + // Disconnect the interrupt. For KMDF, this calls the kernel DDI, and for + // UMDF, sends a sync message to reflector. + // + DisconnectInternal(); + + if (IsActiveForWake()) { + // + // Since the interrupt has been disconnected, it not longer active + // for wake + // + SetActiveForWake(FALSE); + } + + m_Connected = FALSE; + +#if FX_IS_KERNEL_MODE + m_Active = FALSE; +#endif + +Exit: + m_Disconnecting = FALSE; + + return finalStatus; +} + + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::ForceDisconnect( + VOID + ) +{ + ULONG flags; + + // + // Since we have no context or coordination of power state when these calls + // are made, our only recourse is to see if the device is power pagable or + // not and use that as the basis for our flags. + // + if (m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + flags = NotifyResourcesNoFlags; + } + else { + flags = NotifyResourcesNP; + } + + // + // Log the event because the driver is not allow the state machine to handle + // the interrupt's state. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Force disconnect called on WDFDEVICE %p, WDFINTERRUPT %p, PKINTERRUPT %p", + m_Device->GetHandle(), GetHandle(), m_Interrupt); + + m_ForceDisconnected = TRUE; + + return Disconnect(flags); +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::ForceReconnect( + VOID + ) +{ + ULONG flags; + + // + // Since we have no context or coordination of power state when these calls + // are made, our only recourse is to see if the device is power pagable or + // not and use that as the basis for our flags. + // + if (m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + flags = NotifyResourcesNoFlags; + } + else { + flags = NotifyResourcesNP; + } + + // + // Log the event because the driver is not allow the state machine to handle + // the interrupt's state. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Force connect called on WDFDEVICE %p, WDFINTERRUPT %p, PKINTERRUPT %p", + m_Device->GetHandle(), GetHandle(), m_Interrupt); + + m_ForceDisconnected = FALSE; + + return Connect(flags); +} + +// +// Called by the system work item to finish the rundown +// +VOID +FxInterrupt::FlushAndRundown() +{ + FxObject* pObject; + + // + // This called at PASSIVE_LEVEL which is required for + // IoDisconnectInterrupt and KeFlushQueuedDpcs + // + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + // + // If we have the KeFlushQueuedDpcs function call it + // to ensure the DPC routine is no longer running before + // we release the final reference to memory and the framework objects + // + FlushQueuedDpcs(); + + // + // Do mode-specific work. + // + FlushAndRundownInternal(); + + // + // Release the reference taken in FxInterrupt::Initialize + // + if (m_Device != NULL) { + pObject = m_Device; + m_Device = NULL; + + pObject->RELEASE(this); + } + + // + // Release the reference taken in FxInterrupt::Initialize + // + RELEASE(_InterruptThunk); +} + +// +// Enable interrupts +// +NTSTATUS +FxInterrupt::InterruptEnableInvokeCallback( + VOID + ) +{ + NTSTATUS status; + + if (m_PassiveHandling) { + // + // Passive-level interrupt handling: acquire our internal passive-lock + // after the kernel acquired its own passive-lock and before invoking + // the callback. + // + AcquireLock(); + status = m_EvtInterruptEnable(GetHandle(), + m_Device->GetHandle()); + ReleaseLock(); + } + else { + // + // DIRQL interrupt handling: invoke the callback. + // + status = m_EvtInterruptEnable(GetHandle(), + m_Device->GetHandle()); + } + + return status; +} + +BOOLEAN +FxInterrupt::_InterruptEnableThunk( + __in PVOID SyncContext + ) +{ + FxInterruptEnableParameters* p; + + p = (FxInterruptEnableParameters*) SyncContext; + + p->ReturnVal = p->Interrupt->InterruptEnableInvokeCallback(); + + return TRUE; +} + +NTSTATUS +FxInterrupt::InterruptEnable( + VOID + ) +{ + FxInterruptEnableParameters params; + + params.Interrupt = this; + params.ReturnVal = STATUS_SUCCESS; + + if (m_EvtInterruptEnable) { + _SynchronizeExecution(m_Interrupt, _InterruptEnableThunk, ¶ms); + } + + return params.ReturnVal; +} + +// +// Disable interrupts +// +NTSTATUS +FxInterrupt::InterruptDisableInvokeCallback( + VOID + ) +{ + NTSTATUS status; + + if (m_PassiveHandling) { + // + // Passive-level interrupt handling: acquire our internal passive-lock + // after the kernel acquired its own passive-lock and before invoking + // the callback. + // + AcquireLock(); + status = m_EvtInterruptDisable(GetHandle(), + m_Device->GetHandle()); + ReleaseLock(); + } + else { + // + // DIRQL interrupt handling: invoke the callback. + // + status = m_EvtInterruptDisable(GetHandle(), + m_Device->GetHandle()); + } + + return status; +} + + +BOOLEAN +FxInterrupt::_InterruptDisableThunk( + __in PVOID SyncContext + ) +{ + FxInterruptDisableParameters* p; + + p = (FxInterruptDisableParameters*) SyncContext; + + p->ReturnVal = p->Interrupt->InterruptDisableInvokeCallback(); + + return TRUE; +} + +NTSTATUS +FxInterrupt::InterruptDisable( + VOID + ) +{ + FxInterruptDisableParameters params; + + params.Interrupt = this; + params.ReturnVal = STATUS_SUCCESS; + + if (m_EvtInterruptDisable != NULL) { + _SynchronizeExecution(m_Interrupt, _InterruptDisableThunk, ¶ms); + } + + return params.ReturnVal; +} + +BOOLEAN +FxInterrupt::QueueWorkItemForIsr( + VOID + ) +{ + BOOLEAN queued; + + // + // Using this function is optional, + // but the caller better have registered a handler + // +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + ASSERT(m_EvtInterruptWorkItem != NULL); +#else + ASSERT(m_EvtInterruptWorkItem != NULL || m_EvtInterruptDpc != NULL); +#endif + + if (Mx::MxGetCurrentIrql() > DISPATCH_LEVEL) { + // + // Note: if the caller runs at DIRQL, the function returns the result + // of KeInsertQueueDpc() and not that of WorkItem.TryToQueue(). + // The latter result is lost. Docs should clarify this behavior. + // +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + queued = Mx::MxInsertQueueDpc(&m_Dpc, this, NULL); +#else + queued = FALSE; + FX_VERIFY(INTERNAL, TRAPMSG("Not expected")); +#endif + } + else { + queued = m_SystemWorkItem->TryToEnqueue(_InterruptWorkItemCallback, this); + } + + return queued; +} + +VOID +FxInterrupt::_InterruptWorkItemCallback( + __in PVOID DeferredContext + ) +/*++ + +Routine Description: + Thunk used to invoke EvtInterruptWorkItem at passive-level + +--*/ +{ + ASSERT(DeferredContext != NULL); + ((FxInterrupt*)DeferredContext)->WorkItemHandler(); +} + +VOID +FxInterrupt::FlushQueuedWorkitem( + VOID + ) +{ + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->WaitForExit(); + } +} + +#pragma prefast(push) +#pragma prefast(disable:__WARNING_UNEXPECTED_IRQL_CHANGE, "Used unannotated pointers previously") + +VOID +FxInterrupt::AcquireLock( + ) +{ + if (FALSE == m_PassiveHandling) { + struct _KINTERRUPT* kinterrupt = GetInterruptPtr(); + + // + // DIRQL interrupt handling. + // + ASSERTMSG("Can't synchronize when the interrupt isn't connected: ", + kinterrupt != NULL); + + if (NULL != kinterrupt) { + m_OldIrql = Mx::MxAcquireInterruptSpinLock(kinterrupt); + } + } + else { + // + // Passive-level interrupt handling when automatic serialization is off. + // + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + ASSERT(m_WaitLock != NULL); + m_WaitLock->AcquireLock(GetDriverGlobals(), NULL); + } +} +#pragma prefast(pop) + +BOOLEAN +FxInterrupt::TryToAcquireLock( + ) +{ + LONGLONG timeout = 0; + + ASSERTMSG("TryToAcquireLock is only available for passive-level " + "interrupt handling: ", m_PassiveHandling); + + if (FALSE == m_PassiveHandling) { + return FALSE; + } + + ASSERT(m_WaitLock != NULL); + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + // + // Passive-level interrupt handling. Automatic serialization is off. + // + return FxWaitLockInternal::IsLockAcquired( + m_WaitLock->AcquireLock(GetDriverGlobals(), &timeout) + ); +} + +#pragma prefast(push) +#pragma prefast(disable:__WARNING_UNEXPECTED_IRQL_CHANGE, "Used unannotated pointers previously") + +VOID +FxInterrupt::ReleaseLock( + ) +{ + if (FALSE == m_PassiveHandling) { + struct _KINTERRUPT* kinterrupt = GetInterruptPtr(); + + // + // DIRQL interrupt handling. + // + ASSERTMSG("Can't synchronize when the interrupt isn't connected: ", + kinterrupt != NULL); + + if (NULL != kinterrupt) { +#pragma prefast(suppress:__WARNING_CALLER_FAILING_TO_HOLD, "Unable to annotate ReleaseLock for this case."); + Mx::MxReleaseInterruptSpinLock(kinterrupt, m_OldIrql); + } + } + else { + // + // Passive-level interrupt handling when automatic serialization is off. + // + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + ASSERT(m_WaitLock != NULL); +#pragma prefast(suppress:__WARNING_CALLER_FAILING_TO_HOLD, "Unable to annotate ReleaseLock for this case."); + m_WaitLock->ReleaseLock(GetDriverGlobals()); + } +} +#pragma prefast(pop) + +BOOLEAN +FxInterrupt::_InterruptSynchronizeThunk( + __in PVOID SyncContext + ) +{ + FxInterruptSyncParameters* p; + BOOLEAN result; + + p = (FxInterruptSyncParameters*) SyncContext; + + if (p->Interrupt->m_PassiveHandling) { + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + // + // Passive-level interrupt handling: acquire our internal passive-lock + // after the kernel acquired its own passive-lock and before invoking + // the callback. + // + p->Interrupt->AcquireLock(); + result = p->Callback(p->Interrupt->GetHandle(), p->Context); + p->Interrupt->ReleaseLock(); + } + else { + result = p->Callback(p->Interrupt->GetHandle(), p->Context); + } + + return result; +} + +BOOLEAN +FxInterrupt::Synchronize( + __in PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + __in WDFCONTEXT Context + ) +{ + struct _KINTERRUPT* kinterrupt; + FxInterruptSyncParameters params; + + params.Interrupt = this; + params.Callback = Callback; + params.Context = Context; + + kinterrupt = GetInterruptPtr(); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + ASSERTMSG("Can't synchronize when the interrupt isn't connected: ", + kinterrupt != NULL); +#endif + + return _SynchronizeExecution(kinterrupt, + _InterruptSynchronizeThunk, + ¶ms); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/eventqueuekm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/eventqueuekm.cpp new file mode 100644 index 00000000000..76f262ba957 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/eventqueuekm.cpp @@ -0,0 +1,119 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + EventQueueKm.cpp + +Abstract: + + This module implements kernel mode specific functionality of event queue + + This functionality needed to be separated out since the KM portion takes + a reference on driver object because KM MxWorkItem::_Free does not wait for + callback to return (i.e. rundown synchronously). + + MxWorkItem::_Free in UM currently waits for callback to return (i.e. runs + down synchronously) hence does not need a reference on driver/devstack + object (see comments on top of MxWorkItemUm.h file). + + In future if UM work-item is made similar to km workitem, UMDF may need to + ensure that modules stay loaded, though the mechanism to ensure that would + likely be different from a reference on the driver. It would likely be a + reference on the devicestack object. + +Environment: + + Kernel mode only + +Revision History: + + + + +--*/ + +#include "pnppriv.hpp" + +VOID +FxWorkItemEventQueue::QueueWorkItem( + VOID + ) +{ + // + // The work item will take a reference on KMDF itself. This will keep KMDF's + // image around (but not necessarily prevent DriverUnload from being called) + // so that the code after we set the done event will be in memory and not + // unloaded. We must do this because there is no explicit reference between + // the client driver and KMDF, so when the io manager calls the client's + // DriverUnload, it has no way of managing KMDF's ref count to stay in memory + // when the loader unloads KMDF explicitly in response to DriverUnload. + // + // We manually take a reference on the client so that we provide the same + // functionality that IO workitems do. The client driver's image will have + // a reference on it after it has returned. + // + + + + + Mx::MxReferenceObject(m_PkgPnp->GetDriverGlobals()->Driver->GetDriverObject()); + + // + // Prevent FxDriverGlobals from being deleted until the workitem finishes + // its work. In case of a bus driver with a PDO in removed + // state, if the bus is removed, the removal of PDO may happen in a workitem + // and may result in unload routine being called before the PDO package is + // deallocated. Since FxPool deallocation code touches FxDriverGlobals + // (a pointer of which is located in the header of each FxPool allocated + // object), taking this ref prevents the globals from going away until a + // corresponding deref at the end of workitem. + // + m_PkgPnp->GetDriverGlobals()->ADDREF(_WorkItemCallback); + + m_WorkItem.Enqueue( + (PMX_WORKITEM_ROUTINE) _WorkItemCallback, + (FxEventQueue*) this); +} + +VOID +FxWorkItemEventQueue::_WorkItemCallback( + __in MdDeviceObject DeviceObject, + __in PVOID Context + ) +/*++ + +Routine Description: + This is the work item that attempts to run the machine on a thread + separate from the one the caller was using. It implements step 9 above. + +--*/ +{ + FxWorkItemEventQueue* This = (FxWorkItemEventQueue*) Context; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + UNREFERENCED_PARAMETER(DeviceObject); + + MdDriverObject pDriverObject; + + pFxDriverGlobals = This->m_PkgPnp->GetDriverGlobals(); + + // + // Capture the driver object before we call the EventQueueWoker() because + // the time it returns, This could be freed. + + + + pDriverObject = pFxDriverGlobals->Driver->GetDriverObject(); + + This->EventQueueWorker(); + + // + // Release the ref on FxDriverGlobals taken before queuing this workitem. + // + pFxDriverGlobals->RELEASE(_WorkItemCallback); + + Mx::MxDereferenceObject(pDriverObject); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgfdokm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgfdokm.cpp new file mode 100644 index 00000000000..5b65240a539 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgfdokm.cpp @@ -0,0 +1,596 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgFdo.cpp + +Abstract: + + This module implements the pnp/power package for the driver + framework. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + + +--*/ + +#include "..\pnppriv.hpp" + +#include +#include + + +#if defined(EVENT_TRACING) +// Tracing support +extern "C" { +#include "FxPkgFdoKm.tmh" +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PnpFilterResourceRequirements( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp FilterResourceRequirements IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + PIO_RESOURCE_REQUIREMENTS_LIST pWdmRequirementsList; + PIO_RESOURCE_REQUIREMENTS_LIST pNewWdmList; + NTSTATUS status; + FxIoResReqList *pIoResReqList; + WDFIORESREQLIST reqlist; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering FilterResourceRequirements handler"); + + if (m_DeviceFilterRemoveResourceRequirements.m_Method != NULL) { + + pWdmRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) Irp->GetInformation(); + + status = STATUS_INSUFFICIENT_RESOURCES; + + pIoResReqList = FxIoResReqList::_CreateFromWdmList(GetDriverGlobals(), + pWdmRequirementsList, + FxResourceAllAccessAllowed); + + if (pIoResReqList != NULL) { + status = pIoResReqList->Commit(NULL, (PWDFOBJECT) &reqlist); + + // Commit should never fail because we own all object state + ASSERT(NT_SUCCESS(status)); + UNREFERENCED_PARAMETER(status); + + status = m_DeviceFilterRemoveResourceRequirements.Invoke( + m_Device->GetHandle(), pIoResReqList->GetHandle()); + + if (NT_SUCCESS(status) && pIoResReqList->IsChanged()) { + pNewWdmList = pIoResReqList->CreateWdmList(); + + if (pNewWdmList != NULL) { + // + // List could be missing previously + // + if (pWdmRequirementsList != NULL) { + // + // Propagate BusNumber to our new list. + // + pNewWdmList->BusNumber = pWdmRequirementsList->BusNumber; + + MxMemory::MxFreePool(pWdmRequirementsList); + } + + Irp->SetInformation((ULONG_PTR) pNewWdmList); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + // + // No matter what, free the resource requirements list object. If + // we need another one when adding resources, another one will be + // allocated. + // + pIoResReqList->DeleteObject(); + pIoResReqList = NULL; + } + } + else { + // + // No filtering on the way down, set status to STATUS_SUCCESS so we + // send the irp down the stack. + // + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + status = SendIrpSynchronously(Irp); + } + + // + // If we do not handle the IRP on the way down and the PDO does not handle + // the IRP, we can have a status of STATUS_NOT_SUPPORTED. We still want to + // process the irp in this state. + // + if (NT_SUCCESS(status) || status == STATUS_NOT_SUPPORTED) { + NTSTATUS filterStatus; + + // + // Give the Framework objects a pass at the list. + // + filterStatus = FxPkgPnp::FilterResourceRequirements( + (PIO_RESOURCE_REQUIREMENTS_LIST*)(&Irp->GetIrp()->IoStatus.Information) + ); + + if (!NT_SUCCESS(filterStatus)) { + status = filterStatus; + } + else if (m_DeviceFilterAddResourceRequirements.m_Method != NULL) { + // + // Now give the driver a shot at it. + // + pWdmRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) + Irp->GetInformation(); + + pIoResReqList = FxIoResReqList::_CreateFromWdmList( + GetDriverGlobals(), pWdmRequirementsList, FxResourceAllAccessAllowed); + + if (pIoResReqList != NULL) { + status = pIoResReqList->Commit(NULL, (PWDFOBJECT) &reqlist); + UNREFERENCED_PARAMETER(status); + + // + // Since we absolutely control the lifetime of pIoResReqList, this + // should never fail + // + ASSERT(NT_SUCCESS(status)); + + status = m_DeviceFilterAddResourceRequirements.Invoke( + m_Device->GetHandle(), reqlist); + + // + // It is possible the child driver modified the resource list, + // and if so we need to update the requirements list. + // + if (NT_SUCCESS(status) && pIoResReqList->IsChanged()) { + pNewWdmList = pIoResReqList->CreateWdmList(); + + if (pNewWdmList != NULL) { + // + // List could be missing previously + // + if (pWdmRequirementsList != NULL) { + // + // Propagate BusNumber to our new list. + // + pNewWdmList->BusNumber = pWdmRequirementsList->BusNumber; + + ExFreePool(pWdmRequirementsList); + } + + Irp->SetInformation((ULONG_PTR) pNewWdmList); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + pIoResReqList->DeleteObject(); + pIoResReqList = NULL; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + } + + CompletePnpRequest(Irp, status); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting FilterResourceRequirements handler, %!STATUS!", + status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryCapabilitiesCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(Context); + + ASSERTMSG("Not implemented for KMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PnpQueryCapabilities( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryCapabilities IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + + HandleQueryCapabilities(Irp); + + status = SendIrpSynchronously(Irp); + + // + // Now that the IRP has returned to us, we modify what the bus driver + // set up. + // + if (NT_SUCCESS(status)) { + HandleQueryCapabilitiesCompletion(Irp); + } + + CompletePnpRequest(Irp, status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryPnpDeviceStateCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(Context); + + ASSERTMSG("Not implemented for KMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryPnpDeviceState( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryPnpDeviceState IRP. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + FxPkgFdo* pThis; + NTSTATUS status; + + pThis = (FxPkgFdo*) This; + + status = pThis->SendIrpSynchronously(Irp); + + if (status == STATUS_NOT_SUPPORTED) { + // + // Morph into a successful code so that we process the request + // + status = STATUS_SUCCESS; + Irp->SetStatus(status); + } + + if (NT_SUCCESS(status)) { + pThis->HandleQueryPnpDeviceStateCompletion(Irp); + } + else { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Lower stack returned error for query pnp device state, %!STATUS!", + status); + } + + // + // Since we already sent the request down the stack, we must complete it + // now. + // + return pThis->CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::Initialize( + __in PWDFDEVICE_INIT DeviceInit + ) +/*++ + + + + + + + + +Routine Description: + + After creating a FxPkgFdo, the driver writer will initialize it by passing + a set of driver callbacks that allow the driver writer to customize the + behavior when handling certain IRPs. + + This is the place to do any initialization that might fail. + +Arguments: + + Device - a pointer to the FxDevice + + DispatchTable - a driver supplied table of callbacks + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pGlobals; + WDF_CHILD_LIST_CONFIG config; + size_t totalDescriptionSize = 0; + WDFCHILDLIST hList; + NTSTATUS status; + + pGlobals = GetDriverGlobals(); + + status = FxPkgPnp::Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + status = AllocateEnumInfo(); + if (!NT_SUCCESS(status)) { + return status; + } + + #pragma prefast(suppress: __WARNING_PASSING_FUNCTION_UNEXPECTED_NULL, "Static child lists do not use the EvtChildListCreateDevice callback") + WDF_CHILD_LIST_CONFIG_INIT(&config, + sizeof(FxStaticChildDescription), + NULL); + + status = FxChildList::_ComputeTotalDescriptionSize(pGlobals, + &config, + &totalDescriptionSize); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxChildList::_CreateAndInit(&m_StaticDeviceList, + pGlobals, + WDF_NO_OBJECT_ATTRIBUTES, + totalDescriptionSize, + m_Device, + &config, + TRUE); + if (!NT_SUCCESS(status)) { + return status; + } + + status = m_StaticDeviceList->Commit(WDF_NO_OBJECT_ATTRIBUTES, + (WDFOBJECT*) &hList, + m_Device); + + if (!NT_SUCCESS(status)) { + m_StaticDeviceList->DeleteFromFailedCreate(); + m_StaticDeviceList = NULL; + + return status; + } + + // + // This will be released in the destructor + // + m_StaticDeviceList->ADDREF(this); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::QueryForDsfInterface( + VOID + ) +{ + WDF_DSF_INTERFACE dsfInterface; + NTSTATUS status; + BOOLEAN derefQI = FALSE; + + RtlZeroMemory(&dsfInterface, sizeof(dsfInterface)); + + // + // Since there are some stacks that are not PnP re-entrant (like USBHUB, + // xpsp2), we specify that the QI goes only to our attached device and + // not to the top of the stack as a normal QI irp would. + // + // We also do this a preventative measure for other stacks we don't know + // about internally and do not have access to when testing. + // + status = m_Device->QueryForInterface(&GUID_WDF_DSF_INTERFACE, + (PINTERFACE) &dsfInterface, + sizeof(dsfInterface), + WDM_DSF_INTERFACE_V1_0, + NULL, + m_Device->GetAttachedDevice() + ); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Lower stack does not have a DSF interface"); + status = STATUS_SUCCESS; + goto Done; + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Lower stack returned an error for query DSF interface, %!STATUS!", + status); + goto Done; + } + + derefQI = TRUE; + + // + // Basic run time checks. + // + if (dsfInterface.Interface.Version != WDM_DSF_INTERFACE_V1_0) { + status = STATUS_REVISION_MISMATCH; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Lower DSF stack supports v(%x), requested v(%x), %!STATUS!", + dsfInterface.Interface.Version, + WDM_DSF_INTERFACE_V1_0, + status); + goto Done; + } + + // + // Ex functions should be both set or cleared. + // Active/Inactive functions should be both set or cleared. + // Ex function must be present. + // Note: !!(ptr) expression below converts ptr value to true/false value. + // I.e., ptr==NULL to false and ptr!=NULL to true. + // + if (!((!!(dsfInterface.IoConnectInterruptEx) == + !!(dsfInterface.IoDisconnectInterruptEx)) && + (!!(dsfInterface.IoReportInterruptActive) == + !!(dsfInterface.IoReportInterruptInactive)) && + (dsfInterface.IoConnectInterruptEx != NULL) + )) { + status = STATUS_DATA_ERROR; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Function mismatch detected in DSF interface, %!STATUS!", + status); + goto Done; + } + + // + // Info is correct. + // + m_IoConnectInterruptEx = dsfInterface.IoConnectInterruptEx; + m_IoDisconnectInterruptEx = dsfInterface.IoDisconnectInterruptEx; + + // + // If DSF interface provides active/inactive functions then use them + // + if (dsfInterface.IoReportInterruptActive != NULL) + { + m_IoReportInterruptActive = dsfInterface.IoReportInterruptActive; + m_IoReportInterruptInactive = dsfInterface.IoReportInterruptInactive; + } + +Done: + + // + // The contract with the DSF layer is to release the interface right away; + // the embedded interrupt function ptrs will be valid until this driver is + // unloaded. + // + if (derefQI) { + dsfInterface.Interface.InterfaceDereference(dsfInterface.Interface.Context); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::AskParentToRemoveAndReenumerate( + VOID + ) +/*++ + +Routine Description: + This routine asks the PDO to ask its parent bus driver to Surprise-Remove + and re-enumerate the PDO. This will be done only at the point of + catastrophic software failure, and occasionally after catastrophic hardware + failure. + +Arguments: + None + +Return Value: + status + + --*/ +{ + PREENUMERATE_SELF_INTERFACE_STANDARD pInterface; + + pInterface = &m_SurpriseRemoveAndReenumerateSelfInterface; + + if (pInterface->SurpriseRemoveAndReenumerateSelf != NULL) { + pInterface->SurpriseRemoveAndReenumerateSelf(pInterface->Context); + + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpdokm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpdokm.cpp new file mode 100644 index 00000000000..8d21d10e4b8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpdokm.cpp @@ -0,0 +1,387 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgPdoKM.cpp + +Abstract: + + This module implements the Pnp package for Pdo devices. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + + + +--*/ + +#include "..\pnppriv.hpp" +#include + +// Tracing support +#if defined(EVENT_TRACING) +extern "C" { +#include "FxPkgPdoKM.tmh" +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryResources( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->PnpQueryResources(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PnpQueryResources( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryResources IRP. We return + the resources that the device is currently consuming. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + FxCmResList *pResList = NULL; + PCM_RESOURCE_LIST pWdmResourceList; + WDFCMRESLIST list; + NTSTATUS status; + + // + // It is only necessary to create a collection if the caller is interested + // in this callback. + // + if (m_DeviceResourcesQuery.m_Method == NULL) { + return CompletePnpRequest(Irp, Irp->GetStatus()); + } + + pWdmResourceList = NULL; + + status = FxCmResList::_CreateAndInit(&pResList, + GetDriverGlobals(), + m_Device, + WDF_NO_OBJECT_ATTRIBUTES, + FxResourceAllAccessAllowed); + if (!NT_SUCCESS(status)) { + goto exit; + } + + status = pResList->Commit(NULL, (PWDFOBJECT) &list); + + if (NT_SUCCESS(status)) { + status = m_DeviceResourcesQuery.Invoke( + m_Device->GetHandle(), list); + + if (NT_SUCCESS(status)) { + // + // Walk the resource collection and create the appropriate + // CM_RESOURCE_LIST. + // + if (pResList->Count()) { + pWdmResourceList = pResList->CreateWdmList(); + } + else { + // + // The driver didn't add any resources, so we'll just + // ignore this Irp. + // + // Return that status that was passed in. + // + status = Irp->GetStatus(); + pWdmResourceList = (PCM_RESOURCE_LIST) Irp->GetInformation(); + } + } + } + + pResList->DeleteObject(); + + exit: + Irp->SetInformation((ULONG_PTR) pWdmResourceList); + return CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->PnpQueryResourceRequirements(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PnpQueryResourceRequirements( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryResourceRequirements IRP. + We return the set (of sets) of possible resources that we could accept + which would allow our device to work. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + PIO_RESOURCE_REQUIREMENTS_LIST pWdmRequirementsList; + FxIoResReqList *pIoResReqList = NULL; + PSINGLE_LIST_ENTRY ple; + NTSTATUS status; + + status = STATUS_SUCCESS; + + m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals()); + + + + + // We know for sure that the PDO is known to pnp now because it has received + // this query resource requirements request. + m_Device->m_PdoKnown = TRUE; + + // + // Now that it is a known PDO, we can register interfaces on it whose + // registration was delayed because the PDO was unknown at the time of the + // call to WdfDeviceCreateDeviceInterface. If it is not the first time + // then we re-register (see comments below for reason). + // + for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { + FxDeviceInterface *pDeviceInterface; + + pDeviceInterface = FxDeviceInterface::_FromEntry(ple); + + // + // At this time the interface may be in registered or unregistered state. + // The reason being that pnp may unregister the interface from underneath + // during the life of PDO (note that drivers never unregister explicitly + // as there is no unregistration API, and the scenarios in which it can + // happen are given below). Therefore WDF needs to re-register the interface, + // otherwise driver may end up with an unregistered interface and fail to + // enable interface. + // + // Pnp can unregister the interface in following cases: + // 1. The driver is uninstalled, and re-installed + // In this case, the stack is torn down but the PDO is not + // deleted. Pnp deletes the interface registration, however WDF + // doesn't delete the interface structure because it is deleted as + // part of PDO deletion in destructor. When the driver is re-installed + // Pnp sends another query resource requirements irp and WDF needs to + // re-register at this time. + // + // 2. Pnp couldn't find a driver and loaded a NULL driver while + // waiting for reinstall to happen from WU. This is similar to case above + // except that the pnp activities are transparent to user. + // In this case, PDO was never started. However it did get + // the query resource requirements irp and therefore its interface + // was registered by WDF. Pnp deleted the interface registration + // when installing NULL driver. When pnp finally finds a driver from + // WU, it sends another query resource requirement irp. At this time, + // WDF needs to re-register. + // + // In both the above cases, WDF has to re-register (and free previous + // sym link) when query resource requirements irp arrives again. Note + // that Pnp doesn't delete the interface registration during disable, + // s/w surprise-removal, or resource rebalance. In case of resource + // rebalance, query resource requirement irp is sent after stop, and + // WDF will end up registering again even though pnp did not unregister + // the interface. This is fine because kernel API for registration + // allows multiple calls to register, and in case registration already + // exists it returns informational status (not error status) + // STATUS_OBJECT_NAME_EXISTS and also returns the same symbolic link. + // + // + // Free the symbolic link if already present + // + if (pDeviceInterface->m_SymbolicLinkName.Buffer != NULL) { + RtlFreeUnicodeString(&pDeviceInterface->m_SymbolicLinkName); + RtlZeroMemory(&pDeviceInterface->m_SymbolicLinkName, + sizeof(pDeviceInterface->m_SymbolicLinkName)); + } + + // + // Register. Note that if the interface was already registered, the + // call to IoRegisterDeviceInterface will return informational status + // (not error status) STATUS_OBJECT_NAME_EXISTS and also return the + // symbolic link. + // + status = pDeviceInterface->Register( + m_Device->GetPhysicalDevice() + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "could not register device interface on PDO WDFDEVICE %p, " + "!devobj %p, failing IRP_MN_QUERY_RESOURCE_REQUIREMENTS %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), status); + break; + } + } + + m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals()); + + if (!NT_SUCCESS(status)) { + return CompletePnpRequest(Irp, status); + } + + // + // Driver writer is not interested in this callback, forgoe the allocation + // of the FxCollection and complete the request here. + // + if (m_DeviceResourceRequirementsQuery.m_Method == NULL) { + return CompletePnpRequest(Irp, status); + } + + pWdmRequirementsList = NULL; + + // + // Create a collection which will be populated by the + // bus driver. + // + status = FxIoResReqList::_CreateAndInit(&pIoResReqList, + GetDriverGlobals(), + WDF_NO_OBJECT_ATTRIBUTES, + FxResourceAllAccessAllowed); + if (!NT_SUCCESS(status)) { + goto exit; + } + + WDFIORESREQLIST reqlist; + + // + // Get a handle to the collection that can be passed to the driver. + // + status = pIoResReqList->Commit(NULL, (PWDFOBJECT) &reqlist); + + // + // We control the object's state, this should never fail + // + ASSERT(NT_SUCCESS(status)); + UNREFERENCED_PARAMETER(status); + + // + // Call the driver. The driver will populate the resource collection + // with a set of child collections which will contain each of the + // possible resource assignments. + // + status = m_DeviceResourceRequirementsQuery.Invoke( + m_Device->GetHandle(), reqlist); + + if (NT_SUCCESS(status)) { + if (pIoResReqList->Count()) { + // + // Create a IO_RESOURCE_REQUIREMENTS_LIST based on the + // contents of our collection. + // + pWdmRequirementsList = pIoResReqList->CreateWdmList(); + + if (pWdmRequirementsList != NULL) { + Irp->SetInformation((ULONG_PTR) pWdmRequirementsList); + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else { + // + // The driver didn't add any resources, so we'll just + // ignore this request. + // + // Return the status that was passed in. + // + status = Irp->GetStatus(); + } + } + + pIoResReqList->DeleteObject(); + + exit: + return CompletePnpRequest(Irp, status); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpFilterResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + Filter resource requirements for the PDO. A chance to further muck with + the resources assigned to the device. + +Arguments: + This - the package + + Irp - the request + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + + // + // Give the Framework objects a pass at the list. + // + status = ((FxPkgPdo*) This)->FilterResourceRequirements( + (PIO_RESOURCE_REQUIREMENTS_LIST*)(&Irp->GetIrp()->IoStatus.Information) + ); + + if (NT_SUCCESS(status)) { + // + // Upon successful internal filtering, return the embedded status. + // + status = Irp->GetStatus(); + } + else { + // + // Only on failure do we change the status of the irp + // + Irp->SetStatus(status); + } + + return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpnpkm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpnpkm.cpp new file mode 100644 index 00000000000..31f8086dcc5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpnpkm.cpp @@ -0,0 +1,624 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "..\pnppriv.hpp" + +#include +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxPkgPnpKM.tmh" +#endif +} + +NTSTATUS +FxPkgPnp::FilterResourceRequirements( + __in IO_RESOURCE_REQUIREMENTS_LIST **IoList + ) +/*++ + +Routine Description: + + This routine traverses one or more alternate _IO_RESOURCE_LISTs in the input + IO_RESOURCE_REQUIREMENTS_LIST looking for interrupt descriptor and applies + the policy set by driver in the interrupt object to the resource descriptor. + + LBI - Line based interrupt + MSI - Message Signalled interrupt + + Here are the assumptions made about the order of descriptors. + + - An IoRequirementList can have one or more alternate IoResourceList + - Each IoResourceList can have one or more resource descriptors + - A descriptor can be default (unique), preferred, or alternate descriptors + - A preferred descriptor can have zero or more alternate descriptors (P, A, A, A..) + - In an IoResourceList, there can be one or more LBI descriptors + (non-pci devices)(P,A,P,A) + - In an IoResourceList, there can be only one preferred MSI 2.2 + (single or multi message) descriptor + - In an IoResourceList, there cannot be MSI2.2 and MSI-X descriptors + - In an IoResourceList, there can be one or more MSI-X descriptor + - An alternate descriptor cannot be a very first descriptor in the list + + + Now with that assumption, this routines parses the list looking for interrupt + descriptor. + + - If it finds a LBI, it starts with the very first interrupt object and applies + the policy set by the driver to the resource descriptor. + - If it's finds an MSI2.2 then it starts with the first interrupt object and applies + the policy. If the MSI2.2 is a multi-message one then it loops thru looking for + as many interrupt object as there are messages. It doesn't fail the IRP, if the + interrupt objects are less than the messages. + - If there is an alternate descriptor then it applies the same policy from the + interrupt object that it used for the preceding preferred descriptor. + - Framework always uses FULLY_SPECIFIED connection type for both LBI and MSI + interrupts including MSI-X + - Framework will apply the policy on the descriptor set by the driver only + if the policy is already not included in the resource descriptor. This is + to allow the policy set in the registry to take precedence over the hard + coded driver policy. + - If the driver registers filter resource requirement and applies the policy + on its own (by escaping to WDM) then framework doesn't override that. + +Arguments: + + IoList - Pointer to the list part of an IRP_MN_FILTER_RESOURCE_REQUIREMENTS. + +Return Value: + + NTSTATUS + +--*/ +{ + ULONG altResListIndex; + PIO_RESOURCE_REQUIREMENTS_LIST pIoRequirementList; + PIO_RESOURCE_LIST pIoResList; + + pIoRequirementList = *IoList; + + if (pIoRequirementList == NULL) { + return STATUS_SUCCESS; + } + + if (IsListEmpty(&m_InterruptListHead)) { + // + // No interrupt objects created to filter resource requirements. + // + return STATUS_SUCCESS; + } + + pIoResList = pIoRequirementList->List; + + // + // Parse one or more alternative resource lists. + // + for (altResListIndex = 0; + altResListIndex < pIoRequirementList->AlternativeLists; + altResListIndex++) { + PLIST_ENTRY pIntListEntryForMSI; + PLIST_ENTRY pIntListEntryForLBI; + BOOLEAN multiMessageMSI22Found; + BOOLEAN previousDescMSI; + ULONG descIndex; + + multiMessageMSI22Found = FALSE; + previousDescMSI = FALSE; + + pIntListEntryForMSI = &m_InterruptListHead; + pIntListEntryForLBI = &m_InterruptListHead; + + // + // Traverse each _IO_RESOURCE_LISTs looking for interrupt descriptors + // and call FilterResourceRequirements method so that it can apply + // policy set on the interrupt object into the resource-descriptor. + // + + for (descIndex = 0; descIndex < pIoResList->Count; descIndex++) { + ULONG messageCount; + PIO_RESOURCE_DESCRIPTOR pIoDesc; + FxInterrupt* pInterruptInstance; + + pIoDesc = &pIoResList->Descriptors[descIndex]; + + switch (pIoDesc->Type) { + case CmResourceTypeInterrupt: + + if (FxInterrupt::_IsMessageInterrupt(pIoDesc->Flags)) { + + previousDescMSI = TRUE; + + // + // We will advance to the next interrupt object if the resource + // is not an alternate resource descriptor. A resource list can + // have a preferred and zero or more alternate resource descriptors + // for the same resource. We need to apply the same policy on the + // alternate desc that we applied on the preferred one in case one + // of the alernate desc is selected for this device. An alternate + // resource descriptor can't be the first descriptor in a list. + // + if ((pIoDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0) { + pIntListEntryForMSI = pIntListEntryForMSI->Flink; + } + + if (pIntListEntryForMSI == &m_InterruptListHead) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Not enough interrupt objects created for MSI by WDFDEVICE 0x%p ", + m_Device->GetHandle()); + break; + } + + pInterruptInstance = CONTAINING_RECORD(pIntListEntryForMSI, FxInterrupt, m_PnpList); + messageCount = pIoDesc->u.Interrupt.MaximumVector - pIoDesc->u.Interrupt.MinimumVector + 1; + + if (messageCount > 1) { + // + // PCI spec guarantees that there can be only one preferred/default + // MSI 2.2 descriptor in a single list. + // + if ((pIoDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0) { +#if DBG + ASSERT(multiMessageMSI22Found == FALSE); +#else + UNREFERENCED_PARAMETER(multiMessageMSI22Found); +#endif + multiMessageMSI22Found = TRUE; + + } + } + else { + // + // This is either single message MSI 2.2 or MSI-X interrupts + // + DO_NOTHING(); + } + + pInterruptInstance->FilterResourceRequirements(pIoDesc); + } + else { + + // + // We will advance to next interrupt object if the desc is not an alternate + // descriptor. For non PCI devices, the first LBI interrupt desc can't be an + // alternate descriptor. + // + if ((pIoDesc->Option & IO_RESOURCE_ALTERNATIVE) == 0) { + pIntListEntryForLBI = pIntListEntryForLBI->Flink; + } + + // + // An LBI can be first alternate resource if there are preceding MSI(X) descriptors + // listed in the list. In that case, this descriptor is the alternate interrupt resource + // for all of the MSI messages. As a result, we will use the first interrupt object from + // the list if this ends up being assigned by the system instead of MSI. + // + if (previousDescMSI) { + ASSERT(pIoDesc->Option & IO_RESOURCE_ALTERNATIVE); + pIntListEntryForLBI = m_InterruptListHead.Flink; + previousDescMSI = FALSE; + } + + // + // There can be one or more LBI interrupts and each LBI interrupt + // could have zero or more alternate descriptors. + // + if (pIntListEntryForLBI == &m_InterruptListHead) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Not enough interrupt objects created for LBI by WDFDEVICE 0x%p ", + m_Device->GetHandle()); + break; + } + + pInterruptInstance = CONTAINING_RECORD(pIntListEntryForLBI, FxInterrupt, m_PnpList); + + pInterruptInstance->FilterResourceRequirements(pIoDesc); + } + + break; + + default: + break; + } + } + + // + // Since the Descriptors is a variable length list, you cannot get to the next + // alternate list by doing pIoRequirementList->List[altResListIndex]. + // Descriptors[descIndex] will now point to the end of the descriptor list. + // If there is another alternate list, it would be begin there. + // + pIoResList = (PIO_RESOURCE_LIST) &pIoResList->Descriptors[descIndex]; + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::AllocateDmaEnablerList( + VOID + ) +{ + FxSpinLockTransactionedList* pList; + NTSTATUS status; + KIRQL irql; + + if (m_DmaEnablerList != NULL) { + return STATUS_SUCCESS; + } + + Lock(&irql); + if (m_DmaEnablerList == NULL) { + pList = new (GetDriverGlobals()) FxSpinLockTransactionedList(); + + if (pList != NULL) { + m_DmaEnablerList = pList; + status = STATUS_SUCCESS; + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + else { + // + // Already have a DMA list + // + status = STATUS_SUCCESS; + } + Unlock(irql); + + return status; +} + +VOID +FxPkgPnp::AddDmaEnabler( + __in FxDmaEnabler* Enabler + ) +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Adding DmaEnabler %p, WDFDMAENABLER %p", + Enabler, Enabler->GetObjectHandle()); + + m_DmaEnablerList->Add(GetDriverGlobals(), &Enabler->m_TransactionLink); +} + +VOID +FxPkgPnp::RemoveDmaEnabler( + __in FxDmaEnabler* Enabler + ) +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Removing DmaEnabler %p, WDFDMAENABLER %p", + Enabler, Enabler->GetObjectHandle()); + + m_DmaEnablerList->Remove(GetDriverGlobals(), &Enabler->m_TransactionLink); +} + +VOID +FxPkgPnp::WriteStateToRegistry( + __in HANDLE RegKey, + __in PUNICODE_STRING ValueName, + __in ULONG Value + ) +{ + ZwSetValueKey(RegKey, ValueName, 0, REG_DWORD, &Value, sizeof(Value)); +} + +NTSTATUS +FxPkgPnp::UpdateWmiInstanceForS0Idle( + __in FxWmiInstanceAction Action + ) +{ + FxWmiProvider* pProvider; + NTSTATUS status; + + switch(Action) { + case AddInstance: + if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance == NULL) { + FxWmiInstanceInternalCallbacks cb; + + cb.SetInstance = _S0IdleSetInstance; + cb.QueryInstance = _S0IdleQueryInstance; + cb.SetItem = _S0IdleSetItem; + + status = RegisterPowerPolicyWmiInstance( + &GUID_POWER_DEVICE_ENABLE, + &cb, + &m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance); + + if (!NT_SUCCESS(status)) { + return status; + } + } + else { + pProvider = m_PowerPolicyMachine.m_Owner->m_IdleSettings. + WmiInstance->GetProvider(); + + // + // Enable the WMI GUID by adding the instance back to the provider's + // list. If there is an error, ignore it. It just means we were + // racing with another thread removing or adding the instance. + // + (void) pProvider->AddInstance( + m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance, + TRUE + ); + } + break; + + case RemoveInstance: + if (m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance != NULL) { + // + // Disable the WMI guid by removing it from the provider's list of + // instances. + // + pProvider = m_PowerPolicyMachine.m_Owner->m_IdleSettings. + WmiInstance->GetProvider(); + + pProvider->RemoveInstance( + m_PowerPolicyMachine.m_Owner->m_IdleSettings.WmiInstance + ); + } + break; + + default: + ASSERT(FALSE); + break; + } + + return STATUS_SUCCESS;; +} + +VOID +FxPkgPnp::ReadRegistryS0Idle( + __in PCUNICODE_STRING ValueName, + __out BOOLEAN *Enabled + ) +{ + NTSTATUS status; + FxAutoRegKey hKey; + + status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_READ); + + // + // Modify the value of Enabled only if success + // + if (NT_SUCCESS(status)) { + ULONG value; + + status = FxRegKey::_QueryULong( + hKey.m_Key, ValueName, &value); + + if (NT_SUCCESS(status)) { + // + // Normalize the ULONG value into a BOOLEAN + // + *Enabled = (value == FALSE) ? FALSE : TRUE; + } + } +} + +NTSTATUS +FxPkgPnp::UpdateWmiInstanceForSxWake( + __in FxWmiInstanceAction Action + ) +{ + FxWmiProvider* pProvider; + NTSTATUS status; + + switch(Action) { + case AddInstance: + if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance == NULL) { + FxWmiInstanceInternalCallbacks cb; + + cb.SetInstance = _SxWakeSetInstance; + cb.QueryInstance = _SxWakeQueryInstance; + cb.SetItem = _SxWakeSetItem; + + status = RegisterPowerPolicyWmiInstance( + &GUID_POWER_DEVICE_WAKE_ENABLE, + &cb, + &m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance); + + if (!NT_SUCCESS(status)) { + return status; + } + } else { + pProvider = m_PowerPolicyMachine.m_Owner->m_WakeSettings. + WmiInstance->GetProvider(); + + // + // Enable the WMI GUID by adding the instance back to the provider's + // list. If there is an error, ignore it. It just means we were + // racing with another thread removing or adding the instance. + // + (void) pProvider->AddInstance( + m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance, + TRUE + ); + } + break; + + case RemoveInstance: + if (m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance != NULL) { + // + // Disable the WMI guid by removing it from the provider's list of + // instances. + // + pProvider = m_PowerPolicyMachine.m_Owner->m_WakeSettings. + WmiInstance->GetProvider(); + + pProvider->RemoveInstance( + m_PowerPolicyMachine.m_Owner->m_WakeSettings.WmiInstance + ); + } + break; + + default: + ASSERT(FALSE); + break; + } + + return STATUS_SUCCESS; +} + +VOID +FxPkgPnp::ReadRegistrySxWake( + __in PCUNICODE_STRING ValueName, + __out BOOLEAN *Enabled + ) +{ + FxAutoRegKey hKey; + NTSTATUS status; + + status = m_Device->OpenSettingsKey(&hKey.m_Key, STANDARD_RIGHTS_READ); + + // + // Modify the value of Enabled only if success + // + if (NT_SUCCESS(status)) { + ULONG value; + + status = FxRegKey::_QueryULong( + hKey.m_Key, ValueName, &value); + + if (NT_SUCCESS(status)) { + // + // Normalize the ULONG value into a BOOLEAN + // + *Enabled = (value == FALSE) ? FALSE : TRUE; + } + } +} + +VOID +PnpPassThroughQIWorker( + __in MxDeviceObject* Device, + __inout FxIrp* Irp, + __inout FxIrp* ForwardIrp + ) +{ + PIO_STACK_LOCATION pFwdStack, pCurStack; + + pCurStack = Irp->GetCurrentIrpStackLocation(); + + ForwardIrp->SetStatus(STATUS_NOT_SUPPORTED); + + pFwdStack = ForwardIrp->GetNextIrpStackLocation(); + pFwdStack->MajorFunction = Irp->GetMajorFunction(); + pFwdStack->MinorFunction = Irp->GetMinorFunction(); + + RtlCopyMemory(&pFwdStack->Parameters.QueryInterface, + &pCurStack->Parameters.QueryInterface, + sizeof(pFwdStack->Parameters.QueryInterface)); + + ForwardIrp->SetInformation(Irp->GetInformation()); + ForwardIrp->SendIrpSynchronously(Device->GetObject()); + + pFwdStack = ForwardIrp->GetNextIrpStackLocation(); + + RtlCopyMemory(&pCurStack->Parameters.QueryInterface, + &pFwdStack->Parameters.QueryInterface, + sizeof(pCurStack->Parameters.QueryInterface)); +} + +VOID +FxPkgPnp::RevokeDmaEnablerResources( + __in FxDmaEnabler *DmaEnabler + ) +{ + DmaEnabler->RevokeResources(); +} + +VOID +FxPkgPnp::QueryForD3ColdInterface( + VOID + ) +{ + MxDeviceObject deviceObject; + PDEVICE_OBJECT topOfStack; + PDEVICE_OBJECT pdo; + FxAutoIrp irp; + NTSTATUS status; + + // + // This function can be invoked multiple times, particularly if filters + // send IRP_MN_QUERY_CAPABILITIES. So bail out if the interface has already + // been acquired. + // + + if ((m_D3ColdInterface.InterfaceDereference != NULL) || + (m_D3ColdInterface.GetIdleWakeInfo != NULL) || + (m_D3ColdInterface.SetD3ColdSupport != NULL)) { + return; + } + + pdo = m_Device->GetPhysicalDevice(); + + if (pdo == NULL) { + return; + } + + // + // Get the top of stack device object, even though normal filters and the + // FDO may not have been added to the stack yet to ensure that this + // query-interface is seen by bus filters. Specifically, in a PCI device + // which is soldered to the motherboard, ACPI will be on the stack and it + // needs to see this IRP. + // + topOfStack = IoGetAttachedDeviceReference(pdo); + deviceObject.SetObject(topOfStack); + if (deviceObject.GetObject() != NULL) { + irp.SetIrp(FxIrp::AllocateIrp(deviceObject.GetStackSize())); + if (irp.GetIrp() == NULL) { + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to allocate IRP to get D3COLD_SUPPORT_INTERFACE from !devobj %p", + pdo); + } else { + + // + // Initialize the Irp + // + irp.SetStatus(STATUS_NOT_SUPPORTED); + + irp.ClearNextStack(); + irp.SetMajorFunction(IRP_MJ_PNP); + irp.SetMinorFunction(IRP_MN_QUERY_INTERFACE); + irp.SetParameterQueryInterfaceType(&GUID_D3COLD_SUPPORT_INTERFACE); + irp.SetParameterQueryInterfaceVersion(D3COLD_SUPPORT_INTERFACE_VERSION); + irp.SetParameterQueryInterfaceSize(sizeof(m_D3ColdInterface)); + irp.SetParameterQueryInterfaceInterfaceSpecificData(NULL); + irp.SetParameterQueryInterfaceInterface((PINTERFACE)&m_D3ColdInterface); + + status = irp.SendIrpSynchronously(deviceObject.GetObject()); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "!devobj %p declined to supply D3COLD_SUPPORT_INTERFACE", + pdo); + + RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface)); + } + } + } + ObDereferenceObject(topOfStack); +} + +VOID +FxPkgPnp::DropD3ColdInterface( + VOID + ) +{ + if (m_D3ColdInterface.InterfaceDereference != NULL) { + m_D3ColdInterface.InterfaceDereference(m_D3ColdInterface.Context); + } + + RtlZeroMemory(&m_D3ColdInterface, sizeof(m_D3ColdInterface)); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/interruptobjectkm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/interruptobjectkm.cpp new file mode 100644 index 00000000000..f93fc0de701 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/interruptobjectkm.cpp @@ -0,0 +1,569 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + InterruptObject.cpp + +Abstract: + + This module implements a frameworks managed interrupt object + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + + + + + + +--*/ + +#include "pnppriv.hpp" + +// Tracing support +#include "InterruptObjectKm.tmh" + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::InitializeInternal( + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ) +{ + UNREFERENCED_PARAMETER(Parent); + UNREFERENCED_PARAMETER(Configuration); + + DO_NOTHING(); + + return STATUS_SUCCESS; +} + +VOID +FxInterrupt::DpcHandler( + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) +{ + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + ASSERT(m_EvtInterruptDpc != NULL); + + FX_TRACK_DRIVER(GetDriverGlobals()); + + // + // Call the drivers registered DpcForIsr event callback + // + if (m_CallbackLock != NULL) { + KIRQL irql = 0; + + m_CallbackLock->Lock(&irql); + m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle()); + m_CallbackLock->Unlock(irql); + } + else { + m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle()); + } + + return; +} + +BOOLEAN +FxInterrupt::QueueDpcForIsr( + VOID + ) +{ + BOOLEAN queued; + + // + // Using this function is optional, + // but the caller better have registered a handler + // + ASSERT(m_EvtInterruptDpc != NULL); + + queued = KeInsertQueueDpc(&m_Dpc, this, NULL); + + return queued; +} + +VOID +FxInterrupt::WorkItemHandler( + VOID + ) +{ + ASSERT(m_EvtInterruptWorkItem != NULL ); + + FX_TRACK_DRIVER(GetDriverGlobals()); + + // + // Call the drivers registered WorkItemForIsr event callback + // + if (m_CallbackLock != NULL) { + KIRQL irql = 0; + + m_CallbackLock->Lock(&irql); + + FxPerfTraceWorkItem(&m_EvtInterruptWorkItem); + m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle()); + m_CallbackLock->Unlock(irql); + } + else { + FxPerfTraceWorkItem(&m_EvtInterruptWorkItem); + m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle()); + } + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::ConnectInternal( + VOID + ) +{ + IO_CONNECT_INTERRUPT_PARAMETERS connectParams; + FxPkgPnp* fxPkgPnp; + + fxPkgPnp = m_Device->m_PkgPnp; + + // + // Tell the PnP Manager to connect the interrupt. + // + ASSERT(fxPkgPnp->m_IoConnectInterruptEx != NULL); + + // + // We're running on Longhorn or later (or somebody backported the new + // interrupt code,) so tell the PnP manager everything we can about this + // device. + // + RtlZeroMemory(&connectParams, sizeof(connectParams)); + + if (FxIsProcessorGroupSupported()) { + connectParams.Version = CONNECT_FULLY_SPECIFIED_GROUP; + } + else { + connectParams.Version = CONNECT_FULLY_SPECIFIED; + } + + connectParams.FullySpecified.PhysicalDeviceObject = m_Device->GetPhysicalDevice(); + connectParams.FullySpecified.InterruptObject = &m_Interrupt; + connectParams.FullySpecified.ServiceRoutine = _InterruptThunk; + connectParams.FullySpecified.ServiceContext = this; + connectParams.FullySpecified.SpinLock = m_SpinLock; + connectParams.FullySpecified.FloatingSave = m_FloatingSave; + connectParams.FullySpecified.Vector = m_InterruptInfo.Vector; + connectParams.FullySpecified.Irql = m_InterruptInfo.Irql; + connectParams.FullySpecified.ProcessorEnableMask = m_InterruptInfo.TargetProcessorSet; + connectParams.FullySpecified.Group = m_InterruptInfo.Group; + connectParams.FullySpecified.InterruptMode = m_InterruptInfo.Mode; + connectParams.FullySpecified.ShareVector = + m_InterruptInfo.ShareDisposition == CmResourceShareShared ? TRUE : FALSE; + connectParams.FullySpecified.SynchronizeIrql = m_SynchronizeIrql; + + return fxPkgPnp->m_IoConnectInterruptEx(&connectParams); +} + +VOID +FxInterrupt::DisconnectInternal( + VOID + ) +{ + IO_DISCONNECT_INTERRUPT_PARAMETERS params; + PKINTERRUPT interruptObject; + FxPkgPnp* fxPkgPnp; + + fxPkgPnp = m_Device->m_PkgPnp; + + // + // Now null these pointers so that we can catch anyone trying to use them + // erroneously. + // + interruptObject = m_Interrupt; + m_Interrupt = NULL; + + // + // Disconnect the interrupt. + // + ASSERT(fxPkgPnp->m_IoDisconnectInterruptEx != NULL); + + RtlZeroMemory(¶ms, sizeof(params)); + + if (FxIsProcessorGroupSupported()) { + params.Version = CONNECT_FULLY_SPECIFIED_GROUP; + } + else { + params.Version = CONNECT_FULLY_SPECIFIED; + } + + params.ConnectionContext.InterruptObject = interruptObject; + + fxPkgPnp->m_IoDisconnectInterruptEx(¶ms); + + return; +} + +VOID +FxInterrupt::FilterResourceRequirements( + __inout PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor + ) +/*++ + +Routine Description: + + This function allows an interrupt object to change the + IoResourceRequirementsList that the PnP Manager sends during + IRP_MN_FILTER_RESOURCE_REQUIREMENTS. This function takes a single + IoResourceDescriptor and applies default or user specified policy. + +Arguments: + + IoResourceDescriptor - Pointer to descriptor that matches this interrupt object + +Return Value: + + VOID + +--*/ +{ + // + // Set sharing policy. + // + switch (m_ShareVector) { + case WdfTrue: + // + // Override the bus driver's value, explicitly sharing this interrupt. + // + IoResourceDescriptor->ShareDisposition = CmResourceShareShared; + break; + + case WdfFalse: + // + // Override the bus driver's value, explicitly claiming this interrupt + // as non-shared. + // + IoResourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive; + break; + + case WdfUseDefault: + default: + // + // Leave the bus driver's value alone. + // + break; + } + + // + // Apply policy. Only do this if we are running on an OS which supports + // the notion of Interrupt Policy and if the policy is not already included + // by the bus driver based on registry settings. + // + if (FxLibraryGlobals.IoConnectInterruptEx != NULL && + m_SetPolicy && + (IoResourceDescriptor->Flags & CM_RESOURCE_INTERRUPT_POLICY_INCLUDED) == 0x0) { + + IoResourceDescriptor->Flags |= CM_RESOURCE_INTERRUPT_POLICY_INCLUDED; + IoResourceDescriptor->u.Interrupt.AffinityPolicy = (IRQ_DEVICE_POLICY)m_Policy; + IoResourceDescriptor->u.Interrupt.PriorityPolicy = (IRQ_PRIORITY)m_Priority; + IoResourceDescriptor->u.Interrupt.TargetedProcessors = m_Processors.Mask; + IoResourceDescriptor->u.Interrupt.Group = m_Processors.Group; + } +} + +VOID +FxInterrupt::FlushQueuedDpcs( + VOID + ) +{ + KeFlushQueuedDpcs(); +} + +BOOLEAN +FxInterrupt::_InterruptThunk( + __in struct _KINTERRUPT *Interrupt, + __in PVOID ServiceContext + ) + +/*++ + +Routine Description: + + This is the C routine called by the kernels INTERRUPT handler + +Arguments: + +Return Value: + +--*/ + +{ + FxInterrupt* interrupt; + BOOLEAN result; + + UNREFERENCED_PARAMETER(Interrupt); + + interrupt = (FxInterrupt*)ServiceContext; + ASSERT( interrupt->m_EvtInterruptIsr != NULL ); + + if (interrupt->m_IsEdgeTriggeredNonMsiInterrupt == TRUE) { + // + // If KMDF is in the process of disconnecting this interrupt, discard it. + // + if (interrupt->m_Disconnecting == TRUE) { + return FALSE; + } + + // + // Captures the interrupt object as a backup in case interrupts start + // to arrive before IoConnectInterruptEx sets FxInterrupt.m_Interrupt. + // + interrupt->m_InterruptCaptured = Interrupt; + } + // + // If the interrupt is not connected, treat this as spurious interrupt. + // + else if (NULL == interrupt->m_Interrupt) { + return FALSE; + } + + if (interrupt->IsWakeCapable()) { + // + // if it is a wake capable interrupt, we will hand it off + // to the state machine so that it can power up the device + // if required and then invoke the ISR callback + // + ASSERT(interrupt->m_PassiveHandling); + FxPerfTracePassiveInterrupt(&interrupt->m_EvtInterruptIsr); + return interrupt->WakeInterruptIsr(); + } + + if (interrupt->m_PassiveHandling) { + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); + + // + // Acquire our internal passive-lock after the kernel acquired its own + // passive-lock and before invoking the callback. + // + interrupt->AcquireLock(); + + FxPerfTracePassiveInterrupt(&interrupt->m_EvtInterruptIsr); + + result = interrupt->m_EvtInterruptIsr( + interrupt->GetHandle(), + interrupt->m_InterruptInfo.MessageNumber); + interrupt->ReleaseLock(); + } + else { + + FxPerfTraceInterrupt(&interrupt->m_EvtInterruptIsr); + + result = interrupt->m_EvtInterruptIsr( + interrupt->GetHandle(), + interrupt->m_InterruptInfo.MessageNumber); + } + + return result; +} + +VOID +FxInterrupt::_InterruptDpcThunk( + __in PKDPC Dpc, + __in_opt PVOID DeferredContext, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) +/*++ + +Routine Description: + + Thunk used to invoke EvtInterruptDpc at DPC-level, or to queue a work-item + for invoking EvtInterruptWorkItem at passive-level. + +--*/ +{ + FxInterrupt* interrupt; + + UNREFERENCED_PARAMETER(Dpc); + + ASSERT(DeferredContext != NULL); + interrupt = (FxInterrupt*) DeferredContext; + + if (interrupt->m_SystemWorkItem == NULL) { + + FxPerfTraceDpc(&interrupt->m_EvtInterruptDpc); + + interrupt->DpcHandler(SystemArgument1, SystemArgument2); + } + else { + interrupt->m_SystemWorkItem->TryToEnqueue(_InterruptWorkItemCallback, + interrupt); + } +} + +VOID +FxInterrupt::FlushAndRundownInternal( + VOID + ) +{ + // + // Rundown the workitem. + // + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->DeleteObject(); + m_SystemWorkItem = NULL; + } + + // + // If present, delete the default passive-lock. + // + if (m_DisposeWaitLock) { + ASSERT(m_WaitLock != NULL); + m_WaitLock->DeleteObject(); + m_WaitLock = NULL; + m_DisposeWaitLock = FALSE; + } +} + +BOOLEAN +FxInterrupt::_InterruptMarkDisconnecting( + _In_opt_ PVOID SyncContext + ) +{ + FxInterrupt* pFxInterrupt; + + ASSERT(SyncContext != NULL); + pFxInterrupt = (FxInterrupt*)SyncContext; + + // + // This callback is invoked only if m_IsEdgeTriggeredNonMsiInterrupt + // is TRUE. This will cause _InterruptThunk to discard subsequent + // interrupts until m_Disconnecting is reset to FALSE. + // + pFxInterrupt->m_Disconnecting = TRUE; + + return TRUE; +} + +VOID +FxInterrupt::ReportActive( + _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 active even though" + " it is not connected.", GetHandle()); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return; + } + + if (fxPkgPnp->m_IoReportInterruptActive == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Driver is calling DDI WdfInterruptReportActive() on an OS that " + "doesn't support the DDI."); + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return; + } + } + + // + // No need to report active if interrupt is already active + // + if (m_Active) { + return; + } + + RtlZeroMemory(¶meters, sizeof(parameters)); + + if (FxIsProcessorGroupSupported()) { + parameters.Version = CONNECT_FULLY_SPECIFIED_GROUP; + } + else { + parameters.Version = CONNECT_FULLY_SPECIFIED; + } + + parameters.ConnectionContext.InterruptObject = m_Interrupt; + + fxPkgPnp->m_IoReportInterruptActive(¶meters); + m_Active = TRUE; + + return; +} + +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(¶meters, sizeof(parameters)); + + if (FxIsProcessorGroupSupported()) { + parameters.Version = CONNECT_FULLY_SPECIFIED_GROUP; + } + else { + parameters.Version = CONNECT_FULLY_SPECIFIED; + } + + parameters.ConnectionContext.InterruptObject = m_Interrupt; + + fxPkgPnp->m_IoReportInterruptInactive(¶meters); + m_Active = FALSE; + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/pnpprivkm.hpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/pnpprivkm.hpp new file mode 100644 index 00000000000..a545b6f0057 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/pnpprivkm.hpp @@ -0,0 +1,87 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _PNPPRIVKM_H_ +#define _PNPPRIVKM_H_ + +// public headers +#include "WdfDmaEnabler.h" + +// private headers +#include "FxIrpQueue.hpp" +#include "FxCallback.hpp" + +// +__drv_functionClass(EVT_SYSTEMWORKITEM) +__drv_maxIRQL(PASSIVE_LEVEL) +__drv_maxFunctionIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +typedef +VOID +EVT_SYSTEMWORKITEM( + __in PVOID Parameter + ); + +typedef EVT_SYSTEMWORKITEM *PFN_WDF_SYSTEMWORKITEM; + +// + +#include "FxCallbackSpinlock.hpp" +#include "FxCallbackMutexLock.hpp" +#include "FxPackage.hpp" +#include "IfxMemory.hpp" +#include "FxCallback.hpp" +#include "FxRequestContext.hpp" +#include "FxRequestContextTypes.h" +#include "FxRequestBase.hpp" +#include "FxRequest.hpp" +#include "FxPkgPnp.hpp" +#include "FxPkgIo.hpp" +#include "FxIoQueue.hpp" + +#include "FxDmaEnabler.hpp" +#include "FxSystemWorkItem.hpp" + +#include "FxDsf.h" // DSF support. +#include +#include "FxTelemetry.hpp" + +_Must_inspect_result_ +NTSTATUS +SendDeviceUsageNotificationWorker( + __in MxDeviceObject* RelatedDevice, + __inout FxIrp* RelatedIrp, + __in FxIrp* OriginalIrp, + __in BOOLEAN Revert + ); + +IO_WORKITEM_ROUTINE +_DeviceUsageNotificationWorkItem; + +struct FxUsageWorkitemParameters { + + FxUsageWorkitemParameters( + VOID + ) + { + RelatedDevice = NULL; + RelatedIrp = NULL; + OriginalIrp = NULL; + Status = STATUS_UNSUCCESSFUL; + } + + _In_ MxDeviceObject* RelatedDevice; + + _In_ FxIrp* RelatedIrp; + + _In_ FxIrp* OriginalIrp; + + _In_ BOOLEAN Revert; + + _In_ FxCREvent Event; + + _Out_ NTSTATUS Status; +}; + + +#endif // _PNPPRIVKM_H_ diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/pnpstatemachinekm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/pnpstatemachinekm.cpp new file mode 100644 index 00000000000..4bab9c8f620 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/pnpstatemachinekm.cpp @@ -0,0 +1,238 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PnpStateMachine.cpp + +Abstract: + + This module implements the PnP state machine for the driver framework. + This code was split out from FxPkgPnp.cpp. + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" +#include + +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "PnpStateMachineKM.tmh" +#endif +} + +BOOLEAN +FxPkgPnp::PnpCheckAndIncrementRestartCount( + VOID + ) +/*++ + +Routine Description: + This is a mode-dependent wrapper for PnpIncrementRestartCountLogic, + which determines if this device should ask the bus driver to + reenumerate the device. Please refer to PnpIncrementRestartCountLogic's + comment block for more information. + +Arguments: + None + +Return Value: + TRUE if a restart should be requested. + +--*/ +{ + NTSTATUS status; + FxAutoRegKey settings, restart; + ULONG disposition = 0; + + DECLARE_CONST_UNICODE_STRING(keyNameRestart, L"Restart"); + + status = m_Device->OpenSettingsKey(&settings.m_Key); + if (!NT_SUCCESS(status)) { + return FALSE; + } + + // + // We ask for a volatile key so that upon reboot, the count is purged and we + // start a new fresh restart count. + // + status = FxRegKey::_Create(settings.m_Key, + &keyNameRestart, + &restart.m_Key, + KEY_ALL_ACCESS, + REG_OPTION_VOLATILE, + &disposition); + if (!NT_SUCCESS(status)) { + return FALSE; + } + + return PnpIncrementRestartCountLogic(restart.m_Key, + disposition == REG_CREATED_NEW_KEY); +} + +BOOLEAN +FxPkgPnp::ShouldProcessPnpEventOnDifferentThread( + __in KIRQL CurrentIrql, + __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread + ) +/*++ +Routine Description: + + This function returns whether the PnP state machine should process the + current event on the same thread or on a different one. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Arguemnts: + + CurrentIrql - The current IRQL + + CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of + PnpProcessEvent specified that the event be processed on a different + thread. + +Returns: + TRUE if the PnP state machine should process the event on a different + thread. + + FALSE if the PnP state machine should process the event on the same thread + +--*/ +{ + // + // For KMDF, we ignore what the caller of PnpProcessEvent specified (which + // should always be FALSE, BTW) and base our decision on the current IRQL. + // If we are running at PASSIVE_LEVEL, we process on the same thread else + // we queue a work item. + // + UNREFERENCED_PARAMETER(CallerSpecifiedProcessingOnDifferentThread); + + ASSERT(FALSE == CallerSpecifiedProcessingOnDifferentThread); + + return (CurrentIrql == PASSIVE_LEVEL) ? FALSE : TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::CreatePowerThreadIfNeeded( + VOID + ) +/*++ +Routine description: + If needed, creates a thread for processing power IRPs + +Arguments: + None + +Return value: + An NTSTATUS code indicating success or failure of this function +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + MxDeviceObject pTopOfStack; + + + + + + + + + + + + + pTopOfStack.SetObject( + m_Device->GetAttachedDeviceReference()); + + ASSERT(pTopOfStack.GetObject() != NULL); + + if (pTopOfStack.GetObject() != NULL) { + // + // If the top of the stack is not power pageable, the stack needs a power + // thread. Query for it if we are not a PDO (and create it if the lower + // stack does not support it), and create it if we are a PDO. + // + // Some stacks send a usage notification when processing a start device, so + // a notification could have already traveled through the stack by the time + // the start irp has completed back up to this device. + // + if ((pTopOfStack.GetFlags() & DO_POWER_PAGABLE) == 0 && + HasPowerThread() == FALSE) { + status = QueryForPowerThread(); + + if (!NT_SUCCESS(status)) { + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + } + } + + pTopOfStack.DereferenceObject(); + pTopOfStack.SetObject(NULL); + } + + return status; +} + +NTSTATUS +FxPkgPnp::PnpPrepareHardwareInternal( + VOID + ) +/*++ +Routine description: + This is mode-specific routine for Prepare hardware + +Arguments: + None + +Return value: + none. +--*/ +{ + // + // nothing to do for KMDF. + // + return STATUS_SUCCESS; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/powerpolicystatemachinekm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/powerpolicystatemachinekm.cpp new file mode 100644 index 00000000000..a1aa32c43e4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/powerpolicystatemachinekm.cpp @@ -0,0 +1,245 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerPolicyStateMachineKM.cpp + +Abstract: + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" + +#if FX_IS_KERNEL_MODE +#include +#endif + +#include "FxUsbIdleInfo.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerPolicyStateMachineKM.tmh" +#endif +} + +VOID +FxPkgPnp::PowerPolicyUpdateSystemWakeSource( + __in FxIrp* Irp + ) +/*++ + +Routine Description: + Gets source of wake if OS supports this. + +Arguments: + Irp + +Return Value: + None + + --*/ +{ + // + // Check to see if this device caused the machine to wake up + // + m_PowerPolicyMachine.m_Owner->m_SystemWakeSource = + PoGetSystemWake(Irp->GetIrp()); + + if (m_PowerPolicyMachine.m_Owner->m_SystemWakeSource) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p WW !irp 0x%p is a source of " + "wake", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + Irp->GetIrp()); + } +} + +BOOLEAN +FxPkgPnp::ShouldProcessPowerPolicyEventOnDifferentThread( + __in KIRQL CurrentIrql, + __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread + ) +/*++ +Routine Description: + + This function returns whether the power policy state machine should process + the current event on the same thread or on a different one. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Arguemnts: + + CurrentIrql - The current IRQL + + CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of + PowerPolicyProcessEvent specified that the event be processed on a + different thread. + +Returns: + TRUE if the power policy state machine should process the event on a + different thread. + + FALSE if the power policy state machine should process the event on the + same thread + +--*/ +{ + // + // For KMDF, we ignore what the caller of PowerPolicyProcessEvent specified + // (which should always be FALSE, BTW) and base our decision on the current + // IRQL. If we are running at PASSIVE_LEVEL, we process on the same thread + // else we queue a work item. + // + UNREFERENCED_PARAMETER(CallerSpecifiedProcessingOnDifferentThread); + + ASSERT(FALSE == CallerSpecifiedProcessingOnDifferentThread); + + return (CurrentIrql == PASSIVE_LEVEL) ? FALSE : TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbIdleInfo::Initialize( + VOID + ) +{ + MdIrp pIrp; + MxDeviceObject attachedDevObj; + + attachedDevObj.SetObject(((FxPkgPnp*)m_CallbackInfo.IdleContext)->GetDevice()->GetAttachedDevice()); + + pIrp = FxIrp::AllocateIrp(attachedDevObj.GetStackSize()); + + if (pIrp == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + m_IdleIrp.SetIrp(pIrp); + + return STATUS_SUCCESS; +} + +VOID +FxPkgPnp::PowerPolicySubmitUsbIdleNotification( + VOID + ) +{ + FxIrp* usbIdleIrp; + + // + // This will be set to TRUE if USBSS completion event gets dropped. + // + m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped = FALSE; + + usbIdleIrp = &m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_IdleIrp; + + usbIdleIrp->Reuse(); + + usbIdleIrp->SetCompletionRoutineEx( + m_Device->GetDeviceObject(), + _PowerPolicyUsbSelectiveSuspendCompletionRoutine, + this); + + usbIdleIrp->SetMajorFunction(IRP_MJ_INTERNAL_DEVICE_CONTROL); + usbIdleIrp->SetParameterIoctlCode( + IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION); + usbIdleIrp->SetParameterIoctlInputBufferLength( + sizeof(m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_CallbackInfo)); + usbIdleIrp->SetParameterIoctlType3InputBuffer( + (PVOID) &m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_CallbackInfo); + + m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_IdleIrp.CallDriver( + m_Device->GetAttachedDevice() + ); +} + +VOID +FxPkgPnp::PowerPolicyCancelUsbSS( + VOID + ) +{ + m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_IdleIrp.Cancel(); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +FxUsbIdleInfo::_UsbIdleCallback( + __in PVOID Context + ) +{ + FxPkgPnp* pPkgPnp; + FxUsbIdleInfo* pThis; + FxCREvent event; + + pPkgPnp = (FxPkgPnp*) Context; + + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering USB Selective Suspend Idle callback"); + + pThis = pPkgPnp->m_PowerPolicyMachine.m_Owner->m_UsbIdle; + + ASSERT(pThis->m_IdleCallbackEvent == NULL); + pThis->m_IdleCallbackEvent = event.GetSelfPointer(); + + pPkgPnp->PowerPolicyProcessEvent(PwrPolUsbSelectiveSuspendCallback); + + event.EnterCRAndWaitAndLeave(); + pThis->m_IdleCallbackEvent = NULL; + + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Leaving USB Selective Suspend Idle callback"); +} + + +VOID +FxPowerPolicyMachine::UsbSSCallbackProcessingComplete( + VOID + ) +{ + ASSERT(m_Owner->m_UsbIdle->m_IdleCallbackEvent != NULL); + m_Owner->m_UsbIdle->m_IdleCallbackEvent->Set(); +} + + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/powerstatemachinekm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/powerstatemachinekm.cpp new file mode 100644 index 00000000000..9c340c367e6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/powerstatemachinekm.cpp @@ -0,0 +1,151 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerStateMachineKm.cpp + +Abstract: + + This module implements the Power state machine for the driver framework. + This code was split out from FxPkgPnp.cpp. + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerStateMachineKm.tmh" +#endif +} + +_Must_inspect_result_ +BOOLEAN +FxPkgPnp::PowerDmaPowerUp( + VOID + ) +/*++ + +Routine Description: + Calls FxDmaEnabler::PowerUp on all registered FxDmaEnabler objects. As soon + as a PowerUp call fails, we stop iterating over the list. + +Arguments: + None + +Return Value: + TRUE if PowerUp succeeded on all enablers, FALSE otherwise + + --*/ + +{ + FxTransactionedEntry* ple; + NTSTATUS status; + BOOLEAN result; + + result = TRUE; + + // + // Power up each dma enabler + // + if (m_DmaEnablerList != NULL) { + m_DmaEnablerList->LockForEnum(GetDriverGlobals()); + + ple = NULL; + while ((ple = m_DmaEnablerList->GetNextEntry(ple)) != NULL) { + status = ((FxDmaEnabler*) ple->GetTransactionedObject())->PowerUp(); + + if (!NT_SUCCESS(status)) { + result = FALSE; + break; + } + } + + m_DmaEnablerList->UnlockFromEnum(GetDriverGlobals()); + } + + return result; +} + +BOOLEAN +FxPkgPnp::PowerDmaPowerDown( + VOID + ) +/*++ + +Routine Description: + Calls FxDmaEnabler::PowerDown on all registered FxDmaEnabler objects. All + errors are accumulated, all enablers will be PowerDown'ed. + +Arguments: + None + +Return Value: + TRUE if PowerDown succeeded on all enablers, FALSE otherwise + + --*/ +{ + FxTransactionedEntry* ple; + NTSTATUS status; + BOOLEAN result; + + result = TRUE; + + // + // Power up each dma enabler + // + if (m_DmaEnablerList != NULL) { + m_DmaEnablerList->LockForEnum(GetDriverGlobals()); + + ple = NULL; + while ((ple = m_DmaEnablerList->GetNextEntry(ple)) != NULL) { + status = ((FxDmaEnabler*) ple->GetTransactionedObject())->PowerDown(); + + if (!NT_SUCCESS(status)) { + // + // We do not break out of the loop on power down failure. We will + // continue to power down each channel regardless of the previous + // channel's power down status. + // + result = FALSE; + } + } + + m_DmaEnablerList->UnlockFromEnum(GetDriverGlobals()); + } + + return result; +} + +VOID +FxPkgPnp::_PowerSetSystemWakeSource( + __in FxIrp* Irp + ) +/*++ + +Routine Description: + Set source of wake if OS supports this. + +Arguments: + Irp + +Return Value: + None + + --*/ +{ + PoSetSystemWake(Irp->GetIrp()); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/poxinterfacekm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/poxinterfacekm.cpp new file mode 100644 index 00000000000..ace8053eeb9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/poxinterfacekm.cpp @@ -0,0 +1,460 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "pnppriv.hpp" + +#include +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "PoxInterfaceKm.tmh" +#endif +} + +VOID +FxPoxInterface::StateCallback( + __in PVOID Context, + __in ULONG Component, + __in ULONG State + ) +{ + PPOX_SETTINGS poxSettings = NULL; + FxPoxInterface * pThis = NULL; + + pThis = (FxPoxInterface*) Context; + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p PO_FX_COMPONENT_IDLE_STATE_CALLBACK " + "invoked.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = pThis->GetPowerFrameworkSettings(); + + // + // If the client driver has specified an F-state change callback, invoke it. + // + if ((NULL != poxSettings) && + (NULL != poxSettings->ComponentIdleStateCallback)) { + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p Invoking client driver's " + "PO_FX_COMPONENT_IDLE_STATE_CALLBACK.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + poxSettings->ComponentIdleStateCallback( + poxSettings->PoFxDeviceContext, + Component, + State); + } else { + PoFxCompleteIdleState(pThis->m_PoHandle, Component); + } +} + +VOID +FxPoxInterface::ComponentActiveCallback( + __in PVOID Context, + __in ULONG Component + ) +{ + PPOX_SETTINGS poxSettings = NULL; + FxPoxInterface * pThis = NULL; + + pThis = (FxPoxInterface*) Context; + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK " + "invoked.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = pThis->GetPowerFrameworkSettings(); + + // + // If the client driver has specified a component-active callback, invoke it + // + if ((NULL != poxSettings) && + (NULL != poxSettings->ComponentActiveConditionCallback)) { + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p Invoking client driver's " + "PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + poxSettings->ComponentActiveConditionCallback( + poxSettings->PoFxDeviceContext, + Component + ); + } else { + // + // Nothing to do. + // + DO_NOTHING(); + } + + return; +} + +VOID +FxPoxInterface::ComponentIdleCallback( + __in PVOID Context, + __in ULONG Component + ) +{ + PPOX_SETTINGS poxSettings = NULL; + FxPoxInterface * pThis = NULL; + + pThis = (FxPoxInterface*) Context; + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK " + "invoked.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = pThis->GetPowerFrameworkSettings(); + + // + // If the client driver has specified a component-idle callback, invoke it + // + if ((NULL != poxSettings) && + (NULL != poxSettings->ComponentIdleConditionCallback)) { + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p Invoking client driver's " + "PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + poxSettings->ComponentIdleConditionCallback( + poxSettings->PoFxDeviceContext, + Component + ); + } else { + // + // We're being notified that we're idle, but there is no action that we + // need to take here. We power down the device only when we get the + // device-power-not-required event. + // + PoFxCompleteIdleCondition(pThis->m_PoHandle, Component); + } + return; +} + +VOID +FxPoxInterface::PowerRequiredCallback( + __in PVOID Context + ) +{ + FxPoxInterface * pThis = NULL; + + pThis = (FxPoxInterface*) Context; + pThis->PowerRequiredCallbackWorker(TRUE /* InvokedFromPoxCallback */); + return; +} + +VOID +FxPoxInterface::PowerNotRequiredCallback( + __in PVOID Context + ) +{ + FxPoxInterface * pThis = NULL; + + pThis = (FxPoxInterface*) Context; + pThis->PowerNotRequiredCallbackWorker(TRUE /* InvokedFromPoxCallback */); + PoFxCompleteDevicePowerNotRequired(pThis->m_PoHandle); + return; +} + +_Function_class_(PO_FX_POWER_CONTROL_CALLBACK) +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +FxPoxInterface::PowerControlCallback( + _In_ PVOID Context, + _In_ LPCGUID PowerControlCode, + _In_reads_bytes_opt_(InBufferSize) PVOID InBuffer, + _In_ SIZE_T InBufferSize, + _Out_writes_bytes_opt_(OutBufferSize) PVOID OutBuffer, + _In_ SIZE_T OutBufferSize, + _Out_opt_ PSIZE_T BytesReturned + ) +{ + NTSTATUS status; + PPOX_SETTINGS poxSettings = NULL; + FxPoxInterface * pThis = NULL; + + pThis = (FxPoxInterface*) Context; + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p PO_FX_POWER_CONTROL_CALLBACK invoked.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject() + ); + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = pThis->GetPowerFrameworkSettings(); + + // + // The client driver must have specified a power control callback + // + ASSERT((NULL != poxSettings) && + (NULL != poxSettings->PowerControlCallback)); + + // + // Invoke the client driver's power control callback + // + status = poxSettings->PowerControlCallback(poxSettings->PoFxDeviceContext, + PowerControlCode, + InBuffer, + InBufferSize, + OutBuffer, + OutBufferSize, + BytesReturned); + + DoTraceLevelMessage( + pThis->m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p Client driver's " + "PO_FX_POWER_CONTROL_CALLBACK returned %!STATUS!.", + pThis->m_PkgPnp->GetDevice()->GetHandle(), + pThis->m_PkgPnp->GetDevice()->GetDeviceObject(), + status + ); + + return status; +} + +NTSTATUS +FxPoxInterface::PoxRegisterDevice( + VOID + ) +{ + + NTSTATUS status; + PO_FX_DEVICE poxDevice; + PO_FX_COMPONENT_IDLE_STATE idleState; + PPOX_SETTINGS poxSettings = NULL; + + RtlZeroMemory(&poxDevice, sizeof(poxDevice)); + RtlZeroMemory(&idleState, sizeof(idleState)); + + poxDevice.Version = PO_FX_VERSION_V1; + + // + // Specify callbacks and context + // + poxDevice.ComponentIdleStateCallback = + FxPoxInterface::StateCallback; + poxDevice.ComponentActiveConditionCallback = + FxPoxInterface::ComponentActiveCallback; + poxDevice.ComponentIdleConditionCallback = + FxPoxInterface::ComponentIdleCallback; + poxDevice.DevicePowerRequiredCallback = + FxPoxInterface::PowerRequiredCallback; + poxDevice.DevicePowerNotRequiredCallback = + FxPoxInterface::PowerNotRequiredCallback; + poxDevice.DeviceContext = this; + + // + // We register as a single component device + // + poxDevice.ComponentCount = 1; + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = GetPowerFrameworkSettings(); + + // + // We specify a power control callback only if the client driver supplies us + // a power control callback + // + poxDevice.PowerControlCallback = + ((NULL == poxSettings) || (NULL == poxSettings->PowerControlCallback)) ? + NULL : + FxPoxInterface::PowerControlCallback; + + // + // If the client driver has specified any settings for component 0, use + // them. Otherwise use the default settings. + // + if ((NULL == poxSettings) || (NULL == poxSettings->Component)) { + // + // Default settings + // + + // + // We only support F0 + // + poxDevice.Components[0].IdleStateCount = 1; + + // + // Transition latency should be 0 for F0 + // + idleState.TransitionLatency = 0; + + // + // Residency requirement should be 0 for F0 + // + idleState.ResidencyRequirement = 0; + + // + // The value doesn't matter because we do not support multiple F-states. + // + idleState.NominalPower = PO_FX_UNKNOWN_POWER; + + // + // Specify the state information for F0 + // + poxDevice.Components[0].IdleStates = &idleState; + } + else { + // + // Client driver's settings + // + RtlCopyMemory(&(poxDevice.Components[0]), + poxSettings->Component, + sizeof(poxDevice.Components[0])); + } + + // + // Register with the power framework + // + status = PoFxRegisterDevice( + m_PkgPnp->GetDevice()->GetPhysicalDevice(), + &poxDevice, + &(m_PoHandle) + ); + if (FALSE == NT_SUCCESS(status)) { + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p FxPox::PoxRegisterDevice failed. " + "%!STATUS!.", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + status); + goto exit; + } + + status = STATUS_SUCCESS; + +exit: + return status; + +} + +VOID +FxPoxInterface::PoxStartDevicePowerManagement( + VOID + ) +{ + PoFxStartDevicePowerManagement(m_PoHandle); +} + + +VOID +FxPoxInterface::PoxUnregisterDevice( + VOID + ) +{ + PoFxUnregisterDevice(m_PoHandle); +} + + +VOID +FxPoxInterface::PoxActivateComponent( + VOID + ) +{ + // + // We only support single component and don't + // need to set any flags + // + PoFxActivateComponent(m_PoHandle, + 0, //component + 0 //flags + ); +} + + +VOID +FxPoxInterface::PoxIdleComponent( + VOID + ) +{ + // + // We only support single component and don't + // need to set any flags + // + PoFxIdleComponent(m_PoHandle, + 0, //component + 0 //flags + ); +} + + +VOID +FxPoxInterface::PoxReportDevicePoweredOn( + VOID + ) +{ + PoFxReportDevicePoweredOn(m_PoHandle); +} + + +VOID +FxPoxInterface::PoxSetDeviceIdleTimeout( + __in ULONGLONG IdleTimeout + ) +{ + PoFxSetDeviceIdleTimeout(m_PoHandle, IdleTimeout); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/supportkm.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/supportkm.cpp new file mode 100644 index 00000000000..797237299e3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/supportkm.cpp @@ -0,0 +1,321 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + supportKM.cpp + +Abstract: + + This module implements the pnp support routines. + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" +#include + +#if defined(EVENT_TRACING) +#include "supportKM.tmh" +#endif + +VOID +CopyQueryInterfaceToIrpStack( + __in PPOWER_THREAD_INTERFACE PowerThreadInterface, + __in FxIrp* Irp + ) +{ + PIO_STACK_LOCATION stack; + + stack = Irp->GetCurrentIrpStackLocation(); + + RtlCopyMemory(stack->Parameters.QueryInterface.Interface, + PowerThreadInterface, + PowerThreadInterface->Interface.Size); +} + +_Must_inspect_result_ +NTSTATUS +GetStackCapabilities( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in MxDeviceObject* DeviceInStack, + __in_opt PD3COLD_SUPPORT_INTERFACE D3ColdInterface, + __out PSTACK_DEVICE_CAPABILITIES Capabilities + ) +{ + ULONG i; + FxAutoIrp irp; + NTSTATUS status; + + ASSERT(Capabilities != NULL); + + status = STATUS_INSUFFICIENT_RESOURCES; + + // + // Normally this would be assigned to a local variable on the stack. Since + // query caps iteratively moves down the device's tree until it hits the + // root. As such, stack usage is consumed quickly. While this is only one + // pointer value we are saving, it does eventually add up on very deep stacks. + // + DeviceInStack->SetObject(DeviceInStack->GetAttachedDeviceReference()); + if (DeviceInStack->GetObject() == NULL) { + goto Done; + } + + irp.SetIrp(FxIrp::AllocateIrp(DeviceInStack->GetStackSize())); + if (irp.GetIrp() == NULL) { + goto Done; + } + + // + // Initialize device capabilities. + // + RtlZeroMemory(Capabilities, sizeof(STACK_DEVICE_CAPABILITIES)); + Capabilities->DeviceCaps.Size = sizeof(DEVICE_CAPABILITIES); + Capabilities->DeviceCaps.Version = 1; + Capabilities->DeviceCaps.Address = (ULONG) -1; + Capabilities->DeviceCaps.UINumber = (ULONG) -1; + + // + // Initialize the Irp. + // + irp.SetStatus(STATUS_NOT_SUPPORTED); + + irp.ClearNextStack(); + irp.SetMajorFunction(IRP_MJ_PNP); + irp.SetMinorFunction(IRP_MN_QUERY_CAPABILITIES); + irp.SetParameterDeviceCapabilities(&Capabilities->DeviceCaps); + + status = irp.SendIrpSynchronously(DeviceInStack->GetObject()); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to get DEVICE_CAPABILITIES from !devobj %p, %!STATUS!", + DeviceInStack->GetObject(), status); + goto Done; + } + + // + // Invoke the D3cold support interface. If present, it will tell + // us specifically which D-states will work for generating wake signals + // from specific S-states. + // + // Earlier versions of WDF didn't make this query, so for compatibility, + // we only make it now if the driver was built against WDF 1.11 or + // later. In truth, this just shifts the failure from initialization + // time to run time, because the information that we're presumably + // getting from the BIOS with this interrogation is saying that the + // code in earlier verisions of WDF would have blindly enabled a device + // for wake which simply wasn't capable of generating its wake signal + // from the chosen D-state. Thus the device would have been put into + // a low power state and then failed to resume in response to its wake + // signal. + // + + for (i = 0; i <= PowerSystemHibernate; i++) { + Capabilities->DeepestWakeableDstate[i] = DeviceWakeDepthMaximum; + } + + if (ARGUMENT_PRESENT(D3ColdInterface) && + (D3ColdInterface->GetIdleWakeInfo != NULL) && + DriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + + DEVICE_WAKE_DEPTH deepestWakeableDstate; + + for (i = PowerSystemWorking; i <= PowerSystemHibernate; i++) { + + // + // Failure from D3ColdInterface->GetIdleWakeInfo just means that + // the bus drivers didn't have any information beyond what can + // gleaned from the older Query-Capabilities code path. + // + // In specific ACPI terms, ACPI will respond to this function with + // success whenever there is an _SxW object (where x is the sleep + // state, a value from 0 to 4.) + // + // PCI will respond to this interface if ACPI doesn't override its + // answer and if a parent bus is capable of leaving D0 in S0, and + // if the PCI device has + status = D3ColdInterface->GetIdleWakeInfo( + D3ColdInterface->Context, + (SYSTEM_POWER_STATE)i, + &deepestWakeableDstate + ); + + if (NT_SUCCESS(status)) { + Capabilities->DeepestWakeableDstate[i] = deepestWakeableDstate; + } + } + } + + status = STATUS_SUCCESS; + +Done: + if (DeviceInStack->GetObject() != NULL) { + DeviceInStack->DereferenceObject(); + } + + return status; +} + +VOID +SetD3ColdSupport( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in MxDeviceObject* DeviceInStack, + __in PD3COLD_SUPPORT_INTERFACE D3ColdInterface, + __in BOOLEAN UseD3Cold + ) +{ + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(DeviceInStack); + + if (D3ColdInterface->SetD3ColdSupport != NULL) { + D3ColdInterface->SetD3ColdSupport(D3ColdInterface->Context, UseD3Cold); + } +} + +_Must_inspect_result_ +PVOID +GetIoMgrObjectForWorkItemAllocation( + VOID + ) +/*++ +Routine description: + Returns an IO manager object that can be passed in to IoAllocateWorkItem + +Arguments: + None + +Return value: + Pointer to the object that can be passed in to IoAllocateWorkItem +--*/ +{ + return (PVOID) FxLibraryGlobals.DriverObject; +} + +BOOLEAN +IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable( + VOID + ) +{ + return (NULL != FxLibraryGlobals.PoxRegisterDevice); +} + +_Must_inspect_result_ +NTSTATUS +SendDeviceUsageNotification( + __in MxDeviceObject* RelatedDevice, + __inout FxIrp* RelatedIrp, + __in MxWorkItem* Workitem, + __in FxIrp* OriginalIrp, + __in BOOLEAN Revert + ) +{ + NTSTATUS status; + + // + // use workitem if available + // + if (Workitem->GetWorkItem() != NULL) { + FxUsageWorkitemParameters param; + + param.RelatedDevice = RelatedDevice; + param.RelatedIrp = RelatedIrp; + param.OriginalIrp = OriginalIrp; + param.Revert = Revert; + + // + // Kick off to another thread + // + Workitem->Enqueue(_DeviceUsageNotificationWorkItem, ¶m); + + // + // wait for the workitem to finish + // + param.Event.EnterCRAndWaitAndLeave(); + + status = param.Status; + } + else { + status = SendDeviceUsageNotificationWorker(RelatedDevice, + RelatedIrp, + OriginalIrp, + Revert); + } + + return status; +} + +NTSTATUS +SendDeviceUsageNotificationWorker( + __in MxDeviceObject* RelatedDevice, + __inout FxIrp* RelatedIrp, + __in FxIrp* OriginalIrp, + __in BOOLEAN Revert + ) +{ + MxDeviceObject relatedTopOfStack; + NTSTATUS status; + + relatedTopOfStack.SetObject(RelatedDevice->GetAttachedDeviceReference()); + ASSERT(relatedTopOfStack.GetObject() != NULL); + + // + // Initialize the new IRP with the stack data from the current IRP and + // and send it to the parent stack. + // + RelatedIrp->InitNextStackUsingStack(OriginalIrp); + + if (Revert) { + RelatedIrp->SetParameterUsageNotificationInPath( + !RelatedIrp->GetNextStackParameterUsageNotificationInPath()); + } + + RelatedIrp->SetStatus(STATUS_NOT_SUPPORTED); + + status = RelatedIrp->SendIrpSynchronously(relatedTopOfStack.GetObject()); + + relatedTopOfStack.DereferenceObject(); + + return status; +} + +VOID +_DeviceUsageNotificationWorkItem( + __in MdDeviceObject DeviceObject, + __in PVOID Context + ) +{ + FxUsageWorkitemParameters* param; + NTSTATUS status; + + UNREFERENCED_PARAMETER(DeviceObject); + + param = (FxUsageWorkitemParameters*) Context; + + status = SendDeviceUsageNotificationWorker(param->RelatedDevice, + param->RelatedIrp, + param->OriginalIrp, + param->Revert); + + // + // capture status in notification object + // + param->Status = status; + + // + // set event to allow the origial notifcation thread to proceed + // + param->Event.Set(); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/notpowerpolicyownerstatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/notpowerpolicyownerstatemachine.cpp new file mode 100644 index 00000000000..6541e2d95db --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/notpowerpolicyownerstatemachine.cpp @@ -0,0 +1,593 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + NotPowerPolicyOwnerStateMachine.cpp + +Abstract: + + This module implements the Not Power Policy Owner state machine for the driver + framework. This code was split out from PowerPolicyStateMachine.cpp + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "NotPowerPolicyOwnerStateMachine.tmh" +#endif +} + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerObjectCreatedStates[] = +{ + { PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT }, + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStartingStates[] = +{ + { PwrPolPowerUp, WdfDevStatePwrPolStarted DEBUGGED_EVENT }, + { PwrPolPowerUpFailed, WdfDevStatePwrPolStartingFailed DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStartingSucceededStates[] = +{ + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolGotoDx DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolGotoD0InD0 TRAP_ON_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStartingFailedStates[] = +{ + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerGotoDxStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolDx DEBUGGED_EVENT }, + { PwrPolPowerDownFailed, WdfDevStatePwrPolStartingSucceeded DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerGotoDxInDxStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolDx TRAP_ON_EVENT }, + { PwrPolPowerDownFailed, WdfDevStatePwrPolDx TRAP_ON_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerDxStates[] = +{ + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolGotoD0 DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolGotoDxInDx TRAP_ON_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerGotoD0States[] = +{ + { PwrPolPowerUp, WdfDevStatePwrPolStartingSucceeded DEBUGGED_EVENT }, + { PwrPolPowerUpFailed, WdfDevStatePwrPolStartingSucceeded TRAP_ON_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerGotoD0InD0States[] = +{ + { PwrPolPowerUp, WdfDevStatePwrPolStartingSucceeded TRAP_ON_EVENT }, + { PwrPolPowerUpFailed, WdfDevStatePwrPolStartingSucceeded TRAP_ON_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStoppedStates[] = +{ + { PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT }, + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStoppingWaitForImplicitPowerDownStates[] = +{ + { PwrPolImplicitPowerDown, WdfDevStatePwrPolStoppingSendStatus DEBUGGED_EVENT }, + { PwrPolImplicitPowerDownFailed, WdfDevStatePwrPolStoppingFailed DEBUGGED_EVENT }, + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolStoppingPoweringDown DEBUGGED_EVENT }, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolStoppingPoweringUp DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStoppingPoweringUpStates[] = +{ + { PwrPolPowerUp, WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown DEBUGGED_EVENT }, + { PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown TRAP_ON_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerStoppingPoweringDownStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown DEBUGGED_EVENT }, + { PwrPolPowerDownFailed, WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown DEBUGGED_EVENT }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_NotPowerPolOwnerRemovedStates[] = +{ + { PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT }, + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, +}; + +const NOT_POWER_POLICY_OWNER_STATE_TABLE FxPkgPnp::m_WdfNotPowerPolicyOwnerStates[] = +{ + // current state + // transition function, + // target states + // count of target states + // Queue state + // + { WdfDevStatePwrPolObjectCreated, + NULL, + FxPkgPnp::m_NotPowerPolOwnerObjectCreatedStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerObjectCreatedStates), + TRUE, + }, + + { WdfDevStatePwrPolStarting, + FxPkgPnp::NotPowerPolOwnerStarting, + FxPkgPnp::m_NotPowerPolOwnerStartingStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStartingStates), + FALSE, + }, + + { WdfDevStatePwrPolStarted, + FxPkgPnp::NotPowerPolOwnerStarted, + NULL, + 0, + FALSE, + }, + + { WdfDevStatePwrPolStartingSucceeded, + NULL, + FxPkgPnp::m_NotPowerPolOwnerStartingSucceededStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStartingSucceededStates), + TRUE, + }, + + { WdfDevStatePwrPolGotoDx, + FxPkgPnp::NotPowerPolOwnerGotoDx, + FxPkgPnp::m_NotPowerPolOwnerGotoDxStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerGotoDxStates), + FALSE, + }, + + { WdfDevStatePwrPolGotoDxInDx, + FxPkgPnp::NotPowerPolOwnerGotoDxInDx, + FxPkgPnp::m_NotPowerPolOwnerGotoDxInDxStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerGotoDxInDxStates), + FALSE, + }, + + { WdfDevStatePwrPolDx, + NULL, + FxPkgPnp::m_NotPowerPolOwnerDxStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerDxStates), + TRUE, + }, + + { WdfDevStatePwrPolGotoD0, + FxPkgPnp::NotPowerPolOwnerGotoD0, + FxPkgPnp::m_NotPowerPolOwnerGotoD0States, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerGotoD0States), + FALSE, + }, + + { WdfDevStatePwrPolGotoD0InD0, + FxPkgPnp::NotPowerPolOwnerGotoD0InD0, + FxPkgPnp::m_NotPowerPolOwnerGotoD0InD0States, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerGotoD0InD0States), + FALSE, + }, + + { WdfDevStatePwrPolStopping, + FxPkgPnp::NotPowerPolOwnerStopping, + NULL, + 0, + FALSE, + }, + + { WdfDevStatePwrPolStoppingSendStatus, + FxPkgPnp::NotPowerPolOwnerStoppingSendStatus, + NULL, + 0, + FALSE, + }, + + { WdfDevStatePwrPolStartingFailed, + FxPkgPnp::NotPowerPolOwnerStartingFailed, + FxPkgPnp::m_NotPowerPolOwnerStartingFailedStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStartingFailedStates), + TRUE, + }, + + { WdfDevStatePwrPolStoppingFailed, + FxPkgPnp::NotPowerPolOwnerStoppingFailed, + NULL, + 0, + FALSE, + }, + + { WdfDevStatePwrPolStopped, + NULL, + FxPkgPnp::m_NotPowerPolOwnerStoppedStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStoppedStates), + TRUE, + }, + + { WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown, + NULL, + FxPkgPnp::m_NotPowerPolOwnerStoppingWaitForImplicitPowerDownStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStoppingWaitForImplicitPowerDownStates), + TRUE, + }, + + { WdfDevStatePwrPolStoppingPoweringUp, + FxPkgPnp::NotPowerPolOwnerStoppingPoweringUp, + FxPkgPnp::m_NotPowerPolOwnerStoppingPoweringUpStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStoppingPoweringUpStates), + FALSE, + }, + + { WdfDevStatePwrPolStoppingPoweringDown, + FxPkgPnp::NotPowerPolOwnerStoppingPoweringDown, + FxPkgPnp::m_NotPowerPolOwnerStoppingPoweringDownStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerStoppingPoweringDownStates), + FALSE, + }, + + { WdfDevStatePwrPolRemoved, + FxPkgPnp::NotPowerPolOwnerRemoved, + FxPkgPnp::m_NotPowerPolOwnerRemovedStates, + ARRAY_SIZE(FxPkgPnp::m_NotPowerPolOwnerRemovedStates), + TRUE, + }, + + // the last entry must have WdfDevStatePwrPolNull as the current state + { WdfDevStatePwrPolNull, + NULL, + NULL, + 0, + FALSE, + }, +}; + +VOID +FxPkgPnp::NotPowerPolicyOwnerEnterNewState( + __in WDF_DEVICE_POWER_POLICY_STATE NewState + ) +{ + CPNOT_POWER_POLICY_OWNER_STATE_TABLE entry; + WDF_DEVICE_POWER_POLICY_STATE currentState, newState; + WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA data; + + currentState = m_Device->GetDevicePowerPolicyState(); + newState = NewState; + + while (newState != WdfDevStatePwrPolNull) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering not power policy owner state " + "%!WDF_DEVICE_POWER_POLICY_STATE! from " + "%!WDF_DEVICE_POWER_POLICY_STATE!", m_Device->GetHandle(), + m_Device->GetDeviceObject(), newState, currentState); + + if (m_PowerPolicyStateCallbacks != NULL) { + // + // Callback for leaving the old state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationLeaveState; + data.Data.LeaveState.CurrentState = currentState; + data.Data.LeaveState.NewState = newState; + + m_PowerPolicyStateCallbacks->Invoke(currentState, + StateNotificationLeaveState, + m_Device->GetHandle(), + &data); + } + + m_PowerPolicyMachine.m_States.History[ + m_PowerPolicyMachine.IncrementHistoryIndex()] = (USHORT) newState; + + if (m_PowerPolicyStateCallbacks != NULL) { + // + // Callback for entering the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationEnterState; + data.Data.EnterState.CurrentState = currentState; + data.Data.EnterState.NewState = newState; + + m_PowerPolicyStateCallbacks->Invoke(newState, + StateNotificationEnterState, + m_Device->GetHandle(), + &data); + } + + m_Device->SetDevicePowerPolicyState(newState); + currentState = newState; + + entry = GetNotPowerPolicyOwnerTableEntry(currentState); + + // + // Call the state handler, if there is one. + // + if (entry->StateFunc != NULL) { + newState = entry->StateFunc(this); + } + else { + newState = WdfDevStatePwrPolNull; + } + + if (m_PowerPolicyStateCallbacks != NULL) { + // + // Callback for post processing the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationPostProcessState; + data.Data.PostProcessState.CurrentState = currentState; + + m_PowerPolicyStateCallbacks->Invoke(currentState, + StateNotificationPostProcessState, + m_Device->GetHandle(), + &data); + } + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStarting( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Starting the power policy state machine for a device which is not the power + policy owner. Tell the power state machine to start up. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + This->PowerProcessEvent(PowerImplicitD0); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStarted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Starting the power policy state machine for a device which is not the power + policy owner has succeeded. Indicate status to the pnp state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + This->PnpProcessEvent(PnpEventPwrPolStarted); + return WdfDevStatePwrPolStartingSucceeded; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerGotoDx( + __inout FxPkgPnp* This + ) +{ + This->PowerProcessEvent(PowerCompleteDx); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerGotoDxInDx( + __inout FxPkgPnp* This + ) +{ + This->PowerProcessEvent(PowerCompleteDx); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerGotoD0( + __inout FxPkgPnp* This + ) +{ + This->PowerProcessEvent(PowerCompleteD0); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerGotoD0InD0( + __inout FxPkgPnp* This + ) +{ + This->PowerProcessEvent(PowerCompleteD0); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStopping( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Stopping the power policy state machine for a device which is not the power + policy owner. Tell the power state machine to power down. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown + + --*/ +{ + This->PowerProcessEvent(PowerImplicitD3); + return WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStoppingSendStatus( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Stopping the power policy state machine for a device which is not the power + policy owner has succeeded. Inidcate status to the pnp state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStopped + + --*/ +{ + This->PnpProcessEvent(PnpEventPwrPolStopped); + return WdfDevStatePwrPolStopped; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStartingFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Starting the power policy state machine for a device which is not the power + policy owner has failed. Inidcate status to the pnp state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + This->PnpProcessEvent(PnpEventPwrPolStartFailed); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStoppingFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Stopping the power policy state machine for a device which is not the power + policy owner has failed. Inidcate status to the pnp state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStopped + + --*/ +{ + This->PnpProcessEvent(PnpEventPwrPolStopFailed); + return WdfDevStatePwrPolStopped; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStoppingPoweringUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Right as we attempted to implicitly power down, a real D0 irp came into the + stack. Complete the D0 irp in the power state machine so that the power + state machine can process the implicit power irp + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + This->PowerProcessEvent(PowerCompleteD0); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerStoppingPoweringDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Right as we attempted to implicitly power down, a real Dx irp came into the + stack. Complete the Dx irp in the power state machine so that the power + state machine can process the implicit power irp + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + This->PowerProcessEvent(PowerCompleteDx); + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::NotPowerPolOwnerRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is being removed, so prepare for removal. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + // + // Since we are not the power policy owner, there is nothing to be done. + // Indicate to the PNP state machine that we are ready for removal. + // + This->PnpProcessEvent(PnpEventPwrPolRemoved); + return WdfDevStatePwrPolNull; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pdopower.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pdopower.cpp new file mode 100644 index 00000000000..a95d1635928 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pdopower.cpp @@ -0,0 +1,496 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + PdoPower.cpp + +Abstract: + + This module implements the Pnp package for Pdo devices. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +// Tracing support +#if defined(EVENT_TRACING) +extern "C" { +#include "PdoPower.tmh" +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_DispatchPowerSequence( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ) +/*++ + +Routine Description: + report the power sequence for the child + +Arguments: + This - the package + + Irp - the request + +Return Value: + STATUS_NOT_SUPPORTED + + --*/ +{ + return ((FxPkgPdo*) This)->CompletePowerRequest(Irp, STATUS_NOT_SUPPORTED); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_DispatchSetPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ) +/*++ + +Routine Description: + + This method is invoked when a SetPower IRP enters the driver. + +Arguemnts: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + if (Irp->GetParameterPowerType() == SystemPowerState) { + return ((FxPkgPdo*) This)->DispatchSystemSetPower(Irp); + } + else { + return ((FxPkgPdo*) This)->DispatchDeviceSetPower(Irp); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::DispatchSystemSetPower( + __in FxIrp *Irp + ) +{ + NTSTATUS status; + KIRQL irql; + MxDeviceObject deviceObject(m_Device->GetDeviceObject()); + + status = STATUS_SUCCESS; + + m_SystemPowerState = (BYTE) Irp->GetParameterPowerStateSystemState(); + deviceObject.SetPowerState(SystemPowerState, + Irp->GetParameterPowerState()); + + if (IsPowerPolicyOwner()) { + if (m_SystemPowerState == PowerSystemWorking) { + // + // Ideally we would like to complete the S0 irp before we start + // processing the event in the state machine so that the D0 irp + // comes after the S0 is moving up the stack... + // + // ... BUT ... + // + // ... by allowing the S0 irp to go up the stack first, we must then + // handle pnp requests from the current power policy state (because + // the S0 irp could be the last S irp in the system and when completed, + // the pnp lock is released). So, we process the event first so + // that we can move into a state where we can handle pnp events in + // the power policy state machine. + // + // We mitigate the situation a little bit by forcing the processing of the + // event to occur on the power policy thread rather then in the current + // context. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + PowerPolicyProcessEvent(PwrPolS0); + Mx::MxLowerIrql(irql); + + return CompletePowerRequest(Irp, STATUS_SUCCESS); + } + else { + // + // Power policy state machine will complete the request later + // + SetPendingSystemPowerIrp(Irp); + PowerPolicyProcessEvent(PwrPolSx); + return STATUS_PENDING; + } + } + else { + // + // Since we are not the power policy owner, we just complete all S irps + // + return CompletePowerRequest(Irp, STATUS_SUCCESS); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::DispatchDeviceSetPower( + __in FxIrp *Irp + ) +{ + NTSTATUS status; + + status = STATUS_SUCCESS; + + if (IsPowerPolicyOwner()) { + if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp == FALSE && + m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp == FALSE) { + // + // A power irp arrived, but we did not request it. ASSERT and log + // an error. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Received set device power irp 0x%p on WDFDEVICE 0x%p !devobj 0x%p, " + "but the irp was not requested by the device (the power policy owner)", + Irp->GetIrp(), + m_Device->GetHandle(), + m_Device->GetDeviceObject()); + + ASSERTMSG("Received set device power irp but the irp was not " + "requested by the device (the power policy owner)\n", + FALSE); + } + + // + // We are no longer requesting a power irp because we received the one + // we requested. + // + if (m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE; + } + else { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE; + } + } + + SetPendingDevicePowerIrp(Irp); + + if (Irp->GetParameterPowerStateDeviceState() == PowerDeviceD0) { + PowerProcessEvent(PowerD0); + } + else { + PowerProcessEvent(PowerDx); + } + + return STATUS_PENDING; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_DispatchQueryPower( + __inout FxPkgPnp* This, + __in FxIrp *Irp + ) +/*++ + +Routine Description: + Dispatches query power for system and device requests + +Arguments: + This - the package + + Irp - the query power request + +Return Value: + NTSTATUS + + --*/ +{ + FxPkgPdo* pThis; + NTSTATUS status; + + pThis = ((FxPkgPdo*) This); + + if (Irp->GetParameterPowerType() == SystemPowerState + && + This->PowerPolicyIsWakeEnabled()) { + + status = pThis->PowerPolicyHandleSystemQueryPower( + Irp->GetParameterPowerStateSystemState() + ); + } + else { + status = STATUS_SUCCESS; + } + + return pThis->CompletePowerRequest(Irp, status); +} + +VOID +FxPkgPdo::PowerReleasePendingDeviceIrp( + __in BOOLEAN IrpMustBePresent + ) +{ + MdIrp pIrp; + + pIrp = ClearPendingDevicePowerIrp(); + + UNREFERENCED_PARAMETER(IrpMustBePresent); + ASSERT(IrpMustBePresent == FALSE || pIrp != NULL); + + if (pIrp != NULL) { + FxIrp irp(pIrp); + + CompletePowerRequest(&irp, STATUS_SUCCESS); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PowerCheckParentOverload( + __in BOOLEAN* ParentOn + ) +/*++ + +Routine Description: + This function implements the CheckParent state. Its + job is to determine which state we should go to next based on whether + the parent is in D0. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + + + + + return (m_Device->m_ParentDevice->m_PkgPnp)-> + PowerPolicyCanChildPowerUp(ParentOn); +} + +WDF_DEVICE_POWER_STATE +FxPkgPdo::PowerCheckDeviceTypeOverload( + VOID + ) +/*++ + +Routine Description: + This function implements the Check Type state. This is a PDO. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + return WdfDevStatePowerCheckParentState; +} + +WDF_DEVICE_POWER_STATE +FxPkgPdo::PowerCheckDeviceTypeNPOverload( + VOID + ) +/*++ + +Routine Description: + This function implements the Check Type state. This is a PDO. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + return WdfDevStatePowerCheckParentStateNP; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PowerEnableWakeAtBusOverload( + VOID + ) +/*++ + +Routine Description: + Arms the device at the bus level for wake. This arming is generic since + the bus driver can only configure the device generically. The power policy + owner has already armed the device for wake in a device specific fashion + when it processed the wake irp (EvtDeviceArmDeviceForWakeFromS0/x if the ppo + is a WDF driver). + +Arguments: + None + +Return Value: + NTSTATUS, !NT_SUCCESS if the arm failed + + --*/ +{ + NTSTATUS status; + + // + // The EnableWakeAtBus callback should not be called twice in a row without + // an intermediate call to the DisableWakeAtBus callback. + // + ASSERT(m_EnableWakeAtBusInvoked == FALSE); + + status = m_DeviceEnableWakeAtBus.Invoke( + m_Device->GetHandle(), + (SYSTEM_POWER_STATE) m_SystemPowerState + ); + + if (NT_SUCCESS(status)) { + m_EnableWakeAtBusInvoked = TRUE; + PowerNotifyParentChildWakeArmed(); + } + + return status; +} + +VOID +FxPkgPdo::PowerDisableWakeAtBusOverload( + VOID + ) +/*++ + +Routine Description: + Disarms the device at the bus level for wake. This disarming is generic + since the bus driver can only configure the device generically. The power + policy owner may have already disarmed the device for wake in a device + specific fashion. For a WDF ppo EvtDeviceDisarmDeviceForWakeFromS0/x is + called after the bus has disarmed. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (m_EnableWakeAtBusInvoked) { + m_EnableWakeAtBusInvoked = FALSE; + PowerNotifyParentChildWakeDisarmed(); + + m_DeviceDisableWakeAtBus.Invoke(m_Device->GetHandle()); + } +} + +VOID +FxPkgPdo::PowerParentPowerDereference( + VOID + ) +/*++ + +Routine Description: + Releases the child power reference on the parent device. This allows the + parent to enter into an idle capable state. This power reference does not + prevent the parent from moving into Dx when the system power state changes. + +Arguments: + None + +Return Value: + None + + --*/ +{ + + m_Device->m_ParentDevice->m_PkgPnp->PowerPolicyChildPoweredDown(); +} + +VOID +FxPkgPdo::PowerNotifyParentChildWakeArmed( + VOID + ) +/*++ + +Routine Description: + Notifies the parent device that the child is armed for wake. This will + cause the parent to increment its count of children armed for wake. + +Arguments: + None + +Return Value: + None + + --*/ +{ + FxPowerPolicyOwnerSettings* settings; + + ASSERT(m_Device->m_ParentDevice != NULL); + + + + + + settings = m_Device->m_ParentDevice->m_PkgPnp-> + m_PowerPolicyMachine.m_Owner; + if (settings != NULL) { + settings->IncrementChildrenArmedForWakeCount(); + } +} + +VOID +FxPkgPdo::PowerNotifyParentChildWakeDisarmed( + VOID + ) +/*++ + +Routine Description: + Notifies the parent device that the child is not armed for wake. This will + cause the parent to decrement its count of children armed for wake. + +Arguments: + None + +Return Value: + None + + --*/ +{ + FxPowerPolicyOwnerSettings* settings; + + ASSERT(m_Device->m_ParentDevice != NULL); + + + + + + settings = m_Device->m_ParentDevice->m_PkgPnp-> + m_PowerPolicyMachine.m_Owner; + if (settings != NULL) { + settings->DecrementChildrenArmedForWakeCount(); + } +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pnppriv.hpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pnppriv.hpp new file mode 100644 index 00000000000..66dcfffd86f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pnppriv.hpp @@ -0,0 +1,482 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + pnppriv.hpp + +Abstract: + + This module implements the pnp package for the driver frameworks. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#ifndef _PNPPRIV_H_ +#define _PNPPRIV_H_ + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#define FX_IS_USER_MODE (TRUE) +#define FX_IS_KERNEL_MODE (FALSE) +#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#define FX_IS_USER_MODE (FALSE) +#define FX_IS_KERNEL_MODE (TRUE) +#endif + +// +// common header file for all irphandler\* files +// +#include "irphandlerspriv.hpp" + +// +// public headers +// +#include "wdfDevice.h" +#include "wdfChildList.h" +#include "wdfPdo.h" +#include "wdffdo.h" +#include "wdfQueryInterface.h" +#include "wdfMemory.h" +#include "wdfWmi.h" + + + + + + + + + + + + + + + + + + + +#ifndef _INTERRUPT_COMMON_H_ +#include "WdfInterrupt.h" +#endif +#ifndef _WUDFDDI_TYPES_PRIVATE_H_ +#include "wdfrequest.h" +#include "wdfio.h" +#endif + +// +// private headers +// +#include "FxWaitLock.hpp" +#include "FxTransactionedList.hpp" +#include "FxRelatedDeviceList.hpp" +#include "FxCollection.hpp" + +// support +#include "StringUtil.hpp" +#include "FxString.hpp" +#include "FxDeviceText.hpp" +#include "FxCallback.hpp" +#include "FxSystemThread.hpp" +#include "FxResource.hpp" + +// io +#include "FxPkgIoShared.hpp" + +// +// FxDeviceInitShared.hpp is new header with definition of PdoInit split from +// FxDeviceInit.hpp +// +#include "FxDeviceInitShared.hpp" + +// bus +#include "FxChildList.hpp" + +// FxDevice To Shared interface header +#include "FxDeviceToMxInterface.hpp" + +// mode specific headers +#if FX_IS_KERNEL_MODE +#include "PnpPrivKM.hpp" +#elif FX_IS_USER_MODE +#include "PnpPrivUM.hpp" +#endif + +#include "FxSpinLock.hpp" + +#if FX_IS_KERNEL_MODE +#include "FxInterruptKm.hpp" +#elif FX_IS_USER_MODE +#include "FxInterruptUm.hpp" +#endif + +#if FX_IS_KERNEL_MODE +#include "FxPerfTraceKm.hpp" +#endif + +#include "FxTelemetry.hpp" + +// pnp +#include "FxRelatedDevice.hpp" +#include "FxDeviceInterface.hpp" +#include "FxQueryInterface.hpp" +#include "FxPnpCallbacks.hpp" +#include "FxPackage.hpp" +#include "FxPkgPnp.hpp" +#include "FxWatchDog.hpp" +#include "FxPkgPdo.hpp" +#include "FxPkgFdo.hpp" + +// wmi +#include "FxWmiIrpHandler.hpp" +#include "FxWmiProvider.hpp" +#include "FxWmiInstance.hpp" + + +VOID +PnpPassThroughQIWorker( + __in MxDeviceObject* Device, + __inout FxIrp* Irp, + __inout FxIrp* ForwardIrp + ); + +VOID +CopyQueryInterfaceToIrpStack( + __in PPOWER_THREAD_INTERFACE PowerThreadInterface, + __in FxIrp* Irp + ); + +_Must_inspect_result_ +NTSTATUS +SendDeviceUsageNotification( + __in MxDeviceObject* RelatedDevice, + __in FxIrp* RelatedIrp, + __in MxWorkItem* Workitem, + __in FxIrp* OriginalIrp, + __in BOOLEAN Revert + ); + +_Must_inspect_result_ +NTSTATUS +GetStackCapabilities( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in MxDeviceObject* DeviceInStack, + __in_opt PD3COLD_SUPPORT_INTERFACE D3ColdInterface, + __out PSTACK_DEVICE_CAPABILITIES Capabilities + ); + +VOID +SetD3ColdSupport( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in MxDeviceObject* DeviceInStack, + __in PD3COLD_SUPPORT_INTERFACE D3ColdInterface, + __in BOOLEAN UseD3Cold + ); + +#define SET_TRI_STATE_FROM_STATE_BITS(state, S, FieldName) \ +{ \ + switch (state & (FxPnpState##FieldName##Mask)) { \ + case FxPnpState##FieldName##False : \ + S->FieldName = WdfFalse; \ + break; \ + case FxPnpState##FieldName##True: \ + S->FieldName = WdfTrue; \ + break; \ + case FxPnpState##FieldName##UseDefault : \ + default: \ + S->FieldName = WdfUseDefault; \ + break; \ + } \ +} + +LONG +__inline +FxGetValueBits( + __in WDF_TRI_STATE State, + __in LONG TrueValue, + __in LONG UseDefaultValue + ) +{ + switch (State) { + case WdfFalse: return 0x0; + case WdfTrue: return TrueValue; + case WdfUseDefault: + default: return UseDefaultValue; + } +} + +#define GET_PNP_STATE_BITS_FROM_STRUCT(S, FieldName)\ + FxGetValueBits(S->FieldName, \ + FxPnpState##FieldName##True, \ + FxPnpState##FieldName##UseDefault) + +#define GET_PNP_CAP_BITS_FROM_STRUCT(S, FieldName) \ + FxGetValueBits(S->FieldName, \ + FxPnpCap##FieldName##True, \ + FxPnpCap##FieldName##UseDefault) + +#define GET_POWER_CAP_BITS_FROM_STRUCT(S, FieldName)\ + FxGetValueBits(S->FieldName, \ + FxPowerCap##FieldName##True, \ + FxPowerCap##FieldName##UseDefault) + +__inline +VOID +FxSetPnpDeviceStateBit( + __in PNP_DEVICE_STATE* PnpDeviceState, + __in LONG ExternalState, + __in LONG InternalState, + __in LONG BitMask, + __in LONG TrueValue + ) +{ + LONG bits; + + bits = InternalState & BitMask; + + if (bits == TrueValue) { + *PnpDeviceState |= ExternalState; + } + else if (bits == 0) { // 0 is the always false for every bit-set + *PnpDeviceState &= ~ExternalState; + } +} + +#define SET_PNP_DEVICE_STATE_BIT(State, ExternalState, value, Name) \ + FxSetPnpDeviceStateBit(State, \ + ExternalState, \ + state, \ + FxPnpState##Name##Mask, \ + FxPnpState##Name##True) + +#define SET_PNP_CAP_IF_TRUE(caps, pCaps, FieldName) \ +{ \ + if ((caps & FxPnpCap##FieldName##Mask) == FxPnpCap##FieldName##True) { \ + pCaps->FieldName = TRUE; \ + } \ +} + +#define SET_PNP_CAP_IF_FALSE(caps, pCaps, FieldName) \ +{ \ + if ((caps & FxPnpCap##FieldName##Mask) == FxPnpCap##FieldName##False) { \ + pCaps->FieldName = FALSE; \ + } \ +} + +#define SET_PNP_CAP(caps, pCaps, FieldName) \ +{ \ + if ((caps & FxPnpCap##FieldName##Mask) == FxPnpCap##FieldName##False) { \ + pCaps->FieldName = FALSE; \ + } \ + else if ((caps & FxPnpCap##FieldName##Mask) == FxPnpCap##FieldName##True) { \ + pCaps->FieldName = TRUE; \ + } \ +} + +#define SET_POWER_CAP(caps, pCaps, FieldName) \ +{ \ + if ((caps & FxPowerCap##FieldName##Mask) == FxPowerCap##FieldName##False) { \ + pCaps->FieldName = FALSE; \ + } \ + else if ((caps & FxPowerCap##FieldName##Mask) == FxPowerCap##FieldName##True) { \ + pCaps->FieldName = TRUE; \ + } \ +} + +_Must_inspect_result_ +PVOID +GetIoMgrObjectForWorkItemAllocation( + VOID + ); + + + + + + + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_7; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9, + *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V1_9; + +typedef struct _WDF_PDO_EVENT_CALLBACKS_V1_9 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + +} WDF_PDO_EVENT_CALLBACKS_V1_9, *PWDF_PDO_EVENT_CALLBACKS_V1_9; + + + + + +typedef struct _WDF_INTERRUPT_INFO_V1_7 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + +} WDF_INTERRUPT_INFO_V1_7, *PWDF_INTERRUPT_INFO_V1_7; + +typedef struct _WDF_INTERRUPT_INFO_V1_7 *PWDF_INTERRUPT_INFO_V1_7; +typedef const struct _WDF_INTERRUPT_INFO_V1_7 *PCWDF_INTERRUPT_INFO_V1_7; + +#endif // _PNPPRIV_H_ diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pnpstatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pnpstatemachine.cpp new file mode 100644 index 00000000000..4e7b8dd971b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/pnpstatemachine.cpp @@ -0,0 +1,4793 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PnpStateMachine.cpp + +Abstract: + + This module implements the PnP state machine for the driver framework. + This code was split out from FxPkgPnp.cpp. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" +#include + +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "PnpStateMachine.tmh" +#endif +} + + +// +// The PnP State Machine +// +// This state machine responds to several PnP events: +// +// AddDevice -- Always targets the same state +// IRP_MN_START_DEVICE +// IRP_MN_START_DEVICE Complete -- Handled on the way up the stack +// IRP_MN_QUERY_REMOVE_DEVICE +// IRP_MN_QUERY_STOP_DEVICE +// IRP_MN_CANCEL_REMOVE_DEVICE +// IRP_MN_CANCEL_STOP_DEVICE +// IRP_MN_STOP_DEVICE +// IRP_MN_REMOVE_DEVICE +// IRP_MN_SURPRISE_REMOVE_DEVICE -- Always targets the same state +// IRP_MN_EJECT +// +// Each state has an entry for each of these events, listing the +// target state for each of them. +// + +#if FX_STATE_MACHINE_VERIFY + #define VALIDATE_PNP_STATE(_CurrentState, _NewState) \ + ValidatePnpStateEntryFunctionReturnValue((_CurrentState), (_NewState)) +#else + #define VALIDATE_PNP_STATE(_CurrentState, _NewState) (0) +#endif //FX_STATE_MACHINE_VERIFY + +// @@SMVERIFY_SPLIT_BEGIN + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpInitOtherStates[] = +{ + { PnpEventQueryRemove, WdfDevStatePnpInitQueryRemove DEBUGGED_EVENT }, + { PnpEventRemove, WdfDevStatePnpRemoved DEBUGGED_EVENT }, + { PnpEventParentRemoved, WdfDevStatePnpRemoved DEBUGGED_EVENT }, + { PnpEventSurpriseRemove, WdfDevStatePnpInitSurpriseRemoved DEBUGGED_EVENT }, + { PnpEventEject, WdfDevStatePnpEjectHardware DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpInitStartingOtherStates[] = +{ + { PnpEventStartDeviceFailed, WdfDevStatePnpInit DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpHardwareAvailableOtherStates[] = +{ + { PnpEventPwrPolStartFailed, WdfDevStatePnpHardwareAvailablePowerPolicyFailed DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpQueryStopPendingOtherStates[] = +{ + { PnpEventCancelStop, WdfDevStatePnpQueryCanceled DEBUGGED_EVENT }, + { PnpEventSurpriseRemove, WdfDevStatePnpQueriedSurpriseRemove TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRemovedPdoWaitOtherStates[] = +{ + { PnpEventStartDevice, WdfDevStatePnpPdoRestart DEBUGGED_EVENT }, + { PnpEventRemove, WdfDevStatePnpCheckForDevicePresence DEBUGGED_EVENT }, + { PnpEventParentRemoved, WdfDevStatePnpPdoRemoved DEBUGGED_EVENT }, + { PnpEventSurpriseRemove, WdfDevStatePnpRemovedPdoSurpriseRemoved DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartingOtherStates[] = +{ + { PnpEventPwrPolStartFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedOtherStates[] = +{ + { PnpEventQueryStop, WdfDevStatePnpQueryStopStaticCheck DEBUGGED_EVENT }, + { PnpEventCancelStop, WdfDevStatePnpStartedCancelStop DEBUGGED_EVENT }, + { PnpEventCancelRemove, WdfDevStatePnpStartedCancelRemove DEBUGGED_EVENT }, + { PnpEventRemove, WdfDevStatePnpStartedRemoving DEBUGGED_EVENT }, + { PnpEventSurpriseRemove, WdfDevStatePnpSurpriseRemoveIoStarted DEBUGGED_EVENT }, + { PnpEventPowerUpFailed, WdfDevStatePnpFailedIoStarting DEBUGGED_EVENT }, + { PnpEventPowerDownFailed, WdfDevStatePnpFailedPowerDown DEBUGGED_EVENT }, + { PnpEventStartDevice, WdfDevStatePnpRestart DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpQueryRemovePendingOtherStates[] = +{ + { PnpEventCancelRemove, WdfDevStatePnpQueryCanceled DEBUGGED_EVENT }, + { PnpEventSurpriseRemove, WdfDevStatePnpQueriedSurpriseRemove TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpQueriedRemovingOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpInitQueryRemoveOtherStates[] = +{ + { PnpEventCancelRemove, WdfDevStatePnpInitQueryRemoveCanceled DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStoppedOtherStates[] = +{ + { PnpEventSurpriseRemove, WdfDevStatePnpSurpriseRemove DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStoppedWaitForStartCompletionOtherStates[] = +{ + { PnpEventStartDeviceFailed, WdfDevStatePnpFailed TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedStoppingOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedStoppingFailedOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpEjectFailedOtherStates[] = +{ + { PnpEventSurpriseRemove, WdfDevStatePnpSurpriseRemove TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpStartedRemovingOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpFailedPowerDownOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpFailedIoStartingOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpFailedWaitForRemoveOtherStates[] = +{ + { PnpEventSurpriseRemove, WdfDevStatePnpFailedSurpriseRemoved DEBUGGED_EVENT }, + { PnpEventStartDevice, WdfDevStatePnpFailedStarted TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartOtherStates[] = +{ + { PnpEventPwrPolStopFailed, WdfDevStatePnpHardwareAvailablePowerPolicyFailed DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartReleaseHardware[] = +{ + { PnpEventStartDeviceFailed, WdfDevStatePnpFailed TRAP_ON_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_EVENT_TARGET_STATE FxPkgPnp::m_PnpRestartHardwareAvailableOtherStates[] = +{ + { PnpEventPwrPolStartFailed, WdfDevStatePnpHardwareAvailablePowerPolicyFailed DEBUGGED_EVENT }, + { PnpEventNull, WdfDevStatePnpNull }, +}; + +const PNP_STATE_TABLE FxPkgPnp::m_WdfPnpStates[] = { + // State function + // First transition event & state + // Other transition events & states + // state info + + // WdfDevStatePnpObjectCreated + { NULL, + { PnpEventAddDevice, WdfDevStatePnpInit DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePnpCheckForDevicePresence + { FxPkgPnp::PnpEventCheckForDevicePresence, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpEjectFailed + { NULL, + { PnpEventStartDevice, WdfDevStatePnpPdoRestart DEBUGGED_EVENT }, + FxPkgPnp::m_PnpEjectFailedOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePnpEjectHardware + { FxPkgPnp::PnpEventEjectHardware, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpEjectedWaitingForRemove + { NULL, + { PnpEventRemove, WdfDevStatePnpPdoRemoved DEBUGGED_EVENT }, + NULL, + { TRUE, + PnpEventSurpriseRemove }, // can receive this if parent is surprise + // removed while the ejected pdo is waiting + // for remove. + }, + + // WdfDevStatePnpInit + { NULL, + { PnpEventStartDevice, WdfDevStatePnpInitStarting DEBUGGED_EVENT }, + FxPkgPnp::m_PnpInitOtherStates, + { TRUE, + PnpEventStartDevice }, + }, + + // WdfDevStatePnpInitStarting + { FxPkgPnp::PnpEventInitStarting, + { PnpEventStartDeviceComplete, WdfDevStatePnpHardwareAvailable DEBUGGED_EVENT }, + FxPkgPnp::m_PnpInitStartingOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePnpInitSurpriseRemoved + { FxPkgPnp::PnpEventInitSurpriseRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpHardwareAvailable + { FxPkgPnp::PnpEventHardwareAvailable, + { PnpEventPwrPolStarted, WdfDevStatePnpEnableInterfaces DEBUGGED_EVENT }, + FxPkgPnp::m_PnpHardwareAvailableOtherStates, + { FALSE, + PnpEventPowerUpFailed + }, + }, + + // WdfDevStatePnpEnableInterfaces + { FxPkgPnp::PnpEventEnableInterfaces, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpHardwareAvailablePowerPolicyFailed + { FxPkgPnp::PnpEventHardwareAvailablePowerPolicyFailed, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpQueryRemoveAskDriver + { FxPkgPnp::PnpEventQueryRemoveAskDriver, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpQueryRemovePending + { FxPkgPnp::PnpEventQueryRemovePending, + { PnpEventRemove, WdfDevStatePnpQueriedRemoving DEBUGGED_EVENT }, + FxPkgPnp::m_PnpQueryRemovePendingOtherStates, + { TRUE, + 0, + }, + }, + + // WdfDevStatePnpQueryRemoveStaticCheck + { FxPkgPnp::PnpEventQueryRemoveStaticCheck, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpQueriedRemoving, + { FxPkgPnp::PnpEventQueriedRemoving, + { PnpEventPwrPolStopped, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, + FxPkgPnp::m_PnpQueriedRemovingOtherStates, + { FALSE, + PnpEventPowerDownFailed | // We ignore these power failed events because + PnpEventPowerUpFailed // they will be translated into failed power + // policy events. + }, + }, + + // WdfDevStatePnpQueryStopAskDriver + { FxPkgPnp::PnpEventQueryStopAskDriver, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpQueryStopPending + { FxPkgPnp::PnpEventQueryStopPending, + { PnpEventStop, WdfDevStatePnpStartedStopping DEBUGGED_EVENT }, + FxPkgPnp::m_PnpQueryStopPendingOtherStates, + { TRUE, + 0, + }, + }, + + // WdfDevStatePnpQueryStopStaticCheck + { FxPkgPnp::PnpEventQueryStopStaticCheck, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpQueryCanceled, + { FxPkgPnp::PnpEventQueryCanceled, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpRemoved + { FxPkgPnp::PnpEventRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpPdoRemoved + { FxPkgPnp::PnpEventPdoRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpRemovedPdoWait + { FxPkgPnp::PnpEventRemovedPdoWait, + { PnpEventEject, WdfDevStatePnpEjectHardware DEBUGGED_EVENT }, + FxPkgPnp::m_PnpRemovedPdoWaitOtherStates, + { TRUE, + PnpEventCancelRemove | // Amazingly enough, you can get a cancel q.r. + // on a PDO without seeing the query remove if + // the stack is partially built + PnpEventQueryRemove | // Can get a query remove from the removed state + // when installing a PDO that is disabled + PnpEventPowerDownFailed // We may get this for a PDO if implicit power + // down callbacks were failed. The failed power + // policy stop event took care of rundown. + }, + }, + + // WdfDevStatePnpRemovedPdoSurpriseRemoved + { FxPkgPnp::PnpEventRemovedPdoSurpriseRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpRemovingDisableInterfaces + { FxPkgPnp::PnpEventRemovingDisableInterfaces, + { PnpEventPwrPolRemoved, WdfDevStatePnpRemoved DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpRestarting + { FxPkgPnp::PnpEventRestarting, + { PnpEventPwrPolStarted, WdfDevStatePnpStarted DEBUGGED_EVENT }, + FxPkgPnp::m_PnpRestartingOtherStates, + { FALSE, + PnpEventPowerUpFailed + }, + }, + + // WdfDevStatePnpStarted + { FxPkgPnp::PnpEventStarted, + { PnpEventQueryRemove, WdfDevStatePnpQueryRemoveStaticCheck DEBUGGED_EVENT }, + FxPkgPnp::m_PnpStartedOtherStates, + { TRUE, + 0, + }, + }, + + // WdfDevStatePnpStartedCancelStop + { FxPkgPnp::PnpEventStartedCancelStop, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpStartedCancelRemove + { FxPkgPnp::PnpEventStartedCancelRemove, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpStartedRemoving + { FxPkgPnp::PnpEventStartedRemoving, + { PnpEventPwrPolStopped, WdfDevStatePnpRemovingDisableInterfaces DEBUGGED_EVENT }, + FxPkgPnp::m_PnpStartedRemovingOtherStates, + { TRUE, + PnpEventPowerUpFailed | // device was idled out and in Dx when we got removed + // and this event is due to the power up that occured + // to move it into D0 so it could be disarmed + PnpEventPowerDownFailed + }, + }, + + // WdfDevStatePnpStartingFromStopped + { FxPkgPnp::PnpEventStartingFromStopped, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpStopped + { FxPkgPnp::PnpEventStopped, + { PnpEventStartDevice, WdfDevStatePnpStoppedWaitForStartCompletion DEBUGGED_EVENT }, + FxPkgPnp::m_PnpStoppedOtherStates, + { TRUE, + 0, + }, + }, + + // WdfDevStatePnpStoppedWaitForStartCompletion + { FxPkgPnp::PnpEventStoppedWaitForStartCompletion, + { PnpEventStartDeviceComplete, WdfDevStatePnpStartingFromStopped DEBUGGED_EVENT }, + FxPkgPnp::m_PnpStoppedWaitForStartCompletionOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePnpStartedStopping + { FxPkgPnp::PnpEventStartedStopping, + { PnpEventPwrPolStopped, WdfDevStatePnpStopped DEBUGGED_EVENT }, + FxPkgPnp::m_PnpStartedStoppingOtherStates, + { TRUE, + PnpEventPowerUpFailed | // device was idled out and in Dx when we got stopped + // and this event is due to the power up that occured + // to move it into D0 so it could be disarmed + PnpEventPowerDownFailed + }, + }, + + // The function is named PnpEventSurpriseRemoved with a 'd' because + // PnpEventSurpriseRemove (no 'd') is an event name + + // WdfDevStatePnpSurpriseRemove + { FxPkgPnp::PnpEventSurpriseRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpInitQueryRemove + { FxPkgPnp::PnpEventInitQueryRemove, + { PnpEventRemove, WdfDevStatePnpRemoved DEBUGGED_EVENT }, + FxPkgPnp::m_PnpInitQueryRemoveOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePnpInitQueryRemoveCanceled + { FxPkgPnp::PnpEventInitQueryRemoveCanceled, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePnpFdoRemoved + { FxPkgPnp::PnpEventFdoRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpRemovedWaitForChildren + { NULL, + { PnpEventChildrenRemovalComplete, WdfDevStatePnpRemovedChildrenRemoved DEBUGGED_EVENT }, + NULL, + { TRUE, + PnpEventPowerDownFailed // device power down even from processing remove + }, + }, + + // WdfDevStatePnpQueriedSurpriseRemove + { FxPkgPnp::PnpEventQueriedSurpriseRemove, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpSurpriseRemoveIoStarted + { FxPkgPnp::PnpEventSurpriseRemoveIoStarted, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpFailedPowerDown + { FxPkgPnp::PnpEventFailedPowerDown, + { PnpEventPwrPolStopped, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, + FxPkgPnp::m_PnpFailedPowerDownOtherStates, + { FALSE, + PnpEventPowerDownFailed , + }, + }, + + // WdfDevStatePnpFailedIoStarting + { FxPkgPnp::PnpEventFailedIoStarting, + { PnpEventPwrPolStopped, WdfDevStatePnpFailedOwnHardware DEBUGGED_EVENT }, + FxPkgPnp::m_PnpFailedIoStartingOtherStates, + { FALSE, + PnpEventPowerDownFailed | + + PnpEventPowerUpFailed // if the device idled out and then failed + // d0 entry, the power up failed can be passed + // up by the IoInvalidateDeviceRelations and + // subsequence surprise remove event. + }, + }, + + // WdfDevStatePnpFailedOwnHardware + { FxPkgPnp::PnpEventFailedOwnHardware, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpFailed + { FxPkgPnp::PnpEventFailed, + { PnpEventPwrPolRemoved, WdfDevStatePnpFailedPowerPolicyRemoved DEBUGGED_EVENT }, + NULL, + { FALSE, + 0, + }, + }, + + // WdfDevStatePnpFailedSurpriseRemoved + { FxPkgPnp::PnpEventFailedSurpriseRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0, }, + }, + + // WdfDevStatePnpFailedStarted + { FxPkgPnp::PnpEventFailedStarted, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0, }, + }, + + // WdfDevStatePnpFailedWaitForRemove, + { NULL, + { PnpEventRemove, WdfDevStatePnpRemoved DEBUGGED_EVENT }, + FxPkgPnp::m_PnpFailedWaitForRemoveOtherStates, + { TRUE, + PnpEventPowerUpFailed | // initial power up failed, power policy start + // failed event moved the state machine to the + // failed state first + PnpEventPowerDownFailed | // implicitD3 power down failed + PnpEventQueryRemove | // start succeeded, but we still get a query in + // the removed case + PnpEventCancelStop | // power down failure while processing query stop + // and q.s. irp completed with error + PnpEventCancelRemove // power down failure while processing query remove + // and q.r. irp completed with error + }, + }, + + // WdfDevStatePnpFailedInit + { FxPkgPnp::PnpEventFailedInit, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpPdoInitFailed + { FxPkgPnp::PnpEventPdoInitFailed, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpRestart + { FxPkgPnp::PnpEventRestart, + { PnpEventPwrPolStopped, WdfDevStatePnpRestartReleaseHardware DEBUGGED_EVENT }, + FxPkgPnp::m_PnpRestartOtherStates, + { FALSE, + PnpEventPowerUpFailed | // when stopping power policy, device was in + // Dx and bringing it to D0 succeeded or failed + PnpEventPowerDownFailed // same as power up + }, + }, + + // WdfDevStatePnpRestartReleaseHardware + { FxPkgPnp::PnpEventRestartReleaseHardware, + { PnpEventStartDeviceComplete, WdfDevStatePnpRestartHardwareAvailable DEBUGGED_EVENT }, + FxPkgPnp::m_PnpRestartReleaseHardware, + { TRUE, + PnpEventPowerDownFailed // the previous pwr policy stop + // in WdfDevStaePnpRestart will + // cause these events to show up here + }, + }, + + // WdfDevStatePnpRestartHardwareAvailable + { FxPkgPnp::PnpEventRestartHardwareAvailable, + { PnpEventPwrPolStarted, WdfDevStatePnpStarted DEBUGGED_EVENT }, + FxPkgPnp::m_PnpRestartHardwareAvailableOtherStates, + { TRUE, + PnpEventPowerUpFailed + }, + }, + + // WdfDevStatePnpPdoRestart + { FxPkgPnp::PnpEventPdoRestart, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpFinal + { FxPkgPnp::PnpEventFinal, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { TRUE, + PnpEventPowerDownFailed, // on the final implicit power down, a + // callback returned !NT_SUCCESS + }, + }, + + // WdfDevStatePnpRemovedChildrenRemoved + { FxPkgPnp::PnpEventRemovedChildrenRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { TRUE, + 0 } , + }, + + // WdfDevStatePnpQueryRemoveEnsureDeviceAwake + { FxPkgPnp::PnpEventQueryRemoveEnsureDeviceAwake, + { PnpEventDeviceInD0, WdfDevStatePnpQueryRemovePending DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpQueryStopEnsureDeviceAwake + { FxPkgPnp::PnpEventQueryStopEnsureDeviceAwake, + { PnpEventDeviceInD0, WdfDevStatePnpQueryStopPending DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePnpFailedPowerPolicyRemoved + { FxPkgPnp::PnpEventFailedPowerPolicyRemoved, + { PnpEventNull, WdfDevStatePnpNull }, + NULL, + { FALSE, + 0 } , + }, +}; + +// @@SMVERIFY_SPLIT_END + +VOID +FxPkgPnp::PnpCheckAssumptions( + VOID + ) +/*++ + +Routine Description: + This routine is never actually called by running code, it just has + WDFCASSERTs who upon failure, would not allow this file to be compiled. + + DO NOT REMOVE THIS FUNCTION just because it is not callec by any running + code. + +Arguments: + None + +Return Value: + None + + --*/ +{ + WDFCASSERT(sizeof(FxPnpStateInfo) == sizeof(ULONG)); + + WDFCASSERT((sizeof(m_WdfPnpStates)/sizeof(m_WdfPnpStates[0])) + == + (WdfDevStatePnpNull - WdfDevStatePnpObjectCreated)); + + // we assume these are the same length when we update the history index + WDFCASSERT((sizeof(m_PnpMachine.m_Queue)/sizeof(m_PnpMachine.m_Queue[0])) + == + (sizeof(m_PnpMachine.m_States.History)/ + sizeof(m_PnpMachine.m_States.History[0]))); +} + +/*++ + +The locking model for the PnP state machine requires that events be enqueued +possibly at DISPATCH_LEVEL. It also requires that the PnP state machine be +runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL +lock that guards the event queue and one PASSIVE_LEVEL lock that guards the +state machine itself. + +Algorithm: + +1) Acquire the PnP queue lock. +2) Enqueue the request. Requests are put at the end of the queue, except if + they are PowerUp, or PowerDown, in which case they are put at the head of + the queue. +3) Drop the PnP queue lock. +4) If the thread is running at PASSIVE_LEVEL, skip to step 6. +5) Queue a work item onto any work queue. +6) Attempt to acquire the state machine lock, with a near-zero-length timeout. +7) If successful, skip to step 10. +8) Queue a work item onto any work queue. +9) Acquire the state machine lock. +10) Acquire the PnP queue lock. +11) Attempt to dequeue an event. +12) Drop the PnP queue lock. +13) If there was no event to dequeue, drop the state machine lock and exit. +14) Execute the state handler. This may involve taking one of the other state + machine queue locks, briefly, to deliver an event. +15) Go to Step 10. + +Implementing this algorithm requires three functions. + +PnpProcessEvent -- Implements steps 1-8. +_PnpProcessEventInner -- Implements step 9. +PnpProcessEventInner -- Implements steps 10-15. + +--*/ + +VOID +FxPkgPnp::PnpProcessEvent( + __in FxPnpEvent Event, + __in BOOLEAN ProcessOnDifferentThread + ) +/*++ + +Routine Description: + This function implements steps 1-8 of the algorithm described above. + +Arguments: + Event - Current PnP event + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + KIRQL oldIrql; + + // + // Take the lock, raising to DISPATCH_LEVEL. + // + m_PnpMachine.Lock(&oldIrql); + + if (m_PnpMachine.IsFull()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pnp state %!WDF_DEVICE_PNP_STATE! " + "dropping event %!FxPnpEvent! because of a full queue", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePnpState(), + Event); + + // + // The queue is full. Bail. + // + m_PnpMachine.Unlock(oldIrql); + + ASSERT(!"The PnP queue is full. This shouldn't be able to happen."); + return; + } + + if (m_PnpMachine.IsClosedLocked()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pnp state %!WDF_DEVICE_PNP_STATE! " + "dropping event %!FxPnpEvent! because of a closed queue", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePnpState(), + Event); + + // + // The queue is closed. Bail + // + m_PnpMachine.Unlock(oldIrql); + + return; + } + + // + // Enqueue the event. Whether the event goes on the front + // or the end of the queue depends on which event it is. + // + if (Event & PnpPriorityEventsMask) { + // + // Stick it on the front of the queue, making it the next + // event that will be processed. + // + m_PnpMachine.m_Queue[m_PnpMachine.InsertAtHead()] = Event; + } + else { + // + // Stick it on the end of the queue. + // + m_PnpMachine.m_Queue[m_PnpMachine.InsertAtTail()] = Event; + } + + // + // Drop the lock. + // + m_PnpMachine.Unlock(oldIrql); + + // + // Now, if we are running at PASSIVE_LEVEL, attempt to run the state + // machine on this thread. If we can't do that, then queue a work item. + // + + if (FALSE == ShouldProcessPnpEventOnDifferentThread( + oldIrql, + ProcessOnDifferentThread + )) { + + LONGLONG timeout = 0; + + status = m_PnpMachine.m_StateMachineLock.AcquireLock(GetDriverGlobals(), + &timeout); + + if (FxWaitLockInternal::IsLockAcquired(status)) { + FxPostProcessInfo info; + + // + // We now hold the state machine lock. So call the function that + // dispatches the next state. + // + PnpProcessEventInner(&info); + + m_PnpMachine.m_StateMachineLock.ReleaseLock(GetDriverGlobals()); + + info.Evaluate(this); + return; + } + } + + // + // For one reason or another, we couldn't run the state machine on this + // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing + // is non-zero, that means that the work item is already being enqueued + // on another thread. This is significant, since it means that we can't do + // anything with the work item on this thread, but it's okay, since the + // work item will pick up our work and do it. + // + m_PnpMachine.QueueToThread(); +} + +VOID +FxPkgPnp::_PnpProcessEventInner( + __inout FxPkgPnp* This, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ) +{ + UNREFERENCED_PARAMETER(WorkerContext); + + // + // Take the state machine lock. + // + This->m_PnpMachine.m_StateMachineLock.AcquireLock( + This->GetDriverGlobals() + ); + + // + // Call the function that will actually run the state machine. + // + This->PnpProcessEventInner(Info); + + // + // We are being called from the work item and m_WorkItemRunning is > 0, so + // we cannot be deleted yet. + // + ASSERT(Info->SomethingToDo() == FALSE); + + // + // Now release the lock + // + This->m_PnpMachine.m_StateMachineLock.ReleaseLock( + This->GetDriverGlobals() + ); +} + +VOID +FxPkgPnp::PnpProcessEventInner( + __inout FxPostProcessInfo* Info + ) +/*++ + +Routine Description: + This routine runs the state machine. It implements steps 10-15 of the + algorithm described above. + +--*/ +{ + WDF_DEVICE_PNP_STATE newState; + CPPNP_STATE_TABLE entry; + FxPnpEvent event; + KIRQL oldIrql; + + // + // Process as many events as we can. + // + for ( ; ; ) { + entry = GetPnpTableEntry(m_Device->GetDevicePnpState()); + + // + // Get an event from the queue. + // + m_PnpMachine.Lock(&oldIrql); + + if (m_PnpMachine.IsEmpty()) { + m_PnpMachine.GetFinishedState(Info); + + if (m_PnpMachine.m_FireAndForget) { + m_PnpMachine.m_FireAndForget = FALSE; + Info->m_FireAndForgetIrp = ClearPendingPnpIrp(); + + ASSERT(Info->m_FireAndForgetIrp != NULL); + } + + Info->m_SetRemovedEvent = m_SetDeviceRemoveProcessed; + m_SetDeviceRemoveProcessed = FALSE; + + // + // The queue is empty. + // + m_PnpMachine.Unlock(oldIrql); + + return; + } + + event = m_PnpMachine.m_Queue[m_PnpMachine.GetHead()]; + + // + // At this point, we need to determine whether we can process this + // event. + // + if (event & PnpPriorityEventsMask) { + // + // These are always possible to handle. + // + DO_NOTHING(); + } + else { + // + // Check to see if this state can handle new events. + // + if (entry->StateInfo.Bits.QueueOpen == FALSE) { + // + // This state can't handle new events. + // + m_PnpMachine.Unlock(oldIrql); + return; + } + } + + m_PnpMachine.IncrementHead(); + m_PnpMachine.Unlock(oldIrql); + + // + // Find the entry in the PnP state table that corresponds + // to this event. + // + newState = WdfDevStatePnpNull; + + if (entry->FirstTargetState.PnpEvent == event) { + newState = entry->FirstTargetState.TargetState; + + DO_EVENT_TRAP(&entry->FirstTargetState); + } + else if (entry->OtherTargetStates != NULL) { + ULONG i = 0; + + for (i = 0; + entry->OtherTargetStates[i].PnpEvent != PnpEventNull; + i++) { + if (entry->OtherTargetStates[i].PnpEvent == event) { + newState = entry->OtherTargetStates[i].TargetState; + DO_EVENT_TRAP(&entry->OtherTargetStates[i]); + break; + } + } + } + + if (newState == WdfDevStatePnpNull) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pnp state " + "%!WDF_DEVICE_PNP_STATE! dropping event %!FxPnpEvent!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePnpState(), + event); + + if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) { + COVERAGE_TRAP(); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "WDFDEVICE 0x%p !devobj %p current state " + "%!WDF_DEVICE_PNP_STATE!, policy event %!FxPnpEvent! is not" + " a known dropped event, known dropped events are " + "%!FxPnpEvent!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePnpState(), + event, + entry->StateInfo.Bits.KnownDroppedEvents); + + // DIAG: add diag code here + } + + // + // This state doesn't respond to the Event. Make sure we do not + // drop an event which pends a pnp irp on the floor though. + // + if (event & PnpEventPending) { + // + // In the case of a previous power up/down failure, the following + // can happen + // 1 invalidate device relations + // 2 failure event is posted to pnp state machine + // 3 process power failure event first, but while processing, + // query device state is completed, and failed /removed is reported + // 4 surprise remove comes, the irp is queued, the event is queued + // 5 processing of power failure event continues, gets to + // Failed and completes the s.r irp + // 6 the surprise remove event is processed (the current value + // of the local var event), but since we are already in the + // Failed state, we ignore this event and end up + // here. + // + // This means that if we are processing surprise remove, we cannot + // 100% expect that an irp has been pended. + // + PnpFinishProcessingIrp( + (event == PnpEventSurpriseRemove) ? FALSE : TRUE); + } + else { + DO_NOTHING(); + } + } + else { + // + // Now enter the new state. + // + PnpEnterNewState(newState); + } + } +} + +VOID +FxPkgPnp::PnpEnterNewState( + __in WDF_DEVICE_PNP_STATE State + ) +/*++ + +Routine Description: + This function looks up the handler for a state and + then calls it. + +Arguments: + Event - Current PnP event + +Return Value: + None. + +--*/ +{ + CPPNP_STATE_TABLE entry; + WDF_DEVICE_PNP_STATE currentState, newState; + WDF_DEVICE_PNP_NOTIFICATION_DATA data; + + currentState = m_Device->GetDevicePnpState(); + newState = State; + + while (newState != WdfDevStatePnpNull) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering PnP State " + "%!WDF_DEVICE_PNP_STATE! from %!WDF_DEVICE_PNP_STATE!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + newState, + currentState); + + if (m_PnpStateCallbacks != NULL) { + // + // Callback for leaving the old state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationLeaveState; + data.Data.LeaveState.CurrentState = currentState; + data.Data.LeaveState.NewState = newState; + + m_PnpStateCallbacks->Invoke(currentState, + StateNotificationLeaveState, + m_Device->GetHandle(), + &data); + } + + m_PnpMachine.m_States.History[m_PnpMachine.IncrementHistoryIndex()] = + (USHORT) newState; + + if (m_PnpStateCallbacks != NULL) { + // + // Callback for entering the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationEnterState; + data.Data.EnterState.CurrentState = currentState; + data.Data.EnterState.NewState = newState; + + m_PnpStateCallbacks->Invoke(newState, + StateNotificationEnterState, + m_Device->GetHandle(), + &data); + } + + m_Device->SetDevicePnpState(newState); + currentState = newState; + + entry = GetPnpTableEntry(currentState); + + // + // Call the state handler if one is present and record our new state + // + if (entry->StateFunc != NULL) { + newState = entry->StateFunc(this); + + // + // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled + // + VALIDATE_PNP_STATE(currentState, newState); + } + else { + newState = WdfDevStatePnpNull; + } + + if (m_PnpStateCallbacks != NULL) { + // + // Callback for post processing the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationPostProcessState; + data.Data.PostProcessState.CurrentState = currentState; + + m_PnpStateCallbacks->Invoke(currentState, + StateNotificationPostProcessState, + m_Device->GetHandle(), + &data); + } + } +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventCheckForDevicePresence( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Check For Device + Presence state. This is a state that is specific + to PDOs, so this function should be overloaded by + the PDO class and never called. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + return This->PnpEventCheckForDevicePresenceOverload(); +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventEjectHardware( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Eject Hardware state. + This is a state that is specific to PDOs, so this + function should be overloaded by the PDO class + and never called. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + return This->PnpEventEjectHardwareOverload(); +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventInitStarting( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is recieving a start for the first time. The start is on the way + down the stack. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) { + // + // Start was sent asynchronously down the stack, the irp's completion + // routine will move the state machine to the new state. + // + return WdfDevStatePnpNull; + } + + return WdfDevStatePnpHardwareAvailable; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventInitSurpriseRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This transition should only occur for a PDO. + + The device was initialized, but then it's parent bus was surprise removed. + Complete the surprise remove and wait for the remove. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpInit + + --*/ +{ + This->PnpFinishProcessingIrp(TRUE); + + return WdfDevStatePnpInit; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventHardwareAvailable( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Hardware Available state. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status; + BOOLEAN matched; + + status = STATUS_SUCCESS; + matched = FALSE; + + This->QueryForReenumerationInterface(); + + status = This->CreatePowerThreadIfNeeded(); + + if (NT_SUCCESS(status)) { + status = This->PnpPrepareHardware(&matched); + } + + if (!NT_SUCCESS(status)) { + if (matched == FALSE) { + // + // NOTE: consider going to WdfDevStatePnpFailed instead of yet + // another failed state out of start device handling. + // + + // + // We can handle remove out of the init state, revert back to that + // state. + // + return WdfDevStatePnpFailedInit; + } + else { + // + // EvtDevicePrepareHardware is what failed, goto a state where we + // undo that call. + // + return WdfDevStatePnpFailedOwnHardware; + } + } + + // + // We only query for the capabilities for the power policy owner because + // we use the capabilities to determine the right Dx state when we want to + // wake from S0 or Sx. Since only the power policy owner can enable wake + // behavior, only the owner needs to query for the information. + // + // ALSO, if we are a filter, there are issues in stacks wrt pnp reentrancy. + + + + + + + + // + if (This->IsPowerPolicyOwner()) { + // + // Query the stack for capabilities before telling the stack hw is + // available + // + status = This->QueryForCapabilities(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "could not query caps for stack, %!STATUS!", status); + + This->SetPendingPnpIrpStatus(status); + return WdfDevStatePnpFailedOwnHardware; + } + + This->m_CapsQueried = TRUE; + } + + This->PnpPowerPolicyStart(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventEnableInterfaces( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device has powered up and fully started, now enable the device + interfaces and WMI. We wait until the last possible moment because on + win2k WMI registration is not synchronized with the completion of start + device, so if we register WMI early in start device processing, we could get + wmi requests while we are initializing, which is a race condition we want + to eliminate. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + + status = This->PnpEnableInterfacesAndRegisterWmi(); + + if (!NT_SUCCESS(status)) { + // + // Upon failure, PnpEnableInterfacesAndRegisterWmi already marked the + // irp as failed and recorded an internal error. + // + // FailedPowerDown will gracefully tear down the stack and bring it out + // of D0. + // + return WdfDevStatePnpFailedPowerDown; + } + + return WdfDevStatePnpStarted; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventHardwareAvailablePowerPolicyFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Our previous state called PowerPolicyStart or PowerPolicyStopRemove and the + power state machine could not perform the requested action. We still have + a start irp pending, so set its status and then proceed down the start failure + path. + +Arguments: + This - instance of the state machien + +Return Value: + WdfDevStatePnpFailedOwnHardware + + --*/ +{ + This->SetPendingPnpIrpStatus(STATUS_DEVICE_POWER_FAILURE); + + return WdfDevStatePnpFailedOwnHardware; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryRemoveAskDriver( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Query Remove Ask Driver + state. It's job is to invoke EvtDeviceQueryRemove and then complete the + QueryRemove IRP if needed. + +Arguments: + This - instance of the state machine + +Return Value: + new state + +--*/ +{ + WDF_DEVICE_PNP_STATE state; + NTSTATUS status; + + // + // First, call the driver. If it succeeds, look at whether + // it managed to stop its stuff. + // + status = This->m_DeviceQueryRemove.Invoke(This->m_Device->GetHandle()); + + if (NT_SUCCESS(status)) { + // + // The driver has stopped all of its self managed io. Proceed to + // stop everything before passing the request down the stack. + // + state = WdfDevStatePnpQueryRemoveEnsureDeviceAwake; + } + else { + // + // The callback didn't manage to stop. Go back to the Started state + // where we will complete the pended pnp irp + // + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceQueryRemove failed, %!STATUS!", status); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceQueryRemove returned an invalid status " + "STATUS_NOT_SUPPORTED"); + + if (This->GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierDbgBreakPoint(This->GetDriverGlobals()); + } + } + + state = WdfDevStatePnpStarted; + } + + This->SetPendingPnpIrpStatus(status); + + return state; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryRemoveEnsureDeviceAwake( + __inout FxPkgPnp *This + ) +/*++ +Routine Description: + This function brings the device to a working state if it is idle. If the + device is already in working state, it ensures that it does not idle out. + +Arguments: + This - instance of the state machine + +Return Value: + new state +--*/ +{ + NTSTATUS status; + WDF_DEVICE_PNP_STATE state; + + // + // Make sure that the device is powered on before we send the query remove + // on its way. If we do this after we send the query remove, we could race + // with the remove which removes the reference and we want the device + // powered on when processing remove. + // + status = This->PnpPowerReferenceDuringQueryPnp(); + if (STATUS_PENDING == status) { + // + // Device is transitioning to D0. The Pnp state machine will wait in + // the current state until the transition is complete + // + state = WdfDevStatePnpNull; + } + else if (NT_SUCCESS(status)) { + // + // Already in D0 + // + state = WdfDevStatePnpQueryRemovePending; + } + else { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "StopIdle on WDFDEVICE %p failed, %!STATUS!, failing query remove", + This->m_Device->GetHandle(), status); + + This->SetPendingPnpIrpStatus(status); + + // + // The Started state will complete the irp when it sees the failure + // status set on the irp. + // + state = WdfDevStatePnpStarted; + } + + return state; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryRemovePending( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device has fully stopped. Let go of the query remove irp. + +Arguments: + This - instance of the state machine for this device + +Return Value: + WdfDevStatePnpNull + + --*/ + +{ + FxIrp irp; + + irp.SetIrp(This->ClearPendingPnpIrp()); + (void) This->FireAndForgetIrp(&irp); + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryRemoveStaticCheck( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Query Remove Static Check + state. It's job is to determine whether this device, + in general, can stop. If it can, then we proceed on + to Query Remove Ask Driver. If not, then we go to + back to Started. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status; + BOOLEAN completeQuery; + + completeQuery = TRUE; + + if (This->m_DeviceStopCount != 0) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Failing QueryRemoveDevice because the driver " + "has indicated that it cannot be stopped, count %d", + This->m_DeviceStopCount); + + status = STATUS_INVALID_DEVICE_STATE; + } + else if (This->IsInSpecialUse()) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Failing QueryRemoveDevice due to open special file counts " + "(paging %d, hiber %d, dump %d, boot %d)", + This->GetUsageCount(WdfSpecialFilePaging), + This->GetUsageCount(WdfSpecialFileHibernation), + This->GetUsageCount(WdfSpecialFileDump), + This->GetUsageCount(WdfSpecialFileBoot)); + + status = STATUS_DEVICE_NOT_READY; + } + else { + // + // Go on to next state in the "remove" progression. + // + completeQuery = FALSE; + status = STATUS_SUCCESS; + } + + if (completeQuery) { + // + // Store the status which Started will complete + // + This->SetPendingPnpIrpStatus(status); + + // + // Revert to started + // + return WdfDevStatePnpStarted; + } + else { + // + // Wait for the other state machines to stop + // + return WdfDevStatePnpQueryRemoveAskDriver; + } +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueriedRemoving( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was query removed and is now in the removed state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + // + // It is important to stop power policy before releasing the reference. + // If the reference was released first, we could get into a situation where + // we immediately go idle and then we must send a D0 irp when in the remove. + // If there are devices on top of this device and we send a D0 irp during + // remove processing, the upper devices will be sent an irp after getting a + // pnp remove (and either crash or fail the power irp upon receiving it). + // + This->PnpPowerPolicyStop(); + This->PnpPowerDereferenceSelf(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryStopAskDriver( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Query Stop Ask Driver + state. It's job is to invoke the EvtDeviceQueryStop + callback and then complete the QueryStop IRP if needed. + +Arguments: + This - instance of the state machine + +Return Value: + new state + +--*/ +{ + WDF_DEVICE_PNP_STATE state; + NTSTATUS status; + + // + // First, call the driver. If it succeeds, look at whether + // it managed to stop its stuff. + // + status = This->m_DeviceQueryStop.Invoke(This->m_Device->GetHandle()); + + if (NT_SUCCESS(status)) { + // + // Tell the other state machines to stop + // + state = WdfDevStatePnpQueryStopEnsureDeviceAwake; + } + else { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceQueryStop failed, %!STATUS!", status); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceQueryStop returned an invalid status " + "STATUS_NOT_SUPPORTED"); + + if (This->GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierDbgBreakPoint(This->GetDriverGlobals()); + } + } + + // + // The callback didn't manage to stop. Go back to the Started state. + // + state = WdfDevStatePnpStarted; + } + + This->SetPendingPnpIrpStatus(status); + + return state; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryStopEnsureDeviceAwake( + __inout FxPkgPnp *This + ) +/*++ +Routine Description: + This function brings the device to a working state if it is idle. If the + device is already in working state, it ensures that it does not idle out. + +Arguments: + This - instance of the state machine + +Return Value: + new state +--*/ +{ + NTSTATUS status; + WDF_DEVICE_PNP_STATE state; + + // + // Make sure that the device is powered on before we send the query stop + // on its way. If we do this after we send the query stop, we could race + // with the stop and we want the device powered on when processing stop. + // + status = This->PnpPowerReferenceDuringQueryPnp(); + if (STATUS_PENDING == status) { + // + // Device is transitioning to D0. The Pnp state machine will wait in + // the current state until the transition is complete + // + state = WdfDevStatePnpNull; + } + else if (NT_SUCCESS(status)) { + // + // Already in D0 + // + state = WdfDevStatePnpQueryStopPending; + } + else { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "StopIdle on WDFDEVICE %p failed, %!STATUS!, failing query stop", + This->m_Device->GetHandle(), status); + + This->SetPendingPnpIrpStatus(status); + + // + // The Started state will complete the irp when it sees the failure + // status set on the irp. + // + state = WdfDevStatePnpStarted; + } + + return state; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryStopPending( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Everything in the device has stopped due to the stop device irp. Complete + it now + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ + +{ + FxIrp irp; + + irp.SetIrp(This->ClearPendingPnpIrp()); + (void) This->FireAndForgetIrp(&irp); + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryStopStaticCheck( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Query Stop Static Check state. It's job is to + determine whether this device, in general, can stop. If it can, then we + proceed on to Query Stop Ask Driver. Otherwise we will return to the + Started state. If the driver has set that the state machine should ignore + query stop/remove, the query will succeed, otherwise it will fail + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + +--*/ +{ + NTSTATUS status; + BOOLEAN completeQuery = TRUE; + + if (This->m_DeviceStopCount != 0) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Failing QueryStopDevice because the driver " + "has indicated that it cannot be stopped, count %d", + This->m_DeviceStopCount); + + status = STATUS_INVALID_DEVICE_STATE; + } + else if (This->IsInSpecialUse()) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "Failing QueryStopDevice due to open special file counts (paging %d," + " hiber %d, dump %d, boot %d)", + This->GetUsageCount(WdfSpecialFilePaging), + This->GetUsageCount(WdfSpecialFileHibernation), + This->GetUsageCount(WdfSpecialFileDump), + This->GetUsageCount(WdfSpecialFileBoot)); + + status = STATUS_DEVICE_NOT_READY; + } + else { + // + // Go on to next state in the "stop" progression. + // + status = STATUS_SUCCESS; + completeQuery = FALSE; + } + + if (completeQuery) { + // + // Set the state which started will complete the request with + // + This->SetPendingPnpIrpStatus(status); + + // + // Revert to started + // + return WdfDevStatePnpStarted; + } + else { + // + // Go ask power what the self managed io state is + // + return WdfDevStatePnpQueryStopAskDriver; + } +} + +VOID +FxPkgPnp::PnpEventRemovedCommonCode( + VOID + ) +/*++ + +Routine Description: + This function implements the Removed state. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + // + // Purge non power managed queues now + // + m_Device->m_PkgIo->StopProcessingForPower( + FxIoStopProcessingForPowerPurgeNonManaged + ); + + if (m_SelfManagedIoMachine != NULL) { + m_SelfManagedIoMachine->Cleanup(); + } + + // + // Cleanup WMI *after* EvtDeviceSelfManagedIoCleanup b/c we want to cleanup + // after a well known and documented time. The WMI docs state that you can + // register providers and instances all the way through + // EvtDeviceSelfManagedIoCleanup, so we mark WMI as cleaned up after that + // call. + // + m_Device->WmiPkgCleanup(); + + // + // Mark the device as removed. + // + m_PnpStateAndCaps.Value &= ~FxPnpStateRemovedMask; + m_PnpStateAndCaps.Value |= FxPnpStateRemovedTrue; + + // + // Now call the driver and tell it to cleanup all its software state. + // + // We do the dispose early here before deleting the object + // since the PNP remove event is the main trigger for + // the Dispose chain in the framework. + // + // (Almost everything in the driver is rooted on the device object) + // + + m_Device->EarlyDispose(); + + // + // All the children are in the disposed state, destroy them all. m_Device + // is not destroyed in this call. + // + + m_Device->DestroyChildren(); + + // + // Wait for all children to drain out and cleanup. + // + + m_Device->m_DisposeList->WaitForEmpty(); + +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueryCanceled( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in the queried state (remove or stop) and the query was + canceled. Remove the power reference taken and return to the started state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpStarted + + --*/ +{ + This->PnpPowerDereferenceSelf(); + + return WdfDevStatePnpStarted; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Removed state. It tears down any remaining + children and the moves into a role (FDO/PDO) specific state. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + +--*/ +{ + // + // Remove any child PDOs which may still be lingering around. We do + // the cleanup here so that we do it only once for the PDO which is being + // removed (but may stick around) b/c it was not reported as missing. + // + // + // Iterate over all of the reported children + // + This->ChildListNotifyRemove(&This->m_PendingChildCount); + + // + // Decrement our bias from when the device was (re)started. If all of the + // children removed themselves synchronously, we just move to the cleanup + // state, otherwise wait for all the children to fully process the remove + // before remove the parent so that ordering of removal between parent and + // child is guaranteed (where the order is that all children are cleaned + // up before the parent is cleaned up). + // + if (InterlockedDecrement(&This->m_PendingChildCount) > 0) { + return WdfDevStatePnpRemovedWaitForChildren; + } + else { + return WdfDevStatePnpRemovedChildrenRemoved; + } +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventPdoRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the PDO Removed state. This function is called + when the PDO is actually reported missing to the OS or the FDO is removed. + +Arguments: + none + +Return Value: + new state + +--*/ +{ + return This->PnpEventPdoRemovedOverload(); +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRemovedPdoWait( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Indicates to the remove path that remove processing is done and we will + wait for additional PNP events to arrive at this state machine + +Arguments: + This - Instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + if (This->m_DeviceRemoveProcessed != NULL) { + This->m_SetDeviceRemoveProcessed = TRUE; + } + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRemovedPdoSurpriseRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + PDO has been removed (could have been disabled in user mode) and is now + surprise removed by the underlying bus. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpRemovedPdoWait + + --*/ +{ + // + // Invoke EvtDeviceSurpriseRemove + // + This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); + + // + // Call the overloaded surprise remove handler since + // PnpEventSurpriseRemovePendingOverload will not get called + // + This->PnpEventSurpriseRemovePendingOverload(); + + // + // The surprise remove irp was pended, complete it now + // + This->PnpFinishProcessingIrp(); + + return WdfDevStatePnpRemovedPdoWait; +} + +VOID +FxPkgPnp::PnpCleanupForRemove( + __in BOOLEAN GracefulRemove + ) +/*++ + +Routine Description: + This is a common worker function between surprise remove and the graceful + remove path to do common cleanup. This involves deregistering from WMI, + device interfaces, symbolic links and stopping power managed i/o. + +Arguments: + GracefulRemove - if TRUE, we are in the graceful remove path, otherwise we + are in the surprise remove path. + +Return Value: + None + + --*/ +{ + // + // Disable WMI. + // + m_Device->WmiPkgDeregister(); + + // + // Disable any device interfaces. + // + PnpDisableInterfaces(); + + DeleteSymbolicLinkOverload(GracefulRemove); + + + + + + + + + // Flush/purge top-edge queues + m_Device->m_PkgIo->StopProcessingForPower( + FxIoStopProcessingForPowerPurgeManaged + ); + + // + // Invoke EvtDeviceSelfManagedIoFlush + // + if (m_SelfManagedIoMachine != NULL) { + m_SelfManagedIoMachine->Flush(); + } + + // + // Tell all the resource objects that they no longer own anything. + // + NotifyResourceobjectsToReleaseResources(); + + // + // Flush persistent state to permanent storage. We do this in the failed + // state for the surprise removed case. By storing the state when we are + // surprise removed, if the stack is reenumerated, it will pick up the saved + // state that was just committed. If the state was saved during remove + // device it can be too late because the new instance of the same device + // could already be up and running and not pick up the saved state. + // + // It is important to save the state before completing the (potentially) + // pended pnp irp. Completing the pnp irp will allow a new instance of the + // device to be enumerated and we want to save state before that happens. + // + SaveState(FALSE); + + if (m_SharedPower.m_WaitWakeOwner) { + // + // Don't care about the return code, just blindly try to complete the + // wake request. The function can handle the case where there is no + // irp to complete. + // + (void) PowerIndicateWaitWakeStatus(STATUS_NO_SUCH_DEVICE); + } +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRemovingDisableInterfaces( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Removing Disable + Interfaces state. It disables any device interfaces + and then tells the power policy state machine to prepare for device removal. + +Arguments: + none + +Return Value: + + WdfDevStatePnpNull + +--*/ +{ + NTSTATUS status; + + // + // Surprise remove path releases hardware first then disables the interfaces, + // so do the same in the graceful remove path. + // + + // + // Call the driver and tell it to unmap resources. + // + status = This->PnpReleaseHardware(); + if (!NT_SUCCESS(status)) { + // + // The driver failed to unmap resources. Presumably this means that + // there are now some leaked PTEs. Just log the failure. + // + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceReleaseHardware %p failed, %!STATUS!", + This->m_Device->GetHandle(), status); + } + + This->PnpCleanupForRemove(TRUE); + + // + // Tell the power policy state machine to prepare for device removal + // + This->PnpPowerPolicyRemove(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStarted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Completes the pending request or sends it on its way. + +Arguments: + This - instance of the state machine for the device + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + + This->m_AchievedStart = TRUE; + + // + // Log Telemetry event for the FDO + // + if (This->m_Device->IsPdo() == FALSE) { + This->m_Device->FxLogDeviceStartTelemetryEvent(); + } + + This->PnpFinishProcessingIrp(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStartedCancelStop( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Cancel stop received from the started state. Just return to the started + state where we will handle the pended irp. + +Arguments: + This - Instance of the state machine + +Return Value: + WdfDevStatePnpStarted + + --*/ +{ + UNREFERENCED_PARAMETER(This); + return WdfDevStatePnpStarted; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStartedCancelRemove( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Cancel remove received from the started state. Just return to the started + state where we will handle the pended irp. + +Arguments: + This - Instance of the state machine + +Return Value: + WdfDevStatePnpStarted + + --*/ +{ + UNREFERENCED_PARAMETER(This); + + return WdfDevStatePnpStarted; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStartedRemoving( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Remove directly from started. Power down the other state machines. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + This->PnpPowerPolicyStop(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRestarting( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Cancelling Stop state. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + // + // Send an event to the Power Policy State Machine + // telling it to "Start." + // + This->PnpPowerPolicyStart(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStartingFromStopped( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Restarting From Stopped state. It's job + is to map new resources and then proceed to the Restarting state. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status; + BOOLEAN matched; + + status = This->PnpPrepareHardware(&matched); + + if (!NT_SUCCESS(status)) { + // + // We can handle remove out of the init state, revert back to that state + // + if (matched == FALSE) { + // + // Wait for the remove irp to come in + // + COVERAGE_TRAP(); + return WdfDevStatePnpFailed; + } + else { + // + // EvtDevicePrepareHardware is what failed, goto a state where we + // undo that call. + // + COVERAGE_TRAP(); + return WdfDevStatePnpFailedOwnHardware; + } + } + + return WdfDevStatePnpRestarting; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStopped( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Stopped state. It's job is to invoke + EvtDeviceReleaseHardware. + +Arguments: + none + +Return Value: + + VOID + +--*/ +{ + WDF_DEVICE_PNP_STATE state; + NTSTATUS status; + + status = This->PnpReleaseHardware(); + if (NT_SUCCESS(status)) { + // + // Tell all the resource objects that they no longer own anything. + // + This->NotifyResourceobjectsToReleaseResources(); + + state = WdfDevStatePnpNull; + } + else { + DoTraceLevelMessage(This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceReleaseHardware failed - %!STATUS!", + status); + COVERAGE_TRAP(); + + This->SetInternalFailure(); + state = WdfDevStatePnpFailed; + } + + // + // Send the irp on its merry way. This irp (stop device) cannot be failed + // and must always be sent down the stack. + // + This->PnpFinishProcessingIrp(); + + return state; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStoppedWaitForStartCompletion( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The start irp is coming down from the stopped state. Send it down the stack + and transition to the new state if needed. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) { + // + // The start irp's completion routine will move the state machine into + // the new state. + // + return WdfDevStatePnpNull; + } + + return WdfDevStatePnpStartingFromStopped; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventStartedStopping( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Received a stop irp. Stop the power policy machine and then wait for it to + complete. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + // + // It is important to stop power policy before releasing the reference. + // If the reference was released first, we could get into a situation where + // we immediately go idle and then we must send a D0 irp when in the remove. + // If there are devices on top of this device and we send a D0 irp during + // remove processing, the upper devices will be sent an irp after getting a + // pnp remove (and either crash or fail the power irp upon receiving it). + // + This->PnpPowerPolicyStop(); + This->PnpPowerDereferenceSelf(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventSurpriseRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We got IRP_MN_SURPRISE_REMOVE_DEVICE while the system was pretty far down + the removal path, or never started. Call EvtDeviceSurpriseRemoval, call the + surprise remove virtual and drop into the Failed path. + +Arguments: + This - instance of the state machine + +Return Value: + new device pnp state + + --*/ +{ + // + // Invoke EvtDeviceSurpriseRemove + // + This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); + + // + // Notify the virtual override of the surprise remove. + // + This->PnpEventSurpriseRemovePendingOverload(); + + return WdfDevStatePnpFailed; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventInitQueryRemove( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Query remove from the init state. Complete the pended request. + +Arguments: + This - instance of th state machine. + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + FxIrp irp(This->ClearPendingPnpIrp()); + + irp.SetStatus(STATUS_SUCCESS); + This->FireAndForgetIrp(&irp); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventInitQueryRemoveCanceled( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Handle a query remove canceled from the init state. Complete the pended + request. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpInit + + --*/ +{ + FxIrp irp(This->ClearPendingPnpIrp()); + + This->FireAndForgetIrp(&irp); + + return WdfDevStatePnpInit; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFdoRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + FDO is being removed, hand off to the derived pnp package + +Arguments: + This - instance of the state machine + +Return Value: + new device pnp state + + --*/ +{ + return This->PnpEventFdoRemovedOverload(); +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventQueriedSurpriseRemove( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in a queried (either stop or cancel) state and was surprise + removed from it. + +Arguments: + This - instance of the state machine + +Return Value: + new state, WdfDevStatePnpSurpriseRemoveIoStarted + + --*/ +{ + COVERAGE_TRAP(); + + This->PnpPowerDereferenceSelf(); + + return WdfDevStatePnpSurpriseRemoveIoStarted; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventSurpriseRemoveIoStarted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We got IRP_MN_SURPRISE_REMOVE_DEVICE while the system was more or less + running. Start down the Surprise Remove/Device Failed path. This state + calls EvtDeviceSurpriseRemoval, calls the virtual surprise remove overload, + and then drops into the Failed path. + +Arguments: + This - instance of the state machine + +Return Value: + new device pnp state + + --*/ +{ + // + // Invoke EvtDeviceSurpriseRemove + // + + This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); + + // + // Notify the virtual override of the surprise remove. + // + This->PnpEventSurpriseRemovePendingOverload(); + + return WdfDevStatePnpFailedIoStarting; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedPowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in the started state and failed power down or could not + enable its interfaces. Gracefully power down the device and tear down + the stack. + + The difference between this routine and PnpEventFailedIoStarting is that + FailedIoStarting sends a surprise remove to the power state machine. After + surprise remove has been sent to the power state machine, it will not attempt + to put the device into Dx because it assumes the device is no longer present. + In this error case, we still want the device to be powered down, so we send + a normal stop remove. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + // + // Normal stop so that the power state machine will go through the power off + // path and not skip directly to off like it would if we sent it a surprise + // remove notification. + // + This->PnpPowerPolicyStop(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedIoStarting( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device failed (or was yanked out of the machine) while it was more + or less running. Tell the driver to stop self-managed I/O and drop into + the next state on the failure path. + +Arguments: j + This - instance of the state machine + +Return Value: + new device pnp state + + --*/ +{ + This->PnpPowerPolicySurpriseRemove(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedOwnHardware( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device failed (or was yanked out of the machine) while it owned access + to the hardware. Tell the driver to release resources and drop into + the next state on the failure path. + +Arguments: + This - instance of the state machine + +Return Value: + new device pnp state + + --*/ +{ + // + // Invoke EvtDeviceReleaseHardware + // + (void) This->PnpReleaseHardware(); + + return WdfDevStatePnpFailed; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device failed (or was yanked out of the machine). Disable interfaces, + flush queues and tell the driver to clean up random stuff. + Also ask the power policy state machine to prepare for device removal. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + This->PnpCleanupForRemove(FALSE); + + // + // Tell the power policy state machine to prepare for device removal + // + This->PnpPowerPolicyRemove(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedPowerPolicyRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The power policy state machine has prepared for device removal. Invalidate + the device state and wait for IRP_MN_REMOVE_DEVICE. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpFailedWaitForRemove + + --*/ +{ + // + // Finish processing any pended PnP IRP. Since we can reach this state from + // states where a pnp irp was *not* pended, we do not require a pnp irp to + // have been pended when trying to complete it. + // + This->PnpFinishProcessingIrp(FALSE); + + // + // Request reenumeration if the client driver asked for it or if there was + // an internal failure *and* if the client driver didn't specify failure... + // AND if we have not yet exceeded our restart count within a period of time. + // + if ((This->m_FailedAction == WdfDeviceFailedAttemptRestart || + (This->m_FailedAction == WdfDeviceFailedUndefined && This->m_InternalFailure)) + && + This->PnpCheckAndIncrementRestartCount()) { + // + // No need to invalidate state because we are in a state waiting for + // a remove device anyways so failure is imminent. + // + This->AskParentToRemoveAndReenumerate(); + } + + if (This->m_FailedAction != WdfDeviceFailedUndefined || This->m_InternalFailure) { + // + // If the failure occurred in this device, then tear down the stack if + // we are in a state in which pnp thinks we are started. If we are + // already in a stopped state, this invalidation will do no harm. + // + MxDeviceObject physicalDeviceObject( + This->m_Device->GetPhysicalDevice() + ); + + // + // We need to pass FDO as a parameter as UMDF currently doesn't have + // PDOs and instead needs FDO to invalidate device state. + // + physicalDeviceObject.InvalidateDeviceState( + This->m_Device->GetDeviceObject() //FDO + ); + } + + return WdfDevStatePnpFailedWaitForRemove; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedSurpriseRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device has failed and then received a surprise remove. This can easily + happen on return from low power as following: + + 1 device attempts to enter D0, D0Entry fails + 2 pnp state machine proceeds down failure path and stops at FailedWaitForRemove + 3 bus driver finds device missing, reports it as such and a s.r. irp + arrives + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpFailedWaitForRemove + + --*/ +{ + // + // Invoke EvtDeviceSurpriseRemove + // + This->m_DeviceSurpriseRemoval.Invoke(This->m_Device->GetHandle()); + + // + // Call the overloaded surprise remove handler + // + This->PnpEventSurpriseRemovePendingOverload(); + + // + // The surprise remove irp was pended, complete it now. The irp need not + // be present. If we failed before the surprise irp was sent and the irp + // arrived in the middle of processing the failure, we could have completed + // the s.r. irp in FailedWaitForRemove, which is OK. + // + This->PnpFinishProcessingIrp(FALSE); + + // + // Return back to the failed state where will wait for remove + // + return WdfDevStatePnpFailedWaitForRemove; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedStarted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device failed (probably somewhere in the start path) and got another start + request. Fail the start and return to the state where we will wait for a + remove irp. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpFailedWaitForRemove + + --*/ +{ + // + // Complete the pended start irp with error + // + This->SetPendingPnpIrpStatus(STATUS_INVALID_DEVICE_STATE); + This->PnpFinishProcessingIrp(); + + return WdfDevStatePnpFailedWaitForRemove; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFailedInit( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Processing of the start irp's resources failed. Complete the start irp. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + // + // Release the power thread that we may have previously acquired in + // HardwareAvailable. + // + This->ReleasePowerThread(); + + // + // Deref the reenumeration interface + // + This->ReleaseReenumerationInterface(); + + This->PnpFinishProcessingIrp(); + + return WdfDevStatePnpInit; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventPdoInitFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The driver failed EvtDeviceSoftwareInit. Run cleanup and die. + +Arguments: + This - instance of the state machine + +Return Value: + new device pnp state + + --*/ +{ + COVERAGE_TRAP(); + + + This->m_Device->EarlyDispose(); + + // + // All the children are in the disposed state, destroy them all. m_Device + // is not destroyed in this call. + // + + This->m_Device->DestroyChildren(); + + return WdfDevStatePnpFinal; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRestart( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + A start to start transition has occurred. Go through the normal stop path + first and then restart things. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStateNull or new machine state + + --*/ +{ + // + // Stop the power policy machine so that we simulate stopping first + // + This->PnpPowerPolicyStop(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRestartReleaseHardware( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Release the hardware resources and send the start irp down the stack + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + NTSTATUS status; + + status = This->PnpReleaseHardware(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceReleaseHardware failed with %!STATUS!", status); + + COVERAGE_TRAP(); + + This->SetInternalFailure(); + This->SetPendingPnpIrpStatus(status); + + return WdfDevStatePnpFailed; + } + + if (This->PnpSendStartDeviceDownTheStackOverload() == FALSE) { + // + // The start irp's completion routine will move the state machine into + // the new state. + // + return WdfDevStatePnpNull; + } + + // + // Start happened synchronously. Transition to the new state now. + // + return WdfDevStatePnpRestartHardwareAvailable; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRestartHardwareAvailable( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Prepare the hardware and restart the power and power policy state machines + after a successful start -> start transition where the start irp is coming + up the stack. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + NTSTATUS status; + BOOLEAN matched; + + status = This->PnpPrepareHardware(&matched); + + if (!NT_SUCCESS(status)) { + if (matched == FALSE) { + // + // Wait for the remove irp to come in + // + COVERAGE_TRAP(); + return WdfDevStatePnpFailed; + } + else { + // + // EvtDevicePrepareHardware is what failed, goto a state where we + // undo that call. + // + COVERAGE_TRAP(); + return WdfDevStatePnpFailedOwnHardware; + } + } + + This->PnpPowerPolicyStart(); + + return WdfDevStatePnpNull; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventPdoRestart( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The PDO was in the removed state has received another start irp. Reset state + and then move into the start sequence. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePnpHardwareAvailable + + --*/ +{ + // + // Since this is a PDO and it is being restarted, it could have had an internal + // failure during its previous start. Since we use m_InternalFailure to set + // PNP_DEVICE_FAILED when handling IRP_MN_QUERY_PNP_DEVICE_STATE, it should + // be set to FALSE so we don't immediately fail the device after the start + // has been succeeded. + // + This->m_InternalFailure = FALSE; + This->m_Failed = FALSE; + + // + // The PDO is being restarted and could have previous had a power thread + // running. If so, the reference count goes to zero when removed from a + // started state. Reset back to 1. + // + This->m_PowerThreadInterfaceReferenceCount = 1; + + // + // The count is decremented on the initial started->removed transition (and + // not subsequent removed -> removed transitiosn). On removed -> restarted, + // we need to set the count back to a bias of 1 so when we process the remove + // again we can know if there are any pending child (of this PDO) removals + // that we must wait for. + // + This->m_PendingChildCount = 1; + + // + // Reset WMI state + // + This->m_Device->m_PkgWmi->ResetStateForPdoRestart(); + + + This->m_Device->m_PkgIo->ResetStateForRestart(); + + if (This->IsPowerPolicyOwner()) { + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Reset(); + } + + // + // Set STATUS_SUCCESS in the irp so that the stack will start smoothly after + // we have powered up. + // + This->SetPendingPnpIrpStatus(STATUS_SUCCESS); + + // + // This flag is set on the wake-enabled device powering down path, + // but if the device power down failed it may not have been cleared. + // + This->m_WakeInterruptsKeepConnected = FALSE; + + + // + // This flag is cleared so we can reacquire the start time and state + // + This->m_AchievedStart = FALSE; + + return WdfDevStatePnpHardwareAvailable; +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventRemovedChildrenRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + All of this device's previously enumerated children have been removed. Move + the state machine into its next state based on the device's role. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + return This->PnpGetPostRemoveState(); +} + +WDF_DEVICE_PNP_STATE +FxPkgPnp::PnpEventFinal( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The final resting and dead state for the FxDevice that has been removed. We + release our final reference here and destroy the object. + +Arguments: + This - This instance of the state machine + +Return Value: + WdfDevStatePnpNull + + --*/ +{ + NTSTATUS status; + + // + // We may not have a pnp irp at this stage (esp for PDO which are in the + // removed state and whose parent is being removed) so we use the function + // pointer as the unique tag. + // + // IoReleaseRemoveLockAndWait requires an outstanding reference to release, + // so acquire it before calling it if we are in the case where the PDO is + // being removed with no outstanding PNP remove irp b/c the parent is being + // removed. + // + if (This->m_DeviceRemoveProcessed == NULL) { + status = Mx::MxAcquireRemoveLock( + This->m_Device->GetRemoveLock(), + &FxPkgPnp::PnpEventFinal); + + ASSERT(NT_SUCCESS(status)); + UNREFERENCED_PARAMETER(status); + } + + // + // Indicate to the parent device that we are removed now (vs the destructor + // of the object where we would never reach because in the case of the PDO + // being removed b/c the parent is going away, the parent has a reference + // on the PDO). + + + + + + + + if (This->m_Device->m_ParentWaitingOnChild) { + (This->m_Device->m_ParentDevice->m_PkgPnp)->ChildRemoved(); + } + + + if (This->m_DeviceRemoveProcessed == NULL) { + // + // We can get into this state w/out an event to set when a PDO (this + // device) is in the removed state and then the parent is removed. + // + + // + // After this is called, any irp dispatched to FxDevice::DispatchWithLock + // will fail with STATUS_INVALID_DEVICE_REQUEST. + // + Mx::MxReleaseRemoveLockAndWait( + This->m_Device->GetRemoveLock(), + &FxPkgPnp::PnpEventFinal); + + // + // Delete the object when we exit the state machine. Dispose was run + // early in a previous state. + // + This->m_PnpMachine.SetDelayedDeletion(); + } + else { + // + // The thread which received the pnp remove irp will delete the device + // + This->m_SetDeviceRemoveProcessed = TRUE; + } + + return WdfDevStatePnpNull; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpEnableInterfacesAndRegisterWmi( + VOID + ) +/*++ + +Routine Description: + Enables all of the device interfaces and then registers wmi. + +Arguments: + None + +Return Value: + NT_SUCCESS if all goes well, !NT_SUCCESS otherwise + + --*/ +{ + PSINGLE_LIST_ENTRY ple; + NTSTATUS status; + + status = STATUS_SUCCESS; + + // + // Enable any device interfaces. + // + m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals()); + + m_DeviceInterfacesCanBeEnabled = TRUE; + + for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { + FxDeviceInterface *pDeviceInterface; + + pDeviceInterface = FxDeviceInterface::_FromEntry(ple); + + + + + + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // By this time, the device interface, no matter what the WDFDEVICE role + // will have been registered. + // + ASSERT(pDeviceInterface->m_SymbolicLinkName.Buffer != NULL); +#endif + pDeviceInterface->SetState(TRUE); + + status = STATUS_SUCCESS; + } + + m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals()); + + if (NT_SUCCESS(status)) { + status = m_Device->WmiPkgRegister(); + } + + if (!NT_SUCCESS(status)) { + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + } + + return status; +} + +__drv_when(!NT_SUCCESS(return), __drv_arg(ResourcesMatched, _Must_inspect_result_)) +NTSTATUS +FxPkgPnp::PnpPrepareHardware( + __inout PBOOLEAN ResourcesMatched + ) +/*++ + +Routine Description: + Matches the PNP resources with the WDFINTERRUPT objects registered and then + calls EvtDevicePrepareHardware. All start paths call this function + +Arguments: + ResourcesMatched - indicates to the caller what stage failed if !NT_SUCCESS + is returned + +Return Value: + NT_SUCCESS if all goes well, !NT_SUCCESS if failure occurrs + + --*/ +{ + NTSTATUS status; + *ResourcesMatched = FALSE; + + // + // FxPnpStateRemoved: + // Mark the device a not removed. This is just so that anybody sending + // a PnP IRP_MN_QUERY_DEVICE_STATE gets a reasonable answer. + // + // FxPnpStateFailed, FxPnpStateResourcesChanged: + // Both of these values can be set to true and cause another start to + // be sent down the stack. Reset these values back to false. If there is + // a need to set these values, the driver can set them in + // EvtDevicePrepareHardware. + // + m_PnpStateAndCaps.Value &= ~(FxPnpStateRemovedMask | + FxPnpStateFailedMask | + FxPnpStateResourcesChangedMask); + m_PnpStateAndCaps.Value |= (FxPnpStateRemovedUseDefault | + FxPnpStateFailedUseDefault | + FxPnpStateResourcesChangedUseDefault); + + // + // This will parse the resources and setup all the WDFINTERRUPT handles + // + status = PnpMatchResources(); + + if (!NT_SUCCESS(status)) { + *ResourcesMatched = FALSE; + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + return status; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // Build register resource table + // + status = m_Resources->BuildRegisterResourceTable(); + if (!NT_SUCCESS(status)) { + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + goto exit; + } + + // + // Build Port resource table + // + status = m_Resources->BuildPortResourceTable(); + if (!NT_SUCCESS(status)) { + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + goto exit; + } + + // + // We keep track if the device has any connection resources, + // in which case we allow unrestricted access to interrupts + // regardless of the UmdfDirectHardwareAccess directive. + // + status = m_Resources->CheckForConnectionResources(); + if (!NT_SUCCESS(status)) { + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + goto exit; + } +#endif + + *ResourcesMatched = TRUE; + + m_Device->SetCallbackFlags( + FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE + ); + + status = m_DevicePrepareHardware.Invoke(m_Device->GetHandle(), + m_ResourcesRaw->GetHandle(), + m_Resources->GetHandle()); + + m_Device->ClearCallbackFlags( + FXDEVICE_CALLBACK_IN_PREPARE_HARDWARE + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDevicePrepareHardware failed %!STATUS!", status); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDevicePrepareHardware returned an invalid status " + "STATUS_NOT_SUPPORTED"); + + if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + goto exit; + } + + // + // Now that we have assigned the resources to all the interrupts, figure out + // the highest synch irql for each interrupt set which shares a spinlock. + // + PnpAssignInterruptsSyncIrql(); + + // + // Do mode-specific work. For KMDF, there is nothing additional to do. + // + status = PnpPrepareHardwareInternal(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "PrepareHardware failed %!STATUS!", status); + + SetInternalFailure(); + SetPendingPnpIrpStatus(status); + } + +exit: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpReleaseHardware( + VOID + ) +/*++ + +Routine Description: + Invokes the driver's release hardware callback if present. + Releases any interrupt resources allocated during the prepare hardware callback. + +Arguments: + None + +Return Value: + Driver's release hardware callback return status or + STATUS_SUCCESS if callback is not present. + + --*/ +{ + NTSTATUS status; + FxInterrupt* interrupt; + PLIST_ENTRY le; + + // + // Invoke the device's release hardware callback. + // + status = m_DeviceReleaseHardware.Invoke( + m_Device->GetHandle(), + m_Resources->GetHandle()); + + if (status == STATUS_NOT_SUPPORTED) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceReleaseHardware returned an invalid status " + "STATUS_NOT_SUPPORTED"); + + if (GetDriverGlobals()->IsVerificationEnabled(1, 11, OkForDownLevel)) { + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + if (NT_SUCCESS(status)) { + // + // make sure driver has unmapped its resources + // + m_Resources->ValidateResourceUnmap(); + } + + // + // delete the register and port resource tables + // + m_Resources->DeleteRegisterResourceTable(); + m_Resources->DeletePortResourceTable(); +#endif + + // + // Delete all interrupt objects that were created in the prepare hardware + // callback that the driver did not explicitly delete (in reverse order). + // + le = m_InterruptListHead.Blink; + + while(le != &m_InterruptListHead) { + + // Find the interrupt object pointer. + interrupt = CONTAINING_RECORD(le, FxInterrupt, m_PnpList); + + // Advance the entry before it becomes invalid. + le = le->Blink; + + // Let the interrupt know that 'release hardware' was called. + interrupt->OnPostReleaseHardware(); + } + + return status; +} + +VOID +FxPkgPnp::PnpPowerPolicyStart( + VOID + ) +/*++ + +Routine Description: + Informs the power policy state machine that it should start. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PowerPolicyProcessEvent(PwrPolStart); +} + +VOID +FxPkgPnp::PnpPowerPolicyStop( + VOID + ) +/*++ + +Routine Description: + Informs the power and power policy state machines that they should stop. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PowerPolicyProcessEvent(PwrPolStop); +} + +VOID +FxPkgPnp::PnpPowerPolicySurpriseRemove( + VOID + ) +/*++ + +Routine Description: + Informs the policy state machines that it should stop due to the hardware + being surprise removed. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PowerPolicyProcessEvent(PwrPolSurpriseRemove); +} + +VOID +FxPkgPnp::PnpPowerPolicyRemove( + VOID + ) +/*++ + +Routine Description: + Informs the policy state machine that it should prepare for device removal. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PowerPolicyProcessEvent(PwrPolRemove); +} + +VOID +FxPkgPnp::PnpFinishProcessingIrp( + __in BOOLEAN IrpMustBePresent + ) +/*++ + +Routine Description: + Finishes handling a pended pnp irp + +Arguments: + None + +Return Value: + None + + --*/ +{ + FxIrp irp; + + UNREFERENCED_PARAMETER(IrpMustBePresent); + ASSERT(IrpMustBePresent == FALSE || IsPresentPendingPnpIrp()); + + // + // Start device is the only request we handle on the way back up the stack. + // Also, if we fail any pnp irps that we are allowed to fail, we just + // complete them. + // + if (IsPresentPendingPnpIrp()) { + + irp.SetIrp(GetPendingPnpIrp()); + if (irp.GetMinorFunction() == IRP_MN_START_DEVICE + || + !NT_SUCCESS(irp.GetStatus())) { + + irp.SetIrp(ClearPendingPnpIrp()); + CompletePnpRequest(&irp, irp.GetStatus()); + } + else { + m_PnpMachine.m_FireAndForget = TRUE; + } + } +} + +VOID +FxPkgPnp::PnpDisableInterfaces( + VOID + ) +/*++ + +Routine Description: + Disables all of the registerd interfaces on the device. + +Arguments: + None + +Return Value: + None + + --*/ +{ + PSINGLE_LIST_ENTRY ple; + + m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals()); + + m_DeviceInterfacesCanBeEnabled = FALSE; + + for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { + + FxDeviceInterface *pDeviceInterface; + pDeviceInterface = FxDeviceInterface::_FromEntry(ple); + pDeviceInterface->SetState(FALSE); + } + + m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals()); +} + +VOID +FxPkgPnp::PnpEventSurpriseRemovePendingOverload( + VOID + ) +{ + + // + // Mark all of the children as missing because the parent has just been + // removed. Note that this will happen after all of the children have + // already received the surprise remove event. This is OK because the + // reported status is inspected during the remove device event which will + // happen after the parent finishes processing the surprise event. + // + if (m_EnumInfo != NULL) { + m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); + FxTransactionedEntry* ple; + + ple = NULL; + while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { + FxChildList::_FromEntry(ple)->NotifyDeviceSurpriseRemove(); + } + + m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PnpMatchResources( + VOID + ) +/*++ + +Routine Description: + + This method is called in response to a PnP StartDevice IRP + coming up the stack. It: + + - Captures the device's resources + - Calls out to interested resource objects + - Sends an event to the PnP state machine + +Arguemnts: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ +{ + PCM_RESOURCE_LIST pResourcesRaw; + PCM_RESOURCE_LIST pResourcesTranslated; + FxResourceCm* resCmRaw; + FxResourceCm* resCmTrans; + FxInterrupt* interrupt; + PLIST_ENTRY ple; + NTSTATUS status; + FxCollectionEntry *curRaw, *curTrans, *endTrans; + ULONG messageCount; + FxIrp irp; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering PnpMatchResources"); + + // + // We must clear these flags before calling into the event handler because + // it might set these states back (which is OK). If we don't clear these + // states and the start succeeds, we would endlessly report that our + // resources have changed and be restarted over and over. + // + m_PnpStateAndCaps.Value &= ~(FxPnpStateFailedMask | + FxPnpStateResourcesChangedMask); + m_PnpStateAndCaps.Value |= (FxPnpStateFailedUseDefault | + FxPnpStateResourcesChangedUseDefault); + + irp.SetIrp(m_PendingPnPIrp); + pResourcesRaw = irp.GetParameterAllocatedResources(); + pResourcesTranslated = irp.GetParameterAllocatedResourcesTranslated(); + + status = m_ResourcesRaw->BuildFromWdmList(pResourcesRaw, FxResourceNoAccess); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate raw resource list for WDFDEVICE 0x%p, %!STATUS!", + m_Device->GetHandle(), status); + goto Done; + } + + status = m_Resources->BuildFromWdmList(pResourcesTranslated, FxResourceNoAccess); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate translated resource list for WDFDEVICE 0x%p, %!STATUS!", + m_Device->GetHandle(), status); + goto Done; + } + + // + // reset the stored information in all interrupts in the rebalance case + // + for (ple = m_InterruptListHead.Flink; + ple != &m_InterruptListHead; + ple = ple->Flink) { + interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + interrupt->Reset(); + } + + // + // Now iterate across the resources, looking for ones that correspond + // to objects that we are managing. Tell those objects about the resources + // that were assigned. + // + ple = &m_InterruptListHead; + + endTrans = m_Resources->End(); + + for (curTrans = m_Resources->Start(), curRaw = m_ResourcesRaw->Start(); + curTrans != endTrans; + curTrans = curTrans->Next(), curRaw = curRaw->Next()) { + + ASSERT(curTrans->m_Object->GetType() == FX_TYPE_RESOURCE_CM); + ASSERT(curRaw->m_Object->GetType() == FX_TYPE_RESOURCE_CM); + + resCmRaw = (FxResourceCm*) curRaw->m_Object; + + if (resCmRaw->m_Descriptor.Type == CmResourceTypeInterrupt) { + // + // We're looking at an interrupt resource. + // + if (ple->Flink == &m_InterruptListHead) { + // + // Oops, there are no more interrupt objects. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Not enough interrupt objects created by WDFDEVICE 0x%p", + m_Device->GetHandle()); + break; + } + + resCmTrans = (FxResourceCm*) curTrans->m_Object; + ASSERT(resCmTrans->m_Descriptor.Type == CmResourceTypeInterrupt); + + messageCount = resCmRaw->m_Descriptor.u.MessageInterrupt.Raw.MessageCount; + + if (FxInterrupt::_IsMessageInterrupt(resCmTrans->m_Descriptor.Flags) + && + (messageCount > 1)) { + ULONG i; + // + // Multi-message MSI 2.2 needs to be handled differently + // + for (i = 0, ple = ple->Flink; + i < messageCount && ple != &m_InterruptListHead; + i++, ple = ple->Flink) { + + // + // Get the next interrupt object. + // + interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + + // + // Tell the interrupt object what its resources are. + // + interrupt->AssignResources(&resCmRaw->m_Descriptor, + &resCmTrans->m_Descriptor); + } + } + else { + // + // This is either MSI2.2 with 1 message, MSI-X or Line based. + // + ple = ple->Flink; + interrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + + // + // Tell the interrupt object what its resources are. + // + interrupt->AssignResources(&resCmRaw->m_Descriptor, + &resCmTrans->m_Descriptor); + } + } + } + +#if FX_IS_KERNEL_MODE + + + + + + + + + + // + // If there are any pended I/Os that were sent to the target + // that were pended in the transition to stop, then this will + // resend them. + // + // ISSUE: This has the potential of I/O completing + // before the driver's start callback has been called...but, + // this is the same as the PDO pending a sent irp and completing + // it when the PDO is restarted before the FDO has a change to + // process the start irp which was still pended below. + // + if (m_Device->IsFilter()) { + // + // If this is a filter device, then copy the FILE_REMOVABLE_MEDIA + // characteristic from the lower device. + // + if (m_Device->GetAttachedDevice()->Characteristics & FILE_REMOVABLE_MEDIA) { + ULONG characteristics; + + characteristics = + m_Device->GetDeviceObject()->Characteristics | FILE_REMOVABLE_MEDIA; + + m_Device->GetDeviceObject()->Characteristics = characteristics; + } + + + + + + + + + + + m_Device->SetFilterIoType(); + } + +#endif // FX_IS_KERNEL_MODE + +Done: + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Exiting PnpMatchResources %!STATUS!", status); + + return status; +} + +VOID +FxPkgPnp::PnpAssignInterruptsSyncIrql( + VOID + ) +/*++ + +Routine Description: + Figure out the highest synch irql for each interrupt set which shares a + spinlock. + + foreach(interrupt assigned to this instance) + determine the max sync irql in the set + set all the associated interrupts to the sync irql + set the sync irql on the first interrupt in the set + +Arguments: + None + +Return Value: + None + + --*/ +{ + PLIST_ENTRY ple; + FxInterrupt* pInterrupt; + + for (ple = m_InterruptListHead.Flink; + ple != &m_InterruptListHead; + ple = ple->Flink) { + + KIRQL syncIrql; + + pInterrupt = CONTAINING_RECORD(ple, FxInterrupt, m_PnpList); + + syncIrql = pInterrupt->GetResourceIrql(); + + if (syncIrql == PASSIVE_LEVEL) { + // + // The irql associated with the resources assigned is passive, + // this can happen in the following scenarios: + // + // (1) no resources were assigned. Skip this interrupt b/c it has + // no associated resources. Note: setting the SynchronizeIrql + // to PASSIVE_LEVEL is a no-op. + // + // (2) this interrupt is handled at passive-level. + // Set SynchronizeIrql to passive-level and continue. + // + pInterrupt->SetSyncIrql(PASSIVE_LEVEL); + continue; + } + + if (pInterrupt->IsSharedSpinLock() == FALSE) { + // + // If the interrupt spinlock is not shared, it's sync irql is the + // irql assigned to it in the resources. + // + pInterrupt->SetSyncIrql(syncIrql); + } + else if (pInterrupt->IsSyncIrqlSet() == FALSE) { + FxInterrupt* pFwdInterrupt; + PLIST_ENTRY pleFwd; + + // + // Find all of the other interrupts which share the lock and compute + // the max sync irql. + // + for (pleFwd = ple->Flink; + pleFwd != &m_InterruptListHead; + pleFwd = pleFwd->Flink) { + + pFwdInterrupt = CONTAINING_RECORD(pleFwd, FxInterrupt, m_PnpList); + + // + // If the 2 do not share the same lock, they are not in the same + // set. + // + if (pFwdInterrupt->SharesLock(pInterrupt) == FALSE) { + continue; + } + + if (pFwdInterrupt->GetResourceIrql() > syncIrql) { + syncIrql = pFwdInterrupt->GetResourceIrql(); + } + } + + // + // Now that we found the max sync irql, set it for all interrupts in + // the set which share the lock + // + for (pleFwd = ple->Flink; + pleFwd != &m_InterruptListHead; + pleFwd = pleFwd->Flink) { + + pFwdInterrupt = CONTAINING_RECORD(pleFwd, FxInterrupt, m_PnpList); + + // + // If the 2 do not share the same lock, they are not in the same + // set. + // + if (pFwdInterrupt->SharesLock(pInterrupt) == FALSE) { + continue; + } + + pFwdInterrupt->SetSyncIrql(syncIrql); + } + + // + // Set the sync irql for the first interrupt in the set. We have set + // the sync irql for all other interrupts in the set. + // + pInterrupt->SetSyncIrql(syncIrql); + } + else { + // + // If IsSyncIrqlSet is TRUE, we already covered this interrupt in a + // previous pass of this loop when we computed the max sync irql for + // an interrupt set. + // + ASSERT(pInterrupt->GetSyncIrql() > PASSIVE_LEVEL); + DO_NOTHING(); + } + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::ValidateCmResource( + __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR* CmResourceRaw, + __inout PCM_PARTIAL_RESOURCE_DESCRIPTOR* CmResource + ) +/*++ + +Routine Description: + Makes sure the specified resource is valid. + +Arguments: + CmResourceRaw - the raw resource to validate. + CmResource - the translated resources to validate. + +Return Value: + STATUS_SUCCESS if resource is valid or + NTSTATUS error. + + --*/ +{ + NTSTATUS status; + FxCollectionEntry* cur; + FxCollectionEntry* curRaw; + FxResourceCm* res; + FxResourceCm* resRaw; + PFX_DRIVER_GLOBALS fxDriverGlobals; + + ASSERT(m_ResourcesRaw != NULL); + ASSERT(m_Resources != NULL); + + res = NULL; + resRaw = NULL; + + fxDriverGlobals = GetDriverGlobals(); + + // + // Find the resource in our list. + // + for (cur = m_Resources->Start(), curRaw = m_ResourcesRaw->Start(); + cur != m_Resources->End(); + cur = cur->Next(), curRaw = curRaw->Next()) { + + res = (FxResourceCm*) cur->m_Object; + resRaw = (FxResourceCm*) curRaw->m_Object; + + if (&res->m_DescriptorClone == *CmResource) { + break; + } + } + + // + // Error out if not found. + // + if (cur == m_Resources->End()) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " + "WDFDEVICE 0x%p, %!STATUS!", + *CmResource, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Error out if the associated raw resource is not the same. + // + if (&resRaw->m_DescriptorClone != *CmResourceRaw) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " + "WDFDEVICE 0x%p, %!STATUS!", + *CmResourceRaw, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Make sure driver didn't change any of the PnP settings. + // + if (sizeof(res->m_Descriptor) != + RtlCompareMemory(&res->m_DescriptorClone, + &res->m_Descriptor, + sizeof(res->m_Descriptor))) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " + "driver cannot change the assigned PnP resources, WDFDEVICE 0x%p, " + "%!STATUS!", + *CmResource, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + if (sizeof(resRaw->m_Descriptor) != + RtlCompareMemory(&resRaw->m_DescriptorClone, + &resRaw->m_Descriptor, + sizeof(resRaw->m_Descriptor))) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not valid, " + "driver cannot change the assigned PnP resources, WDFDEVICE 0x%p, " + "%!STATUS!", + *CmResourceRaw, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Return the real descriptor. + // + ASSERT(res != NULL && resRaw != NULL); + *CmResource = &res->m_Descriptor; + *CmResourceRaw = &resRaw->m_Descriptor; + + status = STATUS_SUCCESS; + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::ValidateInterruptResourceCm( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResourceRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmIntResource, + __in PWDF_INTERRUPT_CONFIG Configuration + ) +/*++ + +Routine Description: + Makes sure the specified resource is valid for an interrupt resource. + +Arguments: + CmIntResourceRaw - the raw interrupt resource to validate. + CmIntResource - the translated interrupt resource to validate. + +Return Value: + STATUS_SUCCESS if resource is valid or + NTSTATUS error. + + --*/ +{ + NTSTATUS status; + PLIST_ENTRY le; + FxInterrupt* interrupt; + ULONG messageCount; + PFX_DRIVER_GLOBALS fxDriverGlobals; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmIntResourceRaw; + PCM_PARTIAL_RESOURCE_DESCRIPTOR cmIntResource; + + cmIntResourceRaw = CmIntResourceRaw; + cmIntResource = CmIntResource; + fxDriverGlobals = GetDriverGlobals(); + + // + // Get the real descriptor not the copy. + // + status = ValidateCmResource(&cmIntResourceRaw, &cmIntResource); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Make sure this is an interrupt resource. + // + if (cmIntResourceRaw->Type != CmResourceTypeInterrupt) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The raw PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not an " + "interrupt resource, WDFDEVICE 0x%p, %!STATUS!", + CmIntResourceRaw, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + if (cmIntResource->Type != CmResourceTypeInterrupt) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "The translated PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p is not an " + "interrupt resource, WDFDEVICE 0x%p, %!STATUS!", + CmIntResource, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + // + // Make sure resource was not claimed by another interrupt. + // Multi-message MSI 2.2 interrupts: allowed to reuse claimed resources. + // Driver must create them sequentially. + // Line-based interrupts: allowed to reuse claimed resources. + // Driver can create them out-of-order. + // Other MSI: not allowed to reuse claimed resources. + // + messageCount = 0; + + for (le = m_InterruptListHead.Flink; + le != &m_InterruptListHead; + le = le->Flink) { + + interrupt = CONTAINING_RECORD(le, FxInterrupt, m_PnpList); + + if (cmIntResource != interrupt->GetResources()) { + // + // Multi-message MSI 2.2 interrupts must be sequential. + // + if (messageCount != 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Multi-message MSI 2.2 interrupts must be created " + "sequentially, WDFDEVICE 0x%p, %!STATUS!", + m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + + continue; + } + + if (interrupt->IsWakeCapable() && + Configuration->PassiveHandling) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used " + "to create a wakable interrupt 0x%p, WDFDEVICE 0x%p and " + "any functional interrupt being shared with wakable interrupt " + "can not use passive level handling", + CmIntResource, interrupt->GetHandle(), + m_Device->GetHandle()); + status = STATUS_INVALID_PARAMETER; + goto Done; + } + + if (interrupt->IsPassiveHandling() && + Configuration->CanWakeDevice) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used " + "to create a passive level interrupt 0x%p, WDFDEVICE 0x%p and " + "is now being used to create a wakable interrupt. A functional " + "passive level interrupt can not be shared with wakable interrupt", + CmIntResource, interrupt->GetHandle(), + m_Device->GetHandle()); + status = STATUS_INVALID_PARAMETER; + goto Done; + } + + // + // Check for multi-message MSI 2.2 interrupts. These are allowed + // to use the same resource. + // We allow line based interrupts to reuse claimed resources. + // + if (FxInterrupt::_IsMessageInterrupt(cmIntResource->Flags) == FALSE) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGPNP, + "The PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p was already used " + "to create interrupt 0x%p, WDFDEVICE 0x%p", + CmIntResource, interrupt->GetHandle(), + m_Device->GetHandle()); + continue; + } + + // + // Only allow the correct # of messages. + // + messageCount++; + if (messageCount > + cmIntResourceRaw->u.MessageInterrupt.Raw.MessageCount) { + + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "All the MSI 2.2 interrupts for " + "PCM_PARTIAL_RESOURCE_DESCRIPTOR 0x%p are already created, " + "WDFDEVICE 0x%p, %!STATUS!", + CmIntResource, m_Device->GetHandle(), status); + FxVerifierDbgBreakPoint(fxDriverGlobals); + goto Done; + } + } + + status = STATUS_SUCCESS; + +Done: + return status; +} + +#define RESTART_START_ACHIEVED_NAME L"StartAchieved" +#define RESTART_START_TIME_NAME L"StartTime" +#define RESTART_COUNT_NAME L"Count" + +const PWCHAR FxPkgPnp::m_RestartStartAchievedName = RESTART_START_ACHIEVED_NAME; +const PWCHAR FxPkgPnp::m_RestartStartTimeName = RESTART_START_TIME_NAME; +const PWCHAR FxPkgPnp::m_RestartCountName = RESTART_COUNT_NAME; + +const ULONG FxPkgPnp::m_RestartTimePeriodMaximum = 60; +const ULONG FxPkgPnp::m_RestartCountMaximum = 5; + +BOOLEAN +FxPkgPnp::PnpIncrementRestartCountLogic( + _In_ HANDLE RestartKey, + _In_ BOOLEAN CreatedNewKey + ) +/*++ + +Routine Description: + This routine determines if this device should ask the bus driver to + reenumerate the device. This is determined by how many times the entire + stack has asked for a restart within a given period. This is stack wide + because the settings are stored in a key in the device node itself (which all + devices share). + + The period and number of times a restart are attempted are defined as constants + (m_RestartTimePeriodMaximum, m_RestartCountMaximum)in this class. They are + current defined as a period of 60 seconds and a restart max count of 5. + + The settings are stored in a volatile key so that they do not persist across + machine reboots. Persisting across reboots makes no sense if we restrict the + number of restarts w/in a period. + + The rules are as follows + 1) if the key does not exist, treat this as the beginning of the period + and ask for a reenumeration + 2) if the key exists + a) if the beginning of the period and the restart count cannot be read + do not ask for a reenumeration + b) if the beginning of the period is after the current time, either the + current tick count has wrapped or the key has somehow survived a + reboot. Either way, treat this as a reset of the period and ask + for a reenumeration + c) if the current time is after the period start time and within the + restart period, increment the restart count. if the count is <= + the max restart count, ask for a reenumeration. If it exceeds the + max, do not ask for a reenumeration. + d) if the current time is after the period stat time and exceeds the + maximum period, and if the device as reached the started state, + reset the period, count, and started state, then ask for a + reenumeration. + +Considerations: + There is a reenumeration loop that a device can get caught in. If a device + takes more than m_RestartTimePeriodMaximum to fail m_RestartCountMaximum + times then the device will be caught in this loop. If it is failing on the + way to PnpEventStarted then the device will likely cause a 9F bugcheck. + This is because they hold a power lock while in this loop. If the device + fails after PnpEventStarted then pnp can progress and the device can loop + here indefinitely. We have shipped with this behavior for several releases, + so we are hesitant to completely change this behavior. The concern is that + a device out there relies on this behavior. + +Arguments: + RestartKey - opened handle to the Restart registry key + CreatedNewKey - TRUE if the Restart key was created just now + +Return Value: + TRUE if a restart should be requested. + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG count; + LARGE_INTEGER currentTickCount, startTickCount; + BOOLEAN started, writeTick, writeCount, writeStarted; + + DECLARE_CONST_UNICODE_STRING(valueNameStartTime, RESTART_START_TIME_NAME); + DECLARE_CONST_UNICODE_STRING(valueNameCount, RESTART_COUNT_NAME); + DECLARE_CONST_UNICODE_STRING(valueNameStartAchieved, RESTART_START_ACHIEVED_NAME); + + count = 0; + started = FALSE; + writeTick = FALSE; + writeCount = FALSE; + writeStarted = FALSE; + + Mx::MxQueryTickCount(¤tTickCount); + + started = m_AchievedStart; + if (started) { + // + // Save the fact the driver started without failing + // + writeStarted = TRUE; + } + + + // + // If the key was created right now, there is nothing to check, just write out + // the data. + // + if (CreatedNewKey) { + writeTick = TRUE; + writeCount = TRUE; + + // + // First restart + // + count = 1; + } + else { + ULONG length, type; + + // + // First try to get the start time of when we first attempted a restart + // + status = FxRegKey::_QueryValue(GetDriverGlobals(), + RestartKey, + &valueNameStartTime, + sizeof(startTickCount.QuadPart), + &startTickCount.QuadPart, + &length, + &type); + + if (NT_SUCCESS(status) && + length == sizeof(startTickCount.QuadPart) && type == REG_BINARY) { + + // + // Now try to get the last restart count + // + status = FxRegKey::_QueryULong(RestartKey, + &valueNameCount, + &count); + + if (status == STATUS_OBJECT_NAME_NOT_FOUND) { + // + // We read the start time, but not the count. Assume there was + // at least one previous restart. + // + count = 1; + status = STATUS_SUCCESS; + } + } + + if (NT_SUCCESS(status)) { + if (currentTickCount.QuadPart < startTickCount.QuadPart) { + // + // Somehow the key survived a reboot or the clock overflowed + // and the current time is less then the last time we started + // timing restarts. Either way, just treat this as the first + // time we are restarting. + // + writeTick = TRUE; + writeCount = TRUE; + count = 1; + } + else { + LONGLONG delta; + + // + // Compute the difference in time in 100 ns units + // + delta = (currentTickCount.QuadPart - startTickCount.QuadPart) * + Mx::MxQueryTimeIncrement(); + + if (delta <= WDF_ABS_TIMEOUT_IN_SEC(m_RestartTimePeriodMaximum)) { + // + // We are within the time limit, see if we are within the + // count limit + count++; + + // + // The count starts at one, so include the maximum in the + // compare. + // + if (count <= m_RestartCountMaximum) { + writeCount = TRUE; + } + else { + // + // Exceeded the restart count, do not attempt to restart + // the device. + // + status = STATUS_UNSUCCESSFUL; + } + } + else { + if (started == FALSE) { + ULONG length, type, value; + status = FxRegKey::_QueryValue(GetDriverGlobals(), + RestartKey, + &valueNameStartAchieved, + sizeof(value), + &value, + &length, + &type); + if (!NT_SUCCESS(status) || length != sizeof(value) || + type != REG_DWORD) { + value = 0; + } + started = value != 0; + status = STATUS_SUCCESS; + } + + if (started) { + // + // Exceeded the time limit. This is treated as a reset of + // the time limit, so we will try to restart and reset the + // start time and restart count. + // + writeTick = TRUE; + writeCount = TRUE; + count = 1; + + // + // Erase the fact the driver once started and + // make it do it again to get another 5 attempts to + // restart. + // + writeStarted = TRUE; + started = FALSE; + } + else { + // + // Device never started + // + status = STATUS_UNSUCCESSFUL; + } + } + } + } + } + + if (writeTick) { + // + // Write out the time and the count + // + NTSTATUS status2; + status2 = FxRegKey::_SetValue(RestartKey, + (PUNICODE_STRING)&valueNameStartTime, + REG_BINARY, + ¤tTickCount.QuadPart, + sizeof(currentTickCount.QuadPart)); + // + // Don't let status report success if it was an error prior to _SetValue + // + if(NT_SUCCESS(status)) { + status = status2; + } + } + + if (NT_SUCCESS(status) && writeCount) { + status = FxRegKey::_SetValue(RestartKey, + (PUNICODE_STRING)&valueNameCount, + REG_DWORD, + &count, + sizeof(count)); + } + + if (writeStarted) { + NTSTATUS status2; + DWORD value = started; + status2 = FxRegKey::_SetValue(RestartKey, + (PUNICODE_STRING)&valueNameStartAchieved, + REG_DWORD, + &value, + sizeof(value)); + // + // Don't let status report success if it was an error prior to _SetValue + // + if(NT_SUCCESS(status)) { + status = status2; + } + } + + return NT_SUCCESS(status) ? TRUE : FALSE; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/poweridlestatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/poweridlestatemachine.cpp new file mode 100644 index 00000000000..df7bcd2db57 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/poweridlestatemachine.cpp @@ -0,0 +1,2023 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerIdleStateMachine.cpp + +Abstract: + + This module implements the Power Policy idle state machine for the driver + framework. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerIdleStateMachine.tmh" +#endif +} + +const FxPowerIdleTargetState FxPowerIdleMachine::m_StoppedStates[] = +{ + { PowerIdleEventStart, FxIdleStarted DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_StartedStates[] = +{ + { PowerIdleEventPowerUpComplete, FxIdleStartedPowerUp DEBUGGED_EVENT }, + { PowerIdleEventPowerUpFailed, FxIdleStartedPowerFailed DEBUGGED_EVENT }, + { PowerIdleEventStop, FxIdleStopped DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_DisabledStates[] = +{ + { PowerIdleEventEnabled, FxIdleCheckIoCount DEBUGGED_EVENT }, + { PowerIdleEventDisabled, FxIdleDisabled DEBUGGED_EVENT }, + { PowerIdleEventPowerDown, FxIdleGoingToDx DEBUGGED_EVENT }, + { PowerIdleEventPowerDownFailed, FxIdlePowerFailed DEBUGGED_EVENT }, + { PowerIdleEventPowerUpFailed, FxIdlePowerFailed DEBUGGED_EVENT }, + { PowerIdleEventStop, FxIdleStopped DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_BusyStates[] = +{ + { PowerIdleEventIoDecrement, FxIdleDecrementIo DEBUGGED_EVENT }, + { PowerIdleEventDisabled, FxIdleDisabled DEBUGGED_EVENT }, + { PowerIdleEventPowerDown, FxIdleGoingToDx TRAP_ON_EVENT }, + { PowerIdleEventPowerDownFailed, FxIdlePowerFailed TRAP_ON_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_TimerRunningStates[] = +{ + { PowerIdleEventDisabled, FxIdleDisabling DEBUGGED_EVENT }, + { PowerIdleEventIoIncrement, FxIdleCancelTimer DEBUGGED_EVENT }, + { PowerIdleEventEnabled, FxIdleCancelTimer DEBUGGED_EVENT }, + { PowerIdleEventTimerExpired, FxIdleTimingOut DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_TimedOutStates[] = +{ + { PowerIdleEventPowerDown, FxIdleTimedOutPowerDown DEBUGGED_EVENT }, + { PowerIdleEventPowerDownFailed, FxIdleTimedOutPowerDownFailed DEBUGGED_EVENT }, + { PowerIdleEventDisabled, FxIdleTimedOutDisabled DEBUGGED_EVENT }, + { PowerIdleEventEnabled, FxIdleTimedOutEnabled DEBUGGED_EVENT }, + { PowerIdleEventIoIncrement, FxIdleTimedOutIoIncrement DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_InDxStates[] = +{ + { PowerIdleEventPowerUpComplete, FxIdlePowerUp DEBUGGED_EVENT }, + { PowerIdleEventPowerUpFailed, FxIdleInDxPowerUpFailure DEBUGGED_EVENT }, + { PowerIdleEventPowerDownFailed, FxIdleInDxPowerUpFailure TRAP_ON_EVENT }, + { PowerIdleEventStop, FxIdleInDxStopped DEBUGGED_EVENT }, + { PowerIdleEventDisabled, FxIdleInDxDisabled DEBUGGED_EVENT }, + { PowerIdleEventIoIncrement, FxIdleInDxIoIncrement DEBUGGED_EVENT }, + { PowerIdleEventIoDecrement, FxIdleInDx DEBUGGED_EVENT }, + { PowerIdleEventPowerDown, FxIdleInDx DEBUGGED_EVENT }, + { PowerIdleEventEnabled, FxIdleInDxEnabled DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_WaitForTimeoutStates[] = +{ + { PowerIdleEventTimerExpired, FxIdleTimerExpired DEBUGGED_EVENT }, + { PowerIdleEventPowerDownFailed, FxIdlePowerFailedWaitForTimeout TRAP_ON_EVENT }, + { PowerIdleEventDisabled, FxIdleDisablingWaitForTimeout DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_DisablingWaitForTimeoutStates[] = +{ + { PowerIdleEventTimerExpired, FxIdleDisablingTimerExpired DEBUGGED_EVENT }, +}; + +const FxPowerIdleTargetState FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates[] = +{ + { PowerIdleEventTimerExpired, FxIdlePowerFailed TRAP_ON_EVENT }, +}; + +const FxIdleStateTable FxPowerIdleMachine::m_StateTable[] = +{ + // FxIdleStopped + { FxPowerIdleMachine::Stopped, + FxPowerIdleMachine::m_StoppedStates, + ARRAY_SIZE(FxPowerIdleMachine::m_StoppedStates), + }, + + // FxIdleStarted + { FxPowerIdleMachine::Started, + FxPowerIdleMachine::m_StartedStates, + ARRAY_SIZE(FxPowerIdleMachine::m_StartedStates), + }, + + // FxIdleStartedPowerUp + { FxPowerIdleMachine::StartedPowerUp, + NULL, + 0, + }, + + // FxIdleStartedPowerFailed + { FxPowerIdleMachine::StartedPowerFailed, + NULL, + 0, + }, + + // FxIdleDisabled + { FxPowerIdleMachine::Disabled, + FxPowerIdleMachine::m_DisabledStates, + ARRAY_SIZE(FxPowerIdleMachine::m_DisabledStates), + }, + + // FxIdleCheckIoCount + { FxPowerIdleMachine::CheckIoCount, + NULL, + 0, + }, + + // FxIdleBusy + { NULL, + FxPowerIdleMachine::m_BusyStates, + ARRAY_SIZE(FxPowerIdleMachine::m_BusyStates), + }, + + // FxIdleDecrementIo + { FxPowerIdleMachine::DecrementIo, + NULL, + 0, + }, + + // FxIdleStartTimer + { FxPowerIdleMachine::StartTimer, + NULL, + 0, + }, + + // FxIdleTimerRunning + { NULL, + FxPowerIdleMachine::m_TimerRunningStates, + ARRAY_SIZE(FxPowerIdleMachine::m_TimerRunningStates) + }, + + // FxIdleTimingOut + { FxPowerIdleMachine::TimingOut, + NULL, + 0, + }, + + // FxIdleTimedOut + { NULL, + FxPowerIdleMachine::m_TimedOutStates, + ARRAY_SIZE(FxPowerIdleMachine::m_TimedOutStates), + }, + + // FxIdleTimedOutIoIncrement + { FxPowerIdleMachine::TimedOutIoIncrement, + NULL, + 0, + }, + + // FxIdleTimedOutPowerDown + { FxPowerIdleMachine::TimedOutPowerDown, + NULL, + 0, + }, + + // FxIdleTimedOutPowerDownFailed + { FxPowerIdleMachine::TimedOutPowerDownFailed, + NULL, + 0, + }, + + // FxIdleGoingToDx, + { FxPowerIdleMachine::GoingToDx, + NULL, + 0, + }, + + // FxIdleInDx, + { FxPowerIdleMachine::InDx, + FxPowerIdleMachine::m_InDxStates, + ARRAY_SIZE(FxPowerIdleMachine::m_InDxStates), + }, + + // FxIdleInDxIoIncrement + { FxPowerIdleMachine::InDxIoIncrement, + NULL, + 0, + }, + + // FxIdleInDxPowerUpFailure + { FxPowerIdleMachine::InDxPowerUpFailure, + NULL, + 0, + }, + + // FxIdleInDxStopped + { FxPowerIdleMachine::InDxStopped, + NULL, + 0, + }, + + // FxIdleInDxDisabled + { FxPowerIdleMachine::InDxDisabled, + NULL, + 0, + }, + + // FxIdleInDxEnabled + { FxPowerIdleMachine::InDxEnabled, + NULL, + 0, + }, + + // FxIdlePowerUp + { FxPowerIdleMachine::PowerUp, + NULL, + 0, + }, + + // FxIdlePowerUpComplete + { FxPowerIdleMachine::PowerUpComplete, + NULL, + 0, + }, + + // FxIdleTimedOutDisabled + { FxPowerIdleMachine::TimedOutDisabled, + NULL, + 0, + }, + + // FxIdleTimedOutEnabled + { FxPowerIdleMachine::TimedOutEnabled, + NULL, + 0, + }, + + // FxIdleCancelTimer + { FxPowerIdleMachine::CancelTimer, + NULL, + 0, + }, + + // FxIdleWaitForTimeout + { NULL, + FxPowerIdleMachine::m_WaitForTimeoutStates, + ARRAY_SIZE(FxPowerIdleMachine::m_WaitForTimeoutStates), + }, + + // FxIdleTimerExpired + { FxPowerIdleMachine::TimerExpired, + NULL, + 0, + }, + + // FxIdleDisabling + { FxPowerIdleMachine::Disabling, + NULL, + 0, + }, + + // FxIdleDisablingWaitForTimeout + { NULL, + FxPowerIdleMachine::m_DisablingWaitForTimeoutStates, + ARRAY_SIZE(FxPowerIdleMachine::m_DisablingWaitForTimeoutStates), + }, + + // FxIdleDisablingTimerExpired + { FxPowerIdleMachine::DisablingTimerExpired, + NULL, + 0, + }, + + // FxIdlePowerFailedWaitForTimeout + { NULL, + FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates, + ARRAY_SIZE(FxPowerIdleMachine::m_PowerFailedWaitForTimeoutStates), + }, + + // FxIdlePowerFailed + { FxPowerIdleMachine::PowerFailed, + NULL, + 0, + }, +}; + +__inline +FxPkgPnp* +GetPnpPkg( + __inout FxPowerIdleMachine* This + ) +{ + return CONTAINING_RECORD(This, + FxPowerPolicyOwnerSettings, + m_PowerIdleMachine)->m_PkgPnp; +} + + +FxPowerIdleMachine::FxPowerIdleMachine( + VOID + ) +/*++ + +Routine Description: + Constructs the power idle state machine + +Arguments: + None + +Return Value: + None + + --*/ +{ + // + // m_Lock and m_PowerTimeoutTimer are now being initialized in Init method + // since they may fail for UM. + // + + m_PowerTimeout.QuadPart = 0; + m_CurrentIdleState = FxIdleStopped; + + m_EventHistoryIndex = 0; + m_StateHistoryIndex = 0; + + RtlZeroMemory(&m_EventHistory[0], sizeof(m_EventHistory)); + RtlZeroMemory(&m_StateHistory[0], sizeof(m_StateHistory)); + + m_TagTracker = NULL; +} + +FxPowerIdleMachine::~FxPowerIdleMachine( + VOID + ) +{ + if (m_TagTracker != NULL) { + delete m_TagTracker; + m_TagTracker = NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPowerIdleMachine::Init( + VOID + ) +{ + NTSTATUS status; + + // + // For KM, event initialize always succeeds. For UM, it might fail. + // + status = m_D0NotificationEvent.Initialize(NotificationEvent, TRUE); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // For KM, timer initialize always succeeds. For UM, it might fail. + // + status = m_PowerTimeoutTimer.Initialize(this, _PowerTimeoutDpcRoutine, 0); + if (!NT_SUCCESS(status)) { + return status; + } + + Reset(); + + return STATUS_SUCCESS; +} + +VOID +FxPowerIdleMachine::CheckAssumptions( + VOID + ) +/*++ + +Routine Description: + This routine is never actually called by running code, it just has + WDFCASSERTs who upon failure, would not allow this file to be compiled. + + DO NOT REMOVE THIS FUNCTION just because it is not called by any running + code. + +Arguments: + None + +Return Value: + None + + --*/ +{ + WDFCASSERT((sizeof(m_StateTable)/sizeof(m_StateTable[0])) + == + (FxIdleMax - FxIdleStopped)); +} + +FxPowerIdleStates +FxPowerIdleMachine::Stopped( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + State machine has entered the stopped state, clear the started flag + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleMax + + --*/ +{ + This->m_Flags &= ~FxPowerIdleIsStarted; + + return FxIdleMax; +} + +FxPowerIdleStates +FxPowerIdleMachine::Started( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + State machine has entered the started state, set the started flag + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleMax + + --*/ +{ + This->m_Flags |= FxPowerIdleIsStarted; + + // + // We are in the started state, but we are not powered up. + // + This->m_D0NotificationEvent.Clear(); + + return FxIdleMax; +} + +FxPowerIdleStates +FxPowerIdleMachine::StartedPowerUp( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + We were in the started and powered off state. We are powered up, + so set the event now so that we can wake up any waiters. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleDisabled + + --*/ +{ + // + // Moving from the started state to the powered on state + // + This->SendD0Notification(); + + return FxIdleDisabled; +} + +FxPowerIdleStates +FxPowerIdleMachine::StartedPowerFailed( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The state machine was started, but the initial power up failed. Mark the + failure. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleStarted + + --*/ +{ + // + // Failed to initially power up + // + This->m_Flags |= FxPowerIdlePowerFailed; + + // + // We assume in the started state that the event is set + // + ASSERT(This->m_D0NotificationEvent.ReadState() == 0); + + return FxIdleStarted; +} + +FxPowerIdleStates +FxPowerIdleMachine::Disabled( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + State machine has entered the disabled state, unblock all waiters + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleMax + + --*/ + +{ + This->m_Flags &= ~FxPowerIdleTimerEnabled; + + return FxIdleMax; +} + +FxPowerIdleStates +FxPowerIdleMachine::CheckIoCount( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + Checks the IO count and transitions the appropriate state. This is the + first state we are in after being disabled or after transitioning from Dx to + D0. + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + This->m_Flags |= FxPowerIdleTimerEnabled; + + if (This->m_IoCount == 0) { + return FxIdleStartTimer; + } + else { + return FxIdleBusy; + } +} + +FxPowerIdleStates +FxPowerIdleMachine::DecrementIo( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + Checks the IO count and returns a new state + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + if (This->m_IoCount == 0) { + return FxIdleStartTimer; + } + else { + return FxIdleBusy; + } +} + +FxPowerIdleStates +FxPowerIdleMachine::StartTimer( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The io count is now at zero. Start the idle timer so that when it expires, + the device will move into Dx. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleMax + + --*/ +{ + ASSERT((This->m_Flags & FxPowerIdleTimerEnabled) && This->m_IoCount == 0); + + This->m_Flags |= FxPowerIdleTimerStarted; + This->m_PowerTimeoutTimer.Start(This->m_PowerTimeout, + m_IdleTimerTolerableDelayMS); + + return FxIdleTimerRunning; +} + + +FxPowerIdleStates +FxPowerIdleMachine::TimingOut( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The idle timer has expired. Indicate to the power policy state machine + that it should power down. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleTimedOut + + --*/ +{ +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + GetPnpPkg(This)->PowerPolicyProcessEvent(PwrPolPowerTimeoutExpired); +#else + GetPnpPkg(This)->PowerPolicyProcessEvent( + PwrPolPowerTimeoutExpired, + TRUE // ProcessEventOnDifferentThread + ); +#endif + + // + // Timer is no longer running. Used when we disable the state machine and + // need to know the timer's running state. + // + // + This->m_Flags &= ~FxPowerIdleTimerStarted; + + // + // While the device is still powered up, we are no longer in D0 in terms of + // PowerReference returning immmediately if TRUE is specified to that call. + // + This->m_D0NotificationEvent.Clear(); + + return FxIdleTimedOut; +} + +FxPowerIdleStates +FxPowerIdleMachine::TimedOutIoIncrement( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + A power reference occurred after we notified the power policy machine of + a power timeout, but before we timed out. Send an io present event to the + power policy machine so that it can move into the D0 state/not timed out + state again. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleTimedOut + + --*/ +{ + FxPkgPnp* pPkgPnp; + + pPkgPnp = GetPnpPkg(This); + + if (This->m_Flags & FxPowerIdleIoPresentSent) { + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p idle (in D0) not sending io present event (already sent)", + pPkgPnp->GetDevice()->GetHandle()); + } + else { +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + pPkgPnp->PowerPolicyProcessEvent(PwrPolIoPresent); +#else + pPkgPnp->PowerPolicyProcessEvent( + PwrPolIoPresent, + TRUE // ProcessEventOnDifferentThread + ); +#endif + + This->m_Flags |= FxPowerIdleIoPresentSent; + } + + return FxIdleTimedOut; +} + +FxPowerIdleStates +FxPowerIdleMachine::TimedOutPowerDown( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The idle timer fired and we are now powering down. Clear the flag that + limits our sending of the io present event to one time while in the timed + out state. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleGoingToDx + + --*/ +{ + // + // We can send the io present event again + // + This->m_Flags &= ~FxPowerIdleIoPresentSent; + + return FxIdleGoingToDx; +} + +FxPowerIdleStates +FxPowerIdleMachine::TimedOutPowerDownFailed( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The idle timer fired and we could no power down. Clear the flag that + limits our sending of the io present event to one time while in the timed + out state. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdlePowerFailed + + --*/ +{ + // + // We can send the io present event again + // + This->m_Flags &= ~FxPowerIdleIoPresentSent; + + return FxIdlePowerFailed; +} + +FxPowerIdleStates +FxPowerIdleMachine::GoingToDx( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The device is going into Dx. It could be going into Dx because the idle + timer expired or because the machine is moving into Sx, the reason doesn't + matter though. Clear the in D0 event. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleInDx + + --*/ +{ + This->m_D0NotificationEvent.Clear(); + return FxIdleInDx; +} + +FxPowerIdleStates +FxPowerIdleMachine::InDx( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The device has moved into Dx. If there is no pending io, mark the device + as idle. We can be in Dx with pending io if IoIncrement was called after + the device moved into Dx. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleMax + + --*/ +{ + This->m_Flags |= FxPowerIdleInDx; + + return FxIdleMax; +} + +FxPowerIdleStates +FxPowerIdleMachine::InDxIoIncrement( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + In Dx and the io count went up. Send the event to the power policy state + machine indicating new io is present. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleInDx + + --*/ +{ + FxPkgPnp* pPkgPnp; + + pPkgPnp = GetPnpPkg(This); + + if (This->m_Flags & FxPowerIdleIoPresentSent) { + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p idle (in Dx) not sending io present event (already sent)", + pPkgPnp->GetDevice()->GetHandle()); + } + else { +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + pPkgPnp->PowerPolicyProcessEvent(PwrPolIoPresent); +#else + pPkgPnp->PowerPolicyProcessEvent( + PwrPolIoPresent, + TRUE // ProcessEventOnDifferentThread + ); +#endif + This->m_Flags |= FxPowerIdleIoPresentSent; + } + + return FxIdleInDx; +} + +FxPowerIdleStates +FxPowerIdleMachine::InDxPowerUpFailure( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + Device is in Dx and there was a failure in the power up path. The device + is no longer idle, even though it is stil in Dx. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdlePowerFailed + + --*/ +{ + // + // FxPowerIdleInDx - We are no longer in Dx + // FxPowerIdleIoPresentSent = We can send the io present event again + // + This->m_Flags &= ~(FxPowerIdleInDx | FxPowerIdleIoPresentSent); + + return FxIdlePowerFailed; +} + +FxPowerIdleStates +FxPowerIdleMachine::InDxStopped( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The state machine was stopped while in the Dx state. When the machine is in + the stopped state, the notification event is in the signaled state. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleStopped + + --*/ +{ + // + // When the machine is in the stopped state, the notification event is in + // the signaled state. + // + This->SendD0Notification(); + + // + // We are not longer idle since we are not in the Dx state anymore + // + This->m_Flags &= ~FxPowerIdleInDx; + + // + // We are no longer enabled since we are stopped from the Dx state + // + This->m_Flags &= ~FxPowerIdleTimerEnabled; + + // + // We can send the io present event again + // + This->m_Flags &= ~FxPowerIdleIoPresentSent; + + return FxIdleStopped; +} + +FxPowerIdleStates +FxPowerIdleMachine::InDxDisabled( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The device is in Dx and the state machine is being disabled (most likely due + to a surprise remove). + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleDisabled + + --*/ +{ + // + // Idle timer is being disabled while in Dx. Remain in Dx. + // + This->m_Flags &= ~FxPowerIdleTimerEnabled; + + return FxIdleInDx; +} + +FxPowerIdleStates +FxPowerIdleMachine::InDxEnabled( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The device is in Dx and the state machine is being enabled (most like due + to trying to remain in Dx after Sx->S0. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleInDx + + --*/ +{ + // + // Idle timer is being enabled while in Dx. Remain in Dx. + // + This->m_Flags |= FxPowerIdleTimerEnabled; + + return FxIdleInDx; +} + +FxPowerIdleStates +FxPowerIdleMachine::PowerUp( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The device powered up enough to where we can let waiters go and start pounding + on their hardware. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdlePowerUpComplete + + --*/ +{ + // + // FxPowerIdleInDx - we are not longer idle since we are not in the Dx state + // anymore + // FxPowerIdleIoPresentSent - We can send the io present event again + // + This->m_Flags &= ~(FxPowerIdleInDx | FxPowerIdleIoPresentSent); + + This->SendD0Notification(); + + return FxIdlePowerUpComplete; +} + +FxPowerIdleStates +FxPowerIdleMachine::PowerUpComplete( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The device is moving into D0, determine which D0 state to move into + based on the enabled state and io count. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + if (This->m_Flags & FxPowerIdleTimerEnabled) { + if (This->m_Flags & FxPowerIdleTimerStarted) { + COVERAGE_TRAP(); + return FxIdleTimerRunning; + } + else { + return FxIdleCheckIoCount; + } + } + else { + // + // Not enabled, better not have a timer running + // + ASSERT((This->m_Flags & FxPowerIdleTimerStarted) == 0); + + return FxIdleDisabled; + } +} + +FxPowerIdleStates +FxPowerIdleMachine::TimedOutDisabled( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The power idle state machine is moving into the disabled state. Set the + D0 event. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleDisabled + + --*/ +{ + // + // Notify any waiters that we are now in D0 + // + This->SendD0Notification(); + + // + // We can send the io present event again + // + This->m_Flags &= ~FxPowerIdleIoPresentSent; + + return FxIdleDisabled; +} + +FxPowerIdleStates +FxPowerIdleMachine::TimedOutEnabled( + __inout FxPowerIdleMachine* This + ) +{ + // + // Notify any waiters that we are now in D0 + // + This->SendD0Notification(); + + // + // We can send the io present event again + // + This->m_Flags &= ~FxPowerIdleIoPresentSent; + + return FxIdleCheckIoCount; +} + +FxPowerIdleStates +FxPowerIdleMachine::CancelTimer( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The timer is running and we need to cancel it because of an io increment or + the state machine being disabled. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + if (This->CancelIdleTimer()) { + return FxIdleCheckIoCount; + } + else { + return FxIdleWaitForTimeout; + } +} + +FxPowerIdleStates +FxPowerIdleMachine::TimerExpired( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + The timer was not canceled because it was running. The timer has now + fired, so we can move forward. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleCheckIoCount + + --*/ +{ + This->m_Flags &= ~FxPowerIdleTimerStarted; + + return FxIdleCheckIoCount; +} + +FxPowerIdleStates +FxPowerIdleMachine::Disabling( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + Timer is running and the state machine is being disabled. Cancel the idle + timer. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + if (This->CancelIdleTimer()) { + return FxIdleDisabled; + } + else { + return FxIdleDisablingWaitForTimeout; + } +} + +FxPowerIdleStates +FxPowerIdleMachine::DisablingTimerExpired( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + When disabling the state machine, the timer could not be canceled. The + timer has now expired and the state machine can move forward. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleDisabled + + --*/ +{ + This->m_Flags &= ~FxPowerIdleTimerStarted; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + GetPnpPkg(This)->PowerPolicyProcessEvent(PwrPolPowerTimeoutExpired); +#else + GetPnpPkg(This)->PowerPolicyProcessEvent( + PwrPolPowerTimeoutExpired, + TRUE // ProcessEventOnDifferentThread + ); +#endif + + return FxIdleDisabled; +} + +FxPowerIdleStates +FxPowerIdleMachine::PowerFailed( + __inout FxPowerIdleMachine* This + ) +/*++ + +Routine Description: + A power operation (up or down) failed. Mark the machine as failed so that + PowerReference will fail properly. + +Arguments: + This - instance of the state machine + +Return Value: + FxIdleDisabled + + --*/ +{ + // + // By this time, the timer should be stopped + // + ASSERT((This->m_Flags & FxPowerIdleTimerStarted) == 0); + + This->m_Flags |= FxPowerIdlePowerFailed; + + // + // We are no longer enabled to time out since we are in a failed state + // + This->m_Flags &= ~FxPowerIdleTimerEnabled; + + // + // Wake up any waiters and indicate failure to them. + // + This->SendD0Notification(); + + return FxIdleDisabled; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +__drv_minIRQL(DISPATCH_LEVEL) +__drv_requiresIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +VOID +FxPowerIdleMachine::_PowerTimeoutDpcRoutine( + __in PKDPC Dpc, + __in_opt PVOID Context, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) +/*++ + +Routine Description: + Timer DPC which posts the timeout expired event to the power policy state + machine + +Arguments: + Dpc - DPC + Context, SysArg1, SysArg2 - Unused + +Return Value: + None + + --*/ +{ + FxPowerIdleMachine* pThis; + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + pThis = (FxPowerIdleMachine*) Context; + + pThis->m_Lock.AcquireAtDpcLevel(); + pThis->ProcessEventLocked(PowerIdleEventTimerExpired); + +#if FX_IS_KERNEL_MODE + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PFN_WDF_DRIVER_DEVICE_ADD pDriverDeviceAdd; + + pFxDriverGlobals = GetPnpPkg(pThis)->GetDriverGlobals(); + + // + // We need to provide XPerf with a symbol of the client to figure out + // which component this idle timer is for. Since AddDevice is always there + // we use that to pass the symbol along. + // + pDriverDeviceAdd = pFxDriverGlobals->Driver->GetDriverDeviceAddMethod(); + + FxPerfTraceDpc(&pDriverDeviceAdd); +#endif + + pThis->m_Lock.ReleaseFromDpcLevel(); +} + +VOID +FxPowerIdleMachine::Reset( + VOID + ) +/*++ + +Routine Description: + Reset the state machine to a known state on a PDO restart. + +Arguments: + None + +Return Value: + None + + --*/ +{ + FxPkgPnp* pPkgPnp; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + ASSERT(m_CurrentIdleState == FxIdleStopped); + + m_IoCount = 0; + m_Flags = 0x0; + + pPkgPnp = GetPnpPkg(this); + pFxDriverGlobals = pPkgPnp->GetDriverGlobals(); + + if (pFxDriverGlobals->DebugExtension != NULL && + pFxDriverGlobals->DebugExtension->TrackPower != FxTrackPowerNone) { + // + // Ignore potential failure, power ref tracking is not an essential feature. + // + (void)FxTagTracker::CreateAndInitialize(&m_TagTracker, + pFxDriverGlobals, + FxTagTrackerTypePower, + pFxDriverGlobals->DebugExtension->TrackPower == FxTrackPowerRefsAndStack, + pPkgPnp->GetDevice()); + } + + SendD0Notification(); +} + +VOID +FxPowerIdleMachine::EnableTimer( + VOID + ) +/*++ + +Routine Description: + Public function that the power policy state machine uses to put this state + machine in to an enabled state and potentially start the idle timer. + +Arguments: + None + +Return Value: + None + + --*/ +{ + KIRQL irql; + + m_Lock.Acquire(&irql); + ProcessEventLocked(PowerIdleEventEnabled); + m_Lock.Release(irql); +} + +BOOLEAN +FxPowerIdleMachine::DisableTimer( + VOID + ) +/*++ + +Routine Description: + Public function which the power policy state machine uses to put this state + machine into a disabled state. If necessary, the state machine will attempt + to cancel the idle timer. + +Arguments: + None + +Return Value: + TRUE if the idle timer was cancelled and the caller may proceed directly to + its new state + + FALSE if the idle timer was not cancelled and the caller must wait for the + io timeout event to be posted before proceeding. + + --*/ +{ + KIRQL irql; + BOOLEAN disabledImmediately; + + m_Lock.Acquire(&irql); + + ProcessEventLocked(PowerIdleEventDisabled); + + // + // If FxPowerIdleTimerStarted is still set after disabling the state machine, + // then we could not cancel the timer and we must wait for the timer expired + // event to be posted to this state machine. This state machine will then + // post a PwrPolIoPresent event to power policy. + // + if (m_Flags & FxPowerIdleTimerStarted) { + disabledImmediately = FALSE; + } + else { + disabledImmediately = TRUE; + } + + m_Lock.Release(irql); + + return disabledImmediately; +} + +VOID +FxPowerIdleMachine::Start( + VOID + ) +/*++ + +Routine Description: + Public function that the power policy state machine uses to put this state + machine into a started state so that the caller can call PowerReference + successfully. + +Arguments: + None + +Return Value: + None + + --*/ +{ + KIRQL irql; + m_Lock.Acquire(&irql); + ProcessEventLocked(PowerIdleEventStart); + m_Lock.Release(irql); +} + +VOID +FxPowerIdleMachine::Stop( + VOID + ) +/*++ + +Routine Description: + Public function which the power policy state machine uses to put this state + machine into a state where PowerReference will no longer work. + +Arguments: + None + +Return Value: + None + + --*/ +{ + KIRQL irql; + + m_Lock.Acquire(&irql); + ProcessEventLocked(PowerIdleEventStop); + m_Lock.Release(irql); +} + +_Must_inspect_result_ +NTSTATUS +FxPowerIdleMachine::PowerReferenceWorker( + __in BOOLEAN WaitForD0, + __in FxPowerReferenceFlags Flags, + __in_opt PVOID Tag, + __in_opt LONG Line, + __in_opt PSTR File + ) +/*++ + +Routine Description: + Caller wants to move the device into D0 manually. The caller may optionally + wait synchronously for the transition to occur if the device is currently in + Dx. + +Arguments: + WaitForD0 - TRUE if the caller wants to synchronously wait for the Dx to D0 + transition + + QueryPnpPending - TRUE if we are being called to bring the device back to + working state when a QueryRemove or a QueryStop + +Return Value: + NTSTATUS + + STATUS_SUCCESS - success + STATUS_PENDING - transition is occurring + STATUS_POWER_STATE_INVALID - ower transition has failed + + --*/ +{ + NTSTATUS status; + KIRQL irql; + ULONG count = 0; + + + + + + + + + + + + + + + + + + + + // + // Poke the state machine + // + status = IoIncrementWithFlags(Flags, &count); + + // + // STATUS_PENDING indicates a Dx to D0 transition is occurring right now + // + if (status == STATUS_PENDING) { + if (WaitForD0) { + FxPkgPnp* pPkgPnp; + + ASSERT(Mx::MxGetCurrentIrql() <= APC_LEVEL); + + // + // With the current usage, if WaitForD0 is TRUE, then the only + // acceptable flag is FxPowerReferenceDefault. + // + // If the usage changes in the future such that it is acceptable to + // have WaitForD0 set to TRUE and some flag(s) set, then the ASSERT + // below should be updated accordingly (or removed altogether). + // + ASSERT(FxPowerReferenceDefault == Flags); + + pPkgPnp = GetPnpPkg(this); + + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE %p in thread %p waiting synchronously for Dx to D0 " + "transition", + pPkgPnp->GetDevice()->GetHandle(), + Mx::MxGetCurrentThread()); + + // + // Returns success always + // + (void) FxPowerIdleMachine::WaitForD0(); + + m_Lock.Acquire(&irql); + + // + // If WaitForD0 is TRUE, then the FxPowerIdleSendPnpPowerUpEvent + // flag can't be set. That flag is only used when the PnP state + // machine waits asynchronously for the device to power up during + // query-remove. + // + ASSERT(0 == (m_Flags & FxPowerIdleSendPnpPowerUpEvent)); + + if ((m_Flags & FxPowerIdlePowerFailed) != 0x0 || + (m_Flags & FxPowerIdleIsStarted) == 0x0) { + + // + // Event was set because a power up or down failure occurred + // + status = STATUS_POWER_STATE_INVALID; + + if (m_Flags & FxPowerIdlePowerFailed) { + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE %p waiting for D0 in thread %p failed because of " + "power failure, %!STATUS!", + pPkgPnp->GetDevice()->GetHandle(), + Mx::MxGetCurrentThread(), + status); + } + else { + COVERAGE_TRAP(); + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE %p waiting for D0 in thread %p failed because of " + "invalid state , %!STATUS!", + pPkgPnp->GetDevice()->GetHandle(), + Mx::MxGetCurrentThread(), status); + } + + // + // Decrement the io count that was taken above + // + ASSERT(m_IoCount > 0); + m_IoCount--; + ProcessEventLocked(PowerIdleEventIoDecrement); + } + else { + // + // Successfully returned to D0 + // + status = STATUS_SUCCESS; + } + m_Lock.Release(irql); + } + } + + if (m_TagTracker != NULL) { + // + // Only track the reference if the call was successful + // and the counter was actually incremented. + // + if (status == STATUS_SUCCESS || status == STATUS_PENDING) { + m_TagTracker->UpdateTagHistory(Tag, Line, File, TagAddRef, count); + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPowerIdleMachine::IoIncrement( + VOID + ) +/*++ + +Routine Description: + Public function for any component to increment the io count. The increment + may cause the state machine to move out of the enabled state depending on + the current state. + +Arguments: + None + +Return Value: + STATUS_PENDING if the state machine is transition from idle to non idle + + STATUS_SUCCESS otherwise + + --*/ +{ + return IoIncrementWithFlags(FxPowerReferenceDefault); +} + +_Must_inspect_result_ +NTSTATUS +FxPowerIdleMachine::IoIncrementWithFlags( + __in FxPowerReferenceFlags Flags, + __out_opt PULONG Count + ) +/*++ + +Routine Description: + An enchanced version of FxPowerIdleMachine::IoIncrement that has special + behavior based on flags passed in by the caller. Please read the routine + description of FxPowerIdleMachine::IoIncrement as well. + +Arguments: + Flags - The following flags are defined - + FxPowerReferenceDefault - No special behavior + FxPowerReferenceSendPnpPowerUpEvent - Set the + FxPowerIdleSendPnpPowerUpEvent flag in the idle state machine flags. + This will indicate to the idle state machine that when the device + powers up, it needs to send the PnpEventDeviceInD0 event to the PnP + state machine. + +Return Value: + STATUS_PENDING if the state machine is transition from idle to non idle + + STATUS_SUCCESS otherwise + + --*/ +{ + NTSTATUS status; + KIRQL irql; + + m_Lock.Acquire(&irql); + + if (m_Flags & FxPowerIdlePowerFailed) { + // + // fail without incrementing the count because we are in an + // invalid power state + // + status = STATUS_POWER_STATE_INVALID; + COVERAGE_TRAP(); + } + else if ((m_Flags & FxPowerIdleIsStarted) == 0x0) { + // + // The state machine is not yet in a started state + // + status = STATUS_POWER_STATE_INVALID; + } + else { + m_IoCount++; + if (Count != NULL) { + *Count = m_IoCount; + } + + ProcessEventLocked(PowerIdleEventIoIncrement); + + if (InD0Locked()) { + status = STATUS_SUCCESS; + } + else { + status = STATUS_PENDING; + if (Flags & FxPowerReferenceSendPnpPowerUpEvent) { + m_Flags |= FxPowerIdleSendPnpPowerUpEvent; + } + } + } + m_Lock.Release(irql); + + 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); + } +} + +BOOLEAN +FxPowerIdleMachine::QueryReturnToIdle( + VOID + ) +/*++ + +Routine Description: + Public function which allows the caller to query the current io count on + this state machine. If the count non zero, the device will be brought back + to D0. If zero, the device will remain in Dx. + +Arguments: + None + +Return Value: + if TRUE is returned, there is an outstanding IO. + if FALSE is returned, the device is idle. + + --*/ +{ + KIRQL irql; + BOOLEAN result; + + // + // To return to idle, the following must be true + // 1) the device must be in Dx (FxPowerIdleInDx) + // 2) the timer must *NOT* be running + // 3) an IO count of zero + // + m_Lock.Acquire(&irql); + + // 1 + if ((m_Flags & FxPowerIdleInDx) == FxPowerIdleInDx && + // 2 3 + (m_Flags & FxPowerIdleTimerStarted) == 0 && m_IoCount == 0x0) { + result = TRUE; + } + else { + result = FALSE; + } + + // + // If the caller is querying about returning to idle, then they have + // processed the io present event that we previously sent. We must clear + // the flag, otherwise the following can occur + // 1) new io arrives, send the io present message + // 2) return to idle (io count goes to zero) + // 3) get queried to return to idle, return TRUE + // 4) new io arrives, we do not send the new io present message because the + // FxPowerIdleIoPresentSent flag is set. + // + m_Flags &= ~FxPowerIdleIoPresentSent; + + m_Lock.Release(irql); + + return result; +} + +VOID +FxPowerIdleMachine::SendD0Notification( + VOID + ) +{ + m_D0NotificationEvent.Set(); + + if (m_Flags & FxPowerIdleSendPnpPowerUpEvent) { + + m_Flags &= ~FxPowerIdleSendPnpPowerUpEvent; + + // + // Send an event to the Pnp state machine indicating that the device is + // now in D0. + // +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + GetPnpPkg(this)->PnpProcessEvent(PnpEventDeviceInD0); +#else + GetPnpPkg(this)->PnpProcessEvent( + PnpEventDeviceInD0, + TRUE // ProcessEventOnDifferentThread + ); +#endif + + } + return; +} + +VOID +FxPowerIdleMachine::ProcessPowerEvent( + __in FxPowerIdleEvents Event + ) +/*++ + +Routine Description: + Post a power related event to the state machine. + +Arguments: + Event - the event to post + +Return Value: + None + + --*/ +{ + KIRQL irql; + + // + // All other event types have specialized public functions + // + ASSERT(Event == PowerIdleEventPowerUpComplete || + Event == PowerIdleEventPowerUpFailed || + Event == PowerIdleEventPowerDown || + Event == PowerIdleEventPowerDownFailed); + + m_Lock.Acquire(&irql); + ProcessEventLocked(Event); + m_Lock.Release(irql); +} + +VOID +FxPowerIdleMachine::ProcessEventLocked( + __in FxPowerIdleEvents Event + ) +/*++ + +Routine Description: + Processes an event and runs it through the state machine + +Arguments: + + +Return Value: + + + --*/ + +{ + const FxIdleStateTable* entry; + FxPowerIdleStates newState; + FxPkgPnp* pPkgPnp; + + pPkgPnp = GetPnpPkg(this); + + m_EventHistory[m_EventHistoryIndex] = Event; + m_EventHistoryIndex = (m_EventHistoryIndex + 1) % + (sizeof(m_EventHistory)/sizeof(m_EventHistory[0])); + + entry = &m_StateTable[m_CurrentIdleState-FxIdleStopped]; + newState = FxIdleMax; + + for (ULONG i = 0; i < entry->TargetStatesCount; i++) { + if (entry->TargetStates[i].PowerIdleEvent == Event) { + DO_EVENT_TRAP(&entry->TargetStates[i]); + newState = entry->TargetStates[i].PowerIdleState; + break; + } + } + + if (newState == FxIdleMax) { + switch (Event) { + case PowerIdleEventIoIncrement: + case PowerIdleEventIoDecrement: + // + // We always can handle io increment, io decrement, and query return + // to idle from any state... + // + break; + + case PowerIdleEventEnabled: + if (m_Flags & FxPowerIdleTimerEnabled) { + // + // Getting an enable event while enabled is OK + // + break; + } + // || || Fall || || + // \/ \/ through \/ \/ + + default: + // + // ...but we should not be dropping any other events from this state. + // + + // + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p power idle state %!FxPowerIdleStates!" + " dropping event %!FxPowerIdleEvents!", + pPkgPnp->GetDevice()->GetHandle(), + pPkgPnp->GetDevice()->GetDeviceObject(), + m_CurrentIdleState, Event); + + COVERAGE_TRAP(); + } + } + + while (newState != FxIdleMax) { + + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering power idle state " + "%!FxPowerIdleStates! from %!FxPowerIdleStates!", + pPkgPnp->GetDevice()->GetHandle(), + pPkgPnp->GetDevice()->GetDeviceObject(), + newState, m_CurrentIdleState); + + m_StateHistory[m_StateHistoryIndex] = newState; + m_StateHistoryIndex = (m_StateHistoryIndex + 1) % + (sizeof(m_StateHistory)/sizeof(m_StateHistory[0])); + + m_CurrentIdleState = newState; + entry = &m_StateTable[m_CurrentIdleState-FxIdleStopped]; + + if (entry->StateFunc != NULL) { + newState = entry->StateFunc(this); + } + else { + newState = FxIdleMax; + } + } +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/powerpolicystatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/powerpolicystatemachine.cpp new file mode 100644 index 00000000000..b61ae054062 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/powerpolicystatemachine.cpp @@ -0,0 +1,8403 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerPolicyStateMachine.cpp + +Abstract: + + This module implements the Power Policy state machine for the driver + framework. This code was split out from FxPkgPnp.cpp. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +#if FX_IS_KERNEL_MODE +#include +#endif + +#include "FxUsbIdleInfo.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerPolicyStateMachine.tmh" +#endif +} + +// +// The Power Policy State Machine +// +// This state machine responds to the following events: +// +// PowerUp +// PowerDown +// PowerPolicyStart +// PowerPolicyStop +// IRP_MN_SET_POWER -- System State S0 +// IRP_MN_SET_POWER -- System State Sx +// PowerTimeoutExpired +// IoPresent +// IRP_MN_WAIT_WAKE Complete +// IRP_MN_WAIT_WAKE Failed +// + +#if FX_SUPER_DBG + #define ASSERT_PWR_POL_STATE(_This, _State) \ + ASSERT((_This)->m_Device->GetDevicePowerPolicyState() == (_State)) +#else + #define ASSERT_PWR_POL_STATE(_This, _State) (0) +#endif + +#if FX_STATE_MACHINE_VERIFY + #define VALIDATE_PWR_POL_STATE(_CurrentState, _NewState) \ + ValidatePwrPolStateEntryFunctionReturnValue((_CurrentState), (_NewState)) +#else + #define VALIDATE_PWR_POL_STATE(_CurrentState, _NewState) (0) +#endif //FX_STATE_MACHINE_VERIFY + +// @@SMVERIFY_SPLIT_BEGIN + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolObjectCreatedOtherStates[] = +{ + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartingOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolStartingFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedIdleCapableOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + { PwrPolSurpriseRemove,WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolStartedCancelTimer DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolIdleCapableDeviceIdleOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolDeviceIdleSleeping DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolDeviceIdleStopping DEBUGGED_EVENT }, + { PwrPolSurpriseRemove,WdfDevStatePwrPolDeviceIdleStopping DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolDeviceIdleReturnToActive TRAP_ON_EVENT }, + { PwrPolIoPresent, WdfDevStatePwrPolDeviceIdleReturnToActive DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredNoWakeOtherStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredNoWakeCompletePowerDownOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingUnarmedOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStoppingResetDevice DEBUGGED_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolS0NoWakePowerUp DEBUGGED_EVENT }, + { PwrPolDevicePowerRequired, WdfDevStatePwrPolS0NoWakePowerUp DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolS0NoWakePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolS0NoWakeCompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemSleepNeedWakeOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolSystemSleepPowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolPowerUpForSystemSleepNotSeen TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemSleepNeedWakeCompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolSystemSleepPowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemAsleepWakeArmedOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggered DEBUGGED_EVENT }, + { PwrPolWakeInterruptFired, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemAsleepWakeArmedNPOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP DEBUGGED_EVENT }, + { PwrPolWakeInterruptFired, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceToD0OtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceToD0CompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedWakeCapableOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolStartedCancelTimer DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWakeCapableDeviceIdleOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolDeviceIdleSleeping DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolDeviceIdleStopping TRAP_ON_EVENT }, + { PwrPolSurpriseRemove,WdfDevStatePwrPolDeviceIdleStopping DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolDeviceIdleReturnToActive TRAP_ON_EVENT }, + { PwrPolIoPresent, WdfDevStatePwrPolDeviceIdleReturnToActive DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakePowerDownOtherStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolSleepingPowerDownNotProcessed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownOtherStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableSendWakeOtherStates[] = +{ + { PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm DEBUGGED_EVENT }, + { PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeSucceeded DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableUsbSSOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStoppingCancelUsbSS TRAP_ON_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingCancelUsbSS DEBUGGED_EVENT }, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolWakeCapableUsbSSCompleted DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolCancelUsbSS DEBUGGED_EVENT }, + { PwrPolIoPresent, WdfDevStatePwrPolCancelUsbSS DEBUGGED_EVENT }, + { PwrPolDevicePowerRequired, WdfDevStatePwrPolCancelUsbSS DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingArmedOtherStates[] = +{ + { PwrPolSx, WdfDevStatePwrPolCancelingUsbSSForSystemSleep DEBUGGED_EVENT }, + { PwrPolWakeSuccess, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS DEBUGGED_EVENT }, + { PwrPolWakeFailed, WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS DEBUGGED_EVENT }, + { PwrPolStop, WdfDevStatePwrPolStoppingD0CancelUsbSS DEBUGGED_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS DEBUGGED_EVENT }, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmed TRAP_ON_EVENT }, + { PwrPolDevicePowerRequired, WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS DEBUGGED_EVENT }, + { PwrPolWakeInterruptFired, WdfDevStatePwrPolWaitingArmedWakeInterruptFired DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolDisarmingWakeForSystemSleepCompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolPowerUpForSystemSleepFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepWakeCanceledOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolPowerUpForSystemSleepFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolPowerUpForSystemSleepNotSeen TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWokeFromS0OtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingResetDeviceOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingResetDeviceFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingResetDeviceCompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingResetDeviceFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingD0OtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingD0Failed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingDisarmWakeOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolStoppingD0Failed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingDisarmWakeCancelWakeOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedOtherStates[] = +{ + { PwrPolStop, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolS0IdlePolicyChanged, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStartedWaitForIdleTimeoutOtherStates[] = +{ + { PwrPolStop, WdfDevStatePwrPolStoppingWaitForIdleTimeout TRAP_ON_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingWaitForIdleTimeout TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolIoPresentArmedOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolIoPresentArmedWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolIoPresentArmedWakeCanceledOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolS0WakeCompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeSucceededOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeFailedOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWakeOtherStates[] = +{ + { PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeArrivedOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded DEBUGGED_EVENT }, + { PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapableWakeFailed DEBUGGED_EVENT }, + { PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake DEBUGGED_EVENT }, + { PwrPolWakeInterruptFired, WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableCancelWakeOtherStates[] = +{ + { PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerDownOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolSleepingWakePowerDownFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0OtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0NPOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeCompletePowerUpOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingNoWakePowerDownOtherStates[] = +{ + { PwrPolPowerDown, WdfDevStatePwrPolSleepingPowerDownNotProcessed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingNoWakeCompletePowerDownOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolSystemSleepPowerRequestFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingSendWakeOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + { PwrPolWakeFailed, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedNPOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolSleepingWakePowerDownFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakePowerDownFailedOtherStates[] = +{ + { PwrPolWakeFailed, WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledNPOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNPOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolDevicePowerRequestFailed DEBUGGED_EVENT }, + { PwrPolPowerUpNotSeen, WdfDevStatePwrPolDeviceD0PowerRequestFailed TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolDevicePowerRequestFailedOtherStates[] = +{ + { PwrPolSurpriseRemove, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingOtherStates[] = +{ + { PwrPolPowerDownFailed, WdfDevStatePwrPolStoppingFailed DEBUGGED_EVENT }, + { PwrPolNull,WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppedOtherStates[] = +{ + { PwrPolRemove, WdfDevStatePwrPolStoppedRemoving DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolRestartingOtherStates[] = +{ + { PwrPolPowerUpFailed, WdfDevStatePwrPolRestartingFailed DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolStoppingCancelWakeOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolCancelUsbSSOtherStates[] = +{ + { PwrPolStop, WdfDevStatePwrPolStoppingWaitForUsbSSCompletion TRAP_ON_EVENT }, + { PwrPolSurpriseRemove, WdfDevStatePwrPolStoppingWaitForUsbSSCompletion TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeNPOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolRemovedOtherStates[] = +{ + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggered TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredNPOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeInterruptArrivedOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded TRAP_ON_EVENT }, + { PwrPolPowerDownFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrived TRAP_ON_EVENT }, + { PwrPolPowerDown, WdfDevStatePwrPolWaitingArmedWakeInterruptFiredDuringPowerDown }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrivedOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_EVENT_TARGET_STATE FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredDuringPowerDownOtherStates[] = +{ + { PwrPolWakeSuccess, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS TRAP_ON_EVENT }, + { PwrPolNull, WdfDevStatePwrPolNull }, +}; + +const POWER_POLICY_STATE_TABLE FxPkgPnp::m_WdfPowerPolicyStates[] = +{ + // transition function, + // { first target state }, + // other target states + // queue open, + + // WdfDevStatePwrPolObjectCreated + { NULL, + { PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolObjectCreatedOtherStates, + { TRUE, + PwrPolS0 | // Sx -> S0 transition on a PDO which was enumerated and + // in the disabled state + + PwrPolSx | // Sx transition right after enumeration + PwrPolS0IdlePolicyChanged }, + }, + + // WdfDevStatePwrPolStarting + { FxPkgPnp::PowerPolStarting, + { PwrPolPowerUp, WdfDevStatePwrPolStartingPoweredUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStartingOtherStates, + { FALSE, + PwrPolPowerUpFailed // If the power state machine fails D0 entry upon + // initial start, we will get this event here. The + // pnp s.m. will not rely on the pwr pol s.m. to + // power down the stack in this case. + }, + }, + + // WdfDevStatePwrPolStartingSucceeded + { FxPkgPnp::PowerPolStartingSucceeded, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartingFailed + { FxPkgPnp::PowerPolStartingFailed, + { PwrPolRemove, WdfDevStatePwrPolRemoved DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStartingDecideS0Wake + { FxPkgPnp::PowerPolStartingDecideS0Wake, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from S0 enabled + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartedIdleCapable + { FxPkgPnp::PowerPolStartedIdleCapable, + { PwrPolPowerTimeoutExpired, WdfDevStatePwrPolIdleCapableDeviceIdle DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStartedIdleCapableOtherStates, + { TRUE, + PwrPolS0 | // If the machine send a query Sx and it fails, it will send + // an S0 while in the running state (w/out ever sending a true set Sx irp) + PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived + // being posted in TimerExpiredWakeCapapble and being + // processed, this event will show up in this state if the idle + // setting changed at this exact moment as well + PwrPolPowerUp | // posted by power when we are powering up the first time + PwrPolIoPresent | // posted by the idle state machine. If we return + // to idle this can happen + PwrPolDevicePowerNotRequired | // The device-power-not-required event arrived just after an + // I/O request or or an S0-idle policy change caused us to + // become active again. The event is ignored in this case. + PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already + // powered-up the device proactively because we detected that + // power was needed. The event is ignored in this case. + }, + }, + + // WdfDevStatePwrPolTimerExpiredNoWake + { FxPkgPnp::PowerPolTimerExpiredNoWake, + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredNoWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown + { FxPkgPnp::PowerPolTimerExpiredNoWakeCompletePowerDown, + // NOTE: see the comments PowerPolWaitingArmedUsbSS() about why we query the + // idle state instead of going directly to WdfDevStatePwrPolWaitingUnarmed + { PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredNoWakeCompletePowerDownOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWaitingUnarmed + { NULL, + { PwrPolIoPresent, WdfDevStatePwrPolWaitingUnarmedQueryIdle DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolWaitingUnarmedOtherStates, + { TRUE, + PwrPolS0 | // If the machine send a query Sx and it fails, it will send + // an S0 while in the running state (w/out ever sending a true set Sx irp) + PwrPolDevicePowerNotRequired // When moving from Sx -> S0, we do not power up the + // device if: + // (UsingSystemManagedIdleTimeout == TRUE) and + // (IdleEnabled == TRUE) and + // (WakeFromS0Capable == FALSE) and + // (PowerUpIdleDeviceOnSystemWake == FALSE). + // In this situation, we declare to the active/idle + // state machine that we are idle, but ignore the + // device-power-not-required event, because we are + // already in Dx. + }, + }, + + // WdfDevStatePwrPolWaitingUnarmedQueryIdle + { FxPkgPnp::PowerPolWaitingUnarmedQueryIdle, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolS0NoWakePowerUp + { FxPkgPnp::PowerPolS0NoWakePowerUp, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolS0NoWakeCompletePowerUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolS0NoWakePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolS0NoWakeCompletePowerUp + { FxPkgPnp::PowerPolS0NoWakeCompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolS0NoWakeCompletePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed + { FxPkgPnp::PowerPolSystemSleepFromDeviceWaitingUnarmed, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from Sx enabled + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemSleepNeedWake + { FxPkgPnp::PowerPolSystemSleepNeedWake, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemSleepNeedWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp + { FxPkgPnp::PowerPolSystemSleepNeedWakeCompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolSleeping DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemSleepNeedWakeCompletePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemSleepPowerRequestFailed + { FxPkgPnp::PowerPolSystemSleepPowerRequestFailed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0, }, + }, + + // WdfDevStatePwrPolCheckPowerPageable + { FxPkgPnp::PowerPolCheckPowerPageable, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on which DO_POWER_Xxx flags set on DO + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingWakeWakeArrived + { FxPkgPnp::PowerPolSleepingWakeWakeArrived, + { PwrPolPowerDown, WdfDevStatePwrPolSystemAsleepWakeArmed DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedOtherStates, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess| // -do- + PwrPolWakeInterruptFired // Wake interrupt fired when during power + // down as part of system sleep transition + + }, + }, + + // WdfDevStatePwrPolSleepingWakeRevertArmWake + { FxPkgPnp::PowerPolSleepingWakeRevertArmWake, + { PwrPolWakeFailed, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemAsleepWakeArmed + { FxPkgPnp::PowerPolSystemAsleepWakeArmed, + { PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeEnabled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemAsleepWakeArmedOtherStates, + { TRUE, + PwrPolWakeFailed | // Wake failed while in Sx + PwrPolIoPresent | // IO arrived when the machine was going to Sx + PwrPolPowerTimeoutExpired | // we don't cancel the power timer when we goto + // sleep from an idleable state + PwrPolDevicePowerNotRequired // Upon receiving Sx, we simulated a device-power- + // not-required, so the device-power-requirement + // state machine sent us this event in response. + // We can drop it because we already powered down. + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeEnabled + { FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabled, + { PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledOtherStates, + { FALSE, + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving S0 due to other reasons. + // This event can fire until the wake interrupt + // machine is notified of the power up. + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled + { FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceled, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWakeDisarm DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledOtherStates, + { FALSE, + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving S0 due to other reasons. + // This event can fire until the wake interrupt + // machine is notified of the power up. + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeDisarm + { FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarm, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeTriggered + { NULL, + { PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0 DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0 + { FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWokeDisarm DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0OtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWokeDisarm + { FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarm, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingWakeWakeArrivedNP, + { FxPkgPnp::PowerPolSleepingWakeWakeArrivedNP, + { PwrPolPowerDown, WdfDevStatePwrPolSystemAsleepWakeArmedNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingWakeWakeArrivedNPOtherStates, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess| // -do- + PwrPolWakeInterruptFired // Wake interrupt fired when during power + // down as part of system sleep transition + + }, + }, + + // WdfDevStatePwrPolSleepingWakeRevertArmWakeNP, + { FxPkgPnp::PowerPolSleepingWakeRevertArmWakeNP, + { PwrPolWakeFailed, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingWakeRevertArmWakeNPOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingWakePowerDownFailed + { FxPkgPnp::PowerPolSleepingWakePowerDownFailed, + { PwrPolWakeSuccess, WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled TRAP_ON_EVENT }, + FxPkgPnp::m_PowerPolSleepingWakePowerDownFailedOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled + { FxPkgPnp::PowerPolSleepingWakePowerDownFailedWakeCanceled, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemAsleepWakeArmedNP + { FxPkgPnp::PowerPolSystemAsleepWakeArmedNP, + { PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemAsleepWakeArmedNPOtherStates, + { TRUE, + PwrPolWakeFailed | // Wake failed while in Sx + PwrPolIoPresent | // IO arrived when the machine was going to Sx + PwrPolPowerTimeoutExpired // we don't cancel the power timer when we goto + // sleep from an idleable state + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP + { FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledNP, + { PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledNPOtherStates, + { FALSE, + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving S0 due to other reasons. + // This event can fire until the wake interrupt + // machine is notified of the power up. + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP + { FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNP, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNPOtherStates, + { FALSE, + PwrPolWakeSuccess | // wake succeeded and completed before we could cancel + // the request, so the event ends up here + + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving S0 due to other reasons. + // This event can fire until the wake interrupt + // machine is notified of the power up. + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP + { FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarmNP, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP + { NULL, + { PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP DEBUGGED_EVENT }, + NULL, + { TRUE, + PwrPolIoPresent // I/O arrived before S0 arrival + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP + { FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0NP, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeTriggeredS0NPOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP + { FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarmNP, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp + { FxPkgPnp::PowerPolSystemWakeDeviceWakeCompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeCompletePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleeping + { FxPkgPnp::PowerPolSleeping, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingNoWakePowerDown + { FxPkgPnp::PowerPolSleepingNoWakePowerDown, + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolSleepingNoWakeCompletePowerDown DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingNoWakePowerDownOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingNoWakeCompletePowerDown + { FxPkgPnp::PowerPolSleepingNoWakeCompletePowerDown, + { PwrPolPowerDown, WdfDevStatePwrPolSystemAsleepNoWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingNoWakeCompletePowerDownOtherStates, + { FALSE, + PwrPolWakeArrived // wake arrived event posted after the ww irp + // completed from SleepingSendWake state. Ignore this + // event since wake is already trigged. + }, + }, + + // WdfDevStatePwrPolSleepingNoWakeDxRequestFailed + { FxPkgPnp::PowerPolSleepingNoWakeDxRequestFailed, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingWakePowerDown + { FxPkgPnp::PowerPolSleepingWakePowerDown, + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolSleepingSendWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingWakePowerDownOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingSendWake + { FxPkgPnp::PowerPolSleepingSendWake, + { PwrPolWakeArrived, WdfDevStatePwrPolCheckPowerPageable DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSleepingSendWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemAsleepNoWake + { FxPkgPnp::PowerPolSystemAsleepNoWake, + { PwrPolS0, WdfDevStatePwrPolSystemWakeDeviceWakeDisabled DEBUGGED_EVENT }, + NULL, + { TRUE, + PwrPolS0IdlePolicyChanged | // Policy changed while the device is in Dx + // because of Sx, we will reevaluate the idle + // settings when we return to S0 anyways + PwrPolWakeArrived | // If arming for wake from sx failed, the WakeArrived + // event that was a part of that arming is dequeued here + PwrPolIoPresent | // I/O showed up when going into Sx + PwrPolPowerTimeoutExpired | + PwrPolDevicePowerNotRequired // Upon receiving Sx, we simulated a device-power- + // not-required, so the device-power-requirement + // state machine sent us this event in response. + // We can drop it because we already powered down. + }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeDisabled + { FxPkgPnp::PowerPolSystemWakeDeviceWakeDisabled, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out based on wake from S0 enabled + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceToD0 + { FxPkgPnp::PowerPolSystemWakeDeviceToD0, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceToD0OtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp + { FxPkgPnp::PowerPolSystemWakeDeviceToD0CompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceToD0CompletePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeQueryIdle + { FxPkgPnp::PowerPolSystemWakeQueryIdle, + { PwrPolNull, WdfDevStatePwrPolNull}, // transition out based on timer expiration state + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartedWakeCapable + { FxPkgPnp::PowerPolStartedWakeCapable, + { PwrPolPowerTimeoutExpired, WdfDevStatePwrPolWakeCapableDeviceIdle DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStartedWakeCapableOtherStates, + { TRUE, + PwrPolS0 | // If the machine send a query Sx and it fails, it will send + // an S0 while in the running state (w/out ever sending a true set Sx irp) + PwrPolPowerUp | + PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived + // being posted in TimerExpiredWakeCapapble and being + // processed, this event will show up in this state + + PwrPolWakeSuccess | // wake succeeded while we were trying to cancel it + // while coming out of WaitingArmed b/c of io present + + PwrPolWakeFailed | // wake request failed while we were trying to cancel it + // while coming out of WaitingArmed b/c of io present + + PwrPolUsbSelectiveSuspendCallback | + PwrPolUsbSelectiveSuspendCompleted | // When returning from a success resume + // from USB SS, the completion of the irp will + // occur in the started state + + PwrPolIoPresent | // posted by the idle state machine. If we return + // to idle this can happen + PwrPolDevicePowerNotRequired | // The device-power-not-required event arrived just after an + // I/O request or or an S0-idle policy change caused us to + // become active again. The event is ignored in this case. + PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already + // powered-up the device proactively because we detected that + // power was needed. The event is ignored in this case. + }, + }, + + // WdfDevStatePwrPolTimerExpiredDecideUsbSS + { FxPkgPnp::PowerPolTimerExpiredDecideUsbSS, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown + { FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDown, + { PwrPolPowerDownIoStopped, WdfDevStatePwrPolTimerExpiredWakeCapableSendWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableSendWake + { FxPkgPnp::PowerPolTimerExpiredWakeCapableSendWake, + { PwrPolWakeArrived, WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableSendWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS + { FxPkgPnp::PowerPolTimerExpiredWakeCapableUsbSS, + { PwrPolUsbSelectiveSuspendCallback, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableUsbSSOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived + { FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeArrived, + { PwrPolPowerDown, WdfDevStatePwrPolWaitingArmedUsbSS DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeArrivedOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake + { FxPkgPnp::PowerPolTimerExpiredWakeCapableCancelWake, + { PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled TRAP_ON_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableCancelWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled + { FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeCanceled, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableCleanup + { FxPkgPnp::PowerPolTimerExpiredWakeCapableCleanup, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed + { FxPkgPnp::PowerPolTimerExpiredWakeCapableDxAllocFailed, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown + { FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerDown, + { PwrPolPowerDown, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerDownOtherStates, + { FALSE, + PwrPolWakeSuccess | // arming callback failed while going into Dx armed for wake from S0 + // but bus completed wake request with success + + PwrPolWakeArrived // if the wake request completes before PwrPolWakeArrived + // can be processed in the PwrPolTimerExpiredWakeCapableSendWake + // state, it will show up here + }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp + { FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerUp, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCompletedPowerUpOtherStates, + { FALSE, + PwrPolWakeSuccess | // arming callback failed while going into Dx armed for wake from S0 + // but bus completed wake request with success + + PwrPolWakeArrived // if the wake request completes before PwrPolWakeArrived + // can be processed in the WdfDevStatePwrPolTimerExpiredWakeCapableSendWake + // state, it will show up here + }, + }, + + // WdfDevStatePwrPolWaitingArmedUsbSS + { FxPkgPnp::PowerPolWaitingArmedUsbSS, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWaitingArmed + { NULL, + { PwrPolIoPresent, WdfDevStatePwrPolWaitingArmedQueryIdle DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolWaitingArmedOtherStates, + { TRUE, + PwrPolS0 // If the machine send a query Sx and it fails, it will send + // an S0 while in the running state (w/out ever sending a true set Sx irp) + }, + }, + + // WdfDevStatePwrPolWaitingArmedQueryIdle + { FxPkgPnp::PowerPolWaitingArmedQueryIdle, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolIoPresentArmed + { FxPkgPnp::PowerPolIoPresentArmed, + { PwrPolWakeFailed, WdfDevStatePwrPolIoPresentArmedWakeCanceled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolIoPresentArmedOtherStates, + { FALSE, + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving IO.This event can fire + // until the wake interrupt machine is notified + // of the power up. + }, + }, + + // WdfDevStatePwrPolIoPresentArmedWakeCanceled + { FxPkgPnp::PowerPolIoPresentArmedWakeCanceled, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolS0WakeDisarm DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolIoPresentArmedWakeCanceledOtherStates, + { FALSE, + PwrPolWakeSuccess | // The wake status was already processed before entering + // this state - indicates that the client driver is + // probably propagating a duplicate wake status using + // the WdfDeviceIndicateWakeStatus ddi. + + PwrPolWakeFailed | // The wake status was already processed before entering + // this state - indicates that the client driver is + // probably propagating a duplicate wake status using + // the WdfDeviceIndicateWakeStatus ddi. + + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving IO.This event can fire + // until the wake interrupt machine is notified + // of the power up. + + }, + }, + + // WdfDevStatePwrPolS0WakeDisarm, + { FxPkgPnp::PowerPolS0WakeDisarm, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolS0WakeCompletePowerUp + { FxPkgPnp::PowerPolS0WakeCompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolStartingDecideS0Wake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolS0WakeCompletePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeSucceeded + { FxPkgPnp::PowerPolTimerExpiredWakeSucceeded, + { PwrPolNull, WdfDevStatePwrPolNull }, // transition out is hardcoded in func + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm + { FxPkgPnp::PowerPolTimerExpiredWakeCompletedDisarm, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded + { NULL, + { PwrPolPowerDown, WdfDevStatePwrPolWokeFromS0UsbSS DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeSucceededOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableWakeFailed + { NULL, + { PwrPolPowerDown, WdfDevStatePwrPolWakeFailedUsbSS DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeFailedOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWakeFailedUsbSS + { FxPkgPnp::PowerPolWakeFailedUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmedWakeCanceled TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake + { FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWake, + { PwrPolWakeSuccess, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWakeOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled + { FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS + { FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolDevicePowerRequestFailed TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolCancelingWakeForSystemSleep + { FxPkgPnp::PowerPolCancelingWakeForSystemSleep, + { PwrPolWakeFailed, WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled + { FxPkgPnp::PowerPolCancelingWakeForSystemSleepWakeCanceled, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolCancelingWakeForSystemSleepWakeCanceledOtherStates, + { FALSE, + PwrPolWakeSuccess // Wake completed successfully right as the transition + // from WaitingArmed to goto Sx occurred + }, + }, + + // WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp + { FxPkgPnp::PowerPolDisarmingWakeForSystemSleepCompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolDisarmingWakeForSystemSleepCompletePowerUpOtherStates, + { FALSE, + 0, }, + }, + + // WdfDevStatePwrPolPowerUpForSystemSleepFailed + { FxPkgPnp::PowerPolPowerUpForSystemSleepFailed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWokeFromS0UsbSS + { FxPkgPnp::PowerPolWokeFromS0UsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolWokeFromS0 DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWokeFromS0 + { FxPkgPnp::PowerPolWokeFromS0, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolWokeFromS0NotifyDriver DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolWokeFromS0OtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWokeFromS0NotifyDriver + { FxPkgPnp::PowerPolWokeFromS0NotifyDriver, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingResetDevice + { FxPkgPnp::PowerPolStoppingResetDevice, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingResetDeviceOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp + { FxPkgPnp::PowerPolStoppingResetDeviceCompletePowerUp, + { PwrPolPowerUp, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingResetDeviceCompletePowerUpOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingResetDeviceFailed + { FxPkgPnp::PowerPolStoppingResetDeviceFailed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingD0 + { FxPkgPnp::PowerPolStoppingD0, + { PwrPolPowerUpHwStarted, WdfDevStatePwrPolStoppingDisarmWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingD0OtherStates, + { FALSE, + PwrPolWakeSuccess | // In the waiting armed state, the wake completed + // right after PwrPolStop arrived + PwrPolWakeFailed // wake completed before we could cancel + // the request, so the event may end up here + }, + }, + + // WdfDevStatePwrPolStoppingD0Failed + { FxPkgPnp::PowerPolStoppingD0Failed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingDisarmWake + { FxPkgPnp::PowerPolStoppingDisarmWake, + { PwrPolPowerUp, WdfDevStatePwrPolStoppingDisarmWakeCancelWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingDisarmWakeOtherStates, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess // -do- + }, + }, + + // WdfDevStatePwrPolStoppingDisarmWakeCancelWake + { FxPkgPnp::PowerPolStoppingDisarmWakeCancelWake, + { PwrPolWakeFailed, WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingDisarmWakeCancelWakeOtherStates, + { FALSE, + PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device + // in Dx and the irp completed when the D0 + // irp was sent + }, + }, + + // WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled + { FxPkgPnp::PowerPolStoppingDisarmWakeWakeCanceled, + { PwrPolNull, WdfDevStatePwrPolNull}, // transition to Stopping occurs in function + NULL, + { FALSE, + PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device + // in Dx and the irp completed when the D0 + // irp was sent + }, + }, + + // WdfDevStatePwrPolStopping + { FxPkgPnp::PowerPolStopping, + { PwrPolPowerDown, WdfDevStatePwrPolStoppingSendStatus DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingOtherStates, + { FALSE, + PwrPolUsbSelectiveSuspendCompleted // pwr pol stopped from a usb SS device + // in Dx and the irp completed when the D0 + // irp was sent + }, + }, + + // WdfDevStatePwrPolStoppingFailed + { FxPkgPnp::PowerPolStoppingFailed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingSendStatus + { FxPkgPnp::PowerPolStoppingSendStatus, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingCancelTimer + { FxPkgPnp::PowerPolStoppingCancelTimer, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingWaitForIdleTimeout + { NULL, + { PwrPolPowerTimeoutExpired, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingCancelUsbSS + { FxPkgPnp::PowerPolStoppingCancelUsbSS, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingWaitForUsbSSCompletion + { NULL, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingCancelWake + { FxPkgPnp::PowerPolStoppingCancelWake, + { PwrPolWakeFailed, WdfDevStatePwrPolStopping DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppingCancelWakeOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStopped + { NULL, + { PwrPolStart, WdfDevStatePwrPolRestarting DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStoppedOtherStates, + { TRUE, + PwrPolPowerTimeoutExpired | // idle timer fired right before stopping + // pwr policy and before pwr pol could process + // the timeout + PwrPolIoPresent | // I/O arrived while transitioning to the + // stopped state + PwrPolDevicePowerRequired // Due to a power-related failure, we declared our device state + // as failed and stopped the power policy state machine. But + // before stopping the power policy machine, we would have + // declared ourselves as powered-on (maybe fake) in order to + // move the power framework to a consistent state. Since we've + // already declared ourselves as powered-on, we can drop this. + }, + }, + + // WdfDevStatePwrPolCancelUsbSS + { FxPkgPnp::PowerPolCancelUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStartedCancelTimer DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolCancelUsbSSOtherStates, + { TRUE, + PwrPolIoPresent // I/O arrived while we were waiting for the USB idle notification IOCTL + // to be completed after we had canceled it. It is okay to drop this + // event because we are already in the process to returning to the powered- + // up state. + }, + }, + + // WdfDevStatePwrPolStarted + { FxPkgPnp::PowerPolStarted, + { PwrPolSx, WdfDevStatePwrPolSleeping DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolStartedOtherStates, + { TRUE, + PwrPolS0 | // If the machine send a query Sx and it fails, it will send + // an S0 while in the running state (w/out ever sending a true set Sx irp) + PwrPolWakeArrived | // If the wake request is failed by the bus in between WakeArrived + // being posted in TimerExpiredWakeCapapble and being + // processed, this event will show up in this state if the idle + // setting changed at this exact moment as well + PwrPolWakeSuccess | // returning from Dx armed for wake from Sx, wake + // is completed w/success after S0 irp arrives + PwrPolPowerUp | + PwrPolUsbSelectiveSuspendCompleted | // sent when we move out of the armed + // & idle enabled state into the + // idle disabled state + PwrPolIoPresent |// This just indicates that I/O arrived, which is fine here + PwrPolPowerTimeoutExpired | // this can happen when idle timer is disabled + // due to policy change while powering up. + PwrPolDevicePowerRequired // idle policy changed when device was powered down + // due to S0-idle. The policy change caused us to power + // up. As part of powering up, the device-power-required + // event arrived. Can drop because we already powered-up. + }, + }, + + // WdfDevStatePwrPolStartedCancelTimer + { FxPkgPnp::PowerPolStartedCancelTimer, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartedWaitForIdleTimeout + { NULL, + { PwrPolPowerTimeoutExpired, WdfDevStatePwrPolStartingDecideS0Wake TRAP_ON_EVENT }, + FxPkgPnp::m_PowerPolStartedWaitForIdleTimeoutOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep + { FxPkgPnp::PowerPolStartedWakeCapableCancelTimerForSleep, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartedWakeCapableWaitForIdleTimeout + { NULL, + { PwrPolPowerTimeoutExpired, WdfDevStatePwrPolSleeping TRAP_ON_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS + { FxPkgPnp::PowerPolStartedWakeCapableSleepingUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolSleeping DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep + { FxPkgPnp::PowerPolStartedIdleCapableCancelTimerForSleep, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartedIdleCapableWaitForIdleTimeout + { NULL, + { PwrPolPowerTimeoutExpired, WdfDevStatePwrPolSleeping TRAP_ON_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolDeviceD0PowerRequestFailed + { FxPkgPnp::PowerPolDeviceD0PowerRequestFailed, + { PwrPolNull, WdfDevStatePwrPolNull}, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolDevicePowerRequestFailed + { FxPkgPnp::PowerPolDevicePowerRequestFailed, + { PwrPolStop, WdfDevStatePwrPolStoppingCancelTimer DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolDevicePowerRequestFailedOtherStates, + { TRUE, + PwrPolUsbSelectiveSuspendCompleted | // Device was suspened and surprise + // removed while in Dx + PwrPolS0 | // If the device failed D0Exit while the machine was going into + // Sx, then we will get this event when the machine comes back up + + PwrPolWakeArrived | // wake was completed before PwrPolWakeArrived was + // sent. On immediate power down or up, the power + // operation failed + + PwrPolWakeFailed | // If the device failed exit d0 after being armed, the + // this event will be processed in the failed state + PwrPolDevicePowerRequired | // We can drop because we already declared ourselves + // as being powered on (fake power-on in order to + // move the power framework to consistent state). + PwrPolIoPresent // We're being notified that we need to be powered-on because + // there is I/O to process, but the device is already in failed + // state and is about to be removed. + }, + }, + + // State exists only for the non power policy owner state machine + // WdfDevStatePwrPolGotoDx + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolGotoDxInDx + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { TRUE, + 0 }, + }, + + // State exists only for the non power policy owner state machine + // WdfDevStatePwrPolDx + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { TRUE, + 0 }, + }, + + // State exists only for the non power policy owner state machine + // WdfDevStatePwrPolGotoD0 + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolGotoD0InD0 + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolFinal + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolSleepingPowerDownNotProcessed + { FxPkgPnp::PowerPolSleepingPowerDownNotProcessed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed + { FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownNotProcessed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed + { FxPkgPnp::PowerPolTimerExpiredNoWakePowerDownNotProcessed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer + { FxPkgPnp::PowerPolTimerExpiredNoWakePoweredDownDisableIdleTimer, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingWaitingForImplicitPowerDown + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingPoweringUp + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppingPoweringDown + { NULL, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolPowerUpForSystemSleepNotSeen + { FxPkgPnp::PowerPolPowerUpForSystemSleepNotSeen, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS + { FxPkgPnp::PowerPolWaitingArmedStoppingCancelUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStoppingCancelWake DEBUGGED_EVENT }, + NULL, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess // -do- + }, + }, + + // WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS + { FxPkgPnp::PowerPolWaitingArmedWakeFailedCancelUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmedWakeCanceled TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS + { FxPkgPnp::PowerPolWaitingArmedIoPresentCancelUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolIoPresentArmed DEBUGGED_EVENT }, + NULL, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess | // -do- + PwrPolWakeInterruptFired // wake interrupt fired as we were waking the + // device on receiving IO.This event can fire + // until the wake interrupt machine is notified + // of the power up. + }, + }, + + // WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS + { FxPkgPnp::PowerPolWaitingArmedWakeSucceededCancelUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolWokeFromS0 DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolCancelingUsbSSForSystemSleep + { FxPkgPnp::PowerPolCancelingUsbSSForSystemSleep, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolCancelingWakeForSystemSleep DEBUGGED_EVENT }, + NULL, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess // -do- + }, + }, + + // WdfDevStatePwrPolStoppingD0CancelUsbSS + { FxPkgPnp::PowerPolStoppingD0CancelUsbSS, + { PwrPolUsbSelectiveSuspendCompleted, WdfDevStatePwrPolStoppingD0 TRAP_ON_EVENT }, + NULL, + { FALSE, + PwrPolWakeFailed | // wake completed before we could cancel + // the request, so the event may end up here + PwrPolWakeSuccess // -do- + }, + }, + + // WdfDevStatePwrPolStartingPoweredUp + { FxPkgPnp::PowerPolStartingPoweredUp, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolIdleCapableDeviceIdle + { FxPkgPnp::PowerPolIdleCapableDeviceIdle, + { PwrPolDevicePowerNotRequired, WdfDevStatePwrPolTimerExpiredNoWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolIdleCapableDeviceIdleOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePwrPolDeviceIdleReturnToActive + { FxPkgPnp::PowerPolDeviceIdleReturnToActive, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolDeviceIdleSleeping + { FxPkgPnp::PowerPolDeviceIdleSleeping, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolDeviceIdleStopping + { FxPkgPnp::PowerPolDeviceIdleStopping, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown + { FxPkgPnp::PowerPolTimerExpiredNoWakeUndoPowerDown, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWakeCapableDeviceIdle + { FxPkgPnp::PowerPolWakeCapableDeviceIdle, + { PwrPolDevicePowerNotRequired, WdfDevStatePwrPolTimerExpiredDecideUsbSS DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolWakeCapableDeviceIdleOtherStates, + { TRUE, + PwrPolDevicePowerRequired // The device-power-required event arrived, but we had already + // powered-up the device proactively because we detected that + // power was needed. And after we powered up, we become idle + // again and arrived in our current state before the device- + // power-required event was received. The event is ignored in + // this case. + }, + }, + + // WdfDevStatePwrPolWakeCapableUsbSSCompleted + { FxPkgPnp::PowerPolWakeCapableUsbSSCompleted, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown + { FxPkgPnp::PowerPolTimerExpiredWakeCapableUndoPowerDown, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted + { FxPkgPnp::PowerPolTimerExpiredWakeCompletedHardwareStarted, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStoppedRemoving + { FxPkgPnp::PowerPolStoppedRemoving, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolRemoved + { FxPkgPnp::PowerPolRemoved, + { PwrPolStart, WdfDevStatePwrPolStarting DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolRemovedOtherStates, + { TRUE, + PwrPolSx | // device is disabled (must be a PDO) and then the machine + // moves into an Sx state + PwrPolS0 | // driver failed power up when moving out of S0 Dx idle + // state and system resumed after failure + PwrPolS0IdlePolicyChanged // driver changes S0 idle settings while being + // removed + }, + }, + + // WdfDevStatePwrPolRestarting + { FxPkgPnp::PowerPolRestarting, + { PwrPolPowerUp, WdfDevStatePwrPolStartingSucceeded DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolRestartingOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolRestartingFailed + { FxPkgPnp::PowerPolRestartingFailed, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolStartingPoweredUpFailed + { FxPkgPnp::PowerPolStartingPoweredUpFailed, + { PwrPolPowerDown, WdfDevStatePwrPolStartingFailed DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive + { FxPkgPnp::PowerPolTimerExpiredNoWakeReturnToActive, + { PwrPolNull, WdfDevStatePwrPolNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWaitingArmedWakeInterruptFired + { FxPkgPnp::PowerPolWaitingArmedWakeInterruptFired, + { PwrPolWakeFailed, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired + { FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFired, + { PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeTriggered TRAP_ON_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP + { FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFiredNP, + { PwrPolWakeFailed, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP TRAP_ON_EVENT }, + FxPkgPnp::m_PowerPolSystemWakeDeviceWakeInterruptFiredNPOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived + { FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeInterruptArrived, + { PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapableWakeInterruptArrivedOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrived + { NULL, + { PwrPolWakeFailed, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolTimerExpiredWakeCapablePowerDownFailedWakeInterruptArrivedOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolWaitingArmedWakeInterruptFiredDuringPowerDown + { NULL, + { PwrPolWakeFailed, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS DEBUGGED_EVENT }, + FxPkgPnp::m_PowerPolWaitingArmedWakeInterruptFiredDuringPowerDownOtherStates, + { FALSE, + 0 }, + }, + + // WdfDevStatePwrPolNull + // *** no entry for this state *** +}; + +// @@SMVERIFY_SPLIT_END + +VOID +FxPkgPnp::PowerPolicyCheckAssumptions( + VOID + ) +/*++ + +Routine Description: + This routine is never actually called by running code, it just has + WDFCASSERTs who upon failure, would not allow this file to be compiled. + + DO NOT REMOVE THIS FUNCTION just because it is not callec by any running + code. + +Arguments: + None + +Return Value: + None + + --*/ +{ + WDFCASSERT(sizeof(FxPwrPolStateInfo) == sizeof(ULONG)); + + WDFCASSERT((sizeof(m_WdfPowerPolicyStates)/sizeof(m_WdfPowerPolicyStates[0])) + == + (WdfDevStatePwrPolNull - WdfDevStatePwrPolObjectCreated)); + + // we assume these are the same length when we update the history index + WDFCASSERT((sizeof(m_PowerPolicyMachine.m_Queue)/ + sizeof(m_PowerPolicyMachine.m_Queue[0])) + == + (sizeof(m_PowerPolicyMachine.m_States.History)/ + sizeof(m_PowerPolicyMachine.m_States.History[0]))); +} + +CfxDevice * +IdleTimeoutManagement::GetDevice( + VOID + ) +{ + IdlePolicySettings * idlePolicySettings = NULL; + FxPowerPolicyOwnerSettings * ppoSettings = NULL; + FxPkgPnp * pPkgPnp = NULL; + + idlePolicySettings = (IdlePolicySettings *) CONTAINING_RECORD( + this, + IdlePolicySettings, + m_TimeoutMgmt + ); + ppoSettings = (FxPowerPolicyOwnerSettings *) CONTAINING_RECORD( + idlePolicySettings, + FxPowerPolicyOwnerSettings, + m_IdleSettings + ); + pPkgPnp = ppoSettings->m_PkgPnp; + + return pPkgPnp->GetDevice(); +} + +IdleTimeoutManagement::IdleTimeoutStatusUpdateResult +IdleTimeoutManagement::UpdateIdleTimeoutStatus( + __in IdleTimeoutManagement::IdleTimeoutStatusFlag Flag + ) +{ + LONG idleTimeoutStatusSnapshot; + LONG updatedIdleTimeoutStatus; + LONG preInterlockedIdleTimeoutStatus; + + // + // Take a snapshot of the idle timeout management status + // + idleTimeoutStatusSnapshot = m_IdleTimeoutStatus; + + // + // Verify that the flag we're trying to set is not already set + // + if (0 != (idleTimeoutStatusSnapshot & Flag)) { + return IdleTimeoutStatusFlagAlreadySet; + } + + // + // Verify that the idle timeout management status is not already + // "frozen" + // + if (0 != (idleTimeoutStatusSnapshot & IdleTimeoutStatusFrozen)) { + // + // It was too late to set the flag. The flag value was already + // "frozen". + // + return IdleTimeoutStatusFlagsAlreadyFrozen; + } + + // + // Try to set the flag + // + updatedIdleTimeoutStatus = idleTimeoutStatusSnapshot | Flag; + + preInterlockedIdleTimeoutStatus = InterlockedCompareExchange( + &m_IdleTimeoutStatus, + updatedIdleTimeoutStatus, + idleTimeoutStatusSnapshot + ); + if (preInterlockedIdleTimeoutStatus != idleTimeoutStatusSnapshot) { + + if (0 != (preInterlockedIdleTimeoutStatus & + IdleTimeoutStatusFrozen)) { + // + // It was too late to set the flag. The flag value was already + // "frozen". + // + return IdleTimeoutStatusFlagsAlreadyFrozen; + } + else { + // + // Idle timeout management status is being changed by multiple + // threads in parallel. This is not supported. + // + return IdleTimeoutStatusFlagsUnexpected; + } + } + + // + // We have successfully set the flag + // + return IdleTimeoutStatusFlagsUpdated; +} + +NTSTATUS +IdleTimeoutManagement::UseSystemManagedIdleTimeout( + __in PFX_DRIVER_GLOBALS DriverGlobals + ) +{ + NTSTATUS status; + IdleTimeoutStatusUpdateResult statusUpdateResult; + CfxDevice * device; + + // + // First check if we are running on Windows 8 or above + // + if (_SystemManagedIdleTimeoutAvailable()) { + + // + // Get the device object so we can use it for logging + // + device = GetDevice(); + + // + // Try to update the flag that specifies that the power framework should + // determine the idle timeout. + // + statusUpdateResult = UpdateIdleTimeoutStatus(IdleTimeoutSystemManaged); + + switch (statusUpdateResult) { + case IdleTimeoutStatusFlagsAlreadyFrozen: + { + // + // Status is already frozen. Too late to update it. + // + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p If the power framework is made " + "responsible for determining the idle timeout, then the " + "first call to assign S0-idle policy must occur before the " + "first start IRP is completed. However, in this case, it " + "occurred after the first start IRP was completed. " + "%!STATUS!.", + device->GetHandle(), + device->GetDeviceObject(), + status + ); + FxVerifierDbgBreakPoint(DriverGlobals); + } + break; + + case IdleTimeoutStatusFlagsUnexpected: + { + // + // Status being updated from multiple threads in parallel. Not + // supported. + // + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Calls to assign S0-idle settings " + "and to specify power framework settings are happening in " + "parallel. The driver needs to serialize these calls with " + "respect to each other. %!STATUS!.", + device->GetHandle(), + device->GetDeviceObject(), + status + ); + FxVerifierDbgBreakPoint(DriverGlobals); + } + break; + + case IdleTimeoutStatusFlagAlreadySet: + { + // + // Status flag was already set. This should never happen for the + // IdleTimeoutSystemManaged flag. The caller ensures this. + // + ASSERTMSG( + "IdleTimeoutManagement::UseSystemManagedIdleTimeout was " + "called more than once\n", FALSE); + } + + // + // Fall through + // + // || || || + // \/ \/ \/ + // + case IdleTimeoutStatusFlagsUpdated: + { + status = STATUS_SUCCESS; + } + break; + + default: + { + ASSERTMSG("Unexpected IdleTimeoutStatusUpdateResult value\n", + FALSE); + status = STATUS_INTERNAL_ERROR; + } + } + + } else { + // + // If we're not running on Windows 8 or above, then there is nothing to + // do. + // + status = STATUS_SUCCESS; + } + + return status; +} + +VOID +IdleTimeoutManagement::FreezeIdleTimeoutManagementStatus( + __in PFX_DRIVER_GLOBALS DriverGlobals + ) +{ + LONG idleTimeoutSnapshot; + LONG idleTimeoutStatus; + LONG idleTimeoutPreviousStatus; + CfxDevice * device; + + // + // Get the device object so we can use it for logging + // + device = GetDevice(); + + // + // Take a snapshot of the idle timeout management status + // + idleTimeoutSnapshot = m_IdleTimeoutStatus; + + // + // Set the bit that freezes the status + // + idleTimeoutStatus = idleTimeoutSnapshot | IdleTimeoutStatusFrozen; + + // + // Update the status + // + idleTimeoutPreviousStatus = InterlockedExchange(&m_IdleTimeoutStatus, + idleTimeoutStatus); + + if (idleTimeoutPreviousStatus != idleTimeoutSnapshot) { + // + // An update of idle timeout status is racing with the freezing of idle + // timeout status + // + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP, + "WDFDEVICE %p !devobj %p The driver's S0-idle settings and/or power" + " framework settings did not take effect because they were supplied" + " too late. The driver must ensure that the settings are provided " + "before the first start IRP is completed.", + device->GetHandle(), + device->GetDeviceObject() + ); + FxVerifierDbgBreakPoint(DriverGlobals); + } + + // + // If the driver has specified power framework settings and system managed + // idle timeout is available on this OS, then the driver must have opted for + // system managed idle timeout. + // + if ((0 != (idleTimeoutStatus & IdleTimeoutPoxSettingsSpecified)) && + (_SystemManagedIdleTimeoutAvailable()) && + (0 == (idleTimeoutStatus & IdleTimeoutSystemManaged))) { + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_WARNING, TRACINGPNP, + "WDFDEVICE %p !devobj %p The driver specified power framework " + "settings, but did not opt for system-managed idle timeout.", + device->GetHandle(), + device->GetDeviceObject() + ); + FxVerifierDbgBreakPoint(DriverGlobals); + } +} + +BOOLEAN +IdleTimeoutManagement::UsingSystemManagedIdleTimeout( + VOID + ) +{ + // + // If the value of this constant is changed, the debugger extension needs + // to be fixed as well. + // + C_ASSERT(0x2 == IdleTimeoutSystemManaged); + + return (0 != (m_IdleTimeoutStatus & IdleTimeoutSystemManaged)); +} + +BOOLEAN +IdleTimeoutManagement::DriverSpecifiedPowerFrameworkSettings( + VOID + ) +{ + return (0 != (m_IdleTimeoutStatus & IdleTimeoutPoxSettingsSpecified)); +} + +NTSTATUS +IdleTimeoutManagement::CommitPowerFrameworkSettings( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in PPOX_SETTINGS PoxSettings + ) +{ + NTSTATUS status; + IdleTimeoutStatusUpdateResult statusUpdateResult; + PVOID oldPoxSettings = NULL; + BOOLEAN settingsSuccessfullySaved = FALSE; + CfxDevice * device; + + // + // We should never get here if system-managed idle timeout is not available + // + ASSERT(_SystemManagedIdleTimeoutAvailable()); + + // + // Get the device object so we can use it for logging + // + device = GetDevice(); + + // + // Try to save the driver's power framework settings + // + oldPoxSettings = InterlockedCompareExchangePointer((PVOID*) &m_PoxSettings, + PoxSettings, + NULL // Comparand + ); + if (NULL != oldPoxSettings) { + // + // The driver's power framework settings have already been specified + // earlier. The driver should not be attempting to specify them more + // than once. + // + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p The driver attempted to specify power " + "framework settings more than once. %!STATUS!.", + device->GetHandle(), + device->GetDeviceObject(), + status + ); + FxVerifierDbgBreakPoint(DriverGlobals); + goto exit; + } + settingsSuccessfullySaved = TRUE; + + // + // Try to update the flag that indicates that the client driver has + // specified settings that are to be used when we register with the power + // framework. + // + statusUpdateResult = UpdateIdleTimeoutStatus( + IdleTimeoutPoxSettingsSpecified + ); + switch (statusUpdateResult) { + case IdleTimeoutStatusFlagsAlreadyFrozen: + { + // + // Status is already frozen. Too late to update it. + // + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Power framework settings must be " + "specified before the first start IRP is completed. %!STATUS!.", + device->GetHandle(), + device->GetDeviceObject(), + status + ); + FxVerifierDbgBreakPoint(DriverGlobals); + goto exit; + } + break; + + case IdleTimeoutStatusFlagsUnexpected: + { + // + // Status being updated from multiple threads in parallel. Not + // supported. + // + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + DriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p !devobj %p Calls to assign S0-idle settings and " + "to specify power framework settings are happening in parallel." + " The driver needs to serialize these calls with respect to " + "each other. %!STATUS!.", + device->GetHandle(), + device->GetDeviceObject(), + status + ); + FxVerifierDbgBreakPoint(DriverGlobals); + goto exit; + } + break; + + case IdleTimeoutStatusFlagAlreadySet: + { + // + // Status flag was already set. This should never happen for the + // IdleTimeoutPoxSettingsSpecified flag because we have logic in the + // beginning of this function to ensure that only the first caller + // attempts to set this flag. + // + ASSERTMSG( + "Attempt to set the IdleTimeoutPoxSettingsSpecified flag more " + "than once\n", FALSE); + status = STATUS_INTERNAL_ERROR; + goto exit; + } + + case IdleTimeoutStatusFlagsUpdated: + { + status = STATUS_SUCCESS; + } + break; + + default: + { + ASSERTMSG("Unexpected IdleTimeoutStatusUpdateResult value\n", + FALSE); + status = STATUS_INTERNAL_ERROR; + goto exit; + } + } + + // + // If we get here, we must have a successful status + // + ASSERT(STATUS_SUCCESS == status); + +exit: + if (FALSE == NT_SUCCESS(status)) { + if (settingsSuccessfullySaved) { + // + // Since a failure has occurred, we must reset the pointer to the + // power framework settings. + // + m_PoxSettings = NULL; + } + } + return status; +} + +PolicySettings::~PolicySettings() +{ + + + + + + + +} + +FxPowerPolicyMachine::FxPowerPolicyMachine( + VOID + ) : FxThreadedEventQueue(FxPowerPolicyEventQueueDepth) +{ + m_Owner = NULL; + + RtlZeroMemory(&m_Queue[0], sizeof(m_Queue)); + RtlZeroMemory(&m_States, sizeof(m_States)); + + m_States.History[IncrementHistoryIndex()] = WdfDevStatePwrPolObjectCreated; + + m_SingularEventsPresent = 0x0; +} + +FxPowerPolicyMachine::~FxPowerPolicyMachine( + VOID + ) +{ + if (m_Owner != NULL) { + delete m_Owner; + m_Owner = NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPowerPolicyMachine::InitUsbSS( + VOID + ) +{ + FxUsbIdleInfo* pInfo; + NTSTATUS status; + + // + // The field is already set, we are good to go + // + if (m_Owner->m_UsbIdle != NULL) { + return STATUS_SUCCESS; + } + + pInfo = new (m_PkgPnp->GetDriverGlobals()) FxUsbIdleInfo(m_PkgPnp); + + if (pInfo == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pInfo->Initialize(); + if (!NT_SUCCESS(status)) { + delete pInfo; + return status; + } + + if (InterlockedCompareExchangePointer((PVOID*) &m_Owner->m_UsbIdle, + pInfo, + NULL) == NULL) { + // + // This thread was the one that set the field value. + // + DO_NOTHING(); + } + else { + // + // Another thread raced in and beat this thread in setting the field, + // just delete our allocation and use the other allocated FxUsbIdleInfo. + // + delete pInfo; + } + + return STATUS_SUCCESS; +} + +FxPowerPolicyOwnerSettings::FxPowerPolicyOwnerSettings( + __in FxPkgPnp* PkgPnp + ) : m_PoxInterface(PkgPnp) +{ + ULONG i; + + m_UsbIdle = NULL; + + m_PkgPnp = PkgPnp; + + // + // Default every state to D3 except for system working which is D0 by + // default. + // + m_SystemToDeviceStateMap = 0x0; + + for (i = 0; i < PowerSystemMaximum; i++) { + FxPkgPnp::_SetPowerCapState(i, + i == PowerSystemWorking ? PowerDeviceD0 + : PowerDeviceD3, + &m_SystemToDeviceStateMap); + } + + m_IdealDxStateForSx = PowerDeviceD3; + + m_RequestedPowerUpIrp = FALSE; + m_RequestedPowerDownIrp = FALSE; + m_RequestedWaitWakeIrp = FALSE; + m_WakeCompletionEventDropped = FALSE; + m_PowerFailed = FALSE; + m_CanSaveState = TRUE; + + m_ChildrenCanPowerUp = FALSE; + m_ChildrenPoweredOnCount = 0; + m_ChildrenArmedCount = 0; + + m_WaitWakeStatus = STATUS_NOT_SUPPORTED; + m_SystemWakeSource = FALSE; + m_WaitWakeCancelCompletionOwnership = CancelOwnershipUnclaimed; + + m_PowerCallbackObject = NULL; + m_PowerCallbackRegistration = NULL; +} + +FxPowerPolicyOwnerSettings::~FxPowerPolicyOwnerSettings( + VOID + ) +{ + // + // There are paths which cleanup this object which do not go through the + // pnp state machine, so make sure the power object callback fields are + // freed. In these paths, we are guaranteed PASSIVE_LEVEL b/c there will + // be no dangling references which can cause deletion at a greater IRQL. + // + CleanupPowerCallback(); + + if (m_UsbIdle != NULL) { + delete m_UsbIdle; + m_UsbIdle = NULL; + } +} + +VOID +FxPowerPolicyOwnerSettings::CleanupPowerCallback( + VOID + ) +/*++ + +Routine Description: + Cleans up the power state callback registration for this object. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (m_PowerCallbackRegistration != NULL) { + Mx::UnregisterCallback(m_PowerCallbackRegistration); + m_PowerCallbackRegistration = NULL; + + } + + if (m_PowerCallbackObject != NULL) { + Mx::MxDereferenceObject(m_PowerCallbackObject); + m_PowerCallbackObject = NULL; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPowerPolicyOwnerSettings::Init( + VOID + ) +/*++ + +Routine Description: + Initialize the object. We will try to register a power state callback so + that we can be informed of when the machine is changing S states. We are + interested in system state changes because we need to know when NOT to write + to the registry (to save wake settings) so that we don't cause a deadlock + in a non power pageable device while moving into Sx. + +Arguments: + None + +Return Value: + NTSTATUS + + --*/ +{ + OBJECT_ATTRIBUTES oa; + UNICODE_STRING string; + NTSTATUS status; + + RtlInitUnicodeString(&string, L"\\Callback\\PowerState"); + InitializeObjectAttributes( + &oa, + &string, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + // + // Create a callback object, but we do not want to be the first ones + // to create it (it should be created way before we load in NTOS + // anyways) + // + status = Mx::CreateCallback(&m_PowerCallbackObject, &oa, FALSE, TRUE); + + if (NT_SUCCESS(status)) { + m_PowerCallbackRegistration = Mx::RegisterCallback( + m_PowerCallbackObject, + _PowerStateCallback, + this + ); + + if (m_PowerCallbackRegistration == NULL) { + // + // Non-critical failure, so we'll free the callback object and keep + // going + // + Mx::MxDereferenceObject(m_PowerCallbackObject); + m_PowerCallbackObject = NULL; + } + } + + // + // Initialize FxPowerIdleMachine + // + status = m_PowerIdleMachine.Init(); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +VOID +FxPowerPolicyOwnerSettings::_PowerStateCallback( + __in PVOID Context, + __in_opt PVOID Argument1, + __in_opt PVOID Argument2 + ) +/*++ + +Routine Description: + Callback invoked by the power subsystem when the system is changing S states + +Arguments: + Context - FxPowerPolicyOwnerSettings pointer (the "this" pointer) + + Argument1 - Reason why the callback was invoked, we only care about + PO_CB_SYSTEM_STATE_LOCK + + Argument2 - State transition that is occurring + +Return Value: + None + + --*/ +{ + FxPowerPolicyOwnerSettings* pThis; + + pThis = (FxPowerPolicyOwnerSettings*) Context; + + if (Argument1 != (PVOID) PO_CB_SYSTEM_STATE_LOCK) { + return; + } + + pThis->m_PkgPnp->m_PowerPolicyMachine.m_StateMachineLock.AcquireLock( + pThis->m_PkgPnp->GetDriverGlobals(), + NULL + ); + + if (Argument2 == (PVOID) 0) { + // + // Write out the state if necessary before we turn off the paging path. + // + pThis->m_PkgPnp->SaveState(TRUE); + + // + // Exiting S0 + // + pThis->m_CanSaveState = FALSE; + } + else if (Argument2 == (PVOID) 1) { + // + // We have reentered S0 + // + pThis->m_CanSaveState = TRUE; + + // + // Write out the state if necessary now that the paging path is back + // + pThis->m_PkgPnp->SaveState(TRUE); + } + + pThis->m_PkgPnp->m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock( + pThis->m_PkgPnp->GetDriverGlobals() + ); +} + +/*++ + +The locking model for the Power policy state machine requires that events be enqueued +possibly at DISPATCH_LEVEL. It also requires that the state machine be +runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL +lock that guards the event queue and one PASSIVE_LEVEL lock that guards the +state machine itself. + +The Power policy state machine has a few constraints that the PnP state machine +doesn't. Sometimes it has to call some driver functions at PASSIVE_LEVEL, but +with the disks turned off. This means that these functions absolutely must not +page fault. You might think that this means that we should call the driver at +DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly +safe code. The problem with that approach, though is that it will force much +of the rest of the driver to DISPATCH_LEVEL, which will only push the driver +writer into using lots of asynchronous work items, which will complicate their +code and make it unsafe in a new variety of ways. So we're going to go with +PASSIVE_LEVEL here and setting a timeout of 20 seconds. If the driver faults, +the timer will fire and log the failure. This also means that the driver must +complete these callbacks within 20 seconds. Even beyond that, it means that +the work items must be queued onto a special thread, one that once the machine +has started to go to sleep, never handles any work items that may fault. + +Algorithm: + +1) Acquire the Power policy queue lock. +2) Enqueue the event. events are put at the end of the queue. +3) Drop the Power policy queue lock. +4) If the thread is running at PASSIVE_LEVEL, skip to step 6. +5) Queue a work item onto the special power thread. +6) Attempt to acquire the state machine lock, with a zero-length timeout (*). +7) If successful, skip to step 9. +8) Queue a work item onto the special power thread. +9) Acquire the state machine lock. +10) Acquire the Power policy queue lock. +11) Attempt to dequeue an event. +12) Drop the Power policyqueue lock. +13) If there was no event to dequeue, drop the state machine lock and exit. +14) Execute the state handler. This may involve taking one of the other state + machine queue locks, briefly, to deliver an event. +15) Go to Step 10. + +(*) zero length is different then NULL (infinite) being passed for the timeout + +Implementing this algorithm requires three functions. + +PowerPolicyProcessEvent -- Implements steps 1-8. +_PowerPolicyProcessEventInner -- Implements step 9. +PowerPolicyProcessEventInner -- Implements steps 10-15. + +--*/ + +VOID +FxPkgPnp::PowerPolicyProcessEvent( + __in FxPowerPolicyEvent Event, + __in BOOLEAN ProcessOnDifferentThread + ) +/*++ + +Routine Description: + This function implements steps 1-8 of the algorithm described above. + +Arguments: + Event - Current Power event + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + ULONG mask; + KIRQL irql; + + // + // Take the lock, raising to DISPATCH_LEVEL. + // + m_PowerPolicyMachine.Lock(&irql); + + // + // If the input Event is any of the events described by PowerSingularEventMask, + // then check whether it is already queued up. If so, then dont enqueue this + // Event. + // + if (Event & PowerPolSingularEventMask) { + if ((m_PowerPolicyMachine.m_SingularEventsPresent & Event) == 0x00) { + m_PowerPolicyMachine.m_SingularEventsPresent |= Event; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " + "%!WDF_DEVICE_POWER_POLICY_STATE! dropping event " + "%!FxPowerPolicyEvent! because the Event is already enqueued.", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerPolicyState(), Event); + + m_PowerPolicyMachine.Unlock(irql); + return; + } + } + + if (m_PowerPolicyMachine.IsFull()) { + // + // The queue is full. Bail. + // + m_PowerPolicyMachine.Unlock(irql); + + ASSERT(!"The Power queue is full. This shouldn't be able to happen."); + return; + } + + if (m_PowerPolicyMachine.IsClosedLocked()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " + "%!WDF_DEVICE_POWER_POLICY_STATE! dropping event " + "%!FxPowerPolicyEvent! because of a closed queue", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerPolicyState(), Event); + + // + // The queue is closed. Bail + // + m_PowerPolicyMachine.Unlock(irql); + + return; + } + + // + // Enqueue the event. Whether the event goes on the front + // or the end of the queue depends on which event it is and if we are the + // PPO or not. + // + // Yes, mask could be a member variable of m_PowerPolicyMachine, but why + // waste 4 bytes when it is very easy to figure out? + // + mask = IsPowerPolicyOwner() ? PwrPolPriorityEventsMask + : PwrPolNotOwnerPriorityEventsMask; + + if (Event & mask) { + // + // Stick it on the front of the queue, making it the next event that + // will be processed if, otherwise let these events go by. + // + m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.InsertAtHead()] = Event; + } + else { + // + // Stick it on the end of the queue. + // + m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.InsertAtTail()] = Event; + } + + // + // Drop the lock. + // + m_PowerPolicyMachine.Unlock(irql); + + // + // Now, if we are running at PASSIVE_LEVEL, attempt to run the state + // machine on this thread. If we can't do that, then queue a work item. + // + if (FALSE == ShouldProcessPowerPolicyEventOnDifferentThread( + irql, + ProcessOnDifferentThread + )) { + + LONGLONG timeout = 0; + + status = m_PowerPolicyMachine.m_StateMachineLock.AcquireLock( + GetDriverGlobals(), &timeout); + + if (FxWaitLockInternal::IsLockAcquired(status)) { + FxPostProcessInfo info; + + // + // We now hold the state machine lock. So call the function that + // dispatches the next state. + // + PowerPolicyProcessEventInner(&info); + + // + // The pnp state machine should be the only one deleting the object + // + ASSERT(info.m_DeleteObject == FALSE); + + m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock( + GetDriverGlobals()); + + info.Evaluate(this); + + return; + } + } + + // + // The tag added above will be released when the work item runs + // + + // + // For one reason or another, we couldn't run the state machine on this + // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing + // is non-zero, that means that the work item is already being enqueued + // on another thread. This is significant, since it means that we can't do + // anything with the work item on this thread, but it's okay, since the + // work item will pick up our work and do it. + // + m_PowerPolicyMachine.QueueToThread(); +} + +VOID +FxPkgPnp::_PowerPolicyProcessEventInner( + __inout FxPkgPnp* This, + __inout FxPostProcessInfo* Info, + __in PVOID Context + ) +{ + + UNREFERENCED_PARAMETER(Context); + + // + // Take the state machine lock. + // + This->m_PowerPolicyMachine.m_StateMachineLock.AcquireLock( + This->GetDriverGlobals() + ); + + // + // Call the function that will actually run the state machine. + // + This->PowerPolicyProcessEventInner(Info); + + // + // We are being called from the work item and m_WorkItemRunning is > 0, so + // we cannot be deleted yet. + // + ASSERT(Info->SomethingToDo() == FALSE); + + // + // Now release the lock + // + This->m_PowerPolicyMachine.m_StateMachineLock.ReleaseLock( + This->GetDriverGlobals() + ); +} + +VOID +FxPkgPnp::PowerPolicyProcessEventInner( + __inout FxPostProcessInfo* Info + ) +{ + WDF_DEVICE_POWER_POLICY_STATE newState; + FxPowerPolicyEvent event; + ULONG i; + KIRQL irql; + + if (IsPowerPolicyOwner()) { + CPPOWER_POLICY_STATE_TABLE entry; + + // + // Process as many events as we can. + // + for ( ; ; ) { + entry = GetPowerPolicyTableEntry(m_Device->GetDevicePowerPolicyState()); + + // + // Get an event from the queue. + // + m_PowerPolicyMachine.Lock(&irql); + + if (m_PowerPolicyMachine.IsEmpty()) { + m_PowerPolicyMachine.GetFinishedState(Info); + + // + // The queue is empty. + // + m_PowerPolicyMachine.Unlock(irql); + return; + } + + event = m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.GetHead()]; + + // + // At this point, we need to determine whether we can process this + // event. + // + if (event & PwrPolPriorityEventsMask) { + // + // These are always possible to handle. + // + DO_NOTHING(); + } + else { + // + // Check to see if this state can handle new events, ie if this + // is a green dot (queue open) or red dot (queue *not* open) state. + // + if (entry->StateInfo.Bits.QueueOpen == FALSE) { + // + // This state can't handle new events. + // + m_PowerPolicyMachine.Unlock(irql); + return; + } + } + + // + // If the event obtained from the queue was a singular event, then + // clear the flag to allow other similar events to be put into this + // queue for processing. + // + if (m_PowerPolicyMachine.m_SingularEventsPresent & event) { + m_PowerPolicyMachine.m_SingularEventsPresent &= ~event; + } + + m_PowerPolicyMachine.IncrementHead(); + m_PowerPolicyMachine.Unlock(irql); + + // + // Find the entry in the power policy state table that corresponds + // to this event. + // + newState = WdfDevStatePwrPolNull; + + if (entry->FirstTargetState.PowerPolicyEvent == event) { + newState = entry->FirstTargetState.TargetState; + + DO_EVENT_TRAP(&entry->FirstTargetState); + } + else if (entry->OtherTargetStates != NULL) { + for (i = 0; + entry->OtherTargetStates[i].PowerPolicyEvent != PwrPolNull; + i++) { + if (entry->OtherTargetStates[i].PowerPolicyEvent == event) { + newState = entry->OtherTargetStates[i].TargetState; + DO_EVENT_TRAP(&entry->OtherTargetStates[i]); + break; + } + } + } + + if (newState == WdfDevStatePwrPolNull) { + // + // This state doesn't respond to the event. Just throw the event + // away. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " + "%!WDF_DEVICE_POWER_POLICY_STATE! dropping event " + "%!FxPowerPolicyEvent!", m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerPolicyState(), event); + + if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) { + COVERAGE_TRAP(); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current state " + "%!WDF_DEVICE_POWER_POLICY_STATE!, policy event " + "%!FxPowerPolicyEvent! is not a known dropped " + "event, known dropped events are %!FxPowerPolicyEvent!", + m_Device->GetHandle(), m_Device->GetDeviceObject(), + m_Device->GetDevicePowerPolicyState(), + event, entry->StateInfo.Bits.KnownDroppedEvents); + + + } + + // + // Failsafes for events which have required processing in them. + // + switch (event) { + case PwrPolSx: + // + // The Sx handling code expects that the state machine + // complete the Sx irp. (S0 irps are never pended). Since + // we don't have a state to transition to that will complete + // the request, do so now. + // + // (This can legitimately happen if a PDO is disabled and + // the machines moves into an Sx state.) + // + PowerPolicyCompleteSystemPowerIrp(); + break; + + case PwrPolUsbSelectiveSuspendCompleted: + // + // This state did not handle the event and event got + // dropped. However some state is definitely going to wait + // for this event. That's why we need m_EventDropped flag. + // If we didn't have this flag there will be no way to know + // if the event got dropped and some state will end up + // waiting for it indefinitely. + // + m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped = TRUE; + break; + + case PwrPolUsbSelectiveSuspendCallback: + m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + break; + + case PwrPolWakeSuccess: + case PwrPolWakeFailed: + // + // This state did not handle the event and event got + // dropped. However some state is definitely going to wait + // for this event. That's why we need + // m_WakeCompletionEventDropped flag. If we didn't have this + // flag there will be no way to know if the event got + // dropped and some state will end up waiting for it + // indefinitely. + // + m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped = TRUE; + break; + + default: + DO_NOTHING(); + break; + } + } + else { + // + // Now enter the new state. + // + PowerPolicyEnterNewState(newState); + } + } + } + else { + // + // Process as many events as we can. + // + for ( ; ; ) { + CPNOT_POWER_POLICY_OWNER_STATE_TABLE entry; + +#pragma prefast(suppress:__WARNING_DEREF_NULL_PTR, "The current power policy state will always be in the table so entry will never be NULL") + entry = GetNotPowerPolicyOwnerTableEntry( + m_Device->GetDevicePowerPolicyState() + ); + + // + // Get an event from the queue. + // + m_PowerPolicyMachine.Lock(&irql); + + if (m_PowerPolicyMachine.IsEmpty()) { + // + // The queue is empty. + // + m_PowerPolicyMachine.Unlock(irql); + return; + } + + event = m_PowerPolicyMachine.m_Queue[m_PowerPolicyMachine.GetHead()]; + + // + // At this point, we need to determine whether we can process this + // event. + // + if (event & PwrPolNotOwnerPriorityEventsMask) { + // + // These are always possible to handle. + // + DO_NOTHING(); + } + else { + // + // Check to see if this state can handle new events, ie if this + // is a green dot (queue open) or red dot (queue *not* open) state. + // + if (entry->QueueOpen == FALSE) { + // + // This state can't handle new events. + // + m_PowerPolicyMachine.Unlock(irql); + return; + } + } + + // + // If the event obtained from the queue was a singular event, then + // clear the flag to allow other similar events to be put into this + // queue for processing. + // + if (m_PowerPolicyMachine.m_SingularEventsPresent & event) { + m_PowerPolicyMachine.m_SingularEventsPresent &= ~event; + } + + m_PowerPolicyMachine.IncrementHead(); + m_PowerPolicyMachine.Unlock(irql); + + if (entry != NULL && entry->TargetStatesCount > 0) { + for (i = 0; i < entry->TargetStatesCount; i++) { + if (event == entry->TargetStates[i].PowerPolicyEvent) { + DO_EVENT_TRAP(&entry->TargetStates[i]); + + // + // Now enter the new state. + // + NotPowerPolicyOwnerEnterNewState( + entry->TargetStates[i].TargetState); + break; + } + } + } + } + } +} + +VOID +FxPkgPnp::PowerPolicyEnterNewState( + __in WDF_DEVICE_POWER_POLICY_STATE NewState + ) +/*++ + +Routine Description: + This function looks up the handler for a state and then calls it. + +Arguments: + Event - Current power plicy event + +Return Value: + + NTSTATUS + +--*/ +{ + CPPOWER_POLICY_STATE_TABLE entry; + WDF_DEVICE_POWER_POLICY_STATE currentState, newState; + WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA data; + FxWatchdog watchdog(this); + + currentState = m_Device->GetDevicePowerPolicyState(); + newState = NewState; + + while (newState != WdfDevStatePwrPolNull) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering power policy state " + "%!WDF_DEVICE_POWER_POLICY_STATE! from " + "%!WDF_DEVICE_POWER_POLICY_STATE!", m_Device->GetHandle(), + m_Device->GetDeviceObject(), newState, currentState); + + if (m_PowerPolicyStateCallbacks != NULL) { + // + // Callback for leaving the old state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationLeaveState; + data.Data.LeaveState.CurrentState = currentState; + data.Data.LeaveState.NewState = newState; + + m_PowerPolicyStateCallbacks->Invoke(currentState, + StateNotificationLeaveState, + m_Device->GetHandle(), + &data); + } + + m_PowerPolicyMachine.m_States.History[ + m_PowerPolicyMachine.IncrementHistoryIndex()] = (USHORT) newState; + + if (m_PowerPolicyStateCallbacks != NULL) { + // + // Callback for entering the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationEnterState; + data.Data.EnterState.CurrentState = currentState; + data.Data.EnterState.NewState = newState; + + m_PowerPolicyStateCallbacks->Invoke(newState, + StateNotificationEnterState, + m_Device->GetHandle(), + &data); + } + + m_Device->SetDevicePowerPolicyState(newState); + currentState = newState; + + entry = GetPowerPolicyTableEntry(currentState); + + // + // And call the state handler, if there is one. + // + if (entry->StateFunc != NULL) { + watchdog.StartTimer(currentState); + newState = entry->StateFunc(this); + watchdog.CancelTimer(currentState); + + // + // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled + // + VALIDATE_PWR_POL_STATE(currentState, newState); + + } + else { + newState = WdfDevStatePwrPolNull; + } + + if (m_PowerPolicyStateCallbacks != NULL) { + // + // Callback for post processing the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationPostProcessState; + data.Data.PostProcessState.CurrentState = currentState; + + m_PowerPolicyStateCallbacks->Invoke(currentState, + StateNotificationPostProcessState, + m_Device->GetHandle(), + &data); + } + } +} + + +/*++ + +One of the goals of the Driver Framework is to make it really easy to write +a driver for a device which keeps the device in the lowest useful power state +at all times. This could (and often does) mean that the device remains in the +D0 state whenever the machine is running. Or it could mean that the device is +only in D0 when there are outstanding IRPs in its queues. Or it could mean +that the device is in D0 whenever the driver explicitly says that it has to be. + +Consequently, the Power Policy state machine has a bunch of states that relate +only to managing the state of the device while the system is running, possibly +allowing the device to "idle-out" to low power states while it isn't being +heavily used. Once that idle-out process has begun, there needs to be some +way for the Framework I/O Package and the driver itself to tell the Power Policy +engine that the device must, for some time at least, be in the D0 (high-power, +working) state. The problem is made much harder by the fact that the driver +(or the Framework itself) probably has to stall some operation while the device +is brought back into the D0 state. + +So we've created two operations, PowerReference and PowerDereference, which +tell the Power Policy state machine when a device needs to be in the D0 state. +The I/O Package uses these internally, and the driver may as well. We want +these operations to be as light-weight as possible, so that a driver never +experiences meaningful degradation in performance simply because it chose to +be a good electricity consumer and enabled idle-time power management. +Fortunately, the Framework I/O package can significantly reduce the number of +times that it needs to call these functions by only calling them when the +queue state transitions from empty to non-empty or back again. A caller within +the driver itself will need to be aware that their usage can be somewhat +expensive. + +Furthermore, these functions need to be callable at both PASSIVE_LEVEL and +DISPATCH_LEVEL. This really necessitates two versions, as a PASSIVE_LEVEL +user within the driver probably would like us to block while the device is +moved into D0, while a DISPATCH_LEVEL user (or the Framework I/O package) would +prefer a much more asynchronous mode of use. + +Dealing with these multiple modes involves a fairly complex locking scheme. Here +is a statement of algorithm. + +Locks: + +A) Idle Transition Spinlock - DISPATCH_LEVEL +B) Device in D0 Notification Event - PASSIVE_LEVEL + +Device-wide variables: + + I) Power Reference Count - number of outstanding reasons to be in D0. + II) Idle Timout -- value set by the driver which governs the idle timer +III) Transitioning -- boolean indicating whether we're in the process of + moving the device from Dx to D0. + +PowerDecrement: + +1) Take Idle Transition lock. +3) Decrement of the device-wide power reference count. +3) If that's not zero, drop the lock and exit. +4) Set the driver's Idle Timer. +5) Drop the Idle Transition lock. + +PowerIncrement: + + 1) Take Idle Transition lock. + 2) Increment of the device-wide power reference count. + 3) If that's 1, then we're transitioning out of idle. Goto Step 6. + 4) If Transitioning == TRUE, we need to wait, Goto Step 13. + 5) Drop the Idle Transition lock. Exit. + 6) Cancel the Idle Timer. If that was unsuccessful, then the timer was not + set, which means that the device has either moved out of D0 or it is moving + out of D0. Goto Step 8. + 7) Drop the Idle Transition lock. Exit. + 8) The timer was not succefully cancelled. This means that we have timed out + in the past and we need to put the device back in D0. + Set Transitioning = TRUE. + 9) Drop Idle Transition lock. +10) Reset the D0 Notification Event. +11) Send IoPresent event to the Power Policy state machine. +12) If IRQL == DISPATCH_LEVEL goto Step 15. +13) Wait for the D0 Notification Event. +14) Exit. +15) Note that I/O needs to be restarted later. +16) Exit STATUS_PENDING. + +--*/ +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStarting( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStarting); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Start(); + + This->PowerProcessEvent(PowerImplicitD0); + + // + // Wait for the successful power up before starting any idle timers. If + // the power up fails, we will not send a power policy stop from the pnp + // engine. + // + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartingPoweredUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The power state policy state machine has powered up. Tell the active/idle + state machine to initialize. + + The device needs to be in D0 before the active/idle state machine registers + with the power framework. Therefore, we wait until the power state machine + has brought the device into D0 before we tell the active/idle state machine + to start. Moving the device into D0 allows us to touch hardware if needed + (for example, to determine the number of components in the device) before + registering with the power framework. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + +--*/ +{ + NTSTATUS status; + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingPoweredUp); + + // + // The decision regarding whether or not the power framework determines the + // idle timeout is now "frozen" and cannot be changed unless the device is + // stopped and restarted. + // + This->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.FreezeIdleTimeoutManagementStatus( + This->GetDriverGlobals() + ); + + status = This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.InitializeComponents(); + if (FALSE == NT_SUCCESS(status)) { + return WdfDevStatePwrPolStartingPoweredUpFailed; + } + + return WdfDevStatePwrPolStartingSucceeded; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartingPoweredUpFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We failed to initialize the device's components. We have already started the + power state machine, so ask it to run down before we tell the PNP state + machine to fail device start. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + +--*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingPoweredUpFailed); + + This->PowerProcessEvent(PowerImplicitD3); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartingSucceeded( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The power policy state machine has successfully started. Notify the pnp + state machine that this has occurred and then tell the active/idle state + machine to move to an active state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStartingDecideS0Wake + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingSucceeded); + + This->PnpProcessEvent(PnpEventPwrPolStarted); + + return WdfDevStatePwrPolStartingDecideS0Wake; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartingFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Attempting to bring the device into the D0 state failed. Report the status + to pnp. + +Arguments: + This - instance of the state machine + +Return Value + WdfDevStatePwrPolNull + + --*/ +{ + KIRQL irql; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingFailed); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop(); + + // + // We raise IRQL to dispatch level so that pnp is forced onto its own thread + // to process the PwrPolStartFailed event. If pnp is on the power thread when + // it processes the event and it tries to delete the dedicated thread, it + // will deadlock waiting for the thread its on to exit. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + This->PnpProcessEvent(PnpEventPwrPolStartFailed); + Mx::MxLowerIrql(irql); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartingDecideS0Wake( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartingDecideS0Wake); + + This->PowerPolicyChildrenCanPowerUp(); + + // + // Save idle state if it is dirty. We check when deciding the S0 state + // because any change in the S0 idle settings will go through this state. + // + This->SaveState(TRUE); + + // + // If necessary update the idle timeout hint to the power framework + // + This->m_PowerPolicyMachine.m_Owner->m_PoxInterface.UpdateIdleTimeoutHint(); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled) { + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.WakeFromS0Capable) { + // + // We can idle out and wake from S0 + // + return WdfDevStatePwrPolStartedWakeCapable; + } + else { + // + // We can idle out, but not wake from the idle state + // + return WdfDevStatePwrPolStartedIdleCapable; + } + } + + return WdfDevStatePwrPolStarted; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartedIdleCapable( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedIdleCapable); + + // + // Enable the idle state machine. This will release any threads who are + // waiting for the device to return to D0. + // + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.EnableTimer(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolIdleCapableDeviceIdle( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are now idle. Tell the active/idle state machine to move us to an idle + state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + BOOLEAN canPowerDown; + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolIdleCapableDeviceIdle); + + canPowerDown = This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeclareComponentIdle(); + + // + // If we are using driver-managed idle timeout we can power down immediately + // and so we jump to the next state (that initiates power down) immediately. + // If we are using system-managed idle timeout, we wait in the current state + // for device-power-not-required notification. + // + return (canPowerDown ? + WdfDevStatePwrPolTimerExpiredNoWake : + WdfDevStatePwrPolNull); +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolDeviceIdleReturnToActive( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are idle, but still in D0. We need to return to an active state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceIdleReturnToActive); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + return WdfDevStatePwrPolStartedCancelTimer; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolDeviceIdleSleeping( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are idle, but still in D0. System is going to a low power state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceIdleSleeping); + + // + // Normally we'd make the component active when we get the device-power- + // required notification. But we've not yet processed the device-power-not- + // required notification, so we will not be processing the device-power- + // required notification either. So let's activate the component before we + // process the Sx IRP. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + return WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolDeviceIdleStopping( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are idle, but still in D0. Power policy state machine is being stopped. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceIdleStopping); + + // + // Normally we'd make the component active when we get the device-power- + // required notification. But we've not yet processed the device-power-not- + // required notification, so we will not be processing the device-power- + // required notification either. So let's activate the component before we + // process the stop/remove request. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + return WdfDevStatePwrPolStoppingCancelTimer; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredNoWake( + __inout FxPkgPnp* This + ) +{ + BOOLEAN poweredDown; + NTSTATUS notifyPowerDownStatus; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredNoWake); + + // + // Notify the device power requirement state machine that we are about to + // power down. + // + notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.NotifyDevicePowerDown(); + if (FALSE == NT_SUCCESS(notifyPowerDownStatus)) { + // + // We couldn't notify the device power requirement state machine that + // we are about to power down, because the "device-power-required" + // notification has already arrived. So we should not power down at this + // time. Revert back to the started state. + // + return WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive; + } + + poweredDown = This->PowerPolicyCanIdlePowerDown( + This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState + ); + + if (poweredDown == FALSE) { + // + // Upon failure, revert back to the started state. + // + return WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredNoWakeCompletePowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device idled out and we sent the Dx request. The power state machine has + gone as far as stopping I/O is waiting to be notified to complete the Dx + process. Send the PowerCompleteDx event to move the device fully into Dx. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, + WdfDevStatePwrPolTimerExpiredNoWakeCompletePowerDown); + + This->PowerProcessEvent(PowerCompleteDx); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingUnarmedQueryIdle( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in the WaitingUnarmed state and received a PwrPolIoPresent + event. Before committing the device to move back to D0, check to see if + the device has returned to an idle state. This can easily happen if the + driver causes a power reference in D0Exit accidentally and the power + reference is removed before exiting the function. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingUnarmedQueryIdle); + + // + // If QueryReturnToIdle returns TRUE, return to the waiting state + // + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) { + return WdfDevStatePwrPolWaitingUnarmed; + } + else { + return WdfDevStatePwrPolS0NoWakePowerUp; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolS0NoWakePowerUp( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0NoWakePowerUp); + + // + // Attempt to get back to the D0 state + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolS0NoWakeCompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in a Dx unarmed for wake while in S0 and is now being brought + into the D0 state. The device is currently in a partial D0 state (HW + started), move it into the full D0 state by sending PowerCompleteD0 to the + power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0NoWakeCompletePowerUp); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemSleepFromDeviceWaitingUnarmed( + __inout FxPkgPnp* This + ) +{ + SYSTEM_POWER_STATE systemState; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemSleepFromDeviceWaitingUnarmed); + + systemState = This->PowerPolicyGetPendingSystemState(); + + if (This->PowerPolicyIsWakeEnabled() && + This->PowerPolicyCanWakeFromSystemState(systemState)) { + return WdfDevStatePwrPolSystemSleepNeedWake; + } + else { + return WdfDevStatePwrPolSystemAsleepNoWake; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemSleepNeedWake( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + BOOLEAN result; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemSleepNeedWake); + + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + // + // We are currently in Dx and not armed for wake. While the current Dx + // state may not be the same Dx state we would be for Sx, we can't get to + // D0 to arm ourselves for Sx wake so just leave ourselves as is. + // + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "Failed to allocate D0 request to disarm from wake from S0 to allow " + "arm for wake from Sx, %!STATUS!", status); + + COVERAGE_TRAP(); + + // + // If D0 IRP allocation fails, we don't treat that as an error. Instead, + // we just let the device remain in Dx without arming it for + // wake-from-Sx, even though the driver had enabled wake-from-Sx. + // + return WdfDevStatePwrPolSystemAsleepNoWake; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemSleepNeedWakeCompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The machine is going into Sx while the device was in Dx. We have started + the D0 process. The power state machine has moved the device into the HW + working state and is waiting to be notified to complete the D0 process. + Send the PowerCompleteD0 event to complete it. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, + WdfDevStatePwrPolSystemSleepNeedWakeCompletePowerUp); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemSleepPowerRequestFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Power up failed in the power state machine. Complete the pending system + power irp with success (system ignores the results) even if the Dx irp + failed. + +Arguments: + This - instance of the state machine + +Return Value: + new state WdfDevStatePwrPolDevicePowerRequestFailed + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemSleepPowerRequestFailed); + + This->PowerPolicyCompleteSystemPowerIrp(); + + return WdfDevStatePwrPolDevicePowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolCheckPowerPageable( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Checks to see if the device should move down the power pagable wake path + or the NP path. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ULONG flags; + MxDeviceObject deviceObject; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCheckPowerPageable); + + deviceObject.SetObject(This->m_Device->GetDeviceObject()); + flags = deviceObject.GetFlags(); + + if (flags & DO_POWER_PAGABLE) { + ASSERT((flags & DO_POWER_INRUSH) == 0); + + return WdfDevStatePwrPolSleepingWakeWakeArrived; + } + else { + // + // DO_POWER_INRUSH also gets us to this state, but since it is mutually + // exclusive with DO_POWER_PAGABLE, we don't need to check for it + // + return WdfDevStatePwrPolSleepingWakeWakeArrivedNP; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakeWakeArrived( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is in partial Dx (I/O has stopped) and will now be armed for wake. + Complete the going Dx transition by sending a PowerCompleteDx irp to the + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + ULONG wakeReason; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSleepingWakeWakeArrived); + + ASSERT(This->PowerPolicyCanWakeFromSystemState( + This->PowerPolicyGetPendingSystemState() + )); + + wakeReason = This->PowerPolicyGetCurrentWakeReason(); + + status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.Invoke( + This->m_Device->GetHandle(), + FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeDeviceEnabledFlag), + FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeChildrenArmedFlag) + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p Failed to arm for wake from Sx, %!STATUS!", + This->m_Device->GetHandle(), status); + + return WdfDevStatePwrPolSleepingWakeRevertArmWake; + } + + // + // If the PDO is the Power Policy owner, then enable wake at bus, otherwise + // the power state machine will enable wake at bus. + // + if (This->m_Device->IsPdo()) { + status = This->PowerEnableWakeAtBusOverload(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!", + This->m_Device->GetHandle(), status); + return WdfDevStatePwrPolSleepingWakeRevertArmWake; + } + } + + This->PowerProcessEvent(PowerCompleteDx); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakeRevertArmWake( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSleepingWakeRevertArmWake); + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "reverting arm for wake from Sx due to failure to allocate wait wake " + "request or wait wake request completed immeidately. Device will *NOT* " + "be armed for wake from Sx"); + + // + // Enable calls should be matched with Disable calls even in the failure + // cases. However, for the Enable wake at bus failure, we do not call the + // disable wake at bus method as we try to keep the failure behavior + // consistent with the Power State machine. Only the Device Disarm wake + // callback will be invoked here. + // + This->PowerPolicyDisarmWakeFromSx(); + + // + // attempt to cancel ww + // + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolSleepingNoWakeCompletePowerDown; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemAsleepWakeArmed( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemAsleepWakeArmed); + This->PowerPolicyCompleteSystemPowerIrp(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabled( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabled); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFired( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFired); + + // + // Make a note of the fact that system was woken by + // a wake interrupt of this device + // + This->m_SystemWokenByWakeInterrupt = TRUE; + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + + return WdfDevStatePwrPolSystemWakeDeviceWakeTriggered; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceled( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceled); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarm( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeDisarm); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->PowerPolicyDisarmWakeFromSx(); + + return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarm( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWokeDisarm); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will enable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.Invoke( + This->m_Device->GetHandle() + ); + + This->PowerPolicyDisarmWakeFromSx(); + + return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakeWakeArrivedNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is in partial Dx (I/O has stopped) and will now be armed for wake. + Complete the going Dx transition by sending a PowerCompleteDx irp to the + power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + ULONG wakeReason; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSleepingWakeWakeArrivedNP); + + ASSERT(This->PowerPolicyCanWakeFromSystemState( + This->PowerPolicyGetPendingSystemState() + )); + + wakeReason = This->PowerPolicyGetCurrentWakeReason(); + + status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromSx.Invoke( + This->m_Device->GetHandle(), + FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeDeviceEnabledFlag), + FLAG_TO_BOOL(wakeReason, FxPowerPolicySxWakeChildrenArmedFlag) + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p Failed to arm for wake from Sx, %!STATUS!", + This->m_Device->GetHandle(), status); + + return WdfDevStatePwrPolSleepingWakeRevertArmWakeNP; + } + + // + // If the PDO is the Power Policy owner, then enable wake at bus, otherwise + // the power state machine will enable wake at bus. + // + if (This->m_Device->IsPdo()) { + status = This->PowerEnableWakeAtBusOverload(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!", + This->m_Device->GetHandle(), status); + return WdfDevStatePwrPolSleepingWakeRevertArmWakeNP; + } + } + + This->PowerProcessEvent(PowerCompleteDx); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakeRevertArmWakeNP( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSleepingWakeRevertArmWakeNP); + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "reverting arm for wake from Sx due to failure to allocate wait wake " + "request or wait wake request completed immeidately. Device will *NOT* " + "be armed for wake from Sx"); + + // + // Enable calls should be matched with Disable calls even in the failure + // cases. However, for the Enable wake at bus failure, we do not call the + // disable wake at bus method as we try to keep the failure behavior + // consistent with the Power State machine. Only the Device Disarm wake + // callback will be invoked here. + // + This->PowerPolicyDisarmWakeFromSx(); + + // + // attempt to cancel ww + // + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolSleepingNoWakeCompletePowerDown; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakePowerDownFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Power down failed in the power state machine. Cancel the wait wake irp + that was just sent down and revert the arming before moving to the failed + state. + +Arguments: + This - instance of the state machine. + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSleepingWakePowerDownFailed); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakePowerDownFailedWakeCanceled( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Wait wake irp has been cancelled. Complete the Sx irp and goto the failed + state. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSleepingWakePowerDownFailedWakeCanceled); + + This->PowerPolicyCompleteSystemPowerIrp(); + + return WdfDevStatePwrPolDevicePowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemAsleepWakeArmedNP( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemAsleepWakeArmedNP); + + This->PowerPolicyCompleteSystemPowerIrp(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledNP( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledNP); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeInterruptFiredNP( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeInterruptFiredNP); + + // + // Make a notee of the fact that system was woken by + // a wake interrupt of this device + // + This->m_SystemWokenByWakeInterrupt = TRUE; + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredNP; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeEnabledWakeCanceledNP( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceWakeEnabledWakeCanceledNP); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeDisarmNP( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeDisarmNP); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->PowerPolicyDisarmWakeFromSx(); + + return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeTriggeredS0NP( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeTriggeredS0NP); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWokeDisarmNP( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWokeDisarmNP); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromSxTriggered.Invoke( + This->m_Device->GetHandle() + ); + + This->PowerPolicyDisarmWakeFromSx(); + + return WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeCompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The system went into Sx and the device was armed for wake. The system has + now returned to S0, the device has started the D0 transition, and the device + has been disarmed for wake. We must now complete the D0 transition by sending + PowerCompleteD0 to the power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, + WdfDevStatePwrPolSystemWakeDeviceWakeCompletePowerUp); + + // + // Simulate a device-power-required notification from the power framework. + // An S0-IRP is essentially equivalent to a device-power-required + // notification. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.SimulateDevicePowerRequired(); + + // + // Notify the device-power-requirement state machine that we are powered on + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleeping( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The machine is going into Sx. Send a Dx irp to the stack. The "x" depends + on if the target system state is one which we can wake the system and + the device is enabled to wake from Sx. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS notifyPowerDownStatus; + SYSTEM_POWER_STATE systemState; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleeping); + + // + // If the bus/PDO is not in the hibernate path, then verify that all the + // children have powered down by now. + // + if (This->GetUsageCount(WdfSpecialFileHibernation) == 0 && + This->m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount > 0) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p powering down before child devices have powered down. " + "This usually indicates a faulty child device that completed the Sx " + "irp before sending the Dx irp", + This->m_Device->GetHandle()); + + FxVerifierBreakOnDeviceStateError( + This->m_Device->GetDriverGlobals()); + } + + // + // Simulate a device-power-not-required notification from the power + // framework. An Sx-IRP is essentially equivalent to a device-power-not- + // required notification. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.SimulateDevicePowerNotRequired(); + + // + // Notify the device-power-requirement state machine that we are about to + // power down + // + notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.NotifyDevicePowerDown(); + + // + // We simulated a device-power-not-required notification before we notified + // the device-power-requirement state machine that we are powering down. + // Therefore, our notification should have succeeded. + // + ASSERT(NT_SUCCESS(notifyPowerDownStatus)); + UNREFERENCED_PARAMETER(notifyPowerDownStatus); + + systemState = This->PowerPolicyGetPendingSystemState(); + + if (This->PowerPolicyIsWakeEnabled() && + This->PowerPolicyCanWakeFromSystemState(systemState)) { + return WdfDevStatePwrPolSleepingWakePowerDown; + } + else { + return WdfDevStatePwrPolSleepingNoWakePowerDown; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingNoWakePowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Machine is going into Sx and the device is not enabled to wake from Sx. + Request a D3 irp to put the device into a low power state. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + DEVICE_POWER_STATE dxState; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingNoWakePowerDown); + + dxState = (DEVICE_POWER_STATE) + This->m_PowerPolicyMachine.m_Owner->m_IdealDxStateForSx; + + if (dxState != PowerDeviceD3) { + DEVICE_POWER_STATE dxMappedState; + + // + // Get the lightest Dx state for this Sx state as reported by the + // device capabilities of the stack. + // + dxMappedState = _GetPowerCapState( + This->PowerPolicyGetPendingSystemState(), + This->m_PowerPolicyMachine.m_Owner->m_SystemToDeviceStateMap + ); + + // + // If the ideal desired state is lighter than what the S->D mapping says + // is the lightest supported D state, use the mapping value instead. + // + if (dxState < dxMappedState) { + dxState = dxMappedState; + } + } + + ASSERT(dxState >= PowerDeviceD1 && dxState <= PowerDeviceD3); + + status = This->PowerPolicyPowerDownForSx(dxState, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolSleepingNoWakeDxRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingNoWakeCompletePowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The system has moved into Sx and the device is not armed for wake. The + device in partial Dx (I/O has stopped), transition the device into full + Dx by sending the PowerCompleteDx event to the power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, + WdfDevStatePwrPolSleepingNoWakeCompletePowerDown); + + This->PowerProcessEvent(PowerCompleteDx); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingNoWakeDxRequestFailed( + __inout FxPkgPnp* This + ) +{ + COVERAGE_TRAP(); + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingNoWakeDxRequestFailed); + + This->SetInternalFailure(); + This->PowerPolicyCompleteSystemPowerIrp(); + + if (FALSE == This->m_ReleaseHardwareAfterDescendantsOnFailure) { + This->PnpProcessEvent(PnpEventPowerDownFailed); + } + + return WdfDevStatePwrPolDevicePowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingWakePowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The system is going into Sx and the device is set to arm itself for wake from + Sx. Start the power down process by requesting the Dx irp to stop I/O in + the power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingWakePowerDown); + + status = This->PowerPolicyPowerDownForSx( + This->m_PowerPolicyMachine.m_Owner->m_WakeSettings.DxState, NoRetry + ); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolSleepingNoWakePowerDown; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingSendWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Machine is moving into an Sx state and the device is in a partial Dx (I/O + stopped) state. Send a wait wake request so that the device can be armed + for wake from Sx. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + SYSTEM_POWER_STATE systemState; + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingSendWake); + + // + // We are in a wake-enabled path, keep wake interrupts connected. + // + This->m_WakeInterruptsKeepConnected = TRUE; + + // + // We use the deepest possible Sx state instead of the current Sx state so + // that we can handle the FastS4 case where PowerPolicyGetPendingSystemState + // would return, but we could possible goto S4. By using the deepest + // possible state, we can arm for any possible Sx state that we are capable + // of waking from. + // + systemState = This->PowerPolicyGetDeviceDeepestSystemWakeState(); + + status = This->PowerPolicySendWaitWakeRequest(systemState); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Attempting to send wait wake request for EvtDeviceArmWakeFromSx() " + "failed, %!STATUS!", status); + + COVERAGE_TRAP(); + + return WdfDevStatePwrPolSleepingNoWakeCompletePowerDown; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemAsleepNoWake( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemAsleepNoWake); + + This->PowerPolicyCompleteSystemPowerIrp(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceWakeDisabled( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The machine is moving from Sx->S0 and the device was in Dx and not armed for + wake from Sx. Determine if the device should remain in Dx after the machine + has moved into S0. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceWakeDisabled); + + // + // We do not attempt to let the device remain in Dx if we are using system- + // managed idle timeout. This is because an S0 IRP is equivalent to a + // device-power-required notification from the power framework. In response + // to it, we need to power up the device and notify the power framework that + // the device is powered on. + // + if ((This->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout() == FALSE) + && + (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.Enabled) + && + (This->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.WakeFromS0Capable == FALSE) + && + (This->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.PowerUpIdleDeviceOnSystemWake == FALSE)) { + + return WdfDevStatePwrPolSystemWakeQueryIdle; + } + else { + return WdfDevStatePwrPolSystemWakeDeviceToD0; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceToD0( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeDeviceToD0); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeDeviceToD0CompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The machine was in Sx and the device was not armed for wake from Sx. The + machine is moving back into S0 and the device is in partial D0 (HW has + started). Move the device into full D0 by sending the PowerCompleteD0 + event to the power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolSystemWakeDeviceToD0CompletePowerUp); + + // + // Simulate a device-power-not-required notification from the power + // framework. An S0-IRP is essentially equivalent to a device-power-required + // notification. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.SimulateDevicePowerRequired(); + + // + // Notify the device-power-requirement state machine that we are powered on + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSystemWakeQueryIdle( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSystemWakeQueryIdle); + + // + // This state can be reached only if we are using driver-managed idle + // timeout. + // + ASSERT( + This->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.UsingSystemManagedIdleTimeout() == FALSE + ); + + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) { + return WdfDevStatePwrPolWaitingUnarmed; + } + else { + return WdfDevStatePwrPolSystemWakeDeviceToD0; + } +} + + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartedWakeCapable( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedWakeCapable); + + // + // Enable the idle state machine. This will release any threads who are + // waiting for the device to return to D0. + // + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.EnableTimer(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWakeCapableDeviceIdle( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are now idle. Tell the active/idle state machine to move us to an idle + state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + BOOLEAN canPowerDown; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWakeCapableDeviceIdle); + + canPowerDown = This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeclareComponentIdle(); + + // + // If we are using driver-managed idle timeout we can power down immediately + // and so we jump to the next state (that initiates power down) immediately. + // If we are using system-managed idle timeout, we wait in the current state + // for device-power-not-required notification. + // + return (canPowerDown ? + WdfDevStatePwrPolTimerExpiredDecideUsbSS : + WdfDevStatePwrPolNull); +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredDecideUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Decides how to handle the idle timer firing. If the device is capable of + USB selective suspend, it will move the machine into that path. Otherwise, + the machine will be moved into the normal arm for wake while in D0 path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS + or + WdfDevStatePwrPolTimerExpiredWakeCapable + + --*/ +{ + NTSTATUS notifyPowerDownStatus; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredDecideUsbSS); + + // + // Notify the device power requirement state machine that we are about to + // power down. + // + notifyPowerDownStatus = This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.NotifyDevicePowerDown(); + if (FALSE == NT_SUCCESS(notifyPowerDownStatus)) { + // + // We couldn't notify the device power requirement state machine that + // we are about to power down, because the "device-power-required" + // notification has already arrived. So we should not power down at this + // time. Revert back to the started state. + // + return WdfDevStatePwrPolDeviceIdleReturnToActive; + } + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + return WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS; + } + else { + return WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is enabled to be armed for wake from S0. The device just idled + out and is now about to transition into this state. The first step is to + move into a partial Dx state (I/O stopped), send the wake request, arm the + device, and then move into full Dx. This function starts the transition + by requesting a Dx irp. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ + +{ + BOOLEAN poweredDown; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDown); + + poweredDown = This->PowerPolicyCanIdlePowerDown( + This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.DxState + ); + + if (poweredDown == FALSE) { + // + // Upon failure, revert back to the started state. + // + return WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableSendWake( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCapableSendWake); + + // + // We are in a wake-enabled path, keep wake interrupts connected. + // + This->m_WakeInterruptsKeepConnected = TRUE; + + status = This->PowerPolicySendWaitWakeRequest(PowerSystemWorking); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not allocate wake request for wake from S0, revert arming," + " %!STATUS!", status); + + COVERAGE_TRAP(); + + return WdfDevStatePwrPolTimerExpiredWakeCapableCleanup; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Sends the selective suspend ready irp down to the USB parent + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableUsbSS); + + This->PowerPolicySubmitUsbIdleNotification(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWakeCapableUsbSSCompleted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We've sent the USB idle notification, but the bus driver completed it even + before sending the USB idle callback. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWakeCapableUsbSSCompleted); + + // + // We notified the device power requirement state machine that we are about + // to power down, but eventually we didn't power down. So notify the device + // power requirement state machine that the device should be considered + // powered on. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + return WdfDevStatePwrPolStartedWakeCapable; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeArrived( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is has been armed for wake from S0. It is in a partial Dx state + (I/O stopped) and needs to transition to the total Dx state by sending + a PowerCompleteDx event to the power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCapableWakeArrived); + + status = This->m_PowerPolicyMachine.m_Owner->m_DeviceArmWakeFromS0.Invoke( + This->m_Device->GetHandle() + ); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake; + } + + // + // If the PDO is the Power Policy owner, then enable wake at bus, otherwise + // the power state machine will enable wake at bus. + // + if (This->m_Device->IsPdo()) { + status = This->PowerEnableWakeAtBusOverload(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE %p Failed to Enable Wake at Bus, %!STATUS!", + This->m_Device->GetHandle(), status); + + return WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake; + } + } + + This->PowerProcessEvent(PowerCompleteDx); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableCancelWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device was attempting to enter Dx armed for wake from S0, but + EvtDeviceArmForWakeFromS0 returned failure. Cancel the wait wake irp and + move into Dx. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableCancelWake); + + if (This->PowerPolicyCancelWaitWake() == FALSE) { + return WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeCanceled( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was put into a wake from S0 state and the arm failed. The wait + wake irp has been canceled, now complete the power down. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolTimerExpiredWakeCapableCleanup + + --*/ +{ + UNREFERENCED_PARAMETER(This); + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableWakeCanceled); + + return WdfDevStatePwrPolTimerExpiredWakeCapableCleanup; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableCleanup( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + An attempt to arm the device for wake from S0 has failed. Decide if we need + to complete the USB SS callback or not before completely powering down so + that we can power back up again. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableCleanup); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + COVERAGE_TRAP(); + This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + } + + // + // Cancel UsbSS if present + // + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // wait for Usbss completion event to move us from this state. + // + return WdfDevStatePwrPolNull; + } + + return WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableDxAllocFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device idled out and we attempted to allocate a Dx irp so that we could + be armed for wake from S0. The Dx irp allocation failed. Complete the + USB SS callback and move back into the working state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + COVERAGE_TRAP(); + This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + } + + // + // cancel USB SS irp if capable + // + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // wait for Usbss completion event to move us from this state. + // + return WdfDevStatePwrPolNull; + } + + return WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableUndoPowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device idled out, but a failure occurred when we attempted to power + down. So we need to return to the active state now. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolDeviceIdleReturnToActive + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCapableUndoPowerDown); + + // + // We notified the device power requirement state machine that we are about + // to power down, but eventually we didn't power down. So notify the device + // power requirement state machine that the device should be considered + // powered on. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + return WdfDevStatePwrPolDeviceIdleReturnToActive; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Complete the Dx transition from Dx armed for S0 wake. Upon going into Dx, + we will move back into D0 since the wake completed already (or there was + an error in arming). + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerDown); + + This->PowerProcessEvent(PowerCompleteDx); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCompletedPowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was armed for wake from S0 and the wake completed immediately + (or there was a problem). We put the device into Dx and we are now trying + to bring it back into D0. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + BOOLEAN result; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCompletedPowerUp); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + // + // Disable the timer so that when we move back into D0, the timer is not + // automatically started. Since the timer has already fired, we should never + // get FALSE back (which indicates we should wait for the timer to fire). + // + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + // + // Couldn't allocate power irp, goto the failed state + // + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCompletedHardwareStarted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We went idle and were in the process of powering down, but the wait-wake IRP + completed even before we could arm the device for wake. We finished powering + down the device and we're now powering it back up due to the wait-wake + completion. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, + WdfDevStatePwrPolTimerExpiredWakeCompletedHardwareStarted); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + return WdfDevStatePwrPolS0WakeCompletePowerUp; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Complete the USB SS callback now tha the device is armed and in Dx + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolWaitingArmed + + --*/ +{ + BOOLEAN result; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedUsbSS); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + } + + // + // Disable the timer so that when we move back into D0, the timer is not + // automatically started. Since the timer has already fired, we should never + // get FALSE back (which indicates we should wait for the timer to fire). + // + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + // + // PwrPolIoPresent can be sent before PwrPolPowerTimeoutExpired in the idle + // state machine if the idle s.m. attempts to cancel the timer after it has + // started running. That means the PwrPolIoPresent meant to wake up the + // device and resume from idle is lost. By first querying the idle s.m. + // after moving into Dx we can recover from the lost event. + // + return WdfDevStatePwrPolWaitingArmedQueryIdle; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedQueryIdle( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in the WaitingArmed state and received a PwrPolIoPresent + event. Before committing the device to move back to D0, check to see if + the device has returned to an idle state. This can easily happen if the + driver causes a power reference in D0Exit accidentally and the power + reference is removed before exitting the function. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ + +{ + // + // If QueryReturnToIdle returns TRUE, return to the waiting state + // + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.QueryReturnToIdle()) { + return WdfDevStatePwrPolWaitingArmed; + } + else { + return WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolIoPresentArmed( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolIoPresentArmed); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolIoPresentArmedWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedWakeInterruptFired( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedWakeInterruptFired); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolIoPresentArmedWakeCanceled( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolIoPresentArmedWakeCanceled); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolS0WakeDisarm( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0WakeDisarm); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke( + This->m_Device->GetHandle() + ); + + return WdfDevStatePwrPolS0WakeCompletePowerUp; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolS0WakeCompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are moving back into D0 from being armed for wake from S0. The device + is in partial D0 (hw started) already, so complete the transition to D0 + by posting the PowerCompleteD0 event to the power state machine. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolS0WakeCompletePowerUp); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeSucceeded( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The wake irp succeeded synchronously when we sent it down the stack. Notify + the driver and move immediately back into the working state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStartingDecideS0Wake + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeSucceeded); + + This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.Invoke( + This->m_Device->GetHandle() + ); + + return WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCompletedDisarm( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was armed for wake from Dx in S0. The wake irp completed + before the PwrPolPowerDown was processed. Disarm the device, move to Dx, + and then immediately back to D0. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolTimerExpiredWakeCapableCleanup + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCompletedDisarm); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke( + This->m_Device->GetHandle() + ); + + return WdfDevStatePwrPolTimerExpiredWakeCapableCleanup; + +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWakeFailedUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Wake failed before we got the Dx irp. Complete the SS calback and then + move to the WakeFailed state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolIoPresentArmedWakeCanceled + + --*/ +{ + BOOLEAN result; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWakeFailedUsbSS); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + } + + // + // Disable the timer so that when we move back into D0, the timer is not + // automatically started. Since the timer has already fired, we should never + // get FALSE back (which indicates we should wait for the timer to fire). + // + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + // + // cancel USB SS irp if capable + // + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // wait for Usbss completion event to move us from this state. + // + return WdfDevStatePwrPolNull; + } + + return WdfDevStatePwrPolIoPresentArmedWakeCanceled; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedCancelWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We sent the wake request, but the power state machine failed. Cancel the + wake request and then move to the failed state. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, + WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedCancelWake); + + if (This->PowerPolicyCancelWaitWake() == FALSE) { + return WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The wake request has been canceled. Move to the state where we will decide + if we need to complete the USB SS callback. + + There is no need to disarm for wake from S0 because the failure here is for + the device to power down. We must assume the device is now in Dx and we + cannot touch hw in this state. + +Arguments: + This - instance of the state machine + +Return Value: + new state, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedDecideUsbSS + + --*/ +{ + UNREFERENCED_PARAMETER(This); + + ASSERT_PWR_POL_STATE( + This, + WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedWakeCanceled); + + return WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownFailedUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Complete the USB SS callback if enabled and the move to the failed state + +Arguments: + This - instance of the state machine + +Return Value: + new state, WdfDevStatePwrPolDevicePowerRequestFailed + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownFailedUsbSS); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + } + + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // wait for Usbss completion event to move us from this state. + // + return WdfDevStatePwrPolNull; + } + + return WdfDevStatePwrPolDevicePowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolCancelingWakeForSystemSleep( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCancelingWakeForSystemSleep); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolCancelingWakeForSystemSleepWakeCanceled( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolCancelingWakeForSystemSleepWakeCanceled); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, NoRetry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolPowerUpForSystemSleepNotSeen; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolDisarmingWakeForSystemSleepCompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was armed for wake from S0 and in Dx. The machine is now moving + into Sx. The device is currently in partial D0 (HW started). Disarm wake + from S0 and then move the device fully into D0 (I/0 started). + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolDisarmingWakeForSystemSleepCompletePowerUp); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke( + This->m_Device->GetHandle() + ); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolPowerUpForSystemSleepFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The system is moving into an Sx state and the device was in a Dx armed for + wake from S0 state. Power up has failed (could not allocate the request, + actual power up path failed, etc). Complete the Sx irp and move into a + state where we can be removed when we return to S0. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolDevicePowerRequestFailed + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolPowerUpForSystemSleepFailed); + + This->PowerPolicyCompleteSystemPowerIrp(); + + return WdfDevStatePwrPolDevicePowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWokeFromS0UsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device successfully woke up before we got to the WaitingArmed state. + Complete the USB SS callback while we are in Dx. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolWokeFromS0 + + --*/ +{ + BOOLEAN result; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWokeFromS0UsbSS); + + if (This->m_PowerPolicyMachine.m_Owner->m_IdleSettings.UsbSSCapable) { + This->m_PowerPolicyMachine.UsbSSCallbackProcessingComplete(); + } + + // + // Disable the timer so that when we move back into D0, the timer is not + // automatically started. Since the timer has already fired, we should never + // get FALSE back (which indicates we should wait for the timer to fire). + // + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + // + // Cancel USBSS irp if capable + // + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + return WdfDevStatePwrPolWokeFromS0; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWokeFromS0( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWokeFromS0); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWokeFromS0NotifyDriver( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was armed for wake from S0 and it successfully woke up and triggered + wake. Notify the driver of this on the way back up to D0. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolS0WakeDisarm + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWokeFromS0NotifyDriver); + + This->m_PowerPolicyMachine.m_Owner->m_DeviceWakeFromS0Triggered.Invoke( + This->m_Device->GetHandle() + ); + + return WdfDevStatePwrPolS0WakeDisarm; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingResetDevice( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was in a Dx state, unarmed for wake. The device is not being + removed, so we must disable the idle timer and power up the device so that + we can implicitly power it down. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + BOOLEAN result; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingResetDevice); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingResetDeviceCompletePowerUp( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was idled out and in Dx (not armed for wake from S0). The power + policy state machine is being stopped and the device has been brought into + partial D0 (HW started). Complete the D0 transition by sending PowerCompleteD0 + to the power state machine. + +Arguments: + This - Instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolStoppingResetDeviceCompletePowerUp); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingResetDeviceFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The attempt to power on a device in the idled out state so that we can stop + the power policy state machine failed. Record the error and continue down + the stop path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStopping + + --*/ + +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingResetDeviceFailed); + + This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE; + + // + // Notify the device power requirement state machine that the device should + // be considered powered on, although it is not. Doing this will ensure that + // component activation before device removal will succeed. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + return WdfDevStatePwrPolStopping; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingD0( + __inout FxPkgPnp* This + ) +{ + NTSTATUS status; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingD0); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + + status = This->PowerPolicySendDevicePowerRequest(PowerDeviceD0, Retry); + if (!NT_SUCCESS(status)) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingD0Failed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + While attempting to stop the device and bring it into D0, power up failed. + Record the error and continue. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStoppingDisarmWakeCancelWake + + --*/ + +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingD0Failed); + + This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE; + + // + // Notify the device power requirement state machine that the device should + // be considered powered on, although it is not. Doing this will ensure that + // component activation before device removal will succeed. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + return WdfDevStatePwrPolStoppingDisarmWakeCancelWake; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingDisarmWake( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingDisarmWake); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + // + // If the PDO is the Power Policy owner, then disable wake at bus, otherwise + // the power state machine will disable wake at bus. + // + if (This->m_Device->IsPdo()) { + This->PowerDisableWakeAtBusOverload(); + } + + This->m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromS0.Invoke( + This->m_Device->GetHandle() + ); + + This->PowerProcessEvent(PowerCompleteD0); + + return WdfDevStatePwrPolNull; + +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingDisarmWakeCancelWake( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingDisarmWakeCancelWake); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingDisarmWakeWakeCanceled( + __inout FxPkgPnp* This + ) +{ + UNREFERENCED_PARAMETER(This); + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingDisarmWakeWakeCanceled); + + return WdfDevStatePwrPolStopping; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStopping( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStopping); + + // + // Prevent any children from powering up. Technically this is not necessary + // because if we are getting to this point, all of our children have already + // been implicitly stopped as well, but this keeps the child power up state + // consistent with the power policy state. + // + This->PowerPolicyBlockChildrenPowerUp(); + + // + // This power change event does not need to be synchronous + // + This->PowerProcessEvent(PowerImplicitD3); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The attempt to move the power state machine into a Dx state failed. Report + the failure to pnp and move to the stopped state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStopped + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingFailed); + + This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE; + + return WdfDevStatePwrPolStoppingSendStatus; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingSendStatus( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The power policy machine is about to finish stopping. The final act of + stopping is notify the Pnp state machine of the final outcome. Do so, reset + state, and move to the stopped state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStopped + + --*/ +{ + KIRQL irql; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingSendStatus); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop(); + + // + // We raise IRQL to dispatch level so that pnp is forced onto its own thread + // to process the PwrPolStopped event. If pnp is on the power thread when + // it processes the event and it tries to delete the dedicated thread, it + // will deadlock waiting for the thread its on to exit. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + This->PnpProcessEvent( + This->m_PowerPolicyMachine.m_Owner->m_PowerFailed + ? PnpEventPwrPolStopFailed + : PnpEventPwrPolStopped + ); + Mx::MxLowerIrql(irql); + + // + // Reset back to a non failed state + // + This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = FALSE; + + return WdfDevStatePwrPolStopped; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppedRemoving( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is being removed. Tell the active/idle state machine to + unregister with the power framework. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppedRemoving); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.UninitializeComponents(); + + return WdfDevStatePwrPolRemoved; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolRemoved( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The active/idle state machine has unregistered with the power framework. + Tell the PNP state machine that device removal can proceed. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + KIRQL irql; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolRemoved); + + // + // We raise IRQL to dispatch level so that pnp is forced onto its own thread + // to process the PwrPolRemoved event. If pnp is on the power thread when + // it processes the event and it tries to delete the dedicated thread, it + // will deadlock waiting for the thread it is on to exit. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + This->PnpProcessEvent(PnpEventPwrPolRemoved); + Mx::MxLowerIrql(irql); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolRestarting( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is restarting after being stopped + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolRestarting); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Start(); + + This->PowerProcessEvent(PowerImplicitD0); + + // + // Wait for the successful power up before starting any idle timers. If + // the power up fails, we will not send a power policy stop from the pnp + // engine. + // + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolRestartingFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Power up failed when restarting the device + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStopped + + --*/ +{ + KIRQL irql; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolRestartingFailed); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.Stop(); + + // + // We raise IRQL to dispatch level so that pnp is forced onto its own thread + // to process the PwrPolStartFailed event. If pnp is on the power thread + // when it processes the event and it tries to delete the dedicated thread, + // it will deadlock waiting for the thread it is on to exit. + // + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + This->PnpProcessEvent(PnpEventPwrPolStartFailed); + Mx::MxLowerIrql(irql); + + return WdfDevStatePwrPolStopped; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingCancelTimer( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Moving to the stopping state. Need to cancel the idle timeout timer. + +Arguments: + This - instance of the state machine + +Return Value: + new power policy state + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingCancelTimer); + + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) { + return WdfDevStatePwrPolStopping; + } + else { + // + // Timer was not canceled, move to the state where we wait for the + // timeout event to be posted. + // + return WdfDevStatePwrPolStoppingWaitForIdleTimeout; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingCancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Cancel the USB SS request because we are being stopped or surprise removed + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStoppingWaitForUsbSSCompletion + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingCancelUsbSS); + + // + // We notified the device power requirement state machine that we are about + // to power down, but eventually we didn't power down. So notify the device + // power requirement state machine that the device should be considered + // powered on. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + if (This->PowerPolicyCancelUsbSSIfCapable() == FALSE) { + // + // UsbSS already canceled/completed + // + return WdfDevStatePwrPolStoppingCancelTimer; + } + + return WdfDevStatePwrPolStoppingWaitForUsbSSCompletion; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingCancelWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Cancels the pended wait wake in the case where we are surprise removed and + in a Dx state and armed for wake. + +Arguments: + This - instance of the state machine + +Return Value: + If there was no request to cancel, WdfDevStatePwrPolStopping. If there was, + wait for the wait completion event to be posted before transitioning. + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingCancelWake); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + COVERAGE_TRAP(); + return WdfDevStatePwrPolStopping; + } + else { + return WdfDevStatePwrPolNull; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolCancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The S0 idle policy has changed. Cancel the idle notification so we can move + to another S0 started state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCancelUsbSS); + + // + // We notified the device power requirement state machine that we are about + // to power down, but eventually we didn't power down. So notify the device + // power requirement state machine that the device should be considered + // powered on. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + if (This->PowerPolicyCancelUsbSSIfCapable() == FALSE) { + // + // UsbSS has already been canceled/completed + // + return WdfDevStatePwrPolStartedCancelTimer; + } + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStarted( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is now in the started state (w/regard to power policy). + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStarted); + + // + // We signal we are in D0 even though there is idling out in this state + // because we could have just come from a state which *was* idled out. + // For instance + // 1) We are in WaitingArmed and an io present event moved us out of this state + // 2) Immediately afterward, the s0 idle policy was changed + // 3) When we enter StartingDecideS0Wake, we will move into this state without + // first entering StartedWakeCapable. + // 4) The source of the io present event, if waiting synchronously needs to + // be unblocked. + // + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartedCancelTimer( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is started and we need to cancel the idle timer + +Arguments: + This - instance of the state machine + +Return Value: + new power policy state + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedCancelTimer); + + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) { + return WdfDevStatePwrPolStartingDecideS0Wake; + } + else { + COVERAGE_TRAP(); + return WdfDevStatePwrPolStartedWaitForIdleTimeout; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartedWakeCapableCancelTimerForSleep( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is wake capable and enabled for idling out. Try to disable the + power idle state machine. + +Arguments: + This - instance of the state machine + +Return Value: + new power policy state + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolStartedWakeCapableCancelTimerForSleep); + + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) { + return WdfDevStatePwrPolSleeping; + } + else { + COVERAGE_TRAP(); + return WdfDevStatePwrPolStartedWakeCapableWaitForIdleTimeout; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartedWakeCapableSleepingUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The machine is going to sleep after we have submitted the USB SS request + but before USB has called us back on the go to idle callback. Cancel the + request and wait for its completion + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPol + + --*/ +{ + BOOLEAN result; + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStartedWakeCapableSleepingUsbSS); + + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + + // + // Since the power timeout expired, the disable should not return FALSE + // + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + // + // Cancel USBSS irp + // + This->PowerPolicyCancelUsbSS(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStartedIdleCapableCancelTimerForSleep( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is idle capable and enabled for idling out. Try to disable the + power idle state machine. + +Arguments: + This - instance of the state machine + +Return Value: + new power policy state + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolStartedIdleCapableCancelTimerForSleep); + + if (This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer()) { + return WdfDevStatePwrPolSleeping; + } + else { + COVERAGE_TRAP(); + return WdfDevStatePwrPolStartedIdleCapableWaitForIdleTimeout; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolDeviceD0PowerRequestFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + A D0 request failed, notify pnp. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolDevicePowerRequestFailed + + --*/ +{ + COVERAGE_TRAP(); + + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDeviceD0PowerRequestFailed); + + This->SetInternalFailure(); + + if (FALSE == This->m_ReleaseHardwareAfterDescendantsOnFailure) { + This->PnpProcessEvent(PnpEventPowerUpFailed); + } + + return WdfDevStatePwrPolDevicePowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolDevicePowerRequestFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Either we could not allocate a device power irp or the power state machine + reported failure. Mark the failure and then wait for pnp to send a stop + event. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolDevicePowerRequestFailed); + + // + // In the failure path we still need to notify the children that they can + // power up so that they will unblock. + // + This->PowerPolicyChildrenCanPowerUp(); + + This->m_PowerPolicyMachine.m_Owner->m_PowerFailed = TRUE; + + // + // Notify the device power requirement state machine that the device should + // be considered powered on, although it may not be in reality. Doing this + // will ensure that component activation before device removal will succeed. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + return WdfDevStatePwrPolNull; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolSleepingPowerDownNotProcessed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We requested a Dx irp but a driver layered above our device failed the + request without sending it down the stack. Queue a Tear down the stack and + then move into a state where we will complete the Sx irp. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolSystemSleepPowerRequestFailed + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolSleepingPowerDownNotProcessed); + + This->SetInternalFailure(); + + return WdfDevStatePwrPolSystemSleepPowerRequestFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapablePowerDownNotProcessed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We requested a Dx irp after idling out, but a driver layered above our device + failed the request without sending it down the stack. Queue a tear down the + stack and then move into a state where we can handle tear down. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredWakeCapablePowerDownNotProcessed); + + This->SetInternalFailure(); + + return WdfDevStatePwrPolTimerExpiredWakeCapableDxAllocFailed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredNoWakePowerDownNotProcessed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We requested a Dx irp after idling out, but a driver layered above our device + failed the request without sending it down the stack. Queue a tear down the + stack and then move into a state where we can handle tear down. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStartedIdleCapable + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredNoWakePowerDownNotProcessed); + + This->SetInternalFailure(); + + return WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredNoWakeUndoPowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was idle and attempting to go to Dx (without wake-from-S0), but + a power down failure occurred. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredNoWakeUndoPowerDown); + + // + // We notified the device power requirement state machine that we are about + // to power down, but eventually we didn't power down. So notify the device + // power requirement state machine that the device should be considered + // powered on. + // + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.DeviceIsPoweredOn(); + + return WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredNoWakeReturnToActive( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device was idle and attempting to go to Dx (without wake-from-S0), but + eventually it did not go to Dx. This might have been because a power down + failure occurred or because we received the device power required + notification from the power framework before we could go to Dx. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolNull + + --*/ +{ + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredNoWakeReturnToActive); + + This->m_PowerPolicyMachine.m_Owner-> + m_PoxInterface.RequestComponentActive(); + + return WdfDevStatePwrPolStartedIdleCapable; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredNoWakePoweredDownDisableIdleTimer( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device has fully powered down. Disable the idle timer so that when we + we power up the idle timer will not start running immediately. Rather, + we should power up and only start the idle timer after being explicitly + enabled again. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolWaitingUnarmedQueryIdle + + --*/ +{ + BOOLEAN result; + + ASSERT_PWR_POL_STATE( + This, WdfDevStatePwrPolTimerExpiredNoWakePoweredDownDisableIdleTimer); + + // + // Disable the timer so that when we move back into D0, the timer is not + // automatically started. Since the timer has already fired, we should never + // get FALSE back (which indicates we should wait for the timer to fire). + // + result = This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); + + // + // Check to see if we should immediately power up + // + return WdfDevStatePwrPolWaitingUnarmedQueryIdle; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolPowerUpForSystemSleepNotSeen( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + PowerDeviceD0 request was not forwarded to this driver by upper driver even + though this driver requested it. Power completion routine detects this + condition, and causes transition to this state. Ensure that any pending + S-IRP is completed. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolDeviceD0PowerRequestFailed + + --*/ +{ + if (This->m_PendingSystemPowerIrp != NULL) { + This->PowerPolicyCompleteSystemPowerIrp(); + } + + return WdfDevStatePwrPolDeviceD0PowerRequestFailed; +} + +__drv_sameIRQL +VOID +FxPkgPnp::_PowerPolDeviceWaitWakeComplete( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in_opt PVOID Context, + __in PIO_STATUS_BLOCK IoStatus + ) +/*++ + +Routine Description: + Completion routine for a requested wait wake irp. Called once the wait wake + irp has traveled through the entire stack or when some driver in the stack + completes the wait wake irp. We feed the result of the wait wake operation + back into the power policy state machine through an event. + +Arguments: + Context - instance of the state machine + IoStatus - pointer to the IO_STATUS_BLOCK structure for the completed IRP + All others ignored + +Return Value: + None + + --*/ +{ + FxPkgPnp* pThis; + + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(MinorFunction); + UNREFERENCED_PARAMETER(PowerState); + + pThis = (FxPkgPnp*) Context; + pThis->m_PowerPolicyMachine.m_Owner->m_WaitWakeStatus = IoStatus->Status; + + if (NT_SUCCESS(IoStatus->Status)) { + pThis->PowerPolicyProcessEvent(PwrPolWakeSuccess); + } + else { + pThis->PowerPolicyProcessEvent(PwrPolWakeFailed); + } +} + +__drv_sameIRQL +VOID +FxPkgPnp::_PowerPolDevicePowerDownComplete( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in_opt PVOID Context, + __in PIO_STATUS_BLOCK IoStatus + ) +/*++ + +Routine Description: + Completion routine for a requested power irp. Called once the power irp + has traveled through the entire stack. We feed the result of the power + operation back into the power policy state machine through an event. + +Arguments: + Context - instance of the state machine + All others ignored + +Return Value: + None + + --*/ + +{ + FxPkgPnp* pThis; + + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(MinorFunction); + UNREFERENCED_PARAMETER(PowerState); + UNREFERENCED_PARAMETER(IoStatus); + + pThis = (FxPkgPnp*) Context; + + // + // Note that we are ignoring IoStatus.Status intentionally. If we failed + // power down in this device, we have tracked that state via + // m_PowerDownFailure. If some other device failed power down, we are still + // in the state where we succeeded power down and we don't want to alter + // that yet. + // + // Note that the state machine also handles an upper filter completing the + // Dx irp before our device gets to process it (which would be a bug in the + // filter driver) by handling the PwrPolPowerDown from the appropriate + // state, as an example... + // + // a successful power down state transition looks like this + // 1) power policy state where we request a power irp + // 2) power sends a partial power down message (PwrPolPowerDownIoStopped) + // to power policy, moves to the partial power down state + // 3) power policy tells power to complete the power down + // 4) power completes the irp and we send the power down complete message + // (PwrPolPowerDown) moving from the partial power down state to the + // final power down state + // + // In the case where the top filter driver completes the PIRP without our + // driver seeing it, we will be in the state where we requested a power irp + // and process a power down complete event instead of the partial power down + // event and in this transition, we detect the error. + // + if (pThis->m_PowerMachine.m_PowerDownFailure) { + // + // Clear the faliure condition if we ever attempt to power off this + // device again (highly possible if it is a PDO). + // + pThis->m_PowerMachine.m_PowerDownFailure = FALSE; + + // + // Power down failed, send ourself an even indicating that. + // + pThis->PowerPolicyProcessEvent(PwrPolPowerDownFailed); + + // + // Inform pnp last so that all the other state machines are in the failed + // state by the time we transition the pnp state of the device. + // + if (FALSE == pThis->m_ReleaseHardwareAfterDescendantsOnFailure) { + pThis->PnpProcessEvent(PnpEventPowerDownFailed); + } + } + else { + // + // Power down succeeded, send ourself an even indicating that. + // + pThis->PowerPolicyProcessEvent(PwrPolPowerDown); + } +} + +__drv_sameIRQL +VOID +FxPkgPnp::_PowerPolDevicePowerUpComplete( + __in MdDeviceObject DeviceObject, + __in UCHAR MinorFunction, + __in POWER_STATE PowerState, + __in_opt PVOID Context, + __in PIO_STATUS_BLOCK IoStatus + ) +/*++ + +Routine Description: + Completion routine for a requested power irp. Called once the power irp + has traveled through the entire stack. We feed the result of the power + operation back into the power policy state machine through an event. + +Arguments: + Context - instance of the state machine + All others ignored + +Return Value: + None + + --*/ + +{ + FxPkgPnp* pThis; + + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(MinorFunction); + UNREFERENCED_PARAMETER(PowerState); + UNREFERENCED_PARAMETER(IoStatus); + + pThis = (FxPkgPnp*) Context; + + // + // The state machine handles an upper filter completing the + // D0 irp before our device gets to process it (which would be a bug in the + // filter driver). + // + if (pThis->m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp) { + // + // We requested a Power Irp but that never arrived in dispatch routine. + // We know this because m_RequestedPowerUpIrp is still TRUE at the end of + // the power irp completion (it is set to false when it arrives in + // dispatch routine). + // + DoTraceLevelMessage( + pThis->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "PowerDeviceD0 requested by WDFDEVICE 0x%p !devobj 0x%p, " + "is being completed by upper driver without sending it to " + "driver that requested it", + pThis->m_Device->GetHandle(), + pThis->m_Device->GetDeviceObject()); + + // + // Power-up request not seen, send ourself an event indicating that. + // + pThis->PowerPolicyProcessEvent(PwrPolPowerUpNotSeen); + } +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PowerPolicySendDevicePowerRequest( + __in DEVICE_POWER_STATE DeviceState, + __in SendDeviceRequestAction Action + ) +/*++ + +Routine Description: + Attempts to send a D irp to the stack. The caller can specify if the + request allocation is retried in case of failure. + +Design Notes: + The timeout and number of retries are somewhat magical numbers. They were + picked so that the total amount of time spent attempting to retry would be + under a minute. Any memory pressure the machine would be under after the + first failure should be over by the end of the minute; if not, there are + bigger problems. + + If you look at each of the callers who specify Retry for the Action, nearly + each one transitions to the WdfDevStatePwrPolDevicePowerRequestFailed state + if the request cannot be allocated. This transition could be placed in this + function, but it is not for 2 reasons: + + 1) Keep this function simple + + 2) It makes the flow of the state transition function easier to understand; + all transitions out of the current state happen within top level + transition function + +Arguments: + DeviceState - The new D state being request + + Action - Whether to retry upon failure to allocate the request + +Return Value: + NT_SUCCESS if the request was allocated, !NT_SUCCESS otherwise + + --*/ +{ + MdRequestPowerComplete pCompletionRoutine; + LARGE_INTEGER interval; + NTSTATUS status; + POWER_STATE state; + ULONG i; + + status = STATUS_UNSUCCESSFUL; + interval.QuadPart = WDF_REL_TIMEOUT_IN_MS(500); + state.DeviceState = DeviceState; + + if (DeviceState == PowerDeviceD0) { + // + // We are powering up, we do not synchronize the completion of the D0 irp + // with a potential S0 irp. However we need to ensure that if an upper filter + // driver fails the power irp, we handle it gracefully rather than keep waiting + // for the power irp to arrive. + // + pCompletionRoutine = _PowerPolDevicePowerUpComplete; + } + else { + // + // We are powering down, we synchronize the completion of the Dx irp + // with a potential Sx irp. If there is no pending Sx irp, the state + // machine takes care of it. + // + pCompletionRoutine = _PowerPolDevicePowerDownComplete; + } + + // + // We track when we request power irps to catch someone other then ourselves + // sending power irps to our own stack. + // + if (DeviceState == PowerDeviceD0) { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = TRUE; + } + else { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = TRUE; + } + + for (i = 0; i < 100; i++) { + status = FxIrp::RequestPowerIrp(m_Device->GetDeviceObject(), + IRP_MN_SET_POWER, + state, + pCompletionRoutine, + this); + + // + // If we are not retrying, we always break out + // + if (NT_SUCCESS(status) || Action == NoRetry) { + break; + } + + Mx::MxDelayExecutionThread(KernelMode, FALSE, &interval); + } + + if (!NT_SUCCESS(status)) { + // + // We are no longer requesting a power irp + // + if (DeviceState == PowerDeviceD0) { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerUpIrp = FALSE; + } + else { + m_PowerPolicyMachine.m_Owner->m_RequestedPowerDownIrp = FALSE; + } + + if (Action == Retry) { + COVERAGE_TRAP(); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Could not request D%d irp for device %p (WDFDEVICE %p), " + "%!STATUS!", DeviceState-1, + m_Device->GetDeviceObject(), + m_Device->GetHandle(), status); + } + } + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Requesting D%d irp, %!STATUS!", + DeviceState-1, status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::PowerPolicySendWaitWakeRequest( + __in SYSTEM_POWER_STATE SystemState + ) +{ + NTSTATUS status; + POWER_STATE state; + + state.SystemState = SystemState; + + // + // We track when we request power irps to catch someone other then ourselves + // sending power irps to our own stack. + // + m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = TRUE; + + // + // Since we are sending a fresh wake, clear any state that was meant + // for the last wake IRP + // + m_SystemWokenByWakeInterrupt = FALSE; + + // + // we are requesting new ww irp so re-initialize dropped event tracker. + // + m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped = FALSE; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Requesting wait wake irp for S%d", SystemState-1); + + status = FxIrp::RequestPowerIrp(m_Device->GetDeviceObject(), + IRP_MN_WAIT_WAKE, + state, + _PowerPolDeviceWaitWakeComplete, + this); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Requesting wait wake irp for S%d failed, %!STATUS!", + SystemState-1, status); + + // + // We are no longer requesting a power irp + // + m_PowerPolicyMachine.m_Owner->m_RequestedWaitWakeIrp = FALSE; + } + + return status; +} + +VOID +FxPkgPnp::PowerPolicyCompleteSystemPowerIrp( + VOID + ) +{ + FxIrp irp(m_PendingSystemPowerIrp); + NTSTATUS status; + + ASSERT(m_PendingSystemPowerIrp != NULL); + + status = STATUS_SUCCESS; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Completing system power irp %p (S%d), %!STATUS!", + m_PendingSystemPowerIrp, + irp.GetParameterPowerStateSystemState()-1, + status); + + m_PendingSystemPowerIrp = NULL; + + CompletePowerRequest(&irp, STATUS_SUCCESS); +} + +BOOLEAN +FxPkgPnp::PowerPolicyCancelWaitWake( + VOID + ) +/*++ + +Routine Description: + Completes or cancels a pending wait wake irp depending on if the irp is + present and if the device is the owner of the wait wake irp. + +Arguments: + +Return Value: + + + --*/ +{ + MdIrp wwIrp; + BOOLEAN cancelled, result; + + if (m_SharedPower.m_WaitWakeOwner) { + // + // This will complete the irp and then post the appropriate events to + // both the power and power policy state machines. + // + cancelled = PowerIndicateWaitWakeStatus(STATUS_CANCELLED); + } + else { + wwIrp = (MdIrp) InterlockedExchangePointer( + (PVOID*) &m_SharedPower.m_WaitWakeIrp, NULL); + + if (wwIrp != NULL) { + FxIrp irp(wwIrp); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Successfully got WaitWake irp %p for cancelling", wwIrp); + + result = irp.Cancel(); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Cancel of irp %p returned %d", wwIrp, result); + + + if (m_PowerPolicyMachine.CanCompleteWaitWakeIrp()) { + CompletePowerRequest(&irp, irp.GetStatus()); + } + else { + // + // Irp has been completed by the lower bus driver, that's OK + // because the completion of the request will trigger the + // same transition + // + DO_NOTHING(); + } + + cancelled = TRUE; + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "No WaitWake irp to cancel"); + + cancelled = FALSE; + } + } + + return cancelled; +} + +__drv_sameIRQL +NTSTATUS +FxPkgPnp::_PowerPolicyWaitWakeCompletionRoutine( + __in MdDeviceObject DeviceObject, + __in MdIrp OriginalIrp, + __in_xcount_opt("varies") PVOID Context + ) +{ + FxIrp originalIrp(OriginalIrp); + MdIrp pOldIrp; + FxPkgPnp *pThis; + NTSTATUS status; + + pThis = (FxPkgPnp*) Context; + + if (originalIrp.PendingReturned()) { + originalIrp.MarkIrpPending(); + } + + DoTraceLevelMessage(pThis->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p !devobj %p Completion of WaitWake irp %p," + " %!STATUS!", pThis->m_Device->GetHandle(), + DeviceObject, originalIrp.GetIrp(), + originalIrp.GetStatus()); + + if (NT_SUCCESS(originalIrp.GetStatus())) { + + // + // Check to see if this device caused the machine to wake up + // + pThis->PowerPolicyUpdateSystemWakeSource(&originalIrp); + } + + if (pThis->m_SystemWokenByWakeInterrupt) { + // + // If the system was woken by a wake interrupt, we need to mark this + // device as the wake source. Since we typically cancel the wait + // wake IRP in this path, it is expected that the completion + // status will not be success. We need to change this status code to + // success because power manager ignores the wake source information + // reported by a wait wake IRP that is not completed successfully. + // + pThis->_PowerSetSystemWakeSource(&originalIrp); + originalIrp.SetStatus(STATUS_SUCCESS); + } + + // + // Attempt to gain exclusive ownership of the irp from the cancel call site. + // If we do (indicated by the exchange returning a non-NULL pointer), we can + // complete the request w/out worrying about the cancel call site. + // + // If we can't, we must check to see if we can complete the wait wake irp + // (the cancel call site at least has the irp pointer value and has called + // IoCancelIrp on it). + // + pOldIrp = (MdIrp) InterlockedExchangePointer( + (PVOID*)&pThis->m_SharedPower.m_WaitWakeIrp, NULL); + + ASSERT(pOldIrp == NULL || pOldIrp == originalIrp.GetIrp()); + + if (pOldIrp != NULL || + pThis->m_PowerPolicyMachine.CanCompleteWaitWakeIrp()) { + DoTraceLevelMessage(pThis->GetDriverGlobals(), + TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Completion of WaitWake irp %p", + originalIrp.GetIrp()); + + originalIrp.StartNextPowerIrp(); + + status = STATUS_CONTINUE_COMPLETION; + + Mx::MxReleaseRemoveLock( + &FxDevice::_GetFxWdmExtension( + DeviceObject)->IoRemoveLock, + originalIrp.GetIrp() + ); + } + else { + // + // ************ WARNING ************* + // By this time the IRP may have got completed by cancel call site, so + // don't touch irp *members* in this path (it is ok to use the IRP + // address though as in the log below). + // + DoTraceLevelMessage( + pThis->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Not completing WaitWake irp %p in completion routine", + originalIrp.GetIrp()); + + status = STATUS_MORE_PROCESSING_REQUIRED; + } + + return status; +} + +__drv_sameIRQL +NTSTATUS +FxPkgPnp::_PowerPolicyUsbSelectiveSuspendCompletionRoutine( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp, + __in_xcount_opt("varies") PVOID Context + ) +{ + FxPkgPnp* This; + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER(DeviceObject); + + This = (FxPkgPnp*) Context; + + // + // Parameters DeviceObejct and Irp are always set to NULL in UMDF, so + // don't touch these in UMDF trace + // +#if FX_IS_KERNEL_MODE + DoTraceLevelMessage(This->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p Completion of UsbSS irp %p, %!STATUS!", + This->m_Device, This->m_Device->GetDeviceObject(), + irp.GetIrp(), irp.GetStatus()); + +#elif FX_IS_USER_MODE + UNREFERENCED_PARAMETER(irp); + + DoTraceLevelMessage(This->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p, !devobj %p Completion of UsbSS irp", + This->m_Device, This->m_Device->GetDeviceObject()); +#endif + + // + // Post an event indicating that the irp has been completed + // + This->PowerPolicyProcessEvent( + PwrPolUsbSelectiveSuspendCompleted + ); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +BOOLEAN +FxPkgPnp::PowerPolicyCanIdlePowerDown( + __in DEVICE_POWER_STATE DxState + ) +/*++ + +Routine Description: + Attempts to send a Dx irp down the stack after this device has idled out. + Before the Dx can be set, we must check that no child devices have attempted + to power up in between the idle timer firing and the state machine + processing the event. After we have determined that no children are in + D0, we setup a guard so that any child which attempts to power up after this + point will pend the power up until this device has either powered all the + way down and back up or could not allocate a device power irp + +Arguments: + DxState - the destination device state + +Return Value: + TRUE if the device power irp was sent, FALSE otherwise + + --*/ +{ + BOOLEAN powerDown; + + // + // If we potentially have children, make sure that they are all in Dx before + // the parent powers down. + // + if (m_EnumInfo != NULL) { + m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals()); + if (m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount == 0) { + // + // Setup a guard so that no children power up until we either fail + // this power down or power all the way down and back up. + // + m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp = FALSE; + powerDown = TRUE; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE %p !devobj 0x%p not idling out because there are %d " + "children who are powered up", m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount); + powerDown = FALSE; + } + m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals()); + } + else { + powerDown = TRUE; + } + + if (powerDown) { + NTSTATUS status; + + status = PowerPolicySendDevicePowerRequest(DxState, NoRetry); + + if (!NT_SUCCESS(status)) { + // + // This will set m_ChildrenCanPowerUp to TRUE and send a + // ParentMovesToD0 in case any children powered down in between + // determining if the parent can go idle and failing to do so. + // + PowerPolicyChildrenCanPowerUp(); + + powerDown = FALSE; + } + } + + return powerDown; +} + +VOID +FxPkgPnp::PowerPolicyPostParentToD0ToChildren( + VOID + ) +/*++ + +Routine Description: + Indicates to all of the children that the parent is in D0 + +Arguments: + None + +Return Value: + None. + + --*/ +{ + FxTransactionedEntry* ple; + + ASSERT(IsPowerPolicyOwner()); + + if (m_EnumInfo != NULL) { + m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); + + ple = NULL; + while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { + ((FxChildList*) ple->GetTransactionedObject())->PostParentToD0(); + } + + m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); + } +} + +VOID +FxPkgPnp::PowerPolicyChildrenCanPowerUp( + VOID + ) +/*++ + +Routine Description: + After this function returns, any child devices rooted off of this parent + device can now move into D0. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // + // This can be called for any PPO so we must check first if we have any + // possibility of children. + // + if (m_EnumInfo == NULL) { + return; + } + + if (IsPowerPolicyOwner()) { + m_EnumInfo->AcquireParentPowerStateLock(GetDriverGlobals()); + + // + // When the child attempts to power up, m_ChildrenPoweredOnCount can + // be incremented while the parent is in Dx. The important value + // here is the guard value, m_ChildrenCanPowerUp which must be + // FALSE. + // + // ASSERT (m_PowerPolicyMachine.m_Owner->m_ChildrenPoweredOnCount == 0); + + // + // In the USB SS case, we can return to StartingDecideS0Wake without + // ever attempting to go into a Dx state state, so m_ChildrenCanPowerUp + // can be TRUE. + // + // ASSERT(m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp == FALSE); + + m_PowerPolicyMachine.m_Owner->m_ChildrenCanPowerUp = TRUE; + m_EnumInfo->ReleaseParentPowerStateLock(GetDriverGlobals()); + + // + // Now that we have set the state of the parent, any child which checks + // the power state after we have released the lock will be able to + // power up immediately. We now need to unblock all children which + // checked the parent state before this function was called by posting + // a PowerParentToD0 event to each child (regardless of the PDO device + // power state). + // + PowerPolicyPostParentToD0ToChildren(); + } + else { + // + // Since we are not the power policy owner for the parent device, + // we cannot make any guarantees about the child being in D0 while + // the parent is in D0 so we do not call PowerPostParentToD0ToChildren(). + // Additionally in PowerPolicyCanChildPowerUp(), if the parent (this) + // device is not the PPO, we don't even check the parent D state before + // powering up the child. + // + DO_NOTHING(); + } +} + +VOID +__inline +FxPkgPnp::PowerPolicyDisarmWakeFromSx( + VOID + ) +/*++ + +Routine Description: + Calls into the client driver to disarm itself from wake and the clears the + flag which indicates that the device is a source of system wake. The disarm + callback is the last callback available to the driver to indicate the wake + status of its children and have the wake status propagate upwards to the + PDO's stack. + + --*/ +{ + NTSTATUS wwStatus; + FxTransactionedEntry* ple; + + m_PowerPolicyMachine.m_Owner->m_DeviceDisarmWakeFromSx.Invoke( + m_Device->GetHandle() + ); + + wwStatus = m_PowerPolicyMachine.m_Owner->m_WaitWakeStatus; + + if (wwStatus != STATUS_CANCELLED && + m_EnumInfo != NULL && + PowerPolicyShouldPropagateWakeStatusToChildren()) { + m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); + + ple = NULL; + while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { + ((FxChildList*) ple->GetTransactionedObject())-> + IndicateWakeStatus(wwStatus); + } + + m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); + } + + m_PowerPolicyMachine.m_Owner->m_WaitWakeStatus = STATUS_NOT_SUPPORTED; + + // + // Always set the wake source back to FALSE regardless of it previous value. + // + m_PowerPolicyMachine.m_Owner->m_SystemWakeSource = FALSE; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedStoppingCancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is in Dx and surprise removed. Cancel the idle notification so + we can move to another state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStoppingCancelWake + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedStoppingCancelUsbSS); + + This->m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.DisableTimer(); + + // + // Since we are in Dx and surprise removed, cancel the usb SS irp if it is + // there. Otherwise, the USB PDO will call us back after we have processed + // remove. + // + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + // + // If usbss irp was there it has already been canceled, so march on. + // + return WdfDevStatePwrPolStoppingCancelWake; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedWakeFailedCancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is in Dx armed for wake and wait wake irp got failed. + Cancel the idle notification so we can move to another state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolIoPresentArmedWakeCanceled + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedWakeFailedCancelUsbSS); + + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + // + // If usbss irp was there it has already been canceled, so march on. + // + return WdfDevStatePwrPolIoPresentArmedWakeCanceled; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedIoPresentCancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is in Dx armed for wake. + Cancel the idle notification so we can move to another state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolIoPresentArmed + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedIoPresentCancelUsbSS); + + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + // + // If usbss irp was there it has already been canceled, so march on. + // + return WdfDevStatePwrPolIoPresentArmed; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolWaitingArmedWakeSucceededCancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device woke from S0. + Cancel the idle notification so we can move to another state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolWokeFromS0 + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolWaitingArmedWakeSucceededCancelUsbSS); + + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + // + // If usbss irp was there it has already been canceled, so march on. + // + return WdfDevStatePwrPolWokeFromS0; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolCancelingUsbSSForSystemSleep( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The system is going to sleep.. + Cancel the idle notification so we can move to another state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolCancelingWakeForSystemSleep + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolCancelingUsbSSForSystemSleep); + + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + // + // If usbss irp was there it has already been canceled, so march on. + // + return WdfDevStatePwrPolCancelingWakeForSystemSleep; +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolStoppingD0CancelUsbSS( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Cancel the idle notification so we can move to another state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePwrPolStoppingD0 + + --*/ +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolStoppingD0CancelUsbSS); + + if (This->PowerPolicyCancelUsbSSIfCapable()) { + // + // Usbss completion event will move us from this state. + // + return WdfDevStatePwrPolNull; + } + + // + // If usbss irp was there it has already been canceled, so march on. + // + return WdfDevStatePwrPolStoppingD0; +} + +BOOLEAN +FxPkgPnp::PowerPolicyCancelUsbSSIfCapable( + VOID + ) +/*++ + +Routine Description: + Cancel the idle notification irp if capable + +Arguments: + none + +Return Value: + TRUE if irp was canceled + FALSE if not capable of USBSS or if Irp was already completed. + + --*/ +{ + if (m_PowerPolicyMachine.m_Owner->m_UsbIdle == NULL || + m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped) { + return FALSE; + } + else { + PowerPolicyCancelUsbSS(); + return TRUE; + } +} + +WDF_DEVICE_POWER_POLICY_STATE +FxPkgPnp::PowerPolTimerExpiredWakeCapableWakeInterruptArrived( + __inout FxPkgPnp* This + ) +{ + ASSERT_PWR_POL_STATE(This, WdfDevStatePwrPolTimerExpiredWakeCapableWakeInterruptArrived); + + if (This->PowerPolicyCancelWaitWake() == FALSE && + This->m_PowerPolicyMachine.m_Owner->m_WakeCompletionEventDropped) { + return WdfDevStatePwrPolTimerExpiredWakeCapableWakeSucceeded; + } + + return WdfDevStatePwrPolNull; +} + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/powerstatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/powerstatemachine.cpp new file mode 100644 index 00000000000..6474f5ba4b5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/powerstatemachine.cpp @@ -0,0 +1,5398 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerStateMachine.cpp + +Abstract: + + This module implements the Power state machine for the driver framework. + This code was split out from FxPkgPnp.cpp. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerStateMachine.tmh" +#endif +} + +#if FX_STATE_MACHINE_VERIFY + #define VALIDATE_POWER_STATE(_CurrentState, _NewState) \ + ValidatePowerStateEntryFunctionReturnValue((_CurrentState), (_NewState)) +#else + #define VALIDATE_POWER_STATE(_CurrentState, _NewState) (0) +#endif //FX_STATE_MACHINE_VERIFY + + +// @@SMVERIFY_SPLIT_BEGIN + +// +// The Power State Machine +// +// This state machine responds to power IRPs that relate +// to devices. It is a subordinate, responding either to IRPs +// that are sent by other drivers, or by IRPs that are +// sent by the Power Policy State Machine. +// +// It responds to: +// +// IRP_MN_SET_POWER -- device power IRPs only +// IRP_MN_WAIT_WAKE +// IRP_MN_WAIT_WAKE Complete +// PowerImplicitD0 +// PowerImplicitD3 +// ParentMovesToD0 +// PowerPolicyStop +// PowerMarkPageable +// PowerMarkNonpageable +// + + + + + + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0OtherStates[] = +{ + { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, + { PowerMarkNonpageable, WdfDevStatePowerDecideD0State DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0NPOtherStates[] = +{ + { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, + { PowerMarkPageable, WdfDevStatePowerDecideD0State DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0BusWakeOwnerOtherStates[] = +{ + { PowerWakeArrival, WdfDevStatePowerEnablingWakeAtBus DEBUGGED_EVENT }, + { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, + { PowerMarkNonpageable, WdfDevStatePowerDecideD0State DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0BusWakeOwnerNPOtherStates[] = +{ + { PowerWakeArrival, WdfDevStatePowerEnablingWakeAtBusNP DEBUGGED_EVENT }, + { PowerImplicitD3, WdfDevStatePowerGotoD3Stopped DEBUGGED_EVENT }, + { PowerMarkPageable, WdfDevStatePowerD0BusWakeOwner DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0ArmedForWakeOtherStates[] = +{ + { PowerWakeSucceeded, WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT }, + { PowerWakeFailed, WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT }, + { PowerWakeCanceled, WdfDevStatePowerD0DisarmingWakeAtBus DEBUGGED_EVENT }, + { PowerMarkNonpageable, WdfDevStatePowerD0ArmedForWakeNP TRAP_ON_EVENT }, + { PowerImplicitD3, WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerD0ArmedForWakeNPOtherStates[] = +{ + { PowerWakeSucceeded, WdfDevStatePowerD0DisarmingWakeAtBusNP DEBUGGED_EVENT }, + { PowerWakeFailed, WdfDevStatePowerD0DisarmingWakeAtBusNP TRAP_ON_EVENT }, + { PowerWakeCanceled, WdfDevStatePowerD0DisarmingWakeAtBusNP DEBUGGED_EVENT }, + { PowerMarkPageable, WdfDevStatePowerD0ArmedForWake TRAP_ON_EVENT }, + { PowerImplicitD3, WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus TRAP_ON_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDNotZeroOtherStates[] = +{ + { PowerImplicitD3, WdfDevStatePowerGotoDxStoppedDisableInterrupt DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDNotZeroNPOtherStates[] = +{ + { PowerImplicitD3, WdfDevStatePowerGotoDxStoppedDisableInterruptNP DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_DxArmedForWakeOtherStates[] = +{ + { PowerWakeSucceeded, WdfDevStatePowerWakePending DEBUGGED_EVENT }, + { PowerWakeCanceled, WdfDevStatePowerWakePending DEBUGGED_EVENT }, + { PowerWakeFailed, WdfDevStatePowerWakePending DEBUGGED_EVENT }, + { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWake TRAP_ON_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_DxArmedForWakeNPOtherStates[] = +{ + { PowerWakeSucceeded, WdfDevStatePowerWakePendingNP DEBUGGED_EVENT }, + { PowerWakeFailed, WdfDevStatePowerWakePendingNP DEBUGGED_EVENT }, + { PowerWakeCanceled, WdfDevStatePowerWakePendingNP DEBUGGED_EVENT }, + { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWakeNP TRAP_ON_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_WakePendingOtherStates[] = +{ + { PowerImplicitD0, WdfDevStatePowerCheckParentStateArmedForWake TRAP_ON_EVENT }, + { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWake DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_WakePendingNPOtherStates[] = +{ + { PowerImplicitD0, WdfDevStatePowerCheckParentStateArmedForWakeNP TRAP_ON_EVENT }, + { PowerImplicitD3, WdfDevStatePowerDxStoppedDisarmWakeNP DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerStoppedOtherStates[] = +{ + { PowerDx, WdfDevStatePowerStoppedCompleteDx DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_EVENT_TARGET_STATE FxPkgPnp::m_PowerDxStoppedOtherStates[] = +{ + { PowerD0, WdfDevStatePowerGotoStopped DEBUGGED_EVENT }, + { PowerEventMaximum, WdfDevStatePowerNull }, +}; + +const POWER_STATE_TABLE FxPkgPnp::m_WdfPowerStates[] = +{ + // WdfDevStatePowerObjectCreated + { NULL, + { PowerImplicitD0, WdfDevStatePowerStartingCheckDeviceType DEBUGGED_EVENT }, + NULL, + { TRUE, + PowerMarkPageable | // parent sends usage notifications before the PDO is + PowerMarkNonpageable | // started + PowerParentToD0 | // parent powered up upon enumeration of child + PowerDx | // If we are on top of a power policy owner who sends a Dx + // during start (or after AddDevice, etc) + PowerD0 // If we are on top of a power policy owner who sends a D0 + // to the stack in start device, we can get this event early + }, + }, + + // WdfDevStatePowerCheckDeviceType + { FxPkgPnp::PowerCheckDeviceType, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerCheckDeviceTypeNP + { FxPkgPnp::PowerCheckDeviceTypeNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerCheckParentState + { FxPkgPnp::PowerCheckParentState, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerCheckParentStateNP + { FxPkgPnp::PowerCheckParentStateNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerEnablingWakeAtBus + { FxPkgPnp::PowerEnablingWakeAtBus, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerEnablingWakeAtBusNP + { FxPkgPnp::PowerEnablingWakeAtBusNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerD0 + { FxPkgPnp::PowerDZero, + { PowerDx, WdfDevStatePowerGotoDx DEBUGGED_EVENT }, + FxPkgPnp::m_PowerD0OtherStates, + { TRUE, + PowerImplicitD3 | + PowerD0 // A non WDF power policy owner might send a D0 irp + // while we are in D0 + }, + }, + + // WdfDevStatePowerD0NP + { FxPkgPnp::PowerD0NP, + { PowerDx, WdfDevStatePowerGotoDxNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerD0NPOtherStates, + { TRUE, + PowerD0 // A non WDF power policy owner might send a D0 irp + // while we are in D0 + }, + }, + + // WdfDevStatePowerD0BusWakeOwner + { FxPkgPnp::PowerD0BusWakeOwner, + { PowerDx, WdfDevStatePowerGotoDx DEBUGGED_EVENT }, + FxPkgPnp::m_PowerD0BusWakeOwnerOtherStates, + { TRUE, + PowerWakeSucceeded | // During surprise remove, the pnp state machine + // could complete the ww request and result in + // this event before the pwr pol machine is stopped + PowerWakeCanceled | // while powering up, the wait wake owner canceled + // the ww irp + PowerWakeFailed | // while powering up, the wait wake owner failed + // the ww irp + PowerParentToD0 | + PowerD0 // A non WDF power policy owner might send a D0 irp + // while we are in D0 + }, + }, + + // WdfDevStatePowerD0BusWakeOwnerNP + { FxPkgPnp::PowerD0BusWakeOwnerNP, + { PowerDx, WdfDevStatePowerGotoDxNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerD0BusWakeOwnerNPOtherStates, + { TRUE, + PowerWakeSucceeded | // During surprise remove, the pnp state machine + // could complete the ww request and result in + // this event before the pwr pol machine is stopped + PowerWakeCanceled | // while powering up, the wait wake owner canceled + // the ww irp + PowerParentToD0 | + PowerD0 // A non WDF power policy owner might send a D0 irp + // while we are in D0 + }, + }, + + // WdfDevStatePowerD0ArmedForWake + { FxPkgPnp::PowerD0ArmedForWake, + { PowerDx, WdfDevStatePowerGotoDxArmedForWake DEBUGGED_EVENT }, + FxPkgPnp::m_PowerD0ArmedForWakeOtherStates, + { TRUE, + PowerParentToD0 | + PowerWakeArrival | // PowerIsWakeRequestPresent() returned true in + // WdfDevStatePowerD0BusWakeOwner and raced with + // this event being processed + PowerWakeCanceled | + PowerD0 // A non WDF power policy owner might send a D0 irp + // while we are in D0 + }, + }, + + // WdfDevStatePowerD0ArmedForWakeNP + { FxPkgPnp::PowerD0ArmedForWakeNP, + { PowerDx, WdfDevStatePowerGotoDxArmedForWakeNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerD0ArmedForWakeNPOtherStates, + { TRUE, + PowerParentToD0 | + PowerWakeArrival | // PowerIsWakeRequestPresent() returned true in + // WdfDevStatePowerD0BusWakeOwnerNP and raced with + // this event being processed + PowerWakeCanceled | + PowerD0 // A non WDF power policy owner might send a D0 irp + // while we are in D0 + }, + }, + + // WdfDevStatePowerD0DisarmingWakeAtBus + { FxPkgPnp::PowerD0DisarmingWakeAtBus, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerD0DisarmingWakeAtBusNP + { FxPkgPnp::PowerD0DisarmingWakeAtBusNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerD0Starting + { FxPkgPnp::PowerD0Starting, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerD0StartingConnectInterrupt + { FxPkgPnp::PowerD0StartingConnectInterrupt, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerD0StartingDmaEnable + { FxPkgPnp::PowerD0StartingDmaEnable, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerD0StartingStartSelfManagedIo + { FxPkgPnp::PowerD0StartingStartSelfManagedIo, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDecideD0State + { FxPkgPnp::PowerDecideD0State, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoD3Stopped + { FxPkgPnp::PowerGotoD3Stopped, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStopped + { NULL, + { PowerImplicitD0, WdfDevStatePowerStartingCheckDeviceType DEBUGGED_EVENT }, + FxPkgPnp::m_PowerStoppedOtherStates, + { TRUE, + PowerD0 | // as a filter above the PPO and the PPO powers on the stack + // before seeing a surprise remove or remove irp + PowerWakeFailed | // power policy owner canceled the wake request while + // we were transitioning to stop (or after the + // transition succeeded) + PowerParentToD0 }, + }, + + // WdfDevStatePowerStartingCheckDeviceType + { FxPkgPnp::PowerStartingCheckDeviceType, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStartingChild + { FxPkgPnp::PowerStartingChild, + { PowerParentToD0, WdfDevStatePowerD0Starting DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePowerDxDisablingWakeAtBus + { FxPkgPnp::PowerDxDisablingWakeAtBus, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxDisablingWakeAtBusNP + { FxPkgPnp::PowerDxDisablingWakeAtBusNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDx + { FxPkgPnp::PowerGotoDNotZero, + { PowerCompleteDx, WdfDevStatePowerNotifyingD0ExitToWakeInterrupts DEBUGGED_EVENT }, + NULL, + { FALSE, + PowerWakeArrival | // on a PDO which is the PPO, it will send a wake + // request in this state. + + + PowerParentToD0 // Parent is powering up while this device is powering + // down + }, + }, + + // WdfDevStatePowerGotoDxNP + { FxPkgPnp::PowerGotoDNotZeroNP, + { PowerCompleteDx, WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP DEBUGGED_EVENT }, + NULL, + { FALSE, + PowerWakeArrival | // on a PDO which is the PPO, it will send a wake + // request in this state. + + + PowerParentToD0 // Parent is powering up while this device is powering + // down + }, + }, + + // WdfDevStatePowerGotoDxIoStopped + { FxPkgPnp::PowerGotoDNotZeroIoStopped, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxIoStoppedNP + { FxPkgPnp::PowerGotoDNotZeroIoStoppedNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxNPFailed + { FxPkgPnp::PowerGotoDxNPFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // NOTE: can't use PowerDx as a func name since it's an enum value + // WdfDevStatePowerDx + { NULL, + { PowerD0, WdfDevStatePowerCheckDeviceType DEBUGGED_EVENT }, + FxPkgPnp::m_PowerDNotZeroOtherStates, + { TRUE, + PowerWakeArrival | // on a PDO which is the PPO, it will send a wake + // request in this state. + + + + PowerWakeCanceled | // on a PDO which is the PPO, it will cancel the + // the wake request in this state. Since we didn't + // handle PowerWakeArrival in WdfDevStatePowerGotoDx + // for this scenario, we must also handle the canel + // here. Even if we handle wake arrived in that + // state, the PPO (non KMDF) could send a wake + // request while in Dx and then cancel it in Dx, + // so we must still ignore this event here. + + PowerWakeSucceeded | // on a PDO which is the PPO, a completion of the + // wait wake can arrive in this state. This event + // can be ignored and the pending wait wake will + // be completed. + + PowerImplicitD3 | + PowerParentToD0 | // parent went to D0 first while the PDO was still + // in Dx + + PowerDx // power policy sent a Dx to Dx transition + }, + }, + + // WdfDevStatePowerDxNP + { NULL, + { PowerD0, WdfDevStatePowerCheckDeviceTypeNP DEBUGGED_EVENT }, + FxPkgPnp::m_PowerDNotZeroNPOtherStates, + { TRUE, + PowerWakeArrival | // on a PDO which is the PPO, it will send a wake + // request in this state. + + + + PowerWakeCanceled | // on a PDO which is the PPO, it will cancel the + // the wake request in this state. Since we didn't + // handle PowerWakeArrival in WdfDevStatePowerGotoDx + // for this scenario, we must also handle the canel + // here. Even if we handle wake arrived in that + // state, the PPO (non KMDF) could send a wake + // request while in Dx and then cancel it in Dx, + // so we must still ignore this event here. + + PowerWakeSucceeded | // on a PDO which is the PPO, a completion of the + // wait wake can arrive in this state. This event + // can be ignored and the pending wait wake will + // be completed. + + PowerParentToD0 | // parent went to D0 first while the PDO was still + // in Dx + + PowerDx // power policy sent a Dx to Dx transition + }, + }, + + // WdfDevStatePowerGotoDxArmedForWake + { FxPkgPnp::PowerGotoDxArmedForWake, + { PowerCompleteDx, WdfDevStatePowerGotoDxIoStoppedArmedForWake DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxArmedForWakeNP + { FxPkgPnp::PowerGotoDxArmedForWakeNP, + { PowerCompleteDx, WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxIoStoppedArmedForWake + { FxPkgPnp::PowerGotoDxIoStoppedArmedForWake, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxIoStoppedArmedForWakeNP + { FxPkgPnp::PowerGotoDxIoStoppedArmedForWakeNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxArmedForWake + { NULL, + { PowerD0, WdfDevStatePowerCheckParentStateArmedForWake DEBUGGED_EVENT }, + FxPkgPnp::m_DxArmedForWakeOtherStates, + { TRUE, + PowerParentToD0 // can occur on a PDO when a Dx transition completes + // on the parent and it wakes up before the child + }, + }, + + // WdfDevStatePowerDxArmedForWakeNP + { NULL, + { PowerD0, WdfDevStatePowerCheckParentStateArmedForWakeNP DEBUGGED_EVENT }, + FxPkgPnp::m_DxArmedForWakeNPOtherStates, + { TRUE, + PowerParentToD0 // can occur on a PDO when a Dx transition completes + // on the parent and it wakes up before the child + }, + }, + + // WdfDevStatePowerCheckParentStateArmedForWake + { FxPkgPnp::PowerCheckParentStateArmedForWake, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerCheckParentStateArmedForWakeNP + { FxPkgPnp::PowerCheckParentStateArmedForWakeNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWaitForParentArmedForWake + { NULL, + { PowerParentToD0, WdfDevStatePowerDxDisablingWakeAtBus DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWaitForParentArmedForWakeNP + { NULL, + { PowerParentToD0, WdfDevStatePowerDxDisablingWakeAtBusNP DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStartSelfManagedIo + { FxPkgPnp::PowerStartSelfManagedIo, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStartSelfManagedIoNP + { FxPkgPnp::PowerStartSelfManagedIoNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStartSelfManagedIoFailed + { FxPkgPnp::PowerStartSelfManagedIoFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStartSelfManagedIoFailedNP + { FxPkgPnp::PowerStartSelfManagedIoFailedNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWaitForParent + { NULL, + { PowerParentToD0, WdfDevStatePowerWaking DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWaitForParentNP + { NULL, + { PowerParentToD0, WdfDevStatePowerWakingNP DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakePending + { FxPkgPnp::PowerWakePending, + { PowerD0, WdfDevStatePowerCheckParentStateArmedForWake DEBUGGED_EVENT }, + FxPkgPnp::m_WakePendingOtherStates, + { TRUE, + PowerParentToD0 // parent moved to D0 while the child was moving to + // D0 from Dx armed for wake + }, + }, + + // WdfDevStatePowerWakePendingNP + { FxPkgPnp::PowerWakePendingNP, + { PowerD0, WdfDevStatePowerCheckParentStateArmedForWakeNP DEBUGGED_EVENT }, + FxPkgPnp::m_WakePendingNPOtherStates, + { TRUE, + PowerParentToD0 // parent moved to D0 while the child was moving to + // D0 from Dx armed for wake + }, + }, + + // WdfDevStatePowerWaking + { FxPkgPnp::PowerWaking, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingNP + { FxPkgPnp::PowerWakingNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingConnectInterrupt + { FxPkgPnp::PowerWakingConnectInterrupt, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingConnectInterruptNP + { FxPkgPnp::PowerWakingConnectInterruptNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingConnectInterruptFailed + { FxPkgPnp::PowerWakingConnectInterruptFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingConnectInterruptFailedNP + { FxPkgPnp::PowerWakingConnectInterruptFailedNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingDmaEnable + { FxPkgPnp::PowerWakingDmaEnable, + { PowerCompleteD0, WdfDevStatePowerStartSelfManagedIo DEBUGGED_EVENT }, + NULL, + { FALSE, + PowerParentToD0 // parent moved to D0 while the child was moving to + // D0 from Dx armed for wake + }, + }, + + // WdfDevStatePowerWakingDmaEnableNP + { FxPkgPnp::PowerWakingDmaEnableNP, + { PowerCompleteD0, WdfDevStatePowerStartSelfManagedIoNP DEBUGGED_EVENT }, + NULL, + { FALSE, + PowerParentToD0 // parent moved to D0 while the child was moving to + // D0 from Dx armed for wake + }, + }, + + // WdfDevStatePowerWakingDmaEnableFailed + { FxPkgPnp::PowerWakingDmaEnableFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerWakingDmaEnableFailedNP + { FxPkgPnp::PowerWakingDmaEnableFailedNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerReportPowerUpFailedDerefParent + { FxPkgPnp::PowerReportPowerUpFailedDerefParent, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 + }, + }, + + // WdfDevStatePowerReportPowerUpFailed + { FxPkgPnp::PowerReportPowerUpFailed, + { PowerImplicitD3, WdfDevStatePowerPowerFailedPowerDown DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 + }, + }, + + // WdfDevStatePowerPowerFailedPowerDown + { FxPkgPnp::PowerPowerFailedPowerDown, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerReportPowerDownFailed + { FxPkgPnp::PowerReportPowerDownFailed, + { PowerImplicitD3, WdfDevStatePowerPowerFailedPowerDown DEBUGGED_EVENT }, + NULL, + { TRUE, + 0 }, + }, + + // WdfDevStatePowerInitialConnectInterruptFailed + { FxPkgPnp::PowerInitialConnectInterruptFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerInitialDmaEnableFailed + { FxPkgPnp::PowerInitialDmaEnableFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerInitialSelfManagedIoFailed + { FxPkgPnp::PowerInitialSelfManagedIoFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerInitialPowerUpFailedDerefParent + { FxPkgPnp::PowerInitialPowerUpFailedDerefParent, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerInitialPowerUpFailed + { FxPkgPnp::PowerInitialPowerUpFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxStoppedDisarmWake + { FxPkgPnp::PowerDxStoppedDisarmWake, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxStoppedDisarmWakeNP + { FxPkgPnp::PowerDxStoppedDisarmWakeNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxStoppedDisableInterruptNP + { FxPkgPnp::PowerGotoDxStoppedDisableInterruptNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxStopped + { FxPkgPnp::PowerGotoDxStopped, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxStopped + { NULL, + { PowerImplicitD0, WdfDevStatePowerDxStoppedDecideDxState TRAP_ON_EVENT }, + FxPkgPnp::m_PowerDxStoppedOtherStates, + { TRUE, + 0 }, + }, + + // WdfDevStatePowerGotoStopped + { FxPkgPnp::PowerGotoStopped, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerStoppedCompleteDx + { FxPkgPnp::PowerStoppedCompleteDx, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxStoppedDecideDxState + { FxPkgPnp::PowerDxStoppedDecideDxState, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxStoppedArmForWake + { FxPkgPnp::PowerDxStoppedArmForWake, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerDxStoppedArmForWakeNP + { FxPkgPnp::PowerDxStoppedArmForWakeNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerFinalPowerDownFailed + { FxPkgPnp::PowerFinalPowerDownFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerFinal + { NULL, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoImplicitD3DisarmWakeAtBus + { FxPkgPnp::PowerGotoImplicitD3DisarmWakeAtBus, + { PowerEventMaximum, WdfDevStatePowerNull DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerUpFailed + { FxPkgPnp::PowerUpFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerUpFailedDerefParent + { FxPkgPnp::PowerUpFailedDerefParent, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxFailed + { FxPkgPnp::PowerGotoDxFailed, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerGotoDxStoppedDisableInterrupt + { FxPkgPnp::PowerGotoDxStoppedDisableInterrupt, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerUpFailedNP + { FxPkgPnp::PowerUpFailedNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerUpFailedDerefParentNP + { FxPkgPnp::PowerUpFailedDerefParentNP, + { PowerEventMaximum, WdfDevStatePowerNull }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerNotifyingD0ExitToWakeInterrupts + { FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts, + { PowerWakeInterruptCompleteTransition, WdfDevStatePowerGotoDxIoStopped DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts + { FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts, + { PowerWakeInterruptCompleteTransition, WdfDevStatePowerWakingConnectInterrupt DEBUGGED_EVENT }, + NULL, + { FALSE, + 0 }, + }, + // WdfDevStatePowerNotifyingD0ExitToWakeInterruptsNP + { FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP, + { PowerWakeInterruptCompleteTransition, WdfDevStatePowerGotoDxIoStoppedNP TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerNotifyingD0EntryToWakeInterrupts + { FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP, + { PowerWakeInterruptCompleteTransition, WdfDevStatePowerWakingConnectInterruptNP TRAP_ON_EVENT }, + NULL, + { FALSE, + 0 }, + }, + + // WdfDevStatePowerNull + // *** no entry for this state *** +}; + +// @@SMVERIFY_SPLIT_END + +_Must_inspect_result_ +NTSTATUS +FxPowerMachine::Init( + __inout FxPkgPnp* Pnp, + __in PFN_PNP_EVENT_WORKER WorkerRoutine + ) +{ + NTSTATUS status; + + status = FxThreadedEventQueue::Init(Pnp, WorkerRoutine); + if (!NT_SUCCESS(status)) { + return status; + } + + return STATUS_SUCCESS; +} + +VOID +FxPkgPnp::PowerCheckAssumptions( + VOID + ) +/*++ + +Routine Description: + This routine is never actually called by running code, it just has + WDFCASSERTs who upon failure, would not allow this file to be compiled. + + DO NOT REMOVE THIS FUNCTION just because it is not called by any running + code. + +Arguments: + None + +Return Value: + None + + --*/ +{ + WDFCASSERT(sizeof(FxPowerStateInfo) == sizeof(ULONG)); + + WDFCASSERT((sizeof(m_WdfPowerStates)/sizeof(m_WdfPowerStates[0])) + == + (WdfDevStatePowerNull - WdfDevStatePowerObjectCreated)); + + // we assume these are the same length when we update the history index + WDFCASSERT((sizeof(m_PowerMachine.m_Queue.Events)/ + sizeof(m_PowerMachine.m_Queue.Events[0])) + == + (sizeof(m_PowerMachine.m_States.History)/ + sizeof(m_PowerMachine.m_States.History[0]))); +} + + +/*++ + +The locking model for the Power state machine requires that events be enqueued +possibly at DISPATCH_LEVEL. It also requires that the state machine be +runnable at PASSIVE_LEVEL. Consequently, we have two locks, one DISPATCH_LEVEL +lock that guards the event queue and one PASSIVE_LEVEL lock that guards the +state machine itself. + +The Power state machine has a few constraints that the PnP state machine +doesn't. Sometimes it has to call some driver functions at PASSIVE_LEVEL, but +with the disks turned off. This means that these functions absolutely must not +page fault. You might think that this means that we should call the driver at +DISPATCH_LEVEL, and you'd be right if your only concern were for perfectly +safe code. The problem with that approach, though is that it will force much +of the rest of the driver to DISPATCH_LEVEL, which will only push the driver +writer into using lots of asynchronous work items, which will complicate their +code and make it unsafe in a new variety of ways. So we're going to go with +PASSIVE_LEVEL here and setting a timeout of 20 seconds. If the driver faults, +the timer will fire and log the failure. This also means that the driver must +complete these callbacks within 20 seconds. Even beyond that, it means that +the work items must be queued onto a special thread, one that once the machine +has started to go to sleep, never handles any work items that may fault. + +Algorithm: + +1) Acquire the Power queue lock. +2) Enqueue the request. Requests are put at the end of the queue. +3) Drop the Power queue lock. +4) If the thread is running at PASSIVE_LEVEL, skip to step 6. +5) Queue a work item onto the special power thread. +6) Attempt to acquire the state machine lock, with a near-zero-length timeout. +7) If successful, skip to step 9. +8) Queue a work item onto the special power thread. +9) Acquire the state machine lock. +10) Acquire the Power queue lock. +11) Attempt to dequeue an event. +12) Drop the Power queue lock. +13) If there was no event to dequeue, drop the state machine lock and exit. +14) Execute the state handler. This may involve taking one of the other state + machine queue locks, briefly, to deliver an event. +15) Go to Step 10. + +Implementing this algorithm requires three functions. + +PowerProcessEvent -- Implements steps 1-8. +_PowerProcessEventInner -- Implements step 9. +PowerProcessEventInner -- Implements steps 10-15. + +--*/ + +VOID +FxPkgPnp::PowerProcessEvent( + __in FxPowerEvent Event, + __in BOOLEAN ProcessOnDifferentThread + ) +/*++ + +Routine Description: + This function implements steps 1-8 of the algorithm described above. + +Arguments: + Event - Current Power event + + ProcessOnDifferentThread - Process the event on a different thread + regardless of IRQL. By default this is FALSE as per the declaration. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status; + KIRQL irql; + + // + // Take the lock, raising to DISPATCH_LEVEL. + // + m_PowerMachine.Lock(&irql); + + // + // If the input Event is any of the events described by PowerSingularEventMask, + // then check whether it is already queued up. If so, then dont enqueue this + // Event. + // + if (Event & PowerSingularEventMask) { + if ((m_PowerMachine.m_SingularEventsPresent & Event) == 0x00) { + m_PowerMachine.m_SingularEventsPresent |= Event; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " + "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent! because " + "the Event is already enqueued.", m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerState(), + Event); + + m_PowerMachine.Unlock(irql); + return; + } + } + + if (m_PowerMachine.IsFull()) { + // + // The queue is full. Bail. + // + m_PowerMachine.Unlock(irql); + + ASSERT(!"The Power queue is full. This shouldn't be able to happen."); + return; + } + + if (m_PowerMachine.IsClosedLocked()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current pwr pol state " + "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent! because " + "of a closed queue", m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerState(), + Event); + + // + // The queue is closed. Bail + // + m_PowerMachine.Unlock(irql); + + return; + } + + // + // Enqueue the event. Whether the event goes on the front + // or the end of the queue depends on which event it is. + // + if (Event & PowerPriorityEventsMask) { + // + // Stick it on the front of the queue, making it the next + // event that will be processed. + // + m_PowerMachine.m_Queue.Events[m_PowerMachine.InsertAtHead()] = (USHORT) Event; + } + else { + // + // Stick it on the end of the queue. + // + m_PowerMachine.m_Queue.Events[m_PowerMachine.InsertAtTail()] = (USHORT) Event; + } + + // + // Drop the lock. + // + m_PowerMachine.Unlock(irql); + + // + // Now, if we are running at PASSIVE_LEVEL, attempt to run the state + // machine on this thread. If we can't do that, then queue a work item. + // + + if (irql == PASSIVE_LEVEL && + FALSE == ProcessOnDifferentThread) { + LONGLONG timeout = 0; + + status = m_PowerMachine.m_StateMachineLock.AcquireLock( + GetDriverGlobals(), &timeout); + + if (FxWaitLockInternal::IsLockAcquired(status)) { + FxPostProcessInfo info; + + // + // We now hold the state machine lock. So call the function that + // dispatches the next state. + // + PowerProcessEventInner(&info); + + // + // The pnp state machine should be the only one deleting the object + // + ASSERT(info.m_DeleteObject == FALSE); + + m_PowerMachine.m_StateMachineLock.ReleaseLock(GetDriverGlobals()); + + info.Evaluate(this); + + return; + } + } + + // + // The tag added above will be released when the work item runs + // + + // For one reason or another, we couldn't run the state machine on this + // thread. So queue a work item to do it. If m_PnPWorkItemEnqueuing + // is non-zero, that means that the work item is already being enqueued + // on another thread. This is significant, since it means that we can't do + // anything with the work item on this thread, but it's okay, since the + // work item will pick up our work and do it. + // + m_PowerMachine.QueueToThread(); +} + +VOID +FxPkgPnp::_PowerProcessEventInner( + __in FxPkgPnp* This, + __in FxPostProcessInfo* Info, + __in PVOID WorkerContext + ) +{ + + UNREFERENCED_PARAMETER(WorkerContext); + + // + // Take the state machine lock. + // + This->m_PowerMachine.m_StateMachineLock.AcquireLock( + This->GetDriverGlobals() + ); + + // + // Call the function that will actually run the state machine. + // + This->PowerProcessEventInner(Info); + + // + // We are being called from the work item and m_WorkItemRunning is > 0, so + // we cannot be deleted yet. + // + ASSERT(Info->SomethingToDo() == FALSE); + + // + // Now release the lock + // + This->m_PowerMachine.m_StateMachineLock.ReleaseLock( + This->GetDriverGlobals() + ); +} + +VOID +FxPkgPnp::PowerProcessEventInner( + __inout FxPostProcessInfo* Info + ) +/*++ + +Routine Description: + This routine runs the state machine. It implements steps 10-15 of the + algorithm described above. + +--*/ +{ + WDF_DEVICE_POWER_STATE currentPowerState, newState; + CPPOWER_STATE_TABLE entry; + FxPowerEvent event; + KIRQL oldIrql; + + // + // Process as many events as we can. + // + for (;;) { + + newState = WdfDevStatePowerNull; + currentPowerState = m_Device->GetDevicePowerState(); + entry = GetPowerTableEntry(currentPowerState); + + // + // Get an event from the queue. + // + m_PowerMachine.Lock(&oldIrql); + + if (m_PowerMachine.IsEmpty()) { + m_PowerMachine.GetFinishedState(Info); + + // + // The queue is empty. + // + m_PowerMachine.Unlock(oldIrql); + return; + } + + event = (FxPowerEvent) m_PowerMachine.m_Queue.Events[m_PowerMachine.GetHead()]; + + // + // At this point, we need to determine whether we can process this + // event. + // + if (event & PowerPriorityEventsMask) { + // + // These are always possible to handle. + // + DO_NOTHING(); + } + else { + // + // Check to see if this state can handle new events. + // + if (entry->StateInfo.Bits.QueueOpen == FALSE) { + // + // This state can't handle new events. + // + m_PowerMachine.Unlock(oldIrql); + return; + } + } + + // + // If the event obtained from the queue was a singular event, then + // clear the flag to allow other similar events to be put into this + // queue for processing. + // + if (m_PowerMachine.m_SingularEventsPresent & event) { + m_PowerMachine.m_SingularEventsPresent &= ~event; + } + + m_PowerMachine.IncrementHead(); + m_PowerMachine.Unlock(oldIrql); + + // + // Find the entry in the power state table that corresponds to this event + // + if (entry->FirstTargetState.PowerEvent == event) { + newState = entry->FirstTargetState.TargetState; + + DO_EVENT_TRAP(&entry->FirstTargetState); + } + else if (entry->OtherTargetStates != NULL) { + ULONG i = 0; + + for (i = 0; + entry->OtherTargetStates[i].PowerEvent != PowerEventMaximum; + i++) { + if (entry->OtherTargetStates[i].PowerEvent == event) { + newState = entry->OtherTargetStates[i].TargetState; + DO_EVENT_TRAP(&entry->OtherTargetStates[i]); + break; + } + } + } + + if (newState == WdfDevStatePowerNull) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current power state " + "%!WDF_DEVICE_POWER_STATE! dropping event %!FxPowerEvent!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerState(), event); + + // + // This state doesn't respond to the Event. Potentially throw + // the event away. + // + if ((entry->StateInfo.Bits.KnownDroppedEvents & event) == 0) { + COVERAGE_TRAP(); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGPNP, + "WDFDEVICE %p !devobj 0x%p current state " + "%!WDF_DEVICE_POWER_STATE! event %!FxPowerEvent! is not a " + "known dropped event, known dropped events are " + "%!FxPowerEvent!", m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_Device->GetDevicePowerState(), + event, entry->StateInfo.Bits.KnownDroppedEvents); + + + } + + switch (event) { + case PowerWakeSucceeded: + case PowerWakeFailed: + case PowerWakeCanceled: + // + // There are states where we don't care if the wake completed. + // Since the completion/cancellation of the wake request posts + // an event which it assumes will complete the request, we must + // catch these events here and complete the request. + // + PowerCompletePendedWakeIrp(); + break; + + case PowerD0: + case PowerDx: + // + // There are some (non WDF) power policy owner implementations + // which send Dx to Dx or D0 to D0 transitions to the stack. + // + // We don't explicitly handle them in the state machine. + // + // Instead, we complete the pended irp if are about to drop it + // on the floor. + // + PowerReleasePendingDeviceIrp(); + break; + } + } + else { + // + // Now enter the new state. + // + PowerEnterNewState(newState); + } + } +} + +VOID +FxPkgPnp::PowerEnterNewState( + __in WDF_DEVICE_POWER_STATE State + ) +/*++ + +Routine Description: + This function looks up the handler for a state and + then calls it. + +Arguments: + Event - Current PnP event + +Return Value: + + NTSTATUS + +--*/ +{ + CPPOWER_STATE_TABLE entry; + WDF_DEVICE_POWER_STATE currentState, newState; + WDF_DEVICE_POWER_NOTIFICATION_DATA data; + FxWatchdog watchdog(this); + + currentState = m_Device->GetDevicePowerState(); + newState = State; + + while (newState != WdfDevStatePowerNull) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering Power State " + "%!WDF_DEVICE_POWER_STATE! from %!WDF_DEVICE_POWER_STATE!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), + newState, currentState); + + if (m_PowerStateCallbacks != NULL) { + // + // Callback for leaving the old state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationLeaveState; + data.Data.LeaveState.CurrentState = currentState; + data.Data.LeaveState.NewState = newState; + + m_PowerStateCallbacks->Invoke(currentState, + StateNotificationLeaveState, + m_Device->GetHandle(), + &data); + } + + m_PowerMachine.m_States.History[m_PowerMachine.IncrementHistoryIndex()] = + (USHORT) newState; + + if (m_PowerStateCallbacks != NULL) { + // + // Callback for entering the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationEnterState; + data.Data.EnterState.CurrentState = currentState; + data.Data.EnterState.NewState = newState; + + m_PowerStateCallbacks->Invoke(newState, + StateNotificationEnterState, + m_Device->GetHandle(), + &data); + } + + m_Device->SetDevicePowerState(newState); + currentState = newState; + + entry = GetPowerTableEntry(currentState); + + // + // And call the state handler, if there is one. + // + if (entry->StateFunc != NULL) { + watchdog.StartTimer(currentState); + newState = entry->StateFunc(this); + watchdog.CancelTimer(currentState); + + // + // Validate the return value if FX_STATE_MACHINE_VERIFY is enabled + // + VALIDATE_POWER_STATE(currentState, newState); + + } + else { + newState = WdfDevStatePowerNull; + } + + if (m_PowerStateCallbacks != NULL) { + // + // Callback for post processing the new state + // + RtlZeroMemory(&data, sizeof(data)); + + data.Type = StateNotificationPostProcessState; + data.Data.PostProcessState.CurrentState = currentState; + + m_PowerStateCallbacks->Invoke(currentState, + StateNotificationPostProcessState, + m_Device->GetHandle(), + &data); + } + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerCheckParentState( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Check Parent state. Its only task + is to dispatch to the FDO and PDO logic and handle error. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + NTSTATUS status; + BOOLEAN parentOn; + + status = This->PowerCheckParentOverload(&parentOn); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerUpFailed; + } + else if (parentOn) { + return WdfDevStatePowerWaking; + } + else { + return WdfDevStatePowerWaitForParent; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerCheckParentStateNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Check Parent (NP) state. Its only task + is to dispatch to the FDO and PDO logic. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + NTSTATUS status; + BOOLEAN parentOn; + + status = This->PowerCheckParentOverload(&parentOn); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerUpFailedNP; + } + else if (parentOn) { + return WdfDevStatePowerWakingNP; + } + else { + return WdfDevStatePowerWaitForParentNP; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerCheckDeviceType( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Check Type state. Its only task + is to dispatch to the FDO and PDO logic. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + return This->PowerCheckDeviceTypeOverload(); +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerCheckDeviceTypeNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Check Type (NP) state. Its only task + is to dispatch to the FDO and PDO logic. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + return This->PowerCheckDeviceTypeNPOverload(); +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerEnablingWakeAtBus( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function requests the driver to arm the device in a bus generic fashion. + +Arguments: + The package which contains this instance of the state machine + +Return Value: + new power state + + --*/ +{ + NTSTATUS status; + + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + status = This->PowerEnableWakeAtBusOverload(); + + ASSERT(status != STATUS_CANCELLED); + + if (NT_SUCCESS(status)) { + // + // No matter of the irp status (canceled, pending, completed), we always + // transition to the D0ArmedForWake state because that is where we + // we handle the change in the irp's status. + // + return WdfDevStatePowerD0ArmedForWake; + } + else { + This->PowerCompleteWakeRequestFromWithinMachine(status); + + return WdfDevStatePowerD0BusWakeOwner; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerEnablingWakeAtBusNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function requests the driver to arm the device in a bus generic fashion. + +Arguments: + The package which contains this instance of the state machine + +Return Value: + new power state + + --*/ +{ + NTSTATUS status; + + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && + This->IsPowerPolicyOwner()) == FALSE); + + status = This->PowerEnableWakeAtBusOverload(); + + ASSERT(status != STATUS_CANCELLED); + + if (NT_SUCCESS(status)) { + // + // No matter of the irp status (canceled, pending, completed), we always + // transition to the D0ArmedForWake state because that is where we + // we handle the change in the irp's status. + // + return WdfDevStatePowerD0ArmedForWakeNP; + } + else { + // + // Complete the irp with the error that callback indicated + // + COVERAGE_TRAP(); + + This->PowerCompleteWakeRequestFromWithinMachine(status); + + return WdfDevStatePowerD0BusWakeOwnerNP; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDZero( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + D0 state where we cannot wake the machine + +Arguments: + This - Instance of this state machine + +Return Value: + new power state machine state + + --*/ +{ + if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) { + // + // We are non pageable, go to that state now + // + COVERAGE_TRAP(); + + return WdfDevStatePowerDecideD0State; + } + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0NP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + D0 state where we can't cause paging IO and we cannot wake the machine + +Arguments: + This - Instance of this state machine + +Return Value: + new power state machine state + + --*/ +{ + if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + // + // We are pageable, go to that state now + // + COVERAGE_TRAP(); + return WdfDevStatePowerDecideD0State; + } + + return WdfDevStatePowerNull; +} + + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0BusWakeOwner( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the D0 state. It's job is to figure out whether + we need to swtich to the D0NP state, and to wait around for an event + of some kind or another. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) { + // + // We are non pageable, go to that state now + // + COVERAGE_TRAP(); + + return WdfDevStatePowerDecideD0State; + } + else if (This->PowerIsWakeRequestPresent()) { + return WdfDevStatePowerEnablingWakeAtBus; + } + else { + return WdfDevStatePowerNull; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0BusWakeOwnerNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the D0NP state. It's job is to figure out whether + we need to swtich to the D0 state, and to wait around for an event + of some kind or another. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + // + // Pageable. + // + COVERAGE_TRAP(); + + return WdfDevStatePowerDecideD0State; + } + else if (This->PowerIsWakeRequestPresent()) { + return WdfDevStatePowerEnablingWakeAtBusNP; + } + else { + return WdfDevStatePowerNull; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0ArmedForWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is in D0 and armed for wake. Complete any pended D0 irp if the power + policy owner make a D0 to D0 transition. Transition the NP version of + this state if we are no longer pageable. + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + if ((This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) == 0) { + // + // We are non pageable, go to that state now + // + COVERAGE_TRAP(); + + return WdfDevStatePowerDecideD0State; + } + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0ArmedForWakeNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is in D0 and armed for wake. Complete any pended D0 irp if the power + policy owner make a D0 to D0 transition. Transition the pageable version of + this state if we are no longer NP. + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + // + // We are pageable, go to that state now + // + COVERAGE_TRAP(); + + return WdfDevStatePowerDecideD0State; + } + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoImplicitD3DisarmWakeAtBus( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disarms the bus after we have armed it. The device is going to implicit D3 + and it has not yet been powered down. + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + // + // We should only get into this state when this devobj is a PDO and not a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && + This->IsPowerPolicyOwner()) == FALSE); + + // + // Disarm + // No need to complete the pended ww irp. State machine will complete it + // in PnpFailed handler, or upper driver will cancel it. + // + This->PowerDisableWakeAtBusOverload(); + + return WdfDevStatePowerGotoD3Stopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0DisarmingWakeAtBus( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disarms the bus after we have armed it. The device is still in D0 so it has + not yet powered down. + +Arguments: + This - This instance of the state machine + +Return Value: + None. + + --*/ +{ + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && + This->IsPowerPolicyOwner()) == FALSE); + + // + // Disarm + // + This->PowerDisableWakeAtBusOverload(); + This->PowerCompletePendedWakeIrp(); + + // + // Go back to normal unarmed D0 with bus wake ownership + // + return WdfDevStatePowerD0BusWakeOwner; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0DisarmingWakeAtBusNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disarms the bus after we have armed it. The device is still in D0 so it has + not yet powered down. + +Arguments: + This - This instance of the state machine + +Return Value: + None. + + --*/ +{ + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + // + // Disarm + // + This->PowerDisableWakeAtBusOverload(); + This->PowerCompletePendedWakeIrp(); + + // + // Go back to normal unarmed D0 with bus wake ownership + // + return WdfDevStatePowerD0BusWakeOwnerNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0Starting( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function calls D0Entry and the moves to the next state based on the + result. + +Arguments: + This - instance of the state machine + +Return Value: + new power state + +--*/ +{ + NTSTATUS status; + + // + // Call the driver to tell it to put the hardware into the working + // state. + // + // m_DevicePowerState is the "old" state because we update it after the + // D0Entry callback. + // + status = This->m_DeviceD0Entry.Invoke( + This->m_Device->GetHandle(), + (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state " + "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + This->m_DevicePowerState, status); + + return WdfDevStatePowerInitialPowerUpFailedDerefParent; + } + + return WdfDevStatePowerD0StartingConnectInterrupt; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0StartingConnectInterrupt( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Continues bringing the device into D0 from the D3 final state. This routine + connects and enables the interrupts. If successful it will open up the power + managed i/o queues. + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + NTSTATUS status; + + // + // Connect the interrupt and enable it + // + status = This->NotifyResourceObjectsD0(NotifyResourcesNoFlags); + if (!NT_SUCCESS(status)) { + // + // NotifyResourceObjectsD0 has already logged the error, no need to + // repeat any error messsages here + // + return WdfDevStatePowerInitialConnectInterruptFailed; + } + + status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke( + This->m_Device->GetHandle(), + (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); + + if (!NT_SUCCESS(status)) { + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, " + "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + This->m_DevicePowerState, status); + return WdfDevStatePowerInitialConnectInterruptFailed; + } + + // + // Last, figure out which state to drop into. This is the juncture + // where we figure out if we're doing power in a pageable fashion. + // + return WdfDevStatePowerD0StartingDmaEnable; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0StartingDmaEnable( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is movig to D0 for the first time. Enable any DMA enablers + attached to the device. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + if (This->PowerDmaEnableAndScan(TRUE) == FALSE) { + return WdfDevStatePowerInitialDmaEnableFailed; + } + + return WdfDevStatePowerD0StartingStartSelfManagedIo; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerD0StartingStartSelfManagedIo( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is entering D0 from the final Dx state (either start or restart + perhaps). Send a start event to self managed io and then release + +Arguments: + This - instance of the state machine + +Return Value: + new state machine state + + --*/ +{ + + + + + This->m_Device->m_PkgIo->ResumeProcessingForPower(); + + if (This->m_SelfManagedIoMachine != NULL) { + NTSTATUS status; + + status = This->m_SelfManagedIoMachine->Start(); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerInitialSelfManagedIoFailed; + } + } + + This->PowerSetDevicePowerState(WdfPowerDeviceD0); + + // + // Send the PowerUp event to both the PnP and the Power Policy state machines. + // + This->PowerSendPowerUpEvents(); + + return WdfDevStatePowerDecideD0State; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDecideD0State( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Decide which D0 state we should transition to given the wait wake ownership + of this device and if DO_POWER_PAGABLE is set or not. + +Arguments: + This - instance of the state machine + +Return Value: + new power state + + --*/ +{ + if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + // + // Pageable. + // + if (This->m_SharedPower.m_WaitWakeOwner) { + return WdfDevStatePowerD0BusWakeOwner; + } + else { + return WdfDevStatePowerD0; + } + } + else { + // + // Non-pageable. + // + if (This->m_SharedPower.m_WaitWakeOwner) { + return WdfDevStatePowerD0BusWakeOwnerNP; + } + else { + return WdfDevStatePowerD0NP; + } + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoD3Stopped( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the D3 Stopped state. + +Arguments: + none + +Return Value: + + new power state + +--*/ +{ + NTSTATUS status; + BOOLEAN failed; + + failed = FALSE; + + // + // We *must* call suspend here even though the pnp state machine called self + // managed io stop. Consider the following: + // 1 this device is a filter + // 2 the power policy owner has idle enabled and the device stack is + // currently idled out (in Dx) + // 3 the query remove comes, this driver processes it and succeeds + // self managed io stop + // 4 before the PwrPolStop event is processed in this driver, the pwr policy + // owner moves the stack into D0. + // 5 now this driver processed the PwrPolStop and moves into this state. We + // now need to make sure self managed i/o is in the stopped state before + // doing anything else. + // + + // + // The self managed io state machine can handle a suspend event when it is + // already in the stopped state. + // + // Tell the driver to stop its self-managed I/O. + // + if (This->m_SelfManagedIoMachine != NULL) { + status = This->m_SelfManagedIoMachine->Suspend(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceSelfManagedIoStop failed %!STATUS!", status); + failed = TRUE; + } + } + + + + + + // Top-edge queue hold. + This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); + + if (This->PowerDmaPowerDown() == FALSE) { + failed = TRUE; + } + + status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( + This->m_Device->GetHandle(), + WdfPowerDeviceD3Final + ); + + if (!NT_SUCCESS(status)) { + failed = TRUE; + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, " + "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + WdfPowerDeviceD3Final, status); + } + + // + // Disconnect the interrupt. + // + status = This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect); + if (!NT_SUCCESS(status)) { + // + // NotifyResourceObjectsDx already traced the error + // + failed = TRUE; + } + + // + // Call the driver to tell it to put the hardware into a sleeping + // state. + // + status = This->m_DeviceD0Exit.Invoke(This->m_Device->GetHandle(), + WdfPowerDeviceD3Final); + if (!NT_SUCCESS(status)) { + failed = TRUE; + + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state " + "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + WdfPowerDeviceD3Final, status); + } + + This->PowerSetDevicePowerState(WdfPowerDeviceD3Final); + + // + // If this is a child, release the power reference on the parent + // + This->PowerParentPowerDereference(); + + if (failed) { + return WdfDevStatePowerFinalPowerDownFailed; + } + + This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit); + + // + // If we are not the PPO for the stack we could receive a power irp + // during the middle of an implicit power down so we cannot assume + // that there will be no pended power irp during an implicit power down. + // + ASSERT(This->IsPowerPolicyOwner() ? This->m_PendingDevicePowerIrp == NULL : TRUE); + + return WdfDevStatePowerStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStartingCheckDeviceType( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is implicitly powering up from the created or stopped state. + Determine if this is a PDO or not to determine if we must bring the parent + back into D0. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerStartingChild or WdfDevStatePowerD0Starting + + --*/ +{ + if (This->m_Device->IsPdo()) { + return WdfDevStatePowerStartingChild; + } + else { + return WdfDevStatePowerD0Starting; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStartingChild( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Get the parent into a D0 state + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerNull or WdfDevStatePowerD0Starting + + --*/ +{ + NTSTATUS status; + BOOLEAN parentOn; + + status = This->PowerCheckParentOverload(&parentOn); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "PowerReference on parent WDFDEVICE %p for child WDFDEVICE %p " + "failed, %!STATUS!", This->m_Device->m_ParentDevice->m_Device->GetHandle(), + This->m_Device->GetHandle(), + status); + + return WdfDevStatePowerInitialPowerUpFailed; + } + else if (parentOn) { + // + // Parent is powered on, start the power up sequence + // + return WdfDevStatePowerD0Starting; + } + else { + // + // The call to PowerReference will bring the parent into D0 and + // move us out of this state after we return. + // + return WdfDevStatePowerNull; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxDisablingWakeAtBus( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Disable Wake at Bus state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerWaking + +--*/ +{ + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + This->PowerDisableWakeAtBusOverload(); + + return WdfDevStatePowerWaking; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxDisablingWakeAtBusNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Disable Wake at Bus state. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerWakingNP + +--*/ +{ + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + This->PowerDisableWakeAtBusOverload(); + + return WdfDevStatePowerWakingNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDNotZero( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + State where we go into Dx in the pageable path. + +Arguments: + The instance of this state machine + +Return Value: + new power state + + --*/ +{ + This->PowerGotoDx(); + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDNotZeroNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + State where we go into Dx in the NP path. + +Arguments: + The instance of this state machine + +Return Value: + new power state + + --*/ +{ + This->PowerGotoDx(); + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDNotZeroIoStopped( + __inout FxPkgPnp* This + ) +{ + if (This->PowerGotoDxIoStopped() == FALSE) { + return WdfDevStatePowerGotoDxFailed; + } + + return WdfDevStatePowerDx; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDNotZeroIoStoppedNP( + __inout FxPkgPnp* This + ) +{ + if (This->PowerGotoDxIoStoppedNP() == FALSE) { + return WdfDevStatePowerGotoDxNPFailed; + } + + return WdfDevStatePowerDxNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxNPFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Going to Dx in the NP path failed. Disconnect all the interrupts. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerDownFailed + + --*/ +{ + This->DisconnectInterruptNP(); + + return WdfDevStatePowerReportPowerDownFailed; +} + +VOID +FxPkgPnp::PowerGotoDx( + VOID + ) +/*++ + +Routine Description: + Implements the going into Dx logic for the pageable path. + +Arguments: + None + +Return Value: + None + + --*/ +{ + if (m_SelfManagedIoMachine != NULL) { + NTSTATUS status; + + // + // Tell the driver to stop its self-managed I/O + // + status = m_SelfManagedIoMachine->Suspend(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceSelfManagedIoStop failed %!STATUS!", status); + + m_PowerMachine.m_IoCallbackFailure = TRUE; + } + } + + + + + + // Top-edge queue hold + m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); + + PowerPolicyProcessEvent(PwrPolPowerDownIoStopped); +} + +BOOLEAN +FxPkgPnp::PowerGotoDxIoStopped( + VOID + ) +/*++ + +Routine Description: + Implements the going into Dx logic for the pageable path. + + + +Arguments: + None + +Return Value: + TRUE if the power down succeeded, FALSE otherwise + + --*/ +{ + WDF_POWER_DEVICE_STATE state; + NTSTATUS status; + BOOLEAN failed; + FxIrp irp; + ULONG notifyFlags; + + failed = FALSE; + + // + // First determine the state that will be indicated to the driver + // + irp.SetIrp(m_PendingDevicePowerIrp); + + switch (irp.GetParameterPowerShutdownType()) { + case PowerActionShutdown: + case PowerActionShutdownReset: + case PowerActionShutdownOff: + state = WdfPowerDeviceD3Final; + break; + + default: + state = (WDF_POWER_DEVICE_STATE) irp.GetParameterPowerStateDeviceState(); + break; + } + + // + // Can we even be a power pageable device and be in hibernation path? + // + if (m_SystemPowerState == PowerSystemHibernate && + GetUsageCount(WdfSpecialFileHibernation) != 0) { + COVERAGE_TRAP(); + + // + // This device is in the hibernation path and the target system state is + // S4. Tell the driver that it should do special handling. + // + state = WdfPowerDevicePrepareForHibernation; + } + + if (PowerDmaPowerDown() == FALSE) { + failed = TRUE; + } + + status = m_DeviceD0ExitPreInterruptsDisabled.Invoke( + m_Device->GetHandle(), + state + ); + + if (!NT_SUCCESS(status)) { + failed = TRUE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, " + "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), state, status); + } + + // + // interrupt disable & disconnect + // + + notifyFlags = NotifyResourcesExplicitPowerDown; + + // + // In general, m_WaitWakeIrp is accessed through guarded InterlockedExchange + // operations. However, following is a special case where we just want to know + // the current value. It is possible that the value of m_WaitWakeIrp can + // change right after we query it. Users of NotifyResourcesArmedForWake will + // need to be aware of this fact. + // + // Note that relying on m_WaitWakeIrp to decide whether to disconnect the wake + // interrupts or not is unreliable and may result in a race condition between + // the device powering down and a wake interrupt firing: + // + // Thread A: Device is powering down and is going to disconnect wake interrupts + // unless m_WaitWakeIrp is not NULL. + // Thread B: Wake interrupt fires (holding the OS interrupt lock) which results + // in completing the IRP_MN_WAIT_WAKE and setting m_WaitWakeIrp to NULL. + // Thread then blocks waiting for the device to power up. + // Thread A: m_WaitWakeIrp is NULL so we disconnect the wake interrupt, but are + // blocked waiting to acquire the lock held by the ISR. The deadlock + // results in bugcheck 0x9F since the Dx IRP is being blocked. + // + // The m_WakeInterruptsKeepConnected flag is set when we request a IRP_MN_WAIT_WAKE + // in the device powering down path, and is cleared below once it is used. + // + if (m_SharedPower.m_WaitWakeIrp != NULL || m_WakeInterruptsKeepConnected == TRUE) { + notifyFlags |= NotifyResourcesArmedForWake; + m_WakeInterruptsKeepConnected = FALSE; + } + + status = NotifyResourceObjectsDx(notifyFlags); + if (!NT_SUCCESS(status)) { + // + // NotifyResourceObjectsDx already traced the error + // + failed = TRUE; + } + + // + // Call the driver to tell it to put the hardware into a sleeping + // state. + // + + status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), state); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Exit WDFEVICE 0x%p !devobj 0x%p, new state " + "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), state, status); + + failed = TRUE; + } + + // + // If this is a child, release the power reference on the parent + // + PowerParentPowerDereference(); + + // + // Set our state no matter if power down failed or not + // + PowerSetDevicePowerState(state); + + // + // Stopping self managed io previously failed, convert that failure into + // a local failure here. + // + if (m_PowerMachine.m_IoCallbackFailure) { + m_PowerMachine.m_IoCallbackFailure = FALSE; + failed = TRUE; + } + + if (failed) { + // + // Power policy will use this property when it is processing the + // completion of the Dx irp. + // + m_PowerMachine.m_PowerDownFailure = TRUE; + + // + // This state will record that we encountered an internal error. + // + return FALSE; + } + + PowerSendPowerDownEvents(FxPowerDownTypeExplicit); + + PowerReleasePendingDeviceIrp(); + + return TRUE; +} + +BOOLEAN +FxPkgPnp::PowerGotoDxIoStoppedNP( + VOID + ) +/*++ + +Routine Description: + This function implements going into the Dx state in the NP path. + +Arguments: + None + +Return Value: + TRUE if the power down succeeded, FALSE otherwise + + --*/ +{ + WDF_POWER_DEVICE_STATE state; + NTSTATUS status; + BOOLEAN failed; + FxIrp irp; + + failed = FALSE; + + // + // First determine the state that will be indicated to the driver + // + irp.SetIrp(m_PendingDevicePowerIrp); + + switch (irp.GetParameterPowerShutdownType()) { + case PowerActionShutdown: + case PowerActionShutdownReset: + case PowerActionShutdownOff: + state = WdfPowerDeviceD3Final; + break; + + default: + state = (WDF_POWER_DEVICE_STATE) irp.GetParameterPowerStateDeviceState(); + break; + } + + if (m_SystemPowerState == PowerSystemHibernate && + GetUsageCount(WdfSpecialFileHibernation) != 0) { + // + // This device is in the hibernation path and the target system state is + // S4. Tell the driver that it should do special handling. + // + state = WdfPowerDevicePrepareForHibernation; + } + + if (PowerDmaPowerDown() == FALSE) { + failed = TRUE; + } + + status = m_DeviceD0ExitPreInterruptsDisabled.Invoke( + m_Device->GetHandle(), + state + ); + + if (!NT_SUCCESS(status)) { + failed = TRUE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p, " + "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), state, status); + } + + // + // Interrupt disable (and NO disconnect) + // + status = NotifyResourceObjectsDx(NotifyResourcesNP); + + if (!NT_SUCCESS(status)) { + // + // NotifyResourceObjectsDx already traced the error + // + failed = TRUE; + } + + // + // Call the driver to tell it to put the hardware into a sleeping + // state. + // + + status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), state); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p, new state " + "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), state, status); + + failed = TRUE; + } + + // + // If this is a child, release the power reference on the parent + // + PowerParentPowerDereference(); + + // + // Set our state no matter if power down failed or not + // + PowerSetDevicePowerState(state); + + // + // Stopping self managed io previously failed, convert that failure into + // a local failure here. + // + if (m_PowerMachine.m_IoCallbackFailure) { + m_PowerMachine.m_IoCallbackFailure = FALSE; + failed = TRUE; + } + + if (failed) { + // + // Power policy will use this property when it is processing the + // completion of the Dx irp. + // + m_PowerMachine.m_PowerDownFailure = TRUE; + + // + // This state will record that we encountered an internal error. + // + return FALSE; + } + + PowerSendPowerDownEvents(FxPowerDownTypeExplicit); + + PowerReleasePendingDeviceIrp(); + + return TRUE; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxArmedForWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Dx state when we are armed for wake. + +Arguments: + This - The instance of the state machine + +Return Value: + + new power state + +--*/ +{ + This->PowerGotoDx(); + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxArmedForWakeNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Dx state when we are armed for wake in the NP + path. + +Arguments: + This - The instance of the state machine + +Return Value: + + new power state + +--*/ +{ + This->PowerGotoDx(); + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxIoStoppedArmedForWake( + __inout FxPkgPnp* This + ) +{ + if (This->PowerGotoDxIoStopped() == FALSE) { + return WdfDevStatePowerGotoDxFailed; + } + + return WdfDevStatePowerDxArmedForWake; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxIoStoppedArmedForWakeNP( + __inout FxPkgPnp* This + ) +{ + if (This->PowerGotoDxIoStoppedNP() == FALSE) { + return WdfDevStatePowerGotoDxNPFailed; + } + + return WdfDevStatePowerDxArmedForWakeNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerCheckParentStateArmedForWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The PDO was armed for wake in Dx and needs to be disarmed at the bus level. + The child can only be disarmed while the parent is in D0, so check the state + of the parent. If in D0, move directly to the disarm state, otherwise move + into a wait state and disarm once the parent is in D0. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ + +{ + NTSTATUS status; + BOOLEAN parentOn; + + status = This->PowerCheckParentOverload(&parentOn); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerUpFailed; + } + else if (parentOn) { + return WdfDevStatePowerDxDisablingWakeAtBus; + } + else { + return WdfDevStatePowerWaitForParentArmedForWake; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerCheckParentStateArmedForWakeNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Same as PowerCheckParentStateArmedForWake, but we are in the NP path + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + BOOLEAN parentOn; + + status = This->PowerCheckParentOverload(&parentOn); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerUpFailedNP; + } + else if (parentOn) { + return WdfDevStatePowerDxDisablingWakeAtBusNP; + } + else { + return WdfDevStatePowerWaitForParentArmedForWakeNP; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStartSelfManagedIo( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Start Self-Managed I/O state. It tells the + driver that it can resume operations that were not interlocked with + the PnP and Power state machines. + +Arguments: + This - The instance of the state machine + +Return Value: + + new power state + +--*/ +{ + + + + + + // Top-edge queue release + This->m_Device->m_PkgIo->ResumeProcessingForPower(); + + if (This->m_SelfManagedIoMachine != NULL) { + NTSTATUS status; + + status = This->m_SelfManagedIoMachine->Start(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status); + + return WdfDevStatePowerStartSelfManagedIoFailed; + } + } + + This->PowerSetDevicePowerState(WdfPowerDeviceD0); + + // + // Send the PowerUp event to both the PnP and the Power Policy state + // machines. + // + This->PowerSendPowerUpEvents(); + + This->PowerReleasePendingDeviceIrp(); + + if (This->m_SharedPower.m_WaitWakeOwner) { + return WdfDevStatePowerD0BusWakeOwner; + } + else { + return WdfDevStatePowerD0; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStartSelfManagedIoNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Start Self-Managed I/O state. It tells the + driver that it can resume operations that were not interlocked with + the PnP and Power state machines. + +Arguments: + This - The instance of the state machine + +Return Value: + + new power state + +--*/ +{ + + + + + + // Top-edge queue release + This->m_Device->m_PkgIo->ResumeProcessingForPower(); + + if (This->m_SelfManagedIoMachine != NULL) { + NTSTATUS status; + + status = This->m_SelfManagedIoMachine->Start(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceSelfManagedIoRestart failed - %!STATUS!", status); + + return WdfDevStatePowerStartSelfManagedIoFailedNP; + } + } + + This->PowerSetDevicePowerState(WdfPowerDeviceD0); + + // + // Send the PowerUp event to both the PnP and the Power Policy state machines. + // + This->PowerSendPowerUpEvents(); + + This->PowerReleasePendingDeviceIrp(); + + if (This->m_SharedPower.m_WaitWakeOwner) { + return WdfDevStatePowerD0BusWakeOwnerNP; + } + else { + return WdfDevStatePowerD0NP; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStartSelfManagedIoFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Starting self managed io back up from an explicit Dx to D0 transition failed. + Hold the power managed queues and proceed down the power up failure path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerWakingDmaEnableFailed + + --*/ +{ + + + + + This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); + + return WdfDevStatePowerWakingDmaEnableFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStartSelfManagedIoFailedNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Starting self managed io back up from an explicit Dx to D0 transition failed. + Hold the power managed queues and proceed down the power up failure path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerWakingDmaEnableFailedNP + + --*/ +{ + + + + + This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); + + return WdfDevStatePowerWakingDmaEnableFailedNP; +} + + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakePending( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + State that indicates a successful wake from Dx. Primarily exists so that + the driver writer can register to know about the entrance into this state. + It also completes the pended wait wake request (which posts the appopriate + events to the power policy state machine if it's listening). + +Arguments: + This - The instance of the state machine + +Return Value: + return WdfDevStatePowerNull + + --*/ +{ + This->PowerCompletePendedWakeIrp(); + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakePendingNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + State that indicates a successful wake from Dx. Primarily exists so that + the driver writer can register to know about the entrance into this state. + It also completes the pended wait wake request (which posts the appopriate + events to the power policy state machine if it's listening). + +Arguments: + This - The instance of the state machine + +Return Value: + return WdfDevStatePowerNull + + --*/ +{ + This->PowerCompletePendedWakeIrp(); + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWaking( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the Waking state. Its job is to call into the + driver to tell it to restore its hardware, and then to connect interrupts + and release the queues. + +Arguments: + This - The instance of the state machine + +Return Value: + + new power state + +--*/ +{ + NTSTATUS status; + + // + // m_DevicePowerState is the "old" state because we update it after the + // D0Entry callback in SelfManagedIo or PowerPolicyStopped + // + status = This->m_DeviceD0Entry.Invoke( + This->m_Device->GetHandle(), + (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state " + "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + This->m_DevicePowerState, status); + + return WdfDevStatePowerUpFailedDerefParent; + } + + return WdfDevStatePowerNotifyingD0EntryToWakeInterrupts; +} + + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + This function implements the WakingNP state. Its job is to call into the + driver to tell it to restore its hardware and release the queues. + +Arguments: + This - The instance of the state machine + +Return Value: + + new power state + +--*/ +{ + NTSTATUS status; + + // + // m_DevicePowerState is the "old" state because we update it after the + // D0Entry callback in SelfManagedIoNP or PowerPolicyStopped + // + status = This->m_DeviceD0Entry.Invoke( + This->m_Device->GetHandle(), + (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Entry WDFDEVICE 0x%p !devobj 0x%p, old state " + "%!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + This->m_DevicePowerState, status); + + return WdfDevStatePowerUpFailedDerefParentNP; + } + + return WdfDevStatePowerNotifyingD0EntryToWakeInterruptsNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingConnectInterrupt( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is returning to D0 in the power pageable path. Connect and + enable the interrupts. If that succeeds, scan for children and then + open the power managed I/O queues. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + + // + // interrupt connect and enable + // + status = This->NotifyResourceObjectsD0(NotifyResourcesExplicitPowerup); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerWakingConnectInterruptFailed; + } + + status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke( + This->m_Device->GetHandle(), + (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, " + "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + This->m_DevicePowerState, status); + return WdfDevStatePowerWakingConnectInterruptFailed; + } + + return WdfDevStatePowerWakingDmaEnable; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingConnectInterruptNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is returning to D0 in the power pageable path. + Enable the interrupts. If that succeeds, scan for children and then + open the power managed I/O queues. + +Arguments: + This - instance of the state machine + +Return Value: + new state + + --*/ +{ + NTSTATUS status; + + // + // interrupt enable (already connected b/c they were never disconnected + // during the Dx transition). + // + status = This->NotifyResourceObjectsD0(NotifyResourcesNP); + + if (!NT_SUCCESS(status)) { + return WdfDevStatePowerWakingConnectInterruptFailedNP; + } + + status = This->m_DeviceD0EntryPostInterruptsEnabled.Invoke( + This->m_Device->GetHandle(), + (WDF_POWER_DEVICE_STATE) This->m_DevicePowerState); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0EntryPostInterruptsEnabed WDFDEVICE 0x%p !devobj 0x%p, " + "old state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + This->m_DevicePowerState, status); + return WdfDevStatePowerWakingConnectInterruptFailedNP; + } + + return WdfDevStatePowerWakingDmaEnableNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingConnectInterruptFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Connecting or enabling the interrupts failed. Disable and disconnect any + interrupts which have been connected and maybe enabled. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerUpFailed + + --*/ +{ + This->PowerConnectInterruptFailed(); + + return WdfDevStatePowerReportPowerUpFailedDerefParent; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingConnectInterruptFailedNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Enabling the interrupts failed. Disable and disconnect any + interrupts which have been connected and maybe enabled. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerUpFailed + + --*/ +{ + // + // PowerConnectInterruptFailed will call IoDisconnectInterrupt. Since we + // are in the NP path, this may cause a deadlock between this thread and + // paging I/O. Log something to the IFR so that if the watchdog timer kicks + // in, at least we have context as to why we died. + // + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Force disconnecting interupts on !devobj %p, WDFDEVICE %p", + This->m_Device->GetDeviceObject(), + This->m_Device->GetHandle()); + + This->PowerConnectInterruptFailed(); + + return WdfDevStatePowerReportPowerUpFailedDerefParent; +} + +BOOLEAN +FxPkgPnp::PowerDmaEnableAndScan( + __in BOOLEAN ImplicitPowerUp + ) +{ + FxTransactionedEntry* ple; + + if (PowerDmaPowerUp() == FALSE) { + return FALSE; + } + + if (m_EnumInfo != NULL) { + // + // Scan for children + // + m_EnumInfo->m_ChildListList.LockForEnum(GetDriverGlobals()); + + ple = NULL; + while ((ple = m_EnumInfo->m_ChildListList.GetNextEntry(ple)) != NULL) { + ((FxChildList*) ple->GetTransactionedObject())->ScanForChildren(); + } + + m_EnumInfo->m_ChildListList.UnlockFromEnum(GetDriverGlobals()); + } + + if (ImplicitPowerUp == FALSE) { + PowerPolicyProcessEvent(PwrPolPowerUpHwStarted); + } + + return TRUE; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingDmaEnable( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is returning to D0 from Dx. Power up all DMA enablers and scan + for children. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + if (This->PowerDmaEnableAndScan(FALSE) == FALSE) { + return WdfDevStatePowerWakingDmaEnableFailed; + } + + // + // Return the state that we should drop into next. + // + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingDmaEnableNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The device is returning to D0 from Dx in the NP path. Power up all DMA + enablers and scan for children. + +Arguments: + This - instance of the state machine + +Return Value: + new machine state + + --*/ +{ + if (This->PowerDmaEnableAndScan(FALSE) == FALSE) { + return WdfDevStatePowerWakingDmaEnableFailedNP; + } + + // + // Return the state that we should drop into next. + // + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingDmaEnableFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Powering up a DMA enabler failed. Power down all DMA enablers and progress + down the failed power up path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerWakingConnectInterruptFailed + + --*/ +{ + NTSTATUS status; + + (void) This->PowerDmaPowerDown(); + + status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( + This->m_Device->GetHandle(), + WdfPowerDeviceD3Final + ); + + if (!NT_SUCCESS(status)) { + // + // Report the error, but continue forward + // + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p " + "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + WdfPowerDeviceD3Final, status); + } + + return WdfDevStatePowerWakingConnectInterruptFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerWakingDmaEnableFailedNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Powering up a DMA enabler failed in the NP path. Power down all DMA + enablers and progress down the failed power up path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerWakingConnectInterruptFailedNP + + --*/ +{ + NTSTATUS status; + + COVERAGE_TRAP(); + + (void) This->PowerDmaPowerDown(); + + status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( + This->m_Device->GetHandle(), + WdfPowerDeviceD3Final + ); + + if (!NT_SUCCESS(status)) { + // + // Report the error, but continue forward + // + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p " + "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + WdfPowerDeviceD3Final, status); + } + + return WdfDevStatePowerWakingConnectInterruptFailedNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerReportPowerUpFailedDerefParent( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Power up failed. Release the reference on the parent that was taken at the + start of power up. + +Arguments: + This - instance of the state machine. + +Return Value: + WdfDevStatePowerInitialPowerUpFailed + + --*/ +{ + // + // If this is a child, release the power reference on the parent + // + This->PowerParentPowerDereference(); + + return WdfDevStatePowerReportPowerUpFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerReportPowerUpFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Posts PowerUpFailed event to the PnP state machine and then waits for death. + The pended Power IRP is also completed. + +Arguments: + This - The instance of the state machine + +Return Value: + new power state + + --*/ +{ + This->m_SystemPowerAction = PowerActionNone; + + This->PowerReleasePendingDeviceIrp(); + This->PowerSendPowerUpFailureEvent(); + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerPowerFailedPowerDown( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We failed to power up/down properly and now the power policy state machine wants + to power down the device. Since power policy and pnp rely on power posting + power down events to make forward progress, we must do that here + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerStopped + + --*/ +{ + // + // Even though we failed power up and never really powered down, record our + // state as powered down, so that if we are restarted (can easily happen for + // a PDO), we have the correct previous state. + // + This->PowerSetDevicePowerState(WdfPowerDeviceD3Final); + + This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit); + + return WdfDevStatePowerStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerReportPowerDownFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Posts PowerDownFailed event to the PnP state machine and then waits for death. + The pended Power IRP is also completed. + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerNull + + --*/ +{ + + + + + This->PowerReleasePendingDeviceIrp(); + This->PowerSendPowerDownFailureEvent(FxPowerDownTypeExplicit); + + return WdfDevStatePowerNull; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerInitialConnectInterruptFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + When bringing the device out of the D3 final state, connecting or enabling + the interrupts failed. Disconnect and disable any interrupts which are + connected and possibly enabled. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerInitialPowerUpFailedDerefParent + + --*/ +{ + This->PowerConnectInterruptFailed(); + + return WdfDevStatePowerInitialPowerUpFailedDerefParent; +} + + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerInitialDmaEnableFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Initial power up of the device failed while enabling DMA. Disable any + started DMA enablers and proceed down the initial power up failure path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerInitialConnectInterruptFailed + + --*/ +{ + NTSTATUS status; + + (void) This->PowerDmaPowerDown(); + + status = This->m_DeviceD0ExitPreInterruptsDisabled.Invoke( + This->m_Device->GetHandle(), + WdfPowerDeviceD3Final + ); + + if (!NT_SUCCESS(status)) { + // + // Report the error, but continue forward + // + DoTraceLevelMessage( + This->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0ExitPreInterruptsDisabled WDFDEVICE 0x%p !devobj 0x%p " + "new state %!WDF_POWER_DEVICE_STATE! failed, %!STATUS!", + This->m_Device->GetHandle(), + This->m_Device->GetDeviceObject(), + WdfPowerDeviceD3Final, status); + } + + return WdfDevStatePowerInitialConnectInterruptFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerInitialSelfManagedIoFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + The self managed io start failed when bringing the device out of Dx with an + implicit D0 transition. Hold the power queues that were previous open can + continue to cleanup + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerInitialDmaEnableFailed + + --*/ +{ + + + + + This->m_Device->m_PkgIo->StopProcessingForPower(FxIoStopProcessingForPowerHold); + + return WdfDevStatePowerInitialDmaEnableFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerInitialPowerUpFailedDerefParent( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Dereferences the parent's power ref count we took during start up + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerInitialPowerUpFailed + + --*/ +{ + + // + // If this is a child, release the power reference on the parent + // + This->PowerParentPowerDereference(); + + return WdfDevStatePowerInitialPowerUpFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerInitialPowerUpFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Posts PowerUpFailed event to the PnP state machine and then waits for death. + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerStopped + + --*/ +{ + This->PowerSendPowerUpFailureEvent(); + + return WdfDevStatePowerStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxStoppedDisarmWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disarms the device from wake because the device is being stopped/removed + while in Dx. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerDxStopped + + --*/ +{ + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + This->PowerDisableWakeAtBusOverload(); + + return WdfDevStatePowerGotoDxStoppedDisableInterrupt; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxStoppedDisarmWakeNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disarms the device from wake because the device is being stopped/removed + while in Dx. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerGotoDxStoppedDisableInterruptNP + + --*/ +{ + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + This->PowerDisableWakeAtBusOverload(); + + return WdfDevStatePowerGotoDxStoppedDisableInterruptNP; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxStoppedDisableInterruptNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is in Dx and was implicitly powered down. Disable the interrupt since + the interrupt was not disconnected in the NP power down path. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerGotoDxStopped + + --*/ +{ + This->NotifyResourceObjectsDx(NotifyResourcesSurpriseRemoved); + + return WdfDevStatePowerGotoDxStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxStopped( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Device is in Dx and being removed/stopped. Inform the other state machines + that the device is powered down so that they may continue. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerStopped + + --*/ +{ + This->PowerSendPowerDownEvents(FxPowerDownTypeImplicit); + + return WdfDevStatePowerStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoStopped( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are in the Dx state and the power policy owner sent an explicit D0 irp + to the stack. Transition to the stopped state which will transition to the + D0 state when receiving an implicit D0. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerStopped + + --*/ +{ + // + // We should only get into this state when this devobj is not the power + // policy owner. + // + ASSERT(This->IsPowerPolicyOwner() == FALSE); + + This->PowerReleasePendingDeviceIrp(); + return WdfDevStatePowerStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerStoppedCompleteDx( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We were in the Stopped state and the power policy owner sent an explicit + Dx request to the stack. We will move to the DxStopped state where we will + transition to a Dx state when an implicit D0 is received. + +Arguments: + This - instance of the state machine + +Return Value: + WdfDevStatePowerDxStopped + + --*/ +{ + // + // We should only get into this state when this devobj is not the power + // policy owner. + // + ASSERT(This->IsPowerPolicyOwner() == FALSE); + + This->PowerReleasePendingDeviceIrp(); + return WdfDevStatePowerDxStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxStoppedDecideDxState( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are implicitly powering up the stack while in the Dx state. Decide + which Dx "holding" state to transition to. + +Arguments: + This - instance of the state machine + +Return Value: + new power state + + --*/ +{ + // + // We should only get into this state when this devobj is not the power + // policy owner. + // + ASSERT(This->IsPowerPolicyOwner() == FALSE); + + // + // Move power policy back into a working state + // + // While it seems odd to send a power up in a Dx state, the power up is + // really an indication to the power policy state machine that the implicit + // D0 has been successfully processed, basically, it is a status event more + // then an indication of true power state. + // + This->PowerSendPowerUpEvents(); + + if (This->m_Device->GetDeviceObjectFlags() & DO_POWER_PAGABLE) { + if (This->PowerIsWakeRequestPresent()) { + COVERAGE_TRAP(); + return WdfDevStatePowerDxStoppedArmForWake; + } + else { + return WdfDevStatePowerDx; + } + } + else { + if (This->PowerIsWakeRequestPresent()) { + COVERAGE_TRAP(); + return WdfDevStatePowerDxStoppedArmForWakeNP; + } + else { + COVERAGE_TRAP(); + return WdfDevStatePowerDxNP; + } + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxStoppedArmForWake( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are implicitly powering the stack back up while the device is in Dx + and there is a wait wake request presnt on this device. Enable wake at + the bus level and then move to the appropriate state based on the enabling + status. + +Arguments: + This - instance of the state machine + +Return Value: + new power state + + --*/ +{ + NTSTATUS status; + + COVERAGE_TRAP(); + + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + status = This->PowerEnableWakeAtBusOverload(); + + if (NT_SUCCESS(status)) { + // + // No matter of the irp status (canceled, pending, completed), we always + // transition to the D0ArmedForWake state because that is where we + // we handle the change in the irp's status. + // + COVERAGE_TRAP(); + return WdfDevStatePowerDxArmedForWake; + } + else { + COVERAGE_TRAP(); + This->PowerCompleteWakeRequestFromWithinMachine(status); + return WdfDevStatePowerDx; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerDxStoppedArmForWakeNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + We are implicitly powering the stack back up while the device is in Dx + and there is a wait wake request presnt on this device. Enable wake at + the bus level and then move to the appropriate state based on the enabling + status. + +Arguments: + This - instance of the state machine + +Return Value: + new power state + + --*/ +{ + NTSTATUS status; + + COVERAGE_TRAP(); + + // + // We should only get into this state when this devobj is not a PDO and a + // power policy owner. + // + ASSERT((This->m_Device->IsPdo() && This->IsPowerPolicyOwner()) == FALSE); + + status = This->PowerEnableWakeAtBusOverload(); + + if (NT_SUCCESS(status)) { + // + // No matter of the irp status (canceled, pending, completed), we always + // transition to the D0ArmedForWake state because that is where we + // we handle the change in the irp's status. + // + COVERAGE_TRAP(); + return WdfDevStatePowerDxArmedForWakeNP; + } + else { + COVERAGE_TRAP(); + This->PowerCompleteWakeRequestFromWithinMachine(status); + return WdfDevStatePowerDxNP; + } +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerFinalPowerDownFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Posts PowerDownFailed event to the PnP state machine and then waits for death. + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerStopped + + --*/ +{ + This->PowerSendPowerDownFailureEvent(FxPowerDownTypeImplicit); + + // + // If we are not the PPO for the stack we could receive a power irp + // during the middle of an implicit power down so we cannot assume + // that there will be no pended power irp during an implicit power down. + // + ASSERT(This->IsPowerPolicyOwner() ? This->m_PendingDevicePowerIrp == NULL : TRUE); + + return WdfDevStatePowerStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerUpFailedDerefParent( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disconnects interrupts + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerUpFailed + + --*/ +{ + // + // Notify the interrupt state machines that the power up failed + // + This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); + // + // NotifyResourceObjectsDx will log any errors + // + (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | + NotifyResourcesDisconnectInactive); + + return WdfDevStatePowerReportPowerUpFailedDerefParent; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerUpFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disconnects interrupts + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerUpFailed + + --*/ +{ + COVERAGE_TRAP(); + // + // Notify the interrupt state machines that the power up failed + // + This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); + // + // NotifyResourceObjectsDx will log any errors + // + (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | + NotifyResourcesDisconnectInactive); + + return WdfDevStatePowerReportPowerUpFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxFailed( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disconnects interrupts + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerDownFailed + + --*/ +{ + // + // NotifyResourceObjectsDx will log any errors + // + (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | + NotifyResourcesDisconnectInactive); + + return WdfDevStatePowerReportPowerDownFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerGotoDxStoppedDisableInterrupt( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disconnects interrupts + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerGotoDxStopped + + --*/ +{ + // + // NotifyResourceObjectsDx will log any errors + // + (void) This->NotifyResourceObjectsDx(NotifyResourcesForceDisconnect | + NotifyResourcesDisconnectInactive); + + return WdfDevStatePowerGotoDxStopped; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerUpFailedDerefParentNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disconnects interrupts + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerUpFailed + + --*/ +{ + // + // Notify the interrupt state machines that the power up failed + // + This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); + This->DisconnectInterruptNP(); + + return WdfDevStatePowerReportPowerUpFailedDerefParent; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerUpFailedNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Disconnects interrupts + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerReportPowerUpFailed + + --*/ +{ + // + // Notify the interrupt state machines that the power up failed + // + This->SendEventToAllWakeInterrupts(WakeInterruptEventD0EntryFailed); + This->DisconnectInterruptNP(); + + return WdfDevStatePowerReportPowerUpFailed; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerNotifyingD0EntryToWakeInterrupts( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Notifies the wake interrupt state machines that the device has entered + D0 + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerWakingConnectInterrupt if there are no wake interrupts + or WdfDevStatePowerNull otherwise + + --*/ +{ + if (This->m_WakeInterruptCount == 0) { + return WdfDevStatePowerWakingConnectInterrupt; + } + + This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0); + + return WdfDevStatePowerNull;; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerNotifyingD0ExitToWakeInterrupts( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Notifies the wake interrupt state machines that the device is about + to exit D0 + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerDx if there are no wake interrupts or WdfDevStatePowerNull + otherwise + + --*/ +{ + if (This->m_WakeInterruptCount == 0) { + return WdfDevStatePowerGotoDxIoStopped; + } + + // + // Indiciate to the wake interrupt state machine that the device is + // leaving D0 and also whether the device is armed for wake. The wake + // interrupt machine treats these differently as described below. + // + if (This->m_WakeInterruptsKeepConnected == TRUE || + This->m_SharedPower.m_WaitWakeIrp != NULL) { + This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0); + } + else { + // + // When a wake interrupt is not armed for wake it will be disconnected + // by the power state machine once the wake interrupt state machine + // acknowledges the transition. If the interrupt fires between + // the time this event is posted and it is disconnected, it needs to be + // delivered to the driver or a deadlock could occur between PO state machine + // trying to disconnect the interrupt and the wake interrupt machine + // holding on to the ISR waiting for the device to return to D0 before + // delivering the interrupt. + // + This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0NotArmedForWake); + } + + return WdfDevStatePowerNull;; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerNotifyingD0EntryToWakeInterruptsNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Notifies the wake interrupt state machines that the device has entered + D0 + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerWakingConnectInterruptNP if there are no wake interrupts + or WdfDevStatePowerNull otherwise + + --*/ +{ + if (This->m_WakeInterruptCount == 0) { + return WdfDevStatePowerWakingConnectInterruptNP; + } + + This->SendEventToAllWakeInterrupts(WakeInterruptEventEnteringD0); + + return WdfDevStatePowerNull;; +} + +WDF_DEVICE_POWER_STATE +FxPkgPnp::PowerNotifyingD0ExitToWakeInterruptsNP( + __inout FxPkgPnp* This + ) +/*++ + +Routine Description: + Notifies the wake interrupt state machines that the device is about + to exit D0 + +Arguments: + This - The instance of the state machine + +Return Value: + WdfDevStatePowerDxNP if there are no wake interrupts or WdfDevStatePowerNull + otherwise + + --*/ +{ + if (This->m_WakeInterruptCount == 0) { + return WdfDevStatePowerGotoDxIoStoppedNP; + } + + // + // Indiciate to the wake interrupt state machine that the device is + // leaving D0 and also whether the device is armed for wake. The wake + // interrupt machine treats these differently as described below + // + if (This->m_WakeInterruptsKeepConnected == TRUE || + This->m_SharedPower.m_WaitWakeIrp != NULL) { + This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0); + } + else { + // + // When a wake interrupt is not armed for wake it will be disconnected by + // the power state machine once the wake interrupt state machine + // acknowledges the transition. If the interrupt fires between + // the time this event is posted and it is disconnected, it needs to be + // delivered to the driver or a deadlock could occur between PO state machine + // trying to disconnect the interrupt and the wake interrupt machine holding on + // to the ISR waiting for the device to return to D0 before delivering the + // interrupt. + // + This->SendEventToAllWakeInterrupts(WakeInterruptEventLeavingD0NotArmedForWake); + } + + return WdfDevStatePowerNull;; +} + +VOID +FxPkgPnp::DisconnectInterruptNP( + VOID + ) +{ + // + // NotifyResourceObjectsDx will call IoDisconnectInterrupt. Since we + // are in the NP path, this may cause a deadlock between this thread and + // paging I/O. Log something to the IFR so that if the watchdog timer kicks + // in, at least we have context as to why we died. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Force disconnecting interrupts on !devobj 0x%p, WDFDEVICE %p", + m_Device->GetDeviceObject(), + m_Device->GetHandle()); + + // + // NotifyResourceObjectsDx will log any errors + // + (void) NotifyResourceObjectsDx(NotifyResourcesForceDisconnect); +} + +BOOLEAN +FxPkgPnp::PowerIndicateWaitWakeStatus( + __in NTSTATUS WaitWakeStatus + ) +/*++ + +Routine Description: + If there is a pended wait wake request, this routine will remove the cancel + routine and post the appropriate event to the power state machine. The + consumer of this event will do the actual completion of the wait wake + request. + + The difference between this routine and + PowerCompleteWakeRequestFromWithinMachine is that + PowerCompleteWakeRequestFromWithinMachine is a private API to the state + machine and will attempt to complete the request immediately instead of + deferring the completion through the posting of a power state machine event. + + PowerCompletePendedWakeIrp is used within the state machine to complete the + IRP deferred by this routine. + +Arguments: + WaitWakeStatus - The final status of the wait wake request + +Return Value: + TRUE if there there was a request to cancel + + --*/ +{ + if (PowerMakeWakeRequestNonCancelable(WaitWakeStatus)) { + // + // The power machine will eventually call PowerCompletePendedWakeIrp + // to complete the request. + // + if (WaitWakeStatus == STATUS_CANCELLED) { + PowerProcessEvent(PowerWakeCanceled); + } + else if (NT_SUCCESS(WaitWakeStatus)) { + PowerProcessEvent(PowerWakeSucceeded); + } + else { + PowerProcessEvent(PowerWakeFailed); + } + + return TRUE; + } + else { + return FALSE; + } +} + +VOID +FxPkgPnp::PowerCompletePendedWakeIrp( + VOID + ) +/*++ + +Routine Description: + Completes the wait wake request that was pended by the power state machine. + It is valid if there is no request to complete (the only time there will be + a request to complete is when this power state machine is the wait wake owner + +Arguments: + None + +Return Value: + None + + --*/ +{ + PLIST_ENTRY ple; + KIRQL irql; + + if (m_SharedPower.m_WaitWakeOwner == FALSE) { + COVERAGE_TRAP(); + return; + } + + // + // Pop an irp off of the list + // + m_PowerMachine.m_WaitWakeLock.Acquire(&irql); + ASSERT(IsListEmpty(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList) == FALSE); + ple = RemoveHeadList(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList); + m_PowerMachine.m_WaitWakeLock.Release(irql); + + InitializeListHead(ple); + + FxIrp irp(FxIrp::GetIrpFromListEntry(ple)); + + CompletePowerRequest(&irp, irp.GetStatus()); +} + +VOID +FxPkgPnp::PowerCompleteWakeRequestFromWithinMachine( + __in NTSTATUS WaitWakeStatus + ) +/*++ + +Routine Description: + Completes a wait wake from within the power state machine. Contrary to + PowerIndicateWaitWakeStatus which posts an event to the state machine to + process the irp's status change, this routine attempts to complete the + irp immediately. + +Arguments: + Status - Final status of the wake irp + +Return Value: + None + + --*/ +{ + if (PowerMakeWakeRequestNonCancelable(WaitWakeStatus)) { + PowerCompletePendedWakeIrp(); + } +} + +BOOLEAN +FxPkgPnp::PowerMakeWakeRequestNonCancelable( + __in NTSTATUS WaitWakeStatus + ) +/*++ + +Routine Description: + Attempts to clear the cancel routine from the pended wake request. If + successful, it will put the wake request on a pending wake list to be + completed later by PowerCompletePendedWakeIrp . + +Arguments: + WaitWakeStatus - final status for the wake request + +Return Value: + TRUE if there was a request and we cleared the cancel routine, FALSE + otherwise + + --*/ +{ + KIRQL irql; + BOOLEAN result; + + // + // Currently we assume that if we are the bus wait wake owner and that only + // PDOs can be bus wake owners, so we must have a parent device. + // + ASSERT(m_SharedPower.m_WaitWakeOwner && + (m_Device->m_ParentDevice != NULL)); + + result = FALSE; + + // + // Attempt to retrieve the wait wake irp. We can safely dereference the + // PIRP in while holding the lock as long as it is not NULL. + // + m_PowerMachine.m_WaitWakeLock.Acquire(&irql); + + if (m_SharedPower.m_WaitWakeIrp != NULL) { + MdCancelRoutine pOldCancelRoutine; + FxIrp wwIrp; + + wwIrp.SetIrp(m_SharedPower.m_WaitWakeIrp); + + pOldCancelRoutine = wwIrp.SetCancelRoutine(NULL); + + if (pOldCancelRoutine != NULL) { + FxPkgPnp* pParentPkg; + + pParentPkg = m_Device->m_ParentDevice->m_PkgPnp; + + // + // Propagate the successful wake status from the parent to this + // child's WW IRP if the parent is the PPO for its stack. + // + if (NT_SUCCESS(WaitWakeStatus) && + pParentPkg->IsPowerPolicyOwner() && + pParentPkg->m_PowerPolicyMachine.m_Owner->m_SystemWakeSource) { + // + // The only way that m_SystemWakeSource can be TRUE is if + // FxLibraryGlobals.PoGetSystemWake != NULL and if it is not + // NULL, then FxLibraryGlobals.PoSetSystemWake cannot be NULL + // either. + + + + + + FxPkgPnp::_PowerSetSystemWakeSource(&wwIrp); + + // + // If this PDO is the PPO for its stack, then we must mark this + // device as the system wake source if we have any + // enumerated PDOs off of this PDO so that we can propagate the + // system wake source attribute to our children stacks. + // (For a FDO which is the PPO, we do this in the WW completion + // routine.) + // + if (IsPowerPolicyOwner()) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p WW !irp 0x%p is a source " + "of wake", m_Device->GetHandle(), + m_Device->GetDeviceObject(), + m_SharedPower.m_WaitWakeIrp); + + m_PowerPolicyMachine.m_Owner->m_SystemWakeSource = TRUE; + } + } + + // + // Set the status for the irp when it is completed later + // + wwIrp.SetStatus(WaitWakeStatus); + + // + // Queue the irp for completion later + // + InsertTailList(&m_PowerMachine.m_WaitWakeIrpToBeProcessedList, + wwIrp.ListEntry()); + + wwIrp.SetIrp(NULL); + m_SharedPower.m_WaitWakeIrp = NULL; + result = TRUE; + } + else { + // + // The irp is being canceled as we run here. As soon as the spin + // lock is dropped, the cancel routine will run (or continue if it + // is blocked on this lock). Do nothing here and let the cancel + // routine run its course. + // + ASSERT(wwIrp.IsCanceled()); + DO_NOTHING(); + } + } + m_PowerMachine.m_WaitWakeLock.Release(irql); + + return result; +} + +VOID +FxPkgPnp::PowerSendIdlePowerEvent( + __in FxPowerIdleEvents Event + ) +{ + if (IsPowerPolicyOwner()) { + m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent(Event); + } +} + +VOID +FxPkgPnp::PowerSendPowerDownEvents( + __in FxPowerDownType Type + ) +/*++ + +Routine Description: + The device has powered down, inform the power policy state machine + +Arguments: + Type - the type of power down being performed + +Return Value: + None + + --*/ +{ + // + // If this is an implicit power type, there is completion routine on the + // power irp and we must send these events in the power state machine + // regardless if we are the PPO or not. + // + if (Type == FxPowerDownTypeImplicit) { + PowerSendIdlePowerEvent(PowerIdleEventPowerDown); + + // + // If we are the power policy owner, there is no need to distinguish + // between an implicit power down or an explicit power down since the + // PPO controls all power irps in the stack and a power policy stop + // (e.g. an implicit power down) will not be racing with a real power + // irp. + // + // The non PPO state machine needs to distinguish between the 2 types + // of power downs because both of them may occur simultaneously and we + // don't want to interpret the power down event for the real Dx irp with + // the power down event for the (final) implicit power down. + // + PowerPolicyProcessEvent(IsPowerPolicyOwner() ? PwrPolPowerDown + : PwrPolImplicitPowerDown); + return; + } + + ASSERT(Type == FxPowerDownTypeExplicit); + + // + // If we are the PPO, then we will send PwrPolPowerDown in the completion + // routine passed to PoRequestPowerIrp. If we are not the PPO, we must send + // the event now because we have no such completion routine. + // + if (IsPowerPolicyOwner()) { + // + // Transition the idle state machine to off immediately. + // + m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent( + PowerIdleEventPowerDown + ); + } + else { + // + // If we are not the PPO, there is no idle state machine to send an + // event to and there is no Po request completion routine to send this + // event, so we send it now. + // + PowerPolicyProcessEvent(PwrPolPowerDown); + } +} + +VOID +FxPkgPnp::PowerSendPowerUpEvents( + VOID + ) +/*++ + +Routine Description: + Sends power up events to the pnp and power policy state machines + +Arguments: + None + +Return Value: + None + + --*/ +{ + PowerSendIdlePowerEvent(PowerIdleEventPowerUpComplete); + + // + // This must be called *before* PowerPostParentToD0ToChildren so that we + // clear the child power up guard variable in the power policy state machine + // and then post an event which will unblock the child. + // + PowerPolicyProcessEvent(PwrPolPowerUp); +} + +VOID +FxPkgPnp::PowerSendPowerDownFailureEvent( + __in FxPowerDownType Type + ) +/*++ + +Routine Description: + Sends a power down failure event to the pnp state machine marks an internal + error. + +Arguments: + None + +Return Value: + None + + --*/ +{ + SetInternalFailure(); + + if (IsPowerPolicyOwner()) { + // + // If we are the PPO and this is an explicit power operation, then we + // will send PwrPolPowerDownFailed in the completion routine passed to + // PoRequestPowerIrp. Otherwise, if this is an implicit power operation + // that failed, we need to send the event now because there is no + // Po completion routine to send the event later. + // + if (Type == FxPowerDownTypeImplicit) { + // + // Since there is no power irp to complete, we must send the event + // now. + // + // We only send PwrPolImplicitPowerDownFailed if we are not the + // PPO, so we can't share code with the !PPO path. + // + PowerPolicyProcessEvent(PwrPolPowerDownFailed); + } + else { + ASSERT(Type == FxPowerDownTypeExplicit); + + // + // Process the state change immediately in the idle state machine. + // We should do this only on an explicit power down since the PPO + // will have disabled the idle state machine before attempting an + // implicit power down. + // + m_PowerPolicyMachine.m_Owner->m_PowerIdleMachine.ProcessPowerEvent( + PowerIdleEventPowerDownFailed + ); + } + } + else { + // + // We are not the PPO, so we must send the event now because we have no + // such completion routine. Decide which event to send to the + // !PPO state machine. + // + PowerPolicyProcessEvent( + Type == FxPowerDownTypeImplicit ? PwrPolImplicitPowerDownFailed + : PwrPolPowerDownFailed + ); + + // + // Send the pnp event last becuase if we are in the middle of a Dx + // transition during S0, there is no S irp to guard a pnp state change + // from occurring immediately after sending this event. If we sent it + // before sending the power policy message, power policy might not + // transition to the failed state by the time pnp does creating a + // mismatch. + // + if (FALSE == m_ReleaseHardwareAfterDescendantsOnFailure) { + PnpProcessEvent(PnpEventPowerDownFailed); + } + } +} + +VOID +FxPkgPnp::PowerSendPowerUpFailureEvent( + VOID + ) +/*++ + +Routine Description: + Sends a power up failure event to the pnp state machine marks an internal + error. + +Arguments: + None + +Return Value: + None + + --*/ +{ + SetInternalFailure(); + PowerSendIdlePowerEvent(PowerIdleEventPowerUpFailed); + + PowerPolicyProcessEvent(PwrPolPowerUpFailed); + + if (FALSE == m_ReleaseHardwareAfterDescendantsOnFailure) { + PnpProcessEvent(PnpEventPowerUpFailed); + } +} + +VOID +FxPkgPnp::PowerSetDevicePowerState( + __in WDF_POWER_DEVICE_STATE State + ) +/*++ + +Routine Description: + Stores the state in the object and notifies the system of the change. + +Arguments: + State - new device state + +Return Value: + VOID + + --*/ +{ + POWER_STATE powerState; + + // + // Remember our previous state + // + m_DevicePowerStateOld = m_DevicePowerState; + + // + // Set our new state + // + ASSERT(State <= 0xFF); + m_DevicePowerState = (BYTE) State; + + // + // Notify the system of the new power state. + // + switch (State) { + case WdfPowerDeviceD3Final: + case WdfPowerDevicePrepareForHibernation: + powerState.DeviceState = PowerDeviceD3; + break; + + case WdfPowerDeviceD0: + m_SystemPowerAction = PowerActionNone; + __fallthrough; + + default: + powerState.DeviceState = (DEVICE_POWER_STATE) State; + break; + } + + MxDeviceObject deviceObject(m_Device->GetDeviceObject()); + deviceObject.SetPowerState( + DevicePowerState, + powerState); +} + +VOID +FxPkgPnp::PowerConnectInterruptFailed( + VOID + ) +/*++ + +Routine Description: + Worker routine for all the paths where we are trying to bring the device into + D0 and failed while trying to connect or enable an interrupt. This routine + disables and disconnects all interrupts, calls D0Exit, and sets the device + state. + +Arguments: + This - instance of the state machine + +Return Value: + None + + --*/ + +{ + NTSTATUS status; + + status = NotifyResourceObjectsDx(NotifyResourcesForceDisconnect); + + if (!NT_SUCCESS(status)) { + // + // Report the error, but continue forward + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Interrupt(s) disconnect on WDFDEVICE %p failed, %!STATUS!", + m_Device->GetHandle(), status); + } + + status = m_DeviceD0Exit.Invoke(m_Device->GetHandle(), + WdfPowerDeviceD3Final); + + if (!NT_SUCCESS(status)) { + // + // Report the error, but continue forward + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "EvtDeviceD0Exit WDFDEVICE 0x%p !devobj 0x%p failed, %!STATUS!", + m_Device->GetHandle(), + m_Device->GetDeviceObject(), status); + } + + PowerSetDevicePowerState(WdfPowerDeviceD3Final); +} + + + + + + + + +VOID +FxPkgPnp::_PowerWaitWakeCancelRoutine( + __in MdDeviceObject DeviceObject, + __in MdIrp Irp + ) +/*++ + +Routine Description: + Cancel routine for the pended wait wake irp. This will post an event to + the power state machine to process the cancellation under the machine's + lock and complete the irp later. + +Arguments: + DeviceObject - Instance of this state machine + Irp - The wait wake request being canceled + +Return Value: + None + + --*/ +{ + CfxDevice* pDevice; + FxPkgPdo* pThis; + FxIrp irp(Irp); + KIRQL irql; + + // + // Release the IO cancel spinlock because we use our own + // + Mx::ReleaseCancelSpinLock(irp.GetCancelIrql()); + + pDevice = FxDevice::GetFxDevice(DeviceObject); + pThis = pDevice->GetPdoPkg(); + + ASSERT(pThis->m_SharedPower.m_WaitWakeOwner); + + // + // Clear out the IRQL and set our state to disarming + // + pThis->m_PowerMachine.m_WaitWakeLock.Acquire(&irql); + + ASSERT(pThis->m_SharedPower.m_WaitWakeIrp == Irp && + pThis->m_SharedPower.m_WaitWakeIrp != NULL); + + InsertTailList(&pThis->m_PowerMachine.m_WaitWakeIrpToBeProcessedList, + irp.ListEntry()); + + // + // Set the status for the irp when it is completed later + // + irp.SetStatus(STATUS_CANCELLED); + + pThis->m_SharedPower.m_WaitWakeIrp = NULL; + + pThis->m_PowerMachine.m_WaitWakeLock.Release(irql); + + pThis->PowerProcessEvent(PowerWakeCanceled); +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/poxinterface.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/poxinterface.cpp new file mode 100644 index 00000000000..0b2ce3deea6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/poxinterface.cpp @@ -0,0 +1,579 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PoxInterface.cpp + +Abstract: + + This module implements the power-framework-related logic in WDF. + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PoxInterface.tmh" +#endif +} + +FxPoxInterface::FxPoxInterface( + __in FxPkgPnp* PkgPnp + ) +{ + m_PkgPnp = PkgPnp; + m_PoHandle = NULL; + m_DevicePowerRequired = TRUE; + m_DevicePowerRequirementMachine = NULL; + m_CurrentIdleTimeoutHint = 0; + m_NextIdleTimeoutHint = 0; +} + +FxPoxInterface::~FxPoxInterface( + VOID + ) +{ + if (NULL != m_DevicePowerRequirementMachine) { + delete m_DevicePowerRequirementMachine; + } +} + +NTSTATUS +FxPoxInterface::CreateDevicePowerRequirementMachine( + VOID + ) +{ + NTSTATUS status; + FxDevicePwrRequirementMachine * fxDprMachine = NULL; + + ASSERT(NULL == m_DevicePowerRequirementMachine); + + fxDprMachine = new (m_PkgPnp->GetDriverGlobals()) + FxDevicePwrRequirementMachine(this); + if (NULL == fxDprMachine) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p failed to allocate " + "FxDevicePwrRequirementMachine. %!STATUS!.", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + status); + goto exit; + } + + status = fxDprMachine->Initialize(m_PkgPnp->GetDriverGlobals()); + if (FALSE == NT_SUCCESS(status)) { + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p Device Power Requirement State Machine" + " Initialize() failed, %!STATUS!", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + status); + goto exit; + } + + status = fxDprMachine->Init( + m_PkgPnp, + FxDevicePwrRequirementMachine::_ProcessEventInner + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p Device Power Requirement State Machine" + " Init() failed, %!STATUS!", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + status); + goto exit; + } + + m_DevicePowerRequirementMachine = fxDprMachine; + + status = STATUS_SUCCESS; + +exit: + if (FALSE == NT_SUCCESS(status)) { + if (NULL != fxDprMachine) { + delete fxDprMachine; + } + } + return status; +} + +NTSTATUS +FxPoxInterface::InitializeComponents( + VOID + ) +{ + NTSTATUS status; + PPOX_SETTINGS poxSettings = NULL; + WDFDEVICE fxDevice = NULL; + + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return STATUS_SUCCESS; + } + + // + // We create the device power requirement state machine only if system- + // managed idle timeout is being used. + // + if (NULL == m_DevicePowerRequirementMachine) { + status = CreateDevicePowerRequirementMachine(); + if (FALSE == NT_SUCCESS(status)) { + goto exit; + } + } + + ASSERT(NULL != m_DevicePowerRequirementMachine); + + // + // Register with the power framework + // + status = PoxRegisterDevice(); + + if (FALSE == NT_SUCCESS(status)) { + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p FxPox::PoxRegisterDevice failed. " + "%!STATUS!.", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + status); + goto exit; + } + + // + // At the time of registration, all components are active. When we start the + // power framework's device power management (see below), all components are + // moved to the idle state by default. Take an extra reference on the + // component to prevent this from happening. The power policy state machine + // will evaluate the S0-idle policy later and ask us to drop this reference + // if the policy requires it. + // + PoxActivateComponent(); + + // + // Tell the power framework to start its device power management. This will + // drop a reference on the component, but the component will still remain + // active because of the extra reference we took above. + // + PoxStartDevicePowerManagement(); + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = GetPowerFrameworkSettings(); + + // + // If the driver wanted to receive the POHANDLE, invoke their callback now + // + if ((NULL != poxSettings) && + (NULL != poxSettings->EvtDeviceWdmPostPoFxRegisterDevice)) { + + fxDevice = m_PkgPnp->GetDevice()->GetHandle(); + + status = poxSettings->EvtDeviceWdmPostPoFxRegisterDevice( + fxDevice, + m_PoHandle + ); + if (FALSE == NT_SUCCESS(status)) { + + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p. The client driver has failed the " + "EvtDeviceWdmPostPoFxRegisterDevice callback with %!STATUS!.", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + status); + + // + // Notify the driver that the POHANDLE is about to become invalid + // + if (NULL != poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice) { + poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice( + fxDevice, + m_PoHandle + ); + } + + // + // Unregister with the power framework + // + PoxUnregisterDevice(); + goto exit; + } + } + + // + // Tell the device power requirement state machine that we have registered + // with the power framework + // + m_DevicePowerRequirementMachine->ProcessEvent(DprEventRegisteredWithPox); + +exit: + return status; +} + +VOID +FxPoxInterface::UninitializeComponents( + VOID + ) +{ + PPOX_SETTINGS poxSettings = NULL; + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return; + } + + ASSERT(NULL != m_DevicePowerRequirementMachine); + + // + // If the client driver has specified power framework settings, retrieve + // them. + // + poxSettings = GetPowerFrameworkSettings(); + + // + // Notify the client driver that the POHANDLE is about to become invalid + // + if ((NULL != poxSettings) && + (NULL != poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice)) { + + poxSettings->EvtDeviceWdmPrePoFxUnregisterDevice( + m_PkgPnp->GetDevice()->GetHandle(), + m_PoHandle + ); + } + + // + // Unregister with the power framework + // + PoxUnregisterDevice(); + + // + // Tell the device power requirement state machine that we have unregistered + // with the power framework + // + m_DevicePowerRequirementMachine->ProcessEvent( + DprEventUnregisteredWithPox + ); + return; +} + +VOID +FxPoxInterface::RequestComponentActive( + VOID + ) +{ + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return; + } + + PoxActivateComponent(); + return; +} + +BOOLEAN +FxPoxInterface::DeclareComponentIdle( + VOID + ) +{ + BOOLEAN canPowerDown; + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. We can power down immediately, without + // waiting for device-power-not-required notification. + // + canPowerDown = TRUE; + } else { + // + // System-managed idle timeout + // + PoxIdleComponent(); + + // + // We must wait for device-power-not-required notification before + // powering down. + // + canPowerDown = FALSE; + } + + return canPowerDown; +} + +VOID +FxPoxInterface::UpdateIdleTimeoutHint( + VOID + ) +{ + ULONGLONG idleTimeoutHint; + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return; + } + + if (m_NextIdleTimeoutHint != m_CurrentIdleTimeoutHint) { + m_CurrentIdleTimeoutHint = m_NextIdleTimeoutHint; + + // + // Convert the idle timeout from milliseconds to 100-nanosecond units + // + idleTimeoutHint = ((ULONGLONG) m_CurrentIdleTimeoutHint) * 10 * 1000; + PoxSetDeviceIdleTimeout(idleTimeoutHint); + } + + return; +} + + +NTSTATUS +FxPoxInterface::NotifyDevicePowerDown( + VOID + ) +{ + KIRQL irql; + BOOLEAN canPowerOff; + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. We don't have to take power framework's + // device power requirement into consideration. Just return success. + // + return STATUS_SUCCESS; + } + + // + // Acquire the lock to ensure that device power requirement doesn't change. + // + m_DevicePowerRequiredLock.Acquire(&irql); + if (FALSE == m_DevicePowerRequired) { + // + // Send an event to the device power requirement state machine to tell + // it that we are about to go to Dx. + // + // We send the event inside a lock in order to handle the race condition + // when the power framework notifies us that device power is required at + // the same time that we are about to go to Dx. By sending the event + // inside the lock, we ensure that the DprEventDeviceGoingToDx event is + // always queued to device power requirement state machine before the + // DprEventPoxRequiresPower. + // + // This allows for a clean design in the device power requirement state + // machine by ensuring that it does not have to handle a non-intuitive + // sequence, i.e. DprEventPoxRequiresPower followed by + // DprEventDeviceGoingToDx. This sequence is non-intuitive because it + // doesn't make sense for a device to go to Dx after it has been + // informed that device power is required. Avoiding this non-intuitive + // sequence via locking enables a clean design for the device power + // requirement state machine. + // + m_DevicePowerRequirementMachine->ProcessEvent(DprEventDeviceGoingToDx); + canPowerOff = TRUE; + + } else { + canPowerOff = FALSE; + } + m_DevicePowerRequiredLock.Release(irql); + + return canPowerOff ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; +} + +VOID +FxPoxInterface::DeviceIsPoweredOn( + VOID + ) +{ + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return; + } + + // + // System-managed idle timeout. Notify the device power requirement state + // machine that we are back in D0. + // + m_DevicePowerRequirementMachine->ProcessEvent( + DprEventDeviceReturnedToD0 + ); + return; +} + +PPOX_SETTINGS +FxPoxInterface::GetPowerFrameworkSettings( + VOID + ) +{ + PPOX_SETTINGS poxSettings = NULL; + + if (m_PkgPnp->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.DriverSpecifiedPowerFrameworkSettings()) { + + poxSettings = m_PkgPnp->m_PowerPolicyMachine.m_Owner-> + m_IdleSettings.m_TimeoutMgmt.GetPowerFrameworkSettings(); + + ASSERT(NULL != poxSettings); + } + + return poxSettings; +} + +VOID +FxPoxInterface::DprProcessEventFromPoxCallback( + __in FxDevicePwrRequirementEvents Event + ) +{ + KIRQL irql; + + // + // We should not run the state machine from within a power framework + // callback because we might end up reaching a state where we unregister + // with the power framework. Unregistering from a callback leads to a + // deadlock. Therefore, we raise IRQL before queueing an event to the state + // machine. Raising IRQL causes the event processing to be deferred to a + // worker thread. + // + + // + // This path should only be invoked for kernel mode. For user mode, this + // condition is avoided by reflector guranteeing that it queues a worker + // item to send a Pofx event corresponding to any PoFx callback + // + ASSERT(FX_IS_KERNEL_MODE); + + Mx::MxRaiseIrql(DISPATCH_LEVEL, &irql); + m_DevicePowerRequirementMachine->ProcessEvent(Event); + Mx::MxLowerIrql(irql); +} + +VOID +FxPoxInterface::SimulateDevicePowerRequired( + VOID + ) +{ + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return; + } + + // + // System-managed idle timeout. Notify the device power requirement state + // machine that device power is required. + // + PowerRequiredCallbackWorker(FALSE /* InvokedFromPoxCallback */); + return; +} + +VOID +FxPoxInterface::SimulateDevicePowerNotRequired( + VOID + ) +{ + + if (FALSE == m_PkgPnp->m_PowerPolicyMachine.m_Owner->m_IdleSettings. + m_TimeoutMgmt.UsingSystemManagedIdleTimeout()) { + // + // Driver-managed idle timeout. Nothing to do. + // + return; + } + + // + // System-managed idle timeout. Notify the device power requirement state + // machine that device power is not required. + // + PowerNotRequiredCallbackWorker(FALSE /* InvokedFromPoxCallback */); + return; +} + +VOID +FxPoxInterface::PowerRequiredCallbackWorker( + __in BOOLEAN InvokedFromPoxCallback + ) +{ + KIRQL irql; + + // + // Make a note of the fact that device power is required + // + m_DevicePowerRequiredLock.Acquire(&irql); + m_DevicePowerRequired = TRUE; + m_DevicePowerRequiredLock.Release(irql); + + // + // Send the device-power-required event to the device power requirement + // state machine. + // + if (InvokedFromPoxCallback) { + DprProcessEventFromPoxCallback(DprEventPoxRequiresPower); + } else { + m_DevicePowerRequirementMachine->ProcessEvent(DprEventPoxRequiresPower); + } + return; +} + +VOID +FxPoxInterface::PowerNotRequiredCallbackWorker( + __in BOOLEAN InvokedFromPoxCallback + ) +{ + KIRQL irql; + + // + // Make a note of the fact that device power is not required + // + m_DevicePowerRequiredLock.Acquire(&irql); + m_DevicePowerRequired = FALSE; + m_DevicePowerRequiredLock.Release(irql); + + // + // Send the device-power-not-required event to the device power + // requirement state machine. + // + if (InvokedFromPoxCallback) { + DprProcessEventFromPoxCallback(DprEventPoxDoesNotRequirePower); + } else { + m_DevicePowerRequirementMachine->ProcessEvent( + DprEventPoxDoesNotRequirePower + ); + } + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/selfmanagediostatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/selfmanagediostatemachine.cpp new file mode 100644 index 00000000000..202b2b8ac8c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/selfmanagediostatemachine.cpp @@ -0,0 +1,469 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + SelfManagedIoStateMachine.cpp + +Abstract: + + This module implements the self managed io state machine start / stop logic + in the framework. + +Author: + + + +Environment: + Both kernel and user mode + +Revision History: + + + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "SelfManagedIoStateMachine.tmh" +#endif +} + +// * - We can get a restart from the created state if a PDO is newly enumerated +// but was disabled on a previous enumeration. Treat restart as an init +// in this case. +const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_CreatedStates[] = +{ + { SelfManagedIoEventStart, FxSelfManagedIoInit DEBUGGED_EVENT }, + { SelfManagedIoEventFlush, FxSelfManagedIoCreated DEBUGGED_EVENT }, + { SelfManagedIoEventCleanup, FxSelfManagedIoFinal DEBUGGED_EVENT }, +}; + +const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_InitFailedStates[] = +{ + { SelfManagedIoEventSuspend, FxSelfManagedIoInitFailed DEBUGGED_EVENT }, + { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT }, +}; + +const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StartedStates[] = +{ + { SelfManagedIoEventSuspend, FxSelfManagedIoSuspending DEBUGGED_EVENT }, +}; + +const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_StoppedStates[] = +{ + { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT }, + { SelfManagedIoEventSuspend, FxSelfManagedIoStopped DEBUGGED_EVENT }, + { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT }, +}; + +const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FailedStates[] = +{ + { SelfManagedIoEventFlush, FxSelfManagedIoFlushing DEBUGGED_EVENT }, + { SelfManagedIoEventSuspend, FxSelfManagedIoFailed DEBUGGED_EVENT }, +}; + +const FxSelfManagedIoTargetState FxSelfManagedIoMachine::m_FlushedStates[] = +{ + { SelfManagedIoEventStart, FxSelfManagedIoRestarting DEBUGGED_EVENT }, + { SelfManagedIoEventCleanup, FxSelfManagedIoCleanup DEBUGGED_EVENT }, + { SelfManagedIoEventFlush, FxSelfManagedIoFlushed TRAP_ON_EVENT }, +}; + +const FxSelfManagedIoStateTable FxSelfManagedIoMachine::m_StateTable[] = +{ + // FxSelfManagedIoCreated + { NULL, + FxSelfManagedIoMachine::m_CreatedStates, + ARRAY_SIZE(FxSelfManagedIoMachine::m_CreatedStates), + }, + + // FxSelfManagedIoInit + { FxSelfManagedIoMachine::Init, + NULL, + 0, + }, + + // FxSelfManagedIoInitFailed + { NULL, + FxSelfManagedIoMachine::m_InitFailedStates, + ARRAY_SIZE(FxSelfManagedIoMachine::m_InitFailedStates), + }, + + // FxSelfManagedIoStarted + { NULL, + FxSelfManagedIoMachine::m_StartedStates, + ARRAY_SIZE(FxSelfManagedIoMachine::m_StartedStates), + }, + + // FxSelfManagedIoSuspending + { FxSelfManagedIoMachine::Suspending, + NULL, + 0, + }, + + // FxSelfManagedIoStopped + { NULL, + FxSelfManagedIoMachine::m_StoppedStates, + ARRAY_SIZE(FxSelfManagedIoMachine::m_StoppedStates), + }, + + // FxSelfManagedIoRestarting + { FxSelfManagedIoMachine::Restarting, + NULL, + 0, + }, + + // FxSelfManagedIoFailed + { NULL, + FxSelfManagedIoMachine::m_FailedStates, + ARRAY_SIZE(FxSelfManagedIoMachine::m_FailedStates), + }, + + // FxSelfManagedIoFlushing + { FxSelfManagedIoMachine::Flushing, + NULL, + 0, + }, + + // FxSelfManagedIoFlushed + { NULL, + FxSelfManagedIoMachine::m_FlushedStates, + ARRAY_SIZE(FxSelfManagedIoMachine::m_FlushedStates), + }, + + // FxSelfManagedIoCleanup + { FxSelfManagedIoMachine::Cleanup, + NULL, + 0, + }, + + // FxSelfManagedIoFinal + { NULL, + NULL, + 0, + }, +}; + +FxSelfManagedIoMachine::FxSelfManagedIoMachine( + __in FxPkgPnp* PkgPnp + ) +{ + m_PkgPnp = PkgPnp; + + m_EventHistoryIndex = 0; + m_StateHistoryIndex = 0; + + m_CurrentState = FxSelfManagedIoCreated; + + RtlZeroMemory(&m_Events, sizeof(m_Events)); + RtlZeroMemory(&m_States, sizeof(m_States)); + + // + // Make sure we can fit the state into a byte + // + ASSERT(FxSelfManagedIoMax <= 0xFF); +} + +NTSTATUS +FxSelfManagedIoMachine::_CreateAndInit( + __deref_out FxSelfManagedIoMachine** SelfManagedIoMachine, + __in FxPkgPnp* PkgPnp + ) +{ + NTSTATUS status; + FxSelfManagedIoMachine * selfManagedIoMachine; + + *SelfManagedIoMachine = NULL; + + selfManagedIoMachine = new (PkgPnp->GetDriverGlobals()) FxSelfManagedIoMachine( + PkgPnp + ); + + if (selfManagedIoMachine == NULL) { + DoTraceLevelMessage( + PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Self managed I/O state machine allocation failed for " + "WDFDEVICE 0x%p", + PkgPnp->GetDevice()->GetHandle()); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = selfManagedIoMachine->m_StateMachineLock.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + PkgPnp->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Self managed I/O state machine lock initialization failed for " + "WDFDEVICE 0x%p, %!STATUS!", + PkgPnp->GetDevice()->GetHandle(), + status); + + delete selfManagedIoMachine; + + return status; + } + + *SelfManagedIoMachine = selfManagedIoMachine; + + return status; +} + + +VOID +FxSelfManagedIoMachine::InitializeMachine( + __in PWDF_PNPPOWER_EVENT_CALLBACKS Callbacks + ) +/*++ + +Routine Description: + Sets all the function event callbacks. + +Arguments: + Callbacks - list of callbacks to set + +Return Value: + None + + --*/ +{ + m_DeviceSelfManagedIoCleanup.m_Method = Callbacks->EvtDeviceSelfManagedIoCleanup; + m_DeviceSelfManagedIoFlush.m_Method = Callbacks->EvtDeviceSelfManagedIoFlush; + m_DeviceSelfManagedIoInit.m_Method = Callbacks->EvtDeviceSelfManagedIoInit; + m_DeviceSelfManagedIoSuspend.m_Method = Callbacks->EvtDeviceSelfManagedIoSuspend; + m_DeviceSelfManagedIoRestart.m_Method = Callbacks->EvtDeviceSelfManagedIoRestart; +} + +WDFDEVICE +FxSelfManagedIoMachine::GetDeviceHandle( + VOID + ) +{ + return m_PkgPnp->GetDevice()->GetHandle(); +} + +_Must_inspect_result_ +NTSTATUS +FxSelfManagedIoMachine::ProcessEvent( + __in FxSelfManagedIoEvents Event + ) +/*++ + +Routine Description: + Processes an event and runs it through the state machine. Unlike other + state machines in the framework, this one acquires lock in the event + processing function rather then relying on the caller to do so. + +Arguments: + Event - The event to feed into the state machine. + +Return Value: + result of the event + + --*/ +{ + const FxSelfManagedIoStateTable* entry; + FxSelfManagedIoStates newState; + NTSTATUS status; + + m_StateMachineLock.AcquireLock(m_PkgPnp->GetDriverGlobals()); + + m_Events.History[m_EventHistoryIndex] = (UCHAR) Event; + m_EventHistoryIndex = (m_EventHistoryIndex + 1) % + (sizeof(m_Events.History)/sizeof(m_Events.History[0])); + + entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated]; + newState = FxSelfManagedIoMax; + + for (ULONG i = 0; i < entry->TargetStatesCount; i++) { + if (entry->TargetStates[i].SelfManagedIoEvent == Event) { + DO_EVENT_TRAP(&entry->TargetStates[i]); + newState = entry->TargetStates[i].SelfManagedIoState; + break; + } + } + + if (newState == FxSelfManagedIoMax) { + // + // We always can handle io increment/decrement from any state, but we + // should not be dropping any other events from this state. + // + + COVERAGE_TRAP(); + } + + status = STATUS_SUCCESS; + + while (newState != FxSelfManagedIoMax) { + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p entering self managed io state " + "%!FxSelfManagedIoStates! from %!FxSelfManagedIoStates!", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + newState, m_CurrentState); + + m_States.History[m_StateHistoryIndex] = (UCHAR) newState; + m_StateHistoryIndex = (m_StateHistoryIndex + 1) % + (sizeof(m_States.History)/sizeof(m_States.History[0])); + + m_CurrentState = (BYTE) newState; + entry = &m_StateTable[m_CurrentState-FxSelfManagedIoCreated]; + + if (entry->StateFunc != NULL) { + newState = entry->StateFunc(this, &status); + } + else { + newState = FxSelfManagedIoMax; + } + } + + m_StateMachineLock.ReleaseLock(m_PkgPnp->GetDriverGlobals()); + + return status; +} + +FxSelfManagedIoStates +FxSelfManagedIoMachine::Init( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ) +/*++ + +Routine Description: + Calls the event callback for initializing self managed io. + +Arguments: + This - instance of the state machine + + Status - result of the event callback into the driver + +Return Value: + new machine state + + --*/ +{ + *Status = This->m_DeviceSelfManagedIoInit.Invoke(This->GetDeviceHandle()); + + if (NT_SUCCESS(*Status)) { + return FxSelfManagedIoStarted; + } + else { + return FxSelfManagedIoInitFailed; + } +} + +FxSelfManagedIoStates +FxSelfManagedIoMachine::Suspending( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ) +/*++ + +Routine Description: + Invokes the self managed io suspend event callback. Upon failure goes to + the failed state and awaits teardown of the stack. + +Arguments: + This - instance of the state machine + + Status - result of the event callback into the driver + +Return Value: + new machine state + + --*/ +{ + *Status = This->m_DeviceSelfManagedIoSuspend.Invoke(This->GetDeviceHandle()); + + if (NT_SUCCESS(*Status)) { + return FxSelfManagedIoStopped; + } + else { + return FxSelfManagedIoFailed; + } +} + +FxSelfManagedIoStates +FxSelfManagedIoMachine::Restarting( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ) +/*++ + +Routine Description: + Invokes the self managed io event callback for restarting self managed io + from the stopped state. + +Arguments: + This - instance of the state machine + + Status - result of the event callback into the driver + +Return Value: + new machine state + + --*/ +{ + *Status = This->m_DeviceSelfManagedIoRestart.Invoke(This->GetDeviceHandle()); + + if (NT_SUCCESS(*Status)) { + return FxSelfManagedIoStarted; + } + else { + return FxSelfManagedIoFailed; + } +} + +FxSelfManagedIoStates +FxSelfManagedIoMachine::Flushing( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ) +/*++ + +Routine Description: + Calls the self managed io flush routine. + +Arguments: + This - instance of the state machine + + Status - result of the event callback into the driver + +Return Value: + FxSelfManagedIoFlushed + + --*/ +{ + UNREFERENCED_PARAMETER(Status); + This->m_DeviceSelfManagedIoFlush.Invoke(This->GetDeviceHandle()); + return FxSelfManagedIoFlushed; +} + +FxSelfManagedIoStates +FxSelfManagedIoMachine::Cleanup( + __in FxSelfManagedIoMachine* This, + __out PNTSTATUS Status + ) +/*++ + +Routine Description: + Calls the self managed io cleanup routine. + +Arguments: + This - instance of the state machine + + Status - result of the event callback into the driver + +Return Value: + FxSelfManagedIoFinal + + --*/ +{ + UNREFERENCED_PARAMETER(Status); + + This->m_DeviceSelfManagedIoCleanup.Invoke(This->GetDeviceHandle()); + return FxSelfManagedIoFinal; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/eventqueueum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/eventqueueum.cpp new file mode 100644 index 00000000000..a048af3a709 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/eventqueueum.cpp @@ -0,0 +1,77 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + EventQueueUm.cpp + +Abstract: + + This module implements user mode specific functionality of event queue + + This functionality needed to be separated out since the KM portion takes + a reference on driver object because KM MxWorkItem::_Free does not wait for + callback to return (i.e. rundown synchronously). + + MxWorkItem::_Free in UM currently waits for callback to return (i.e. runs + down synchronously) hence does not need a reference on driver/devstack + object (see comments on top of MxWorkItemUm.h file). + + In future if UM work-item is made similar to km workitem, UMDF may need to + ensure that modules stay loaded, though the mechanism to ensure that would + likely be different from a reference on the driver. It would likely be a + reference on the devicestack object. + +Environment: + + User mode only + +Revision History: + + + + +--*/ + +#include "pnppriv.hpp" + +VOID +FxWorkItemEventQueue::QueueWorkItem( + VOID + ) +{ + // + // In user mode WorkItem::_Free waits for workitem callbacks to return + // So we don't need outstanding reference on driver object or the devstack + // + + m_WorkItem.Enqueue( + (PMX_WORKITEM_ROUTINE) _WorkItemCallback, + (FxEventQueue*) this); +} + +VOID +FxWorkItemEventQueue::_WorkItemCallback( + __in MdDeviceObject DeviceObject, + __in PVOID Context + ) +/*++ + +Routine Description: + This is the work item that attempts to run the machine on a thread + separate from the one the caller was using. It implements step 9 above. + +--*/ +{ + FxWorkItemEventQueue* This = (FxWorkItemEventQueue*) Context; + + UNREFERENCED_PARAMETER(DeviceObject); + + // + // In user mode WorkItem::_Free waits for workitem callbacks to return + // So we don't need outstanding reference on driver object + // + + This->EventQueueWorker(); +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxchildlistum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxchildlistum.cpp new file mode 100644 index 00000000000..ad0a3f1a4e8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxchildlistum.cpp @@ -0,0 +1,601 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxChildListUm.cpp + +Abstract: + + This module implements the FxChildList class + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include + +#pragma warning(push) +#pragma warning(disable:4100) //unreferenced parameter + +FxDeviceDescriptionEntry::FxDeviceDescriptionEntry( + __inout FxChildList* DeviceList, + __in ULONG AddressDescriptionSize, + __in ULONG IdentificationDescriptionSize + ) +{ + UfxVerifierTrapNotImpl(); +} + +FxDeviceDescriptionEntry::~FxDeviceDescriptionEntry() +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +PVOID +FxDeviceDescriptionEntry::operator new( + __in size_t AllocatorBlock, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t TotalDescriptionSize + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +VOID +FxDeviceDescriptionEntry::DeviceSurpriseRemoved( + VOID + ) +{ + UfxVerifierTrapNotImpl(); +} + +BOOLEAN +FxDeviceDescriptionEntry::IsDeviceReportedMissing( + VOID + ) +/*++ + +Routine Description: + This function tells the caller if the description has been reported missing + to the Pnp manager. It does not change the actual state of the description, + unlike IsDeviceRemoved(). + +Arguments: + None + +Return Value: + TRUE if it has been reported missing, FALSE otherwise + + --*/ +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +BOOLEAN +FxDeviceDescriptionEntry::IsDeviceRemoved( + VOID + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +VOID +FxDeviceDescriptionEntry::ProcessDeviceRemoved( + VOID + ) +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +FxDeviceDescriptionEntry* +FxDeviceDescriptionEntry::Clone( + __inout PLIST_ENTRY FreeListHead + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +FxChildList::FxChildList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t TotalDescriptionSize, + __in CfxDevice* Device, + __in BOOLEAN Static + ) : + FxNonPagedObject(FX_TYPE_CHILD_LIST,sizeof(FxChildList), FxDriverGlobals), + m_TotalDescriptionSize(TotalDescriptionSize), + m_EvtCreateDevice(FxDriverGlobals), + m_EvtScanForChildren(FxDriverGlobals) +{ + UfxVerifierTrapNotImpl(); +} + +BOOLEAN +FxChildList::Dispose( + VOID + ) +{ + UfxVerifierTrapNotImpl(); + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::_CreateAndInit( + __out FxChildList** ChildList, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES ListAttributes, + __in size_t TotalDescriptionSize, + __in CfxDevice* Device, + __in PWDF_CHILD_LIST_CONFIG ListConfig, + __in BOOLEAN Static + ) +{ + UfxVerifierTrapNotImpl(); + + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxChildList::Initialize( + __in PWDF_CHILD_LIST_CONFIG Config + ) +{ + UfxVerifierTrapNotImpl(); +} + +WDFDEVICE +FxChildList::GetDevice( + VOID + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +CfxDevice* +FxChildList::GetDeviceFromId( + __in PWDF_CHILD_RETRIEVE_INFO Info + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::GetAddressDescription( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxChildList::GetAddressDescriptionFromEntry( + __in FxDeviceDescriptionEntry* Entry, + __out PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::BeginScan( + __out_opt PULONG ScanTag + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::EndScan( + __inout_opt PULONG ScanTag + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::CancelScan( + __in BOOLEAN EndTheScan, + __inout_opt PULONG ScanTag + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::InitIterator( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::BeginIteration( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::EndIteration( + __inout PWDF_CHILD_LIST_ITERATOR Iterator + ) +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::GetNextDevice( + __out WDFDEVICE* Device, + __inout PWDF_CHILD_LIST_ITERATOR Iterator, + __inout_opt PWDF_CHILD_RETRIEVE_INFO Info + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +WDFDEVICE +FxChildList::GetNextStaticDevice( + __in WDFDEVICE PreviousDevice, + __in ULONG Flags + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::UpdateAsMissing( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Description + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::UpdateDeviceAsMissing( + __in CfxDevice* Device + ) +/*++ + +Routine Description: + Same as UpdateAsMissing except instead of a device description, we have the + device itself. + +Arguments: + Device - the device to mark as missing + +Return Value: + NTSTATUS + + --*/ +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +BOOLEAN +FxChildList::ReenumerateEntryLocked( + __inout FxDeviceDescriptionEntry* Entry, + __in BOOLEAN FromQDR + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +VOID +FxChildList::ReenumerateEntry( + __inout FxDeviceDescriptionEntry* Entry + ) +{ + UfxVerifierTrapNotImpl(); +} + + +VOID +FxChildList::UpdateAllAsPresent( + __in_opt PULONG ScanTag + ) +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::Add( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER IdentificationDescription, + __in_opt PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription, + __in_opt PULONG ScanTag + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxChildList::UpdateAddressDescriptionFromEntry( + __inout FxDeviceDescriptionEntry* Entry, + __in PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER AddressDescription + ) +{ + UfxVerifierTrapNotImpl(); +} + +BOOLEAN +FxChildList::CloneEntryLocked( + __inout PLIST_ENTRY FreeListHead, + __inout FxDeviceDescriptionEntry* Entry, + __in BOOLEAN FromQDR + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +VOID +FxChildList::ProcessModificationsLocked( + __inout PLIST_ENTRY FreeListHead + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::MarkDescriptionNotPresentWorker( + __inout FxDeviceDescriptionEntry* DescriptionEntry, + __in BOOLEAN ModificationCanBeQueued + ) +/*++ + +Routine Description: + + This worker function marks the passed in mod or desc entry in the device + list "not present". The change is enqueued in the mod list but the mod + list is not drained. + +Arguments: + + DescEntry - Matching description entry, if found. + + ModificationCanBeQueued - whether the caller allows for their to be a + modification already queued on the modification list + +Assumes: + DescriptionEntry->IsPresent() == TRUE + +Return Value: + None + +--*/ +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::MarkModificationNotPresentWorker( + __inout PLIST_ENTRY FreeListHead, + __inout FxDeviceDescriptionEntry* ModificationEntry + ) +/*++ + +Routine Description: + + This worker function marks the passed in mod or desc entry in the device + list "not present". The change is enqueued in the mod list but the mod + list is not drained. + +Arguments: + + ModEntry - Matching modification entry, if found. If this parameter is + supplied, DescEntry should be NULL. + +Return Value: + The caller may not necessarily be interested in the transition from reported + as present and not yet created to reported as missing...as such, many + callers of this function will not inspect this return value. + +--*/ +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::DrainFreeListHead( + __inout PLIST_ENTRY FreeListHead + ) +{ + UfxVerifierTrapNotImpl(); +} + +FxDeviceDescriptionEntry* +FxChildList::SearchBackwardsForMatchingModificationLocked( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +FxDeviceDescriptionEntry* +FxChildList::SearchBackwardsForMatchingDescriptionLocked( + __in PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER Id + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::VerifyDescriptionEntry( + __in PLIST_ENTRY Entry + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::VerifyModificationEntry( + __in PLIST_ENTRY Entry + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +BOOLEAN +FxChildList::CreateDevice( + __inout FxDeviceDescriptionEntry* Entry, + __inout PBOOLEAN InvalidateRelations + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::ProcessBusRelations( + __inout PDEVICE_RELATIONS *DeviceRelations + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxChildList::InvokeReportedMissingCallback( + VOID + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::PostParentToD0( + VOID + ) +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::IndicateWakeStatus( + __in NTSTATUS WaitWakeStatus + ) +/*++ + +Routine Description: + Propagates the wait wake status to all the child PDOs. This will cause any + pended wait wake requests to be completed with the given wait wake status. + +Arguments: + WaitWakeStatus - The NTSTATUS value to use for compeleting any pended wait + wake requests on the child PDOs. + +Return Value: + None + + --*/ +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::NotifyDeviceSurpriseRemove( + VOID + ) +/*++ + +Routine Description: + Notification through IFxStateChangeNotification that the parent device is + being surprise removed + +Arguments: + None + +Return Value: + None + + --*/ +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxChildList::NotifyDeviceRemove( + __inout PLONG ChildCount + ) +/*++ + +Routine Description: + Notification through IFxStateChangeNotification that the parent device is + being removed. + +Arguments: + None + +Return Value: + None + + --*/ +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::_ValidateConfig( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_CHILD_LIST_CONFIG Config, + __in size_t* TotalDescriptionSize + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxChildList::_ComputeTotalDescriptionSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_CHILD_LIST_CONFIG Config, + __in size_t* TotalDescriptionSize + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +#pragma warning(pop) diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxinterruptthreadpoolum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxinterruptthreadpoolum.cpp new file mode 100644 index 00000000000..de0194035fd --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxinterruptthreadpoolum.cpp @@ -0,0 +1,400 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxInterruptThreadpoolUm.cpp + +Abstract: + + Threadpool functions for interrupt handling + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "fxmin.hpp" +#include "FxInterruptThreadpoolUm.hpp" + +extern "C" { +#include "FxInterruptThreadpoolUm.tmh" +} + +#define STRSAFE_LIB +#include + +FxInterruptThreadpool::FxInterruptThreadpool( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxGlobalsStump(FxDriverGlobals), + m_Pool(NULL), + m_MinimumThreadCount(MINIMUM_THREAD_COUNT_DEFAULT) +{ + InitializeThreadpoolEnvironment(&m_CallbackEnvironment); +} + +FxInterruptThreadpool::~FxInterruptThreadpool() +{ + // + // close pool + // + if (m_Pool != NULL) { + CloseThreadpool(m_Pool); + m_Pool = NULL; + } + + DestroyThreadpoolEnvironment(&m_CallbackEnvironment); +} + +HRESULT +FxInterruptThreadpool::_CreateAndInit( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _Out_ FxInterruptThreadpool** ppThreadpool + ) +{ + HRESULT hr; + FxInterruptThreadpool* pool = NULL; + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(ppThreadpool), + DriverGlobals->Public.DriverName); + + *ppThreadpool = NULL; + + pool = new (DriverGlobals) FxInterruptThreadpool(DriverGlobals); + if (pool == NULL) + { + hr = ERROR_NOT_ENOUGH_MEMORY; + DoTraceLevelMessage(DriverGlobals, + TRACE_LEVEL_ERROR, TRACINGPNP, + "FxInterruptThreadpool creation failed, " + "%!hresult!", hr); + return hr; + } + + hr = pool->Initialize(); + + if (SUCCEEDED(hr)) + { + *ppThreadpool = pool; + } + else { + delete pool; + } + + return hr; +} + +HRESULT +FxInterruptThreadpool::Initialize( + ) +{ + HRESULT hr = S_OK; + DWORD error; + BOOL bRet; + + // + // Create a thread pool using win32 APIs + // + m_Pool = CreateThreadpool(NULL); + if (m_Pool == NULL) + { + error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Threadpool creation failed, %!winerr!", error); + return hr; + } + + // + // Set maximum thread count to equal the total number of interrupts. + // Set minimum thread count (persistent threads) to equal the lower of + // number of interrupt and number of processors. + // + // We want minimum number of persistent threads to be at least equal to the + // number of interrupt objects so that there is no delay in servicing the + // interrupt if there are processors available (the delay can come due to + // thread pool delay in allocating and initializing a new thread). However, + // there is not much benefit in having more persistent threads than + // processors, as threads would have to wait for processor to become + // available anyways. Therefore, we chose to have the number of persistent + // equal to the Min(number of interrupts, number of processors). + // + // In the current design, if there are more interrupts than + // processors, as soon as one thread finishes servicing the interrupt, both + // the thread and processor will be available to service the next queued + // interrupt. Note that thread pool will queue all the waits and will + // satisfy them in a FIFO manner. + // + // Since we don't know the number of interrupts in the beginning, we will + // start with one and update it when we know the actual number of interrupts + // after processing driver's OnPrepareHardware callback. + // + // Note on interrupt servicing: + // When fx connects the interrupt, it queues an event-based wait block + // to thread pool for each interrupt, so that the interrupt can get serviced + // using one of the thread pool threads when the auto-reset event shared + // with reflector is set by reflector in the DpcForIsr routine queued by Isr. + // While the interrupt is being serviced by one of the threads, no wait block + // is queued to thread pool for that interrupt, so arrival of same interrupt + // signals the event in DpcForIsr but doesn't cause new threads to pick up + // the servicing. Note that other interrupts still have their wait blocks + // queued so they will be serviced as they arrive. + // + // When previous servicing is over (i.e. the ISR callback has been + // invoked and it has returned), Fx queues another wait block to thread pool + // for that interrupt. If the event is already signalled, it would result in + // the same thread (or another) picking up servicing immediately. + // + // This means the interrupt ISR routine can never run concurrently + // for same interrupt. Therefore, there is no need to have more than one + // thread for each interrupt. + // + SetThreadpoolThreadMaximum(m_Pool, 1); + + // + // Create one persistent thread since atleast one interrupt is the most + // likely scenario. We will update this number to have either the same + // number of threads as there are interrupts, or the number of + // processors on the machine. + // + bRet = SetThreadpoolThreadMinimum(m_Pool, m_MinimumThreadCount); + if (bRet == FALSE) { + error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "%!FUNC!: Failed to set minimum threads (%d) in threadpool," + " %!winerr!", m_MinimumThreadCount, error); + goto cleanup; + } + + // + // Associate thread pool with callback environment. + // + SetThreadpoolCallbackPool(&m_CallbackEnvironment, m_Pool); + +cleanup: + + if (FAILED(hr)) { + CloseThreadpool(m_Pool); + m_Pool = NULL; + } + + return hr; +} + +HRESULT +FxInterruptThreadpool::UpdateThreadPoolThreadLimits( + _In_ ULONG InterruptCount + ) +{ + BOOL bRet; + HRESULT hr = S_OK; + SYSTEM_INFO sysInfo; + ULONG minThreadCount = 0; + ULONG procs; + DWORD error; + + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(m_Pool)); + + // + // if there are more than one interrupts then we need to update minimum + // thread count. + // + if (m_MinimumThreadCount >= InterruptCount) { + // + // nothing to do + // + return S_OK; + } + + // + // We want to have number of minimum persistent threads + // = Min(number of interrupts, number of processors). + // See comments in Initialize routine for details. + // + GetSystemInfo(&sysInfo); + procs = sysInfo.dwNumberOfProcessors; + + minThreadCount = min(InterruptCount, procs); + + if (m_MinimumThreadCount < minThreadCount) { + // + // Set threadpool min + // + bRet = SetThreadpoolThreadMinimum(m_Pool, minThreadCount); + if (bRet == FALSE) { + error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to set minimum threads in threadpool," + " TP_POOL 0x%p to %d %!winerr!", m_Pool, minThreadCount, + error); + return hr; + } + + m_MinimumThreadCount = minThreadCount; + } + + // + // set thread pool max to max number of interrupts + // + SetThreadpoolThreadMaximum(m_Pool, InterruptCount); + + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Threads in thread pool TP_POOL 0x%p updated" + " to Max %d Min %d threads", m_Pool, + InterruptCount, minThreadCount); + + return hr; +} + +FxInterruptWaitblock::~FxInterruptWaitblock( + VOID + ) +{ + // + // close the thread pool wait structure + // + if (m_Wait) { + // + // Make sure no event is registered. + // + ClearThreadpoolWait(); + + // + // Wait for all the callbacks to finish. + // + WaitForOutstandingCallbackToComplete(); + + // + // close the wait + // + CloseThreadpoolWait(); + + m_Wait = NULL; + } + + // + // close event handle + // + if (m_Event) { + CloseHandle(m_Event); + m_Event = NULL; + } +} + +HRESULT +FxInterruptWaitblock::_CreateAndInit( + _In_ FxInterruptThreadpool* Threadpool, + _In_ FxInterrupt* Interrupt, + _In_ PTP_WAIT_CALLBACK WaitCallback, + _Out_ FxInterruptWaitblock** Waitblock + ) +{ + HRESULT hr = S_OK; + FxInterruptWaitblock* waitblock = NULL; + PFX_DRIVER_GLOBALS driverGlobals; + + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(Waitblock)); + *Waitblock = NULL; + driverGlobals = Interrupt->GetDriverGlobals(); + + // + // create an instance of interrupt wait block + // + waitblock = new (driverGlobals) FxInterruptWaitblock(driverGlobals); + if (waitblock == NULL) { + hr = E_OUTOFMEMORY; + DoTraceLevelMessage(driverGlobals, + TRACE_LEVEL_ERROR, TRACINGPNP, + "Waitblock creation failed %!hresult!", hr); + goto exit; + } + + hr = waitblock->Initialize(Threadpool, + Interrupt, + WaitCallback); + if (SUCCEEDED(hr)) { + *Waitblock = waitblock; + } + else { + DoTraceLevelMessage(driverGlobals, + TRACE_LEVEL_ERROR, TRACINGPNP, + "Waitblock init failed %!hresult!", hr); + } + +exit: + + if(FAILED(hr) && waitblock != NULL) { + delete waitblock; + } + + return hr; +} + +HRESULT +FxInterruptWaitblock::Initialize( + __in FxInterruptThreadpool* Threadpool, + __in FxInterrupt* Interrupt, + __in PTP_WAIT_CALLBACK WaitCallback + ) +{ + HRESULT hr = S_OK; + DWORD error; + + // + // create a per-interrupt auto-reset event, non-signalled to begin with. + // + m_Event = CreateEvent( + NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes, + FALSE, // BOOL bManualReset, + FALSE, // BOOL bInitialState, + NULL // LPCTSTR lpName + ); + + if (m_Event == NULL) { + error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Event creation failed for FxInterrupt object" + " %!winerr!", error); + goto exit; + } + + // + // create a per-interrupt thread pool wait structure. This wait structure is + // needed to associate an event-based wait callback with threadpool. + // + m_Wait = Threadpool->CreateThreadpoolWait(WaitCallback, + Interrupt); + if (m_Wait == NULL) { + error = GetLastError(); + hr = HRESULT_FROM_WIN32(error); + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Event creation failed for FxInterrupt object" + " %!winerr!", error); + goto exit; + } + +exit: + + return hr; +} + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgfdoum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgfdoum.cpp new file mode 100644 index 00000000000..d5ec1e54e9e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgfdoum.cpp @@ -0,0 +1,322 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgFdoUm.cpp + +Abstract: + + This module implements the pnp/power package for the driver + framework. + +Author: + + + + +Environment: + + User mode only + +Revision History: + + + +--*/ + +#include "..\pnppriv.hpp" + +#include +#include + + +#if defined(EVENT_TRACING) +// Tracing support +extern "C" { +#include "FxPkgFdoUm.tmh" +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PnpFilterResourceRequirements( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp FilterResourceRequirements IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + UNREFERENCED_PARAMETER(Irp); + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::PnpQueryCapabilities( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryCapabilities IRP. + +Arguments: + + Device - a pointer to the FxDevice + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + HandleQueryCapabilities(Irp); + + // + // Set a completion routine on the IRP + // + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutine( + _PnpQueryCapabilitiesCompletionRoutine, + this + ); + + // + // Send the IRP down the stack + // + Irp->CallDriver(m_Device->GetAttachedDevice()); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryCapabilitiesCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ) +{ + NTSTATUS status; + FxPkgFdo* pThis; + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pThis = (FxPkgFdo*) Context; + status = irp.GetStatus(); + + // + // Now that the IRP has returned to us, we modify what the bus driver + // set up. + // + if (NT_SUCCESS(status)) { + pThis->HandleQueryCapabilitiesCompletion(&irp); + } + + pThis->CompletePnpRequest(&irp, status); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryPnpDeviceState( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryPnpDeviceState IRP. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + FxPkgFdo* pThis; + + pThis = (FxPkgFdo*) This; + + // + // Set a completion routine on the IRP + // + Irp->CopyCurrentIrpStackLocationToNext(); + Irp->SetCompletionRoutine( + FxPkgFdo::_PnpQueryPnpDeviceStateCompletionRoutine, + pThis + ); + + // + // Send the IRP down the stack + // + Irp->CallDriver(pThis->m_Device->GetAttachedDevice()); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::_PnpQueryPnpDeviceStateCompletionRoutine( + __in MdDeviceObject DeviceObject, + __inout MdIrp Irp, + __inout PVOID Context + ) +{ + NTSTATUS status; + FxPkgFdo* pThis; + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pThis = (FxPkgFdo*) Context; + status = irp.GetStatus(); + + if (status == STATUS_NOT_SUPPORTED) { + // + // Morph into a successful code so that we process the request + // + status = STATUS_SUCCESS; + irp.SetStatus(status); + } + + if (NT_SUCCESS(status)) { + pThis->HandleQueryPnpDeviceStateCompletion(&irp); + } + else { + DoTraceLevelMessage( + pThis->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Lower stack returned error for query pnp device state, %!STATUS!", + status); + } + + // + // Since we already sent the request down the stack, we must complete it + // now. + // + pThis->CompletePnpRequest(&irp, status); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::Initialize( + __in PWDFDEVICE_INIT DeviceInit + ) +/*++ + + + + + + + + + + + +Routine Description: + + After creating a FxPkgFdo, the driver writer will initialize it by passing + a set of driver callbacks that allow the driver writer to customize the + behavior when handling certain IRPs. + + This is the place to do any initialization that might fail. + +Arguments: + + Device - a pointer to the FxDevice + + DispatchTable - a driver supplied table of callbacks + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pGlobals; + NTSTATUS status; + + pGlobals = GetDriverGlobals(); + + status = FxPkgPnp::Initialize(DeviceInit); + if (!NT_SUCCESS(status)) { + return status; + } + + status = AllocateEnumInfo(); + if (!NT_SUCCESS(status)) { + return status; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgFdo::AskParentToRemoveAndReenumerate( + VOID + ) +/*++ + +Routine Description: + This routine asks the PDO to ask its parent bus driver to Surprise-Remove + and re-enumerate the PDO. This will be done only at the point of + catastrophic software failure, and occasionally after catastrophic hardware + failure. + +Arguments: + None + +Return Value: + status + + --*/ +{ + HRESULT hr; + IWudfDeviceStack2* pDevStack = m_Device->GetDeviceStack2(); + + hr = pDevStack->ReenumerateSelf(); + if (SUCCEEDED(hr)) { + return STATUS_SUCCESS; + } + + return STATUS_NOT_SUPPORTED; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgpdoum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgpdoum.cpp new file mode 100644 index 00000000000..69982860a0c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgpdoum.cpp @@ -0,0 +1,144 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxPkgPdoUM.cpp + +Abstract: + + This module implements the Pnp package for Pdo devices. + +Author: + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" +#include + +// Tracing support +#if defined(EVENT_TRACING) +extern "C" { +#include "FxPkgPdoUM.tmh" +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryResources( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->PnpQueryResources(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PnpQueryResources( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryResources IRP. We return + the resources that the device is currently consuming. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + UNREFERENCED_PARAMETER(Irp); + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpQueryResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +{ + return ((FxPkgPdo*) This)->PnpQueryResourceRequirements(Irp); +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::PnpQueryResourceRequirements( + __inout FxIrp *Irp + ) + +/*++ + +Routine Description: + + This method is invoked in response to a Pnp QueryResourceRequirements IRP. + We return the set (of sets) of possible resources that we could accept + which would allow our device to work. + +Arguments: + + Irp - a pointer to the FxIrp + +Returns: + + NTSTATUS + +--*/ + +{ + UNREFERENCED_PARAMETER(Irp); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPdo::_PnpFilterResourceRequirements( + __inout FxPkgPnp* This, + __inout FxIrp *Irp + ) +/*++ + +Routine Description: + Filter resource requirements for the PDO. A chance to further muck with + the resources assigned to the device. + +Arguments: + This - the package + + Irp - the request + +Return Value: + NTSTATUS + + --*/ +{ + UNREFERENCED_PARAMETER(This); + UNREFERENCED_PARAMETER(Irp); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgpnpum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgpnpum.cpp new file mode 100644 index 00000000000..622d16168bf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxpkgpnpum.cpp @@ -0,0 +1,339 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "..\pnppriv.hpp" + +#include +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxPkgPnpUM.tmh" +#endif +} + +NTSTATUS +FxPkgPnp::FilterResourceRequirements( + __in IO_RESOURCE_REQUIREMENTS_LIST **IoList + ) +{ + UNREFERENCED_PARAMETER(IoList); + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::AllocateDmaEnablerList( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxPkgPnp::AddDmaEnabler( + __in FxDmaEnabler* Enabler + ) +{ + UNREFERENCED_PARAMETER(Enabler); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +FxPkgPnp::RemoveDmaEnabler( + __in FxDmaEnabler* Enabler + ) +{ + UNREFERENCED_PARAMETER(Enabler); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +NTSTATUS +FxPkgPnp::UpdateWmiInstance( + _In_ FxWmiInstanceAction Action, + _In_ BOOLEAN ForS0Idle + ) +{ + HRESULT hr; + NTSTATUS status; + IWudfDeviceStack* devStack; + WmiIdleWakeInstanceUpdate updateType; + + devStack = m_Device->GetDeviceStack(); + + ASSERT(Action != InstanceActionInvalid); + + if (Action == AddInstance) { + updateType = ForS0Idle ? AddS0IdleInstance : AddSxWakeInstance; + } else { + updateType = ForS0Idle ? RemoveS0IdleInstance : RemoveSxWakeInstance; + } + + hr = devStack->UpdateIdleWakeWmiInstance(updateType); + if (S_OK == hr) { + status = STATUS_SUCCESS; + } + else { + PUMDF_VERSION_DATA driverVersion = devStack->GetMinDriverVersion(); + BOOL preserveCompat = + devStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + status = CHostFxUtil::NtStatusFromHr(hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat); + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, + TRACINGPNP, + "failed to send ioctl to update %s WMI instance " + "%!STATUS!", + ForS0Idle ? "S0Idle" : "SxWake", + status); + } + + return status; +} + +NTSTATUS +FxPkgPnp::ReadStateFromRegistry( + _In_ PCUNICODE_STRING ValueName, + _Out_ PULONG Value + ) +{ + DWORD err; + NTSTATUS status; + DWORD data; + DWORD dataSize; + HKEY pwrPolKey = NULL; + IWudfDeviceStack* devStack; + + ASSERT(NULL != Value); + ASSERT(ValueName != NULL && + ValueName->Length != 0 && + ValueName->Buffer != NULL); + + *Value = 0; + devStack = m_Device->GetDeviceStack(); + + err = RegOpenKeyEx(devStack->GetDeviceRegistryKey(), + WUDF_POWER_POLICY_SETTINGS, + 0, + KEY_READ, + &pwrPolKey); + if (ERROR_SUCCESS != err) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, + TRACINGPNP, + "RegOpenKeyEx returned error %d", + err); + goto Clean; + } + + dataSize = sizeof(data); + err = RegQueryValueEx(pwrPolKey, + ValueName->Buffer, + NULL, + NULL, + (BYTE*) &data, + &dataSize); + if (ERROR_SUCCESS != err) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, + TRACINGPNP, + "failed to read registry, " + "RegQueryValueEx returned error %d", + err); + goto Clean; + } + + *Value = data; + err = ERROR_SUCCESS; + +Clean: + if (NULL != pwrPolKey) { + RegCloseKey(pwrPolKey); + } + + if (ERROR_SUCCESS == err) { + status = STATUS_SUCCESS; + } + else { + PUMDF_VERSION_DATA driverVersion = devStack->GetMinDriverVersion(); + BOOL preserveCompat = + devStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + status = CHostFxUtil::NtStatusFromHr(HRESULT_FROM_WIN32(err), + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat); + } + + return status; +} + +VOID +FxPkgPnp::WriteStateToRegistry( + __in HANDLE RegKey, + __in PUNICODE_STRING ValueName, + __in ULONG Value + ) +{ + DWORD err; + HRESULT hr; + HKEY hKey = NULL; + IWudfDeviceStack* devStack; + UMINT::WDF_PROPERTY_STORE_ROOT propertyStore; + + UNREFERENCED_PARAMETER(RegKey); + + ASSERT(ValueName != NULL && + ValueName->Length != 0 && + ValueName->Buffer != NULL); + + devStack = m_Device->GetDeviceStack(); + + propertyStore.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + propertyStore.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; + propertyStore.Qualifier.HardwareKey.ServiceName = WUDF_POWER_POLICY_SETTINGS; + + hr = devStack->CreateRegistryEntry(&propertyStore, + UMINT::WdfPropertyStoreCreateIfMissing, + KEY_QUERY_VALUE | KEY_SET_VALUE, + NULL, + &hKey, + NULL); + if (FAILED(hr)) { + goto Clean; + } + + // + // Failure to save the user's idle/wake settings is not critical and we + // will continue on regardless. Hence we ignore the return value. + // + err = RegSetValueEx(hKey, + ValueName->Buffer, + 0, + REG_DWORD, + (BYTE *) &Value, + sizeof(Value)); + if (err != ERROR_SUCCESS) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, + TRACINGPNP, + "Failed to set Registry value " + "for S0Idle/SxWake error %d", + err); + goto Clean; + } + +Clean: + if (NULL != hKey) { + RegCloseKey(hKey); + } +} + +NTSTATUS +FxPkgPnp::UpdateWmiInstanceForS0Idle( + __in FxWmiInstanceAction Action + ) +{ + NTSTATUS status; + + // + // Send an IOCTL to redirector + // to add/remove S0Idle WMI instance. + // + status = UpdateWmiInstance(Action, TRUE); + + return status; +} + +VOID +FxPkgPnp::ReadRegistryS0Idle( + __in PCUNICODE_STRING ValueName, + __out BOOLEAN *Enabled + ) +{ + NTSTATUS status; + ULONG value; + + status = ReadStateFromRegistry(ValueName, &value); + + // + // Modify value of Enabled only if success + // + if (NT_SUCCESS(status)) { + // + // Normalize the ULONG value into a BOOLEAN + // + *Enabled = (value == FALSE) ? FALSE : TRUE; + } +} + +NTSTATUS +FxPkgPnp::UpdateWmiInstanceForSxWake( + __in FxWmiInstanceAction Action + ) +{ + NTSTATUS status; + + // + // Send an IOCTL to redirector + // to add/remove SxWake WMI instance. + // + status = UpdateWmiInstance(Action, FALSE); + + return status; +} + +VOID +FxPkgPnp::ReadRegistrySxWake( + __in PCUNICODE_STRING ValueName, + __out BOOLEAN *Enabled + ) +{ + NTSTATUS status; + ULONG value; + + status = ReadStateFromRegistry(ValueName, &value); + + // + // Modify value of Enabled only if success + // + if (NT_SUCCESS(status)) { + // + // Normalize the ULONG value into a BOOLEAN + // + *Enabled = (value == FALSE) ? FALSE : TRUE; + } +} + +VOID +PnpPassThroughQIWorker( + __in MxDeviceObject* Device, + __inout FxIrp* Irp, + __inout FxIrp* ForwardIrp + ) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Irp); + UNREFERENCED_PARAMETER(ForwardIrp); + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + + +VOID +FxPkgPnp::RevokeDmaEnablerResources( + __in FxDmaEnabler * /* DmaEnabler */ + ) +{ + // Do nothing +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxqueryinterfaceum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxqueryinterfaceum.cpp new file mode 100644 index 00000000000..215842259ce --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxqueryinterfaceum.cpp @@ -0,0 +1,128 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxQueryInterfaceUm.cpp + +Abstract: + + This module implements the device interface object. + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include + +#pragma warning(push) +#pragma warning(disable:4100) //unreferenced parameter + +FxQueryInterface::FxQueryInterface( + __in CfxDevice* Device, + __in PWDF_QUERY_INTERFACE_CONFIG Config + ) : + m_Device(Device), + m_Interface(NULL) +{ + UfxVerifierTrapNotImpl(); +} + +FxQueryInterface::~FxQueryInterface() +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxQueryInterface::_FormatIrp( + __in PIRP Irp, + __in const GUID* InterfaceGuid, + __out PINTERFACE Interface, + __in USHORT InterfaceSize, + __in USHORT InterfaceVersion, + __in_opt PVOID InterfaceSpecificData + ) +{ + UfxVerifierTrapNotImpl(); +} + +_Must_inspect_result_ +NTSTATUS +FxQueryInterface::_QueryForInterface( + __in PDEVICE_OBJECT TopOfStack, + __in const GUID* InterfaceType, + __out PINTERFACE Interface, + __in USHORT Size, + __in USHORT Version, + __in_opt PVOID InterfaceSpecificData + ) +/*++ + +Routine Description: + Send an IRP_MJPNP/IRP_MN_QUERY_INTERFACE irp to a device object and its + attached stack. + +Arguments: + TargetDevice - device to send the query to. + + InterfaceType - The type of interface to query for + + Interface - The interface to fill out + + Size - Size of Interface in bytes + + Version - Version of the interface to be queried + + InterfaceSpecificData - Addtional interface data to be queried + + +Return Value: + NTSTATUS as indicated by the handler of the QI with in the device stack, + STATUS_NOT_SUPPORTED if the QI is not handled. + + --*/ +{ + UfxVerifierTrapNotImpl(); + + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxQueryInterface::SetEmbedded( + __in PWDF_QUERY_INTERFACE_CONFIG Config, + __in PINTERFACE Interface + ) +/*++ + +Routine Description: + Marks the structure as embedded and sets the configuration. This is used + for FxQueryInterface structs which are embedded in other structures because + at contruction time the Config is not available yet. + + By marking as embedded, FxPkgPnp will not free the structure when it deletes + the query interface chain. + +Arguments: + Config - how the interface behaves + + Interface - the interface that is exported + +Return Value: + None + + --*/ +{ + UfxVerifierTrapNotImpl(); +} + +#pragma warning(pop) diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxrelateddevicelistum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxrelateddevicelistum.cpp new file mode 100644 index 00000000000..c6df7ae4a67 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxrelateddevicelistum.cpp @@ -0,0 +1,86 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxRelatedDeviceListUm.cpp + +Abstract: + This object derives from the transactioned list and provides a unique + object check during the addition of an item. + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include + +_Must_inspect_result_ +NTSTATUS +FxRelatedDeviceList::Add( + __in PFX_DRIVER_GLOBALS /*FxDriverGlobals*/, + __inout FxRelatedDevice* /*Entry*/ + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxRelatedDeviceList::Remove( + __in PFX_DRIVER_GLOBALS /*FxDriverGlobals*/, + __in MdDeviceObject /*Device*/ + ) +{ + UfxVerifierTrapNotImpl(); + return; +} + +_Must_inspect_result_ +FxRelatedDevice* +FxRelatedDeviceList::GetNextEntry( + __in_opt FxRelatedDevice* /*Entry*/ + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxRelatedDeviceList::ProcessAdd( + __in FxTransactionedEntry * /*NewEntry*/ + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +BOOLEAN +FxRelatedDeviceList::Compare( + __in FxTransactionedEntry* /*Entry*/, + __in PVOID /*Data*/ + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +VOID +FxRelatedDeviceList::EntryRemoved( + __in FxTransactionedEntry* /*Entry*/ + ) +{ + UfxVerifierTrapNotImpl(); + return; +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxrelateddeviceum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxrelateddeviceum.cpp new file mode 100644 index 00000000000..df6ee643efd --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxrelateddeviceum.cpp @@ -0,0 +1,49 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRelatedDeviceUm.cpp + +Abstract: + + This module implements the FxRelatedDevice class which is used in usage + notification propagation + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include + +#pragma warning(push) +#pragma warning(disable:4100) //unreferenced parameter + +FxRelatedDevice::FxRelatedDevice( + __in MdDeviceObject DeviceObject, + __in PFX_DRIVER_GLOBALS Globals + ) : FxObject(FX_TYPE_RELATED_DEVICE, 0, Globals), + m_DeviceObject(NULL), + m_State(RelatedDeviceStateNeedsReportPresent) +{ + UfxVerifierTrapNotImpl(); +} + +FxRelatedDevice::~FxRelatedDevice( + VOID + ) +{ + UfxVerifierTrapNotImpl(); +} + +#pragma warning(pop) diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxsystemthreadum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxsystemthreadum.cpp new file mode 100644 index 00000000000..90d0cc4b3c5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxsystemthreadum.cpp @@ -0,0 +1,199 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSystemThreadUm.cpp + +Abstract: + + This is the implementation of the FxSystemThread object. + + +Author: + + + + + +Environment: + + User mode only + +Revision History: + + +--*/ + +#include + +#pragma warning(push) +#pragma warning(disable:4100) //unreferenced parameter + +FxSystemThread::FxSystemThread( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_SYSTEMTHREAD, 0, FxDriverGlobals) +{ + UfxVerifierTrapNotImpl(); +} + +FxSystemThread::~FxSystemThread() +{ + UfxVerifierTrapNotImpl(); +} + +NTSTATUS +FxSystemThread::_CreateAndInit( + __out FxSystemThread** SystemThread, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFDEVICE Device, + __in MdDeviceObject DeviceObject + ) +{ + UfxVerifierTrapNotImpl(); + + return STATUS_NOT_IMPLEMENTED; +} + +// +// Create the system thread in order to be able to service work items +// +// It is recommended this is done from the system process context +// since the threads handle is available to the user mode process +// for a temporary window. XP and later supports OBJ_KERNELHANDLE, but +// DriverFrameworks must support W2K with the same binary. +// +// It is safe to call this at DriverEntry which is in the system process +// to create an initial driver thread, and this driver thread should be +// used for creating any child driver threads on demand. +// +BOOLEAN +FxSystemThread::Initialize() +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +NTSTATUS +FxSystemThread::CreateThread( + VOID + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + + + + + + + + + + + + +// +// This is called to tell the thread to exit. +// +// It must be called from thread context such as +// the driver unload routine since it will wait for the +// thread to exit. +// +BOOLEAN +FxSystemThread::ExitThread() +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +BOOLEAN +FxSystemThread::ExitThreadAsync( + __inout FxSystemThread* Reaper + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +BOOLEAN +FxSystemThread::QueueWorkItem( + __inout PWORK_QUEUE_ITEM WorkItem + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +// +// Attempt to cancel the work item. +// +// Returns TRUE if success. +// +// If returns FALSE, the work item +// routine either has been called, is running, +// or is about to be called. +// +BOOLEAN +FxSystemThread::CancelWorkItem( + __inout PWORK_QUEUE_ITEM WorkItem + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +VOID +FxSystemThread::Thread() +{ + UfxVerifierTrapNotImpl(); +} + + + + + + + + + + + + + +VOID +FxSystemThread::Reaper() +{ + UfxVerifierTrapNotImpl(); +} + +VOID +FxSystemThread::StaticThreadThunk( + __inout PVOID Context + ) +{ + UfxVerifierTrapNotImpl(); +} + + + + + + + + + + + +VOID +FxSystemThread::StaticReaperThunk( + __inout PVOID Context + ) +{ + UfxVerifierTrapNotImpl(); +} + +#pragma warning(pop) diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxwmiirphandlerum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxwmiirphandlerum.cpp new file mode 100644 index 00000000000..dd37db01671 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxwmiirphandlerum.cpp @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiIrpHandlerUm.cpp + +Abstract: + + This module implements the wmi irp handler for the driver frameworks. + +Author: + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "fxmin.hpp" +#include "FxWmiIrpHandler.hpp" + +class FxWmiIrpHandler; + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::PostCreateDeviceInitialize( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + + +VOID +FxWmiIrpHandler::Deregister( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::AddPowerPolicyProviderAndInstance( + __in PWDF_WMI_PROVIDER_CONFIG /* ProviderConfig */, + __in FxWmiInstanceInternalCallbacks* /* InstanceCallbacks */, + __inout FxWmiInstanceInternal** /* Instance */ + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiIrpHandler::Register( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxWmiIrpHandler::Cleanup( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +FxWmiIrpHandler::ResetStateForPdoRestart( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxwmiproviderum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxwmiproviderum.cpp new file mode 100644 index 00000000000..c9ee845d01b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/fxwmiproviderum.cpp @@ -0,0 +1,162 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWmiProviderUm.cpp + +Abstract: + + This module implements the FxWmiProvider object + +Author: + + + + +Environment: + + User mode only + +Revision History: + + +--*/ + +#include +#include +#include +#include +#include +#include + +#pragma warning(push) +#pragma warning(disable:4100) //unreferenced parameter + +FxWmiProvider::FxWmiProvider( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_WMI_PROVIDER_CONFIG Config, + __in CfxDevice* Device + ) : + FxNonPagedObject(FX_TYPE_WMI_PROVIDER, + sizeof(FxWmiProvider), + FxDriverGlobals), + m_FunctionControl(FxDriverGlobals) +{ + UfxVerifierTrapNotImpl(); +} + +FxWmiProvider::~FxWmiProvider() +{ + UfxVerifierTrapNotImpl(); +} + +BOOLEAN +FxWmiProvider::Dispose( + VOID + ) +{ + UfxVerifierTrapNotImpl(); + return FALSE; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::_Create( + __in PFX_DRIVER_GLOBALS CallersGlobals, + __in WDFDEVICE Device, + __in_opt PWDF_OBJECT_ATTRIBUTES ProviderAttributes, + __in PWDF_WMI_PROVIDER_CONFIG WmiProviderConfig, + __out WDFWMIPROVIDER* WmiProvider, + __out FxWmiProvider** Provider + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::AddInstanceLocked( + __in FxWmiInstance* Instance, + __in BOOLEAN NoErrorIfPresent, + __out PBOOLEAN Update, + __in AddInstanceAction Action + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::AddInstance( + __in FxWmiInstance* Instance, + __in BOOLEAN NoErrorIfPresent + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxWmiProvider::RemoveInstance( + __in FxWmiInstance* Instance + ) +{ + UfxVerifierTrapNotImpl(); +} + +ULONG +FxWmiProvider::GetInstanceIndex( + __in FxWmiInstance* Instance + ) +{ + UfxVerifierTrapNotImpl(); + return ((ULONG) -1); +} + +_Must_inspect_result_ +FxWmiInstance* +FxWmiProvider::GetInstanceReferenced( + __in ULONG Index, + __in PVOID Tag + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +_Must_inspect_result_ +FxWmiInstance* +FxWmiProvider::GetInstanceReferencedLocked( + __in ULONG Index, + __in PVOID Tag + ) +{ + UfxVerifierTrapNotImpl(); + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiProvider::FunctionControl( + __in WDF_WMI_PROVIDER_CONTROL Control, + __in BOOLEAN Enable + ) +{ + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +ULONG +FxWmiProvider::GetRegistrationFlagsLocked( + VOID + ) +{ + UfxVerifierTrapNotImpl(); + return ((ULONG) -1); +} + +#pragma warning(pop) diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/interruptobjectum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/interruptobjectum.cpp new file mode 100644 index 00000000000..d620344bd71 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/interruptobjectum.cpp @@ -0,0 +1,804 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + InterruptObjectUm.cpp + +Abstract: + + This module implements a frameworks managed interrupt object + +Author: + +Environment: + + User mode only + +Revision History: + + + +--*/ + +#include "fxmin.hpp" +#include "FxInterruptThreadpoolUm.hpp" + +extern "C" { +#include "InterruptObjectUm.tmh" +} + +#define STRSAFE_LIB +#include + +_Must_inspect_result_ +NTSTATUS +FxInterrupt::InitializeInternal( + __in FxObject* Parent, + __in PWDF_INTERRUPT_CONFIG Configuration + ) +{ + IWudfDeviceStack *deviceStack; + HRESULT hr; + NTSTATUS status = STATUS_SUCCESS; + FxInterruptThreadpool* pool = NULL; + CM_SHARE_DISPOSITION shareVector; + + UNREFERENCED_PARAMETER(Parent); + + deviceStack = m_Device->GetDeviceStack(); + + switch (m_ShareVector) { + case WdfTrue: + // + // Override the bus driver's value, explicitly sharing this interrupt. + // + shareVector = CmResourceShareShared; + break; + + case WdfFalse: + // + // Override the bus driver's value, explicitly claiming this interrupt + // as non-shared. + // + shareVector = CmResourceShareDeviceExclusive; + break; + + case WdfUseDefault: + default: + // + // Leave the bus driver's value alone. + // + shareVector = CmResourceShareUndetermined; + break; + } + + // + // Create a thread pool if not already created. An interrupt is created in + // one of the pnp callbacks (OnAddDevice, OnPrepareHarwdare etc) so there is + // no race in getting and setting the theradpool pointer. + // + pool = m_Device->GetInterruptThreadpool(); + if (pool == NULL) { + hr = FxInterruptThreadpool::_CreateAndInit(GetDriverGlobals(), + &pool); + if (FAILED(hr)) + { + goto exit; + } + + m_Device->SetInterruptThreadpool(pool); + } + + // + // create an instance of interruypt wait block + // + hr = FxInterruptWaitblock::_CreateAndInit(pool, + this, + FxInterrupt::_InterruptThunk, + &m_InterruptWaitblock); + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Waitblock creation failed for CWdfInterrupt object" + " %!hresult!", hr); + goto exit; + } + + // + // Send an IOCTL to redirector to create and initialize an interrupt object + // + deviceStack = m_Device->GetDeviceStack(); + + hr = deviceStack->InitializeInterrupt((WUDF_INTERRUPT_CONTEXT) this, + m_InterruptWaitblock->GetEventHandle(), + shareVector, + &m_RdInterruptContext + ); + + if (SUCCEEDED(hr)) + { + status = STATUS_SUCCESS; + } + else + { + PUMDF_VERSION_DATA driverVersion = deviceStack->GetMinDriverVersion(); + + BOOL preserveCompat = + deviceStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + status = CHostFxUtil::NtStatusFromHr( + hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat + ); + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "failed to initialize interrupt " + "%!STATUS!", status); + + goto exit; + } + +exit: + + // + // Dispose will do cleanup. No need to cleanup here. + // + + return status; +} + +NTSTATUS +FxInterrupt::ConnectInternal( + VOID + ) +{ + HRESULT hr; + NTSTATUS status; + IWudfDeviceStack2 *deviceStack; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + BOOLEAN isRdConnectingOrConnected = FALSE; + + pFxDriverGlobals = GetDriverGlobals(); + deviceStack = m_Device->GetDeviceStack2(); + + // + // reset the interrupt event to non-signaled state to start with a + // clean slate. + // + m_InterruptWaitblock->ResetEvent(); + + // + // Open the queue and enqueue an interrupt event wait to the threadpool + // before connecting the interrupt in the reflector. This minimizes the + // processing delay for interrupts that fire as soon as they are connected, + // like GPIO button devices that have no means to explicitly enable and + // disable interrupts at the hardware level. + // + StartThreadpoolWaitQueue(); + + // + // Tell the PnP Manager to connect the interrupt. Send a message to + // redirector to do so. When ConnectInterrupt returns a failure code, + // we use isRdConnectingOrConnected to check if the failure was due + // to an already connected or currently connecting interrupt. + // + hr = deviceStack->ConnectInterrupt(m_RdInterruptContext, + &isRdConnectingOrConnected); + if (FAILED(hr)) + { + if (isRdConnectingOrConnected) { + // + // The connect call failed because we asked the Reflector to connect + // an already connected or currently connecting interrupt. Perhaps the + // client made a redundant call to WdfInterruptEnable. In this case, + // we want to keep the threadpool active so that we continue to receive + // and acknowledge interrupts - otherwise RdIsrPassiveLevel may time out. + // + DoTraceLevelMessage(pFxDriverGlobals, + TRACE_LEVEL_ERROR, TRACINGPNP, + "Multiple connection attempts for !WDFINTERRUPT 0x%p", + GetHandle()); + + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(2, 19)) { + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Multiple interrupt connection attempts", FALSE), + pFxDriverGlobals->Public.DriverName); + } + } + else { + // + // Connecting the interrupt in the reflector failed, which means + // that IoConnectInterruptEx either failed or was not called at all. + // All we need to do in this case is revert the actions done by + // StartThreadpoolWaitQueue above, which are closing the queue + // and removing the enqueued interrupt event wait. + // + StopAndFlushThreadpoolWaitQueue(); + } + + PUMDF_VERSION_DATA driverVersion = deviceStack->GetMinDriverVersion(); + BOOL preserveCompat = + deviceStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + status = CHostFxUtil::NtStatusFromHr( + hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat + ); + + DoTraceLevelMessage(pFxDriverGlobals, + TRACE_LEVEL_ERROR, TRACINGPNP, + "Connect message to reflector returned failure " + "%!hresult!", hr); + + return status; + } + + status = STATUS_SUCCESS; + + return status; +} + +VOID +FxInterrupt::DisconnectInternal( + VOID + ) +{ + IWudfDeviceStack *deviceStack; + HRESULT hr; + InterruptControlType controlType; + + // + // Tell the PnP Manager to disconnect the interrupt. + // Send a message to redirector to do so. + // + deviceStack = m_Device->GetDeviceStack(); + + controlType = InterruptControlTypeDisconnect; + hr = deviceStack->ControlInterrupt(m_RdInterruptContext, controlType); + if (FAILED(hr)) + { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Disconnect message to reflector returned failure " + "%!hresult!", hr); + + FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("Disconnect message to reflector returned failure. "), + GetDriverGlobals()->Public.DriverName); + } + + // + // Now that interrupt has been disconnected, flush the threadpool. Note that + // we need to do this after disconnect because if we did it before disconnect, + // we might drop any spurious interrupts that were generated after + // the driver disabled interrupt generation in its Disable callback, + // and after the DPCs were flushed. Fx can't drop spurious interrupt + // because if the interrupt is level-triggered then refelctor would be waiting + // for acknowledgement. The fact that disconnect command to reflector has + // returned to fx guarantees that there are no more interrupts pending in + // reflector. + // + StopAndFlushThreadpoolWaitQueue(); + + // + // There might still be WorkItemForIsr running as a result of + // the handling of spurious interrupt by driver, so we need to flush the + // workitem as well. + // + FlushQueuedWorkitem(); + + return; +} + +VOID +FxInterrupt::SetPolicyInternal( + __in WDF_INTERRUPT_POLICY Policy, + __in WDF_INTERRUPT_PRIORITY Priority, + __in PGROUP_AFFINITY TargetProcessorSet + ) +{ + IWudfDeviceStack *deviceStack; + HRESULT hr; + + deviceStack = m_Device->GetDeviceStack(); + + // + // Tell reflector to set the policy of interrupt. + // + hr = deviceStack->SetInterruptPolicy(m_RdInterruptContext, + Policy, + Priority, + TargetProcessorSet); + if (FAILED(hr)) + { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "SetPolicy message to reflector returned failure " + "%!hresult!", hr); + } + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), GetDriverGlobals()->Public.DriverName); + + return; +} + +VOID +FxInterrupt::FilterResourceRequirements( + __inout PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor + ) +/*++ + +Routine Description: + + This function allows an interrupt object to change the + IoResourceRequirementsList that the PnP Manager sends during + IRP_MN_FILTER_RESOURCE_REQUIREMENTS. This function takes a single + IoResourceDescriptor and applies default or user specified policy. + +Arguments: + + IoResourceDescriptor - Pointer to descriptor that matches this interrupt object + +Return Value: + + VOID + +--*/ +{ + UNREFERENCED_PARAMETER(IoResourceDescriptor); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +FxInterrupt::ResetInternal( + VOID + ) +{ + IWudfDeviceStack *deviceStack; + InterruptControlType controlType; + HRESULT hr; + + if (m_RdInterruptContext == NULL) { + // + // Reflector hasn't yet created a partner interrupt object so nothing + // to do. + // + return; + } + + // + // Send a message to redirector to reset interrupt info. + // + deviceStack = m_Device->GetDeviceStack(); + + controlType = InterruptControlTypeResetInterruptInfo; + hr = deviceStack->ControlInterrupt(m_RdInterruptContext, controlType); + if (FAILED(hr)) + { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "ResetInterruptInfo message to reflector returned failure " + "%!hresult!", hr); + } + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), GetDriverGlobals()->Public.DriverName); + + return; +} + +VOID +FxInterrupt::RevokeResourcesInternal( + VOID + ) +{ + IWudfDeviceStack *deviceStack; + InterruptControlType controlType; + HRESULT hr; + + if (m_RdInterruptContext == NULL) { + // + // Reflector hasn't yet created a partner interrupt object so nothing + // to do. + // + return; + } + + // + // Send a message to redirector to revoke interrupt resources. + // + deviceStack = m_Device->GetDeviceStack(); + + controlType = InterruptControlTypeRevokeResources; + hr = deviceStack->ControlInterrupt(m_RdInterruptContext, controlType); + if (FAILED(hr)) + { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "RevokeResources message to reflector returned failure " + "%!hresult!", hr); + } + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), GetDriverGlobals()->Public.DriverName); + + return; +} + +VOID +FxInterrupt::FlushQueuedDpcs( + VOID + ) +{ + IWudfDeviceStack *deviceStack; + HRESULT hr; + + // + // Send a message to redirector to flush DPCs. + // + deviceStack = m_Device->GetDeviceStack(); + hr = deviceStack->ControlInterrupt(m_RdInterruptContext, + InterruptControlTypeFlushQueuedDpcs); + if (FAILED(hr)) + { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "FlushQueuedDpcs message to reflector returned failure " + "%!hresult!", hr); + + FX_VERIFY_WITH_NAME(INTERNAL, + TRAPMSG("FlushQueuedDpcs message to reflector returned failure"), + GetDriverGlobals()->Public.DriverName); + } + + return; +} + +VOID +FxInterrupt::AssignResourcesInternal( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescRaw, + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescTrans, + __in PWDF_INTERRUPT_INFO InterruptInfo + ) +{ + IWudfDeviceStack *deviceStack; + HRESULT hr; + + // + // level-triggered interrupt handling is supported only on win8 and newer. + // + if (IsLevelTriggered(CmDescTrans->Flags) && + FxIsPassiveLevelInterruptSupported() == FALSE) { + hr = E_INVALIDARG; + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to assign interrupt resource to interrupt object" + "because interrupt resource is for level-triggered interrupt" + "which is not supported on this platform. See the docs for info on" + "supported platforms. %!hresult!\n", hr); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), TRAPMSG( + "Failed to assign interrupt resource to interrupt object" + "because interrupt resource is for level-triggered interrupt" + "which is not supported on this platform. See the docs for info on" + "supported platforms."), + GetDriverGlobals()->Public.DriverName); + } + + // + // Sharing is only supported for level-triggered interrupts. We allow + // shared latched interrupts in order to accomodate incorrect device + // firmwares that mistakenly declare their exclusive resources as shared. + // Genuinely shared edge-triggered interrupts will cause a deadlock + // because of how the OS handles non-passive latched interrupts with + // multiple registered handlers. See RdInterrupt::AssignResources + // for details. + // + if (IsLevelTriggered(CmDescTrans->Flags) == FALSE && + CmDescTrans->ShareDisposition != CmResourceShareDeviceExclusive) { + + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_WARNING, TRACINGPNP, + "The resource descriptor indicates that this is a shared " + "edge-triggered interrupt. UMDF only supports sharing of " + "level-triggered interrupts. Please check if your device " + "firmware mistakenly declares this resource as shared " + "instead of device exclusive. If the resource is in fact " + "shared, then UMDF does not support this device.\n"); + } + + // + // Tell the PnP Manager to assign resources to the interrupt. + // Send a message to redirector to do so. + // + deviceStack = m_Device->GetDeviceStack(); + + hr = deviceStack->AssignInterruptResources(m_RdInterruptContext, + CmDescRaw, + CmDescTrans, + InterruptInfo, + m_PassiveHandlingByRedirector); + if (FAILED(hr)) + { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "AssignResources message to reflector returned failure " + "%!hresult!\n", hr); + } + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_HR(hr), + GetDriverGlobals()->Public.DriverName); + +} + +VOID +FxInterrupt::ThreadpoolWaitCallback( + VOID + ) +{ + BOOLEAN claimed; + + // + // ETW event for performance measurement + // + EventWriteEVENT_UMDF_FX_INTERRUPT_NOTIFICATION_RECEIVED( + m_InterruptInfo.MessageNumber + ); + + // + // Invoke the ISR callback under interrupt lock. + // + if (IsWakeCapable()) { + // + // if it is a wake capable interrupt, we will hand it off + // to the state machine so that it can power up the device + // if required and then invoke the ISR callback + // + claimed = WakeInterruptIsr(); + } else { + AcquireLock(); + claimed = m_EvtInterruptIsr(GetHandle(), + m_InterruptInfo.MessageNumber + ); + ReleaseLock(); + } + + // + // Queue another wait. MSDN: You must re-register the event with the + // wait object before signaling it each time to trigger the wait callback. + // + if (m_CanQueue) { + QueueSingleWaitOnInterruptEvent(); + } + + // + // Return acknowledgement to reflector if it's handled at passive level + // by reflector. + // + if (m_PassiveHandlingByRedirector) { + IWudfDeviceStack *deviceStack; + HRESULT hr; + + deviceStack = m_Device->GetDeviceStack(); + + hr = deviceStack->AcknowledgeInterrupt(m_RdInterruptContext, claimed); + + if (FAILED(hr)) { + DoTraceLevelMessage(GetDriverGlobals(), + TRACE_LEVEL_ERROR, TRACINGPNP, + "AcknowledgeInterrupt message to reflector returned " + "failure. Check UMDF log for failure reason. %!hresult!", hr); + + FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("AcknowledgeInterrupt message to " + "reflector returned failure. Check UMDF log for failure reason. "), + GetDriverGlobals()->Public.DriverName); + } + } + + return; +} + +VOID +FxInterrupt::QueueSingleWaitOnInterruptEvent( + VOID + ) +{ + m_InterruptWaitblock->SetThreadpoolWait(); +} + +VOID +FxInterrupt::StartThreadpoolWaitQueue( + VOID + ) +{ + m_CanQueue = TRUE; + + QueueSingleWaitOnInterruptEvent(); +} + +VOID +FxInterrupt::StopAndFlushThreadpoolWaitQueue( + VOID + ) +{ + // + // We need to stop the threadpool wait queue and accomplish the following: + // 1) Prevent any new waits from being queued. + // 2) Removed any waits already queued. + // 3) Wait for interrupt isr callback to complete. + // + + // + // Prevent any more enquing now that interrupt has been disconnected. + // + m_CanQueue = FALSE; + + // + // wait for isr callback + // + m_InterruptWaitblock->WaitForOutstandingCallbackToComplete(); + + // + // remove any waits already queued + // + m_InterruptWaitblock->ClearThreadpoolWait(); + + // + // wait for callback. This additional wait for callback is needed to + // handle the follwoing race: + // - CanQueue is set to false in this thread + // - Callback is executing at statement after CanQueue check so it did not + // see false. + // - this thread waits for callback + // - callback thread queues a wait and returns + // - the wait earlier queued is satisfied and callback runs + // - this thread clears the queue (there is nothing to clear) but there is + // still a callback runnning and this thread needs to wait. + // + m_InterruptWaitblock->WaitForOutstandingCallbackToComplete(); +} + +VOID +CALLBACK +FxInterrupt::_InterruptThunk( + PTP_CALLBACK_INSTANCE Instance, + PVOID Parameter, + PTP_WAIT Wait, + TP_WAIT_RESULT WaitResult + ) +{ + FxInterrupt* fxInterrupt = (FxInterrupt*) Parameter; + + UNREFERENCED_PARAMETER(Instance); + UNREFERENCED_PARAMETER(Wait); + UNREFERENCED_PARAMETER(WaitResult); + + fxInterrupt->ThreadpoolWaitCallback(); + + return; +} + +VOID +FxInterrupt::FlushAndRundownInternal( + VOID + ) +{ + // + // flush the threadpool callbacks + // + StopAndFlushThreadpoolWaitQueue(); + + // + // Rundown the workitem. + // + if (m_SystemWorkItem != NULL) { + m_SystemWorkItem->DeleteObject(); + m_SystemWorkItem = NULL; + } + + // + // If present, delete the default passive-lock. + // + if (m_DisposeWaitLock) { + ASSERT(m_WaitLock != NULL); + m_WaitLock->DeleteObject(); + m_WaitLock = NULL; + m_DisposeWaitLock = FALSE; + } + + // + // waitblock destructor will ensure event and waitblock cleanup. + // + if (m_InterruptWaitblock != NULL) { + delete m_InterruptWaitblock; + m_InterruptWaitblock = NULL; + } + + // + // No need to explicitly delete the COM wrapper (CWdfInterrupt). + // The COM wrapper will get deleted in fxInterrupt's destroy callback when + // the object tree reference taken during creation will be released. + // +} + +BOOLEAN +FxInterrupt::QueueDpcForIsr( + VOID + ) +{ + FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("Not implemented"), + GetDriverGlobals()->Public.DriverName); + return FALSE; +} + +VOID +FxInterrupt::WorkItemHandler( + VOID + ) +{ + // + // For UMDF, we allow drivers to call WdfInterruptQueueDpcdForIsr, and + // internally we queue a workitem and invoke EvtInterruptDpc. Only + // one of the callbacks EvtInterruptDpc or EvtInterruptWorkitem is + // allowed. + // + ASSERT(m_EvtInterruptWorkItem != NULL || m_EvtInterruptDpc != NULL); + ASSERT((m_EvtInterruptWorkItem != NULL && m_EvtInterruptDpc != NULL) == FALSE); + + FX_TRACK_DRIVER(GetDriverGlobals()); + + // + // Call the drivers registered WorkItemForIsr event callback + // + if (m_CallbackLock != NULL) { + KIRQL irql = 0; + + m_CallbackLock->Lock(&irql); + if (m_EvtInterruptWorkItem != NULL) { + m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle()); + } + else { + m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle()); + } + m_CallbackLock->Unlock(irql); + } + else { + if (m_EvtInterruptWorkItem != NULL) { + m_EvtInterruptWorkItem(GetHandle(), m_Device->GetHandle()); + } + else { + m_EvtInterruptDpc(GetHandle(), m_Device->GetHandle()); + } + } + + return; +} + +BOOLEAN +_SynchronizeExecution( + __in MdInterrupt Interrupt, + __in MdInterruptSynchronizeRoutine SynchronizeRoutine, + __in PVOID SynchronizeContext + ) +{ + FxInterruptEnableParameters* pParams; + BOOLEAN isPassive; + + UNREFERENCED_PARAMETER(Interrupt); + + pParams = (FxInterruptEnableParameters*) SynchronizeContext; + isPassive = pParams->Interrupt->IsPassiveHandling(); + FX_VERIFY(INTERNAL, CHECK("Must be Passive Interrupt", isPassive)); + + // + // The internal synchronize routine will call the routine under lock + // + return SynchronizeRoutine(SynchronizeContext); +} diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/pnpprivum.hpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/pnpprivum.hpp new file mode 100644 index 00000000000..786a6eb9083 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/pnpprivum.hpp @@ -0,0 +1,14 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef _PNPPRIVUM_H_ +#define _PNPPRIVUM_H_ + +#pragma warning(push) +#pragma warning(disable:4200) // nonstandard extension used : zero-sized array in struct/union +#include +#pragma warning(pop) + +#include + +#endif // _PNPPRIVUM_H_ diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/pnpstatemachineum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/pnpstatemachineum.cpp new file mode 100644 index 00000000000..011c8a131bb --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/pnpstatemachineum.cpp @@ -0,0 +1,178 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PnpStateMachineUm.cpp + +Abstract: + + This module implements the PnP state machine for the driver framework. + This code was split out from FxPkgPnp.cpp. + +Author: + + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PnpStateMachineUM.tmh" +#endif +} + +BOOLEAN +FxPkgPnp::PnpCheckAndIncrementRestartCount( + VOID + ) +/*++ + +Routine Description: + This is a mode-dependent wrapper for PnpIncrementRestartCountLogic, + which determines if this device should ask the bus driver to + reenumerate the device. Please refer to PnpIncrementRestartCountLogic's + comment block for more information. + +Arguments: + None + +Return Value: + TRUE if a restart should be requested. + +--*/ +{ + HRESULT hr; + FxAutoRegKey restart; + FxDevice* device; + IWudfDeviceStack* deviceStack; + UMINT::WDF_PROPERTY_STORE_ROOT propertyStore; + UMINT::WDF_PROPERTY_STORE_DISPOSITION disposition; + + device = GetDevice(); + deviceStack = device->GetDeviceStack(); + + propertyStore.LengthCb = sizeof(UMINT::WDF_PROPERTY_STORE_ROOT); + propertyStore.RootClass = UMINT::WdfPropertyStoreRootClassHardwareKey; + propertyStore.Qualifier.HardwareKey.ServiceName = L"WudfDiagnostics"; + + hr = deviceStack->CreateRegistryEntry(&propertyStore, + UMINT::WdfPropertyStoreCreateVolatile, + KEY_QUERY_VALUE | KEY_SET_VALUE, + L"Restart", + (HKEY*)&restart.m_Key, + &disposition); + if (FAILED(hr)) { + return FALSE; + } + + return PnpIncrementRestartCountLogic(restart.m_Key, + disposition == UMINT::CreatedNewStore); +} + +BOOLEAN +FxPkgPnp::ShouldProcessPnpEventOnDifferentThread( + __in KIRQL CurrentIrql, + __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread + ) +/*++ +Routine Description: + + This function returns whether the PnP state machine should process the + current event on the same thread or on a different one. + + This function has been added to work around a bug in the state machines. + The idle state machine always calls PnpProcessEvent with the idle state + machine lock held. Some events sent by the idle state machine can cause the + Pnp state machine to invoke FxPowerIdleMachine::IoDecrement(). + FxPowerIdleMachine::IoDecrement() will try to acquire the idle state + machine lock, which is already being held, so it will result in a recursive + acquire of the idle state machine lock. + + The above bug only affects UMDF, but not KMDF. In KMDF, the idle state + machine lock is a spinlock. When PnpProcessEvent is called, it is called + with the spinlock held and hence at dispatch level. Note that if called at + a non-passive IRQL, PnpProcessEvent will always queue a work item to + process the event at passive IRQL later. Queuing a work item forces + processing to happen on a different thread and hence we don't attempt to + recursively acquire the spinlock. On the other hand, with UMDF we are + always at passive IRQL and hence we process the event on the same thread + and run into the recursive acquire problem. + + + + + + + + +Arguments: + + CurrentIrql - The current IRQL + + CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of + PnpProcessEvent specified that the event be processed on a different + thread. + +Returns: + TRUE if the PnP state machine should process the event on a different + thread. + + FALSE if the PnP state machine should process the event on the same thread + +--*/ +{ + // + // For UMDF, we ignore the IRQL and just do what the caller of + // PnpProcessEvent wants. + // + UNREFERENCED_PARAMETER(CurrentIrql); + + return CallerSpecifiedProcessingOnDifferentThread; +} + +_Must_inspect_result_ +NTSTATUS +FxPkgPnp::CreatePowerThreadIfNeeded( + VOID + ) +/*++ +Routine description: + If needed, creates a thread for processing power IRPs + +Arguments: + None + +Return value: + An NTSTATUS code indicating success or failure of this function +--*/ +{ + // + // For UMDF, we never need a power thread, so just return success. + // + return STATUS_SUCCESS; +} + +NTSTATUS +FxPkgPnp::PnpPrepareHardwareInternal( + VOID + ) +{ + // + // Update maximum interrupt thread count now that we know how many + // total interrupts we have. + // + return GetDevice()->UpdateInterruptThreadpoolLimits(); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerpolicystatemachineum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerpolicystatemachineum.cpp new file mode 100644 index 00000000000..d5e6ecce8f0 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerpolicystatemachineum.cpp @@ -0,0 +1,213 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerPolicyStateMachineUM.cpp + +Abstract: + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" + +#include "FxUsbIdleInfo.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerPolicyStateMachineUM.tmh" +#endif +} + +VOID +FxPkgPnp::PowerPolicyUpdateSystemWakeSource( + __in FxIrp* Irp + ) +/*++ + +Routine Description: + Gets source of wake if OS supports this. + +Arguments: + Irp + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + UNREFERENCED_PARAMETER(Irp); + + if (m_Device->IsPdo()) { + + pFxDriverGlobals = GetDriverGlobals(); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "For PDOs, FxPkgPnp::PowerPolicyUpdateSystemWakeSource should NOT " + "be a no-op!"); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +BOOLEAN +FxPkgPnp::ShouldProcessPowerPolicyEventOnDifferentThread( + __in KIRQL CurrentIrql, + __in BOOLEAN CallerSpecifiedProcessingOnDifferentThread + ) +/*++ +Routine Description: + + This function returns whether the power policy state machine should process + the current event on the same thread or on a different one. + + This function has been added to work around a bug in the state machines. + The idle state machine always calls PowerPolicyProcessEvent with the idle + state machine lock held. Some events sent by the idle state machine can + cause the power policy state machine to invoke + FxPowerIdleMachine::QueryReturnToIdle(). + FxPowerIdleMachine::QueryReturnToIdle() will try to acquire the idle state + machine lock, which is already being held, so it will result in a recursive + acquire of the idle state machine lock. + + The above bug only affects UMDF, but not KMDF. In KMDF, the idle state + machine lock is a spinlock. When PowerPolicyProcessEvent is called, it is + called with the spinlock held and hence at dispatch level. Note that if + called at a non-passive IRQL, PowerPolicyProcessEvent will always queue a + work item to process the event at passive IRQL later. Queuing a work item + forces processing to happen on a different thread and hence we don't + attempt to recursively acquire the spinlock. On the other hand, with UMDF + we are always at passive IRQL and hence we process the event on the same + thread and run into the recursive acquire problem. + + + + + + + + +Arguments: + + CurrentIrql - The current IRQL + + CallerSpecifiedProcessingOnDifferentThread - Whether or not caller of + PowerPolicyProcessEvent specified that the event be processed on a + different thread. + +Returns: + TRUE if the power policy state machine should process the event on a + different thread. + + FALSE if the power policy state machine should process the event on the + same thread + +--*/ +{ + // + // For UMDF, we ignore the IRQL and just do what the caller of + // PowerPolicyProcessEvent wants. + // + UNREFERENCED_PARAMETER(CurrentIrql); + + return CallerSpecifiedProcessingOnDifferentThread; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbIdleInfo::Initialize( + VOID + ) +{ + HRESULT hr; + NTSTATUS status; + FxDevice* device; + IWudfDeviceStack *devStack; + + device = ((FxPkgPnp*)m_CallbackInfo.IdleContext)->GetDevice(); + devStack = device->GetDeviceStack(); + + hr = devStack->InitializeUsbSS(); + if (S_OK == hr) { + status = STATUS_SUCCESS; + } + else { + PUMDF_VERSION_DATA driverVersion = devStack->GetMinDriverVersion(); + BOOL preserveCompat = + devStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + status = CHostFxUtil::NtStatusFromHr(hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat); + } + + return status; +} + +VOID +FxPkgPnp::PowerPolicySubmitUsbIdleNotification( + VOID + ) +{ + // + // This will be set to TRUE if USBSS completion event gets dropped. + // + m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_EventDropped = FALSE; + + m_Device->GetDeviceStack()->SubmitUsbIdleNotification( + &(m_PowerPolicyMachine.m_Owner->m_UsbIdle->m_CallbackInfo), + _PowerPolicyUsbSelectiveSuspendCompletionRoutine, + this); +} + +VOID +FxPkgPnp::PowerPolicyCancelUsbSS( + VOID + ) +{ + m_Device->GetDeviceStack()->CancelUsbSS(); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +FxUsbIdleInfo::_UsbIdleCallback( + __in PVOID Context + ) +{ + FxPkgPnp* pPkgPnp; + + pPkgPnp = (FxPkgPnp*) Context; + + DoTraceLevelMessage( + pPkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "Entering USB Selective Suspend Idle callback"); + + pPkgPnp->PowerPolicyProcessEvent(PwrPolUsbSelectiveSuspendCallback); +} + + +VOID +FxPowerPolicyMachine::UsbSSCallbackProcessingComplete( + VOID + ) +{ + FxDevice* device = m_PkgPnp->GetDevice(); + + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGPNP, + "USB Selective Suspend Idle callback processing is complete"); + + device->GetDeviceStack()->SignalUsbSSCallbackProcessingComplete(); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerstatemachineum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerstatemachineum.cpp new file mode 100644 index 00000000000..98809bf301c --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/powerstatemachineum.cpp @@ -0,0 +1,103 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + PowerStateMachineUm.cpp + +Abstract: + + This module implements the Power state machine for the driver framework. + This code was split out from FxPkgPnp.cpp. + +Author: + + + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "PowerStateMachineUm.tmh" +#endif +} + +_Must_inspect_result_ +BOOLEAN +FxPkgPnp::PowerDmaPowerUp( + VOID + ) +/*++ + +Routine Description: + Calls FxDmaEnabler::PowerUp on all registered FxDmaEnabler objects. As soon + as a PowerUp call fails, we stop iterating over the list. + +Arguments: + None + +Return Value: + TRUE if PowerUp succeeded on all enablers, FALSE otherwise + + --*/ + +{ + return TRUE; +} + +BOOLEAN +FxPkgPnp::PowerDmaPowerDown( + VOID + ) +/*++ + +Routine Description: + Calls FxDmaEnabler::PowerDown on all registered FxDmaEnabler objects. All + errors are accumulated, all enablers will be PowerDown'ed. + +Arguments: + None + +Return Value: + TRUE if PowerDown succeeded on all enablers, FALSE otherwise + + --*/ +{ + return TRUE; +} + +VOID +FxPkgPnp::_PowerSetSystemWakeSource( + __in FxIrp* Irp + ) +/*++ + +Routine Description: + Set source of wake if OS supports this. + +Arguments: + Irp + +Return Value: + None + + --*/ +{ + UNREFERENCED_PARAMETER(Irp); + + + + + DO_NOTHING(); +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/poxinterfaceum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/poxinterfaceum.cpp new file mode 100644 index 00000000000..65763a58c92 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/poxinterfaceum.cpp @@ -0,0 +1,125 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "..\pnppriv.hpp" + +#include +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "PoxInterfaceUm.tmh" +#endif +} + +VOID +FxPoxInterface::PoxStartDevicePowerManagement( + ) +{ + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxStartDevicePowerManagement(); + + return; +} + +NTSTATUS +FxPoxInterface::PoxRegisterDevice( + ) +{ + HRESULT hr; + + hr = m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxRegisterDevice(); + + if (S_OK == hr) + { + return STATUS_SUCCESS; + } + else + { + PUMDF_VERSION_DATA driverVersion = m_PkgPnp->GetDevice()->GetDeviceStack()->GetMinDriverVersion(); + + return CHostFxUtil::NtStatusFromHr( + hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + m_PkgPnp->GetDevice()->GetDeviceStack()->ShouldPreserveIrpCompletionStatusCompatibility() + ); + } + +} + +VOID +FxPoxInterface::PoxUnregisterDevice( + VOID + ) +{ + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxUnregisterDevice(); + return; +} + +VOID +FxPoxInterface::PoxActivateComponent( + VOID + ) +{ + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxActivateComponent(); + return; +} + +VOID +FxPoxInterface::PoxIdleComponent( + VOID + ) +{ + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxIdleComponent(); + return; +} + +VOID +FxPoxInterface::PoxReportDevicePoweredOn( + VOID + ) +{ + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxReportDevicePoweredOn(); + return; +} + +VOID +FxPoxInterface::PoxSetDeviceIdleTimeout( + __in ULONGLONG IdleTimeout + ) +{ + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxSetDeviceIdleTimeout(IdleTimeout); + return; +} + + +VOID +FxPoxInterface::PowerRequiredCallbackInvoked( + VOID + ) +{ + PowerRequiredCallbackWorker(FALSE /* InvokedFromPoxCallback */); + return; +} + +VOID +FxPoxInterface::PowerNotRequiredCallbackInvoked( + VOID + ) +{ + // + // Notice that it is important that we first acknowledge the callback + // because once we queue an event in the state machine, the state machine + // could end up calling PoFxUnregister from the same thread + // + m_PkgPnp->GetDevice()->GetDeviceStack2()->PoFxCompleteDevicePowerNotRequired(); + + // + // The contract with the reflector is that the reflector guarantees to + // not send this event from the PoFx callback + // + PowerNotRequiredCallbackWorker(FALSE /* InvokedFromPoxCallback */); + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/supportum.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/supportum.cpp new file mode 100644 index 00000000000..a8b8771221d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/um/supportum.cpp @@ -0,0 +1,149 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + supportUM.cpp + +Abstract: + + This module implements the pnp support routines. + +Author: + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "..\pnppriv.hpp" + +VOID +CopyQueryInterfaceToIrpStack( + __in PPOWER_THREAD_INTERFACE PowerThreadInterface, + __in FxIrp* Irp + ) +{ + UNREFERENCED_PARAMETER(PowerThreadInterface); + UNREFERENCED_PARAMETER(Irp); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +_Must_inspect_result_ +NTSTATUS +GetStackCapabilities( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in MxDeviceObject* DeviceInStack, + __in_opt PD3COLD_SUPPORT_INTERFACE D3ColdInterface, + __out PSTACK_DEVICE_CAPABILITIES Capabilities + ) +{ + HRESULT hr; + NTSTATUS status; + MdDeviceObject deviceObject; + IWudfDeviceStack* deviceStack; + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(D3ColdInterface); + + deviceObject = DeviceInStack->GetObject(); + deviceStack = deviceObject->GetDeviceStackInterface(); + + hr = deviceStack->GetStackCapabilities(Capabilities); + + if (S_OK == hr) { + status = STATUS_SUCCESS; + } + else { + PUMDF_VERSION_DATA driverVersion = deviceStack->GetMinDriverVersion(); + BOOL preserveCompat = + deviceStack->ShouldPreserveIrpCompletionStatusCompatibility(); + + status = CHostFxUtil::NtStatusFromHr(hr, + driverVersion->MajorNumber, + driverVersion->MinorNumber, + preserveCompat); + } + + return status; +} + +VOID +SetD3ColdSupport( + __in PFX_DRIVER_GLOBALS DriverGlobals, + __in MxDeviceObject* DeviceInStack, + __in PD3COLD_SUPPORT_INTERFACE D3ColdInterface, + __in BOOLEAN UseD3Cold + ) +{ + MdDeviceObject deviceObject; + IWudfDeviceStack* deviceStack; + + UNREFERENCED_PARAMETER(DriverGlobals); + UNREFERENCED_PARAMETER(D3ColdInterface); + + deviceObject = DeviceInStack->GetObject(); + deviceStack = deviceObject->GetDeviceStackInterface(); + + deviceStack->SetD3ColdSupport(UseD3Cold); +} + +PVOID +GetIoMgrObjectForWorkItemAllocation( + VOID + ) +/*++ +Routine description: + Returns an IO manager object that can be passed in to IoAllocateWorkItem + +Arguments: + None + +Return value: + Pointer to the object that can be passed in to IoAllocateWorkItem +--*/ +{ + // + // In user-mode we don't need an IO manager object for work item allocation + // so we return NULL. + // + return NULL; +} + +BOOLEAN +IdleTimeoutManagement::_SystemManagedIdleTimeoutAvailable( + VOID + ) +{ + + return TRUE; +} + +_Must_inspect_result_ +NTSTATUS +SendDeviceUsageNotification( + __in MxDeviceObject* RelatedDevice, + __inout FxIrp* RelatedIrp, + __in MxWorkItem* Workitem, + __in FxIrp* OriginalIrp, + __in BOOLEAN Revert + ) +{ + UNREFERENCED_PARAMETER(RelatedDevice); + UNREFERENCED_PARAMETER(RelatedIrp); + UNREFERENCED_PARAMETER(Workitem); + UNREFERENCED_PARAMETER(OriginalIrp); + UNREFERENCED_PARAMETER(Revert); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_NOT_IMPLEMENTED; +} + + diff --git a/sdk/lib/drivers/wdf/shared/irphandlers/pnp/wakeinterruptstatemachine.cpp b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/wakeinterruptstatemachine.cpp new file mode 100644 index 00000000000..d387feaecdc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/irphandlers/pnp/wakeinterruptstatemachine.cpp @@ -0,0 +1,524 @@ +/*++ +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + WakeInterrupt.cpp + +Abstract: + + This module implements the wake interrupt logic in the framework. + +--*/ + +#include "pnppriv.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "WakeInterruptStateMachine.tmh" +#endif +} + +const FxWakeInterruptTargetState +FxWakeInterruptMachine::m_FailedStates[] = +{ + {WakeInterruptEventIsr, WakeInterruptFailed DEBUGGED_EVENT} +}; + +const FxWakeInterruptTargetState +FxWakeInterruptMachine::m_D0States[] = +{ + {WakeInterruptEventIsr, WakeInterruptInvokingEvtIsrInD0 DEBUGGED_EVENT}, + {WakeInterruptEventLeavingD0, WakeInterruptDx DEBUGGED_EVENT}, + {WakeInterruptEventLeavingD0NotArmedForWake, WakeInterruptDxNotArmedForWake DEBUGGED_EVENT} +}; + +const FxWakeInterruptTargetState +FxWakeInterruptMachine::m_DxStates[] = +{ + {WakeInterruptEventEnteringD0, WakeInterruptCompletingD0 DEBUGGED_EVENT}, + {WakeInterruptEventIsr, WakeInterruptWaking DEBUGGED_EVENT}, + {WakeInterruptEventD0EntryFailed, WakeInterruptFailed DEBUGGED_EVENT} +}; + +const FxWakeInterruptTargetState +FxWakeInterruptMachine::m_DxNotArmedForWakeStates[] = +{ + { WakeInterruptEventEnteringD0, WakeInterruptCompletingD0 DEBUGGED_EVENT }, + { WakeInterruptEventIsr, WakeInterruptInvokingEvtIsrInDxNotArmedForWake DEBUGGED_EVENT }, + { WakeInterruptEventD0EntryFailed, WakeInterruptFailed DEBUGGED_EVENT } +}; + +const FxWakeInterruptTargetState +FxWakeInterruptMachine::m_WakingStates[] = +{ + {WakeInterruptEventEnteringD0, WakeInterruptInvokingEvtIsrPostWake DEBUGGED_EVENT}, + {WakeInterruptEventD0EntryFailed, WakeInterruptFailed DEBUGGED_EVENT} +}; + + +const FxWakeInterruptStateTable +FxWakeInterruptMachine::m_StateTable[] = +{ + // WakeInterruptFailed + { FxWakeInterruptMachine::Failed, + FxWakeInterruptMachine::m_FailedStates, + ARRAY_SIZE(FxWakeInterruptMachine::m_FailedStates), + }, + + // WakeInterruptD0 + { NULL, + FxWakeInterruptMachine::m_D0States, + ARRAY_SIZE(FxWakeInterruptMachine::m_D0States), + }, + + // WakeInterruptDx + { FxWakeInterruptMachine::Dx, + FxWakeInterruptMachine::m_DxStates, + ARRAY_SIZE(FxWakeInterruptMachine::m_DxStates), + }, + + // WakeInterruptWaking + { FxWakeInterruptMachine::Waking, + FxWakeInterruptMachine::m_WakingStates, + ARRAY_SIZE(FxWakeInterruptMachine::m_WakingStates), + }, + + // WakeInterruptInvokingEvtIsrPostWakeStates + { FxWakeInterruptMachine::InvokingEvtIsrPostWake, + NULL, + 0, + }, + + // WakeInterruptCompletingD0States + { FxWakeInterruptMachine::CompletingD0, + NULL, + 0, + }, + + // WakeInterruptInvokingEvtIsrInD0 + { FxWakeInterruptMachine::InvokingEvtIsrInD0, + NULL, + 0, + }, + + // WakeInterruptDxNotArmedForWake + { FxWakeInterruptMachine::DxNotArmedForWake, + FxWakeInterruptMachine::m_DxNotArmedForWakeStates, + ARRAY_SIZE(FxWakeInterruptMachine::m_DxNotArmedForWakeStates), + }, + + // WakeInterruptInvokingEvtIsrInDxNotArmedForWake + { FxWakeInterruptMachine::InvokingEvtIsrInDxNotArmedForWake, + NULL, + 0, + }, +}; + +FxWakeInterruptMachine::FxWakeInterruptMachine( + __in FxInterrupt * Interrupt + ) : FxThreadedEventQueue(FxWakeInterruptEventQueueDepth) +{ + // + // Make sure we can fit the state into a byte + // + C_ASSERT(WakeInterruptMax <= 0xFF); + + m_CurrentState = WakeInterruptD0; + + RtlZeroMemory(&m_Queue, sizeof(m_Queue)); + RtlZeroMemory(&m_States, sizeof(m_States)); + + // + // Store the initial state in the state history array + // + m_States.History[IncrementHistoryIndex()] = m_CurrentState; + m_Interrupt = Interrupt; +} + +VOID +FxWakeInterruptMachine::ProcessEvent( + __in FxWakeInterruptEvents Event + ) +{ + NTSTATUS status; + KIRQL irql; + LONGLONG timeout = 0; + + // + // Acquire state machine *queue* lock, raising to DISPATCH_LEVEL + // + Lock(&irql); + + if (IsFull()) { + // + // The queue is full. This should never happen. + // + Unlock(irql); + + ASSERTMSG("The wake interrupt state machine queue is full\n", + FALSE); + return; + } + + if (IsClosedLocked()) { + // + // The queue is closed. This should never happen. + // + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p current wake interrupt state" + " %!FxWakeInterruptStates! dropping event " + "%!FxWakeInterruptEvents! because of a closed queue", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + m_CurrentState, + Event); + + Unlock(irql); + + ASSERTMSG( + "The wake interrupt state machine queue is closed\n", + FALSE + ); + return; + } + + // + // Enqueue the event + // + m_Queue[InsertAtTail()] = Event; + + // + // Drop the state machine *queue* lock + // + Unlock(irql); + + // + // Now, if we are running at PASSIVE_LEVEL, attempt to run the state machine + // on this thread. If we can't do that, then queue a work item. + // + if (irql == PASSIVE_LEVEL) { + // + // Try to acquire the state machine lock + // + status = m_StateMachineLock.AcquireLock( + m_PkgPnp->GetDriverGlobals(), + &timeout + ); + if (FxWaitLockInternal::IsLockAcquired(status)) { + FxPostProcessInfo info; + + // + // We now hold the state machine lock. So call the function that + // dispatches the next state. + // + ProcessEventInner(&info); + + // + // The pnp state machine should be the only one deleting the object + // + ASSERT(info.m_DeleteObject == FALSE); + + // + // Release the state machine lock + // + m_StateMachineLock.ReleaseLock( + m_PkgPnp->GetDriverGlobals() + ); + + info.Evaluate(m_PkgPnp); + + return; + } + } + + // + // For one reason or another, we couldn't run the state machine on this + // thread. So queue a work item to do it. + // + QueueToThread(); + return; +} + +VOID +FxWakeInterruptMachine::_ProcessEventInner( + __inout FxPkgPnp* PkgPnp, + __inout FxPostProcessInfo* Info, + __in PVOID WorkerContext + ) +{ + + UNREFERENCED_PARAMETER(PkgPnp); + + FxWakeInterruptMachine * pThis = (FxWakeInterruptMachine *) WorkerContext; + + // + // Take the state machine lock. + // + pThis->m_StateMachineLock.AcquireLock( + pThis->m_PkgPnp->GetDriverGlobals() + ); + + // + // Call the function that will actually run the state machine. + // + pThis->ProcessEventInner(Info); + + // + // We are being called from the work item and m_WorkItemRunning is > 0, so + // we cannot be deleted yet. + // + ASSERT(Info->SomethingToDo() == FALSE); + + // + // Now release the state machine lock + // + pThis->m_StateMachineLock.ReleaseLock( + pThis->m_PkgPnp->GetDriverGlobals() + ); + + return; +} + +VOID +FxWakeInterruptMachine::ProcessEventInner( + __inout FxPostProcessInfo* Info + ) +{ + KIRQL irql; + FxWakeInterruptEvents event; + const FxWakeInterruptStateTable* entry; + FxWakeInterruptStates newState; + + // + // Process as many events as we can + // + for ( ; ; ) { + // + // Acquire state machine *queue* lock + // + Lock(&irql); + + if (IsEmpty()) { + // + // The queue is empty. + // + GetFinishedState(Info); + Unlock(irql); + return; + } + + // + // Get the event from the queue + // + event = m_Queue[GetHead()]; + IncrementHead(); + + // + // Drop the state machine *queue* lock + // + Unlock(irql); + + // + // Get the state table entry for the current state + // + // NOTE: Prefast complains about buffer overflow if (m_CurrentState == + // WakeInterruptMax), but that should never happen because WakeInterruptMax is not a real + // state. We just use it to represent the maximum value in the enum that + // defines the states. + // + __analysis_assume(m_CurrentState < WakeInterruptMax); + entry = &m_StateTable[m_CurrentState - WakeInterruptFailed]; + + // + // Based on the event received, figure out the next state + // + newState = WakeInterruptMax; + for (ULONG i = 0; i < entry->TargetStatesCount; i++) { + if (entry->TargetStates[i].WakeInterruptEvent == event) { + DO_EVENT_TRAP(&entry->TargetStates[i]); + newState = entry->TargetStates[i].WakeInterruptState; + break; + } + } + + if (newState == WakeInterruptMax) { + // + // Unexpected event for this state + // + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, + TRACINGPNP, + "WDFDEVICE 0x%p !devobj 0x%p wake interrupt state " + "%!FxWakeInterruptStates! dropping event " + "%!FxWakeInterruptEvents!", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + m_CurrentState, + event + ); + + COVERAGE_TRAP(); + } + + while (newState != WakeInterruptMax) { + DoTraceLevelMessage( + m_PkgPnp->GetDriverGlobals(), + TRACE_LEVEL_INFORMATION, + TRACINGPNPPOWERSTATES, + "WDFDEVICE 0x%p !devobj 0x%p entering wake interrupt " + "state %!FxWakeInterruptStates! from " + "%!FxWakeInterruptStates!", + m_PkgPnp->GetDevice()->GetHandle(), + m_PkgPnp->GetDevice()->GetDeviceObject(), + newState, + m_CurrentState + ); + + // + // Update the state history array + // + m_States.History[IncrementHistoryIndex()] = (UCHAR) newState; + + // + // Move to the new state + // + m_CurrentState = (BYTE) newState; + entry = &m_StateTable[m_CurrentState-WakeInterruptFailed]; + + // + // Invoke the state entry function (if present) for the new state + // + if (entry->StateFunc != NULL) { + newState = entry->StateFunc(this); + } + else { + newState = WakeInterruptMax; + } + } + } + + return; +} + + +FxWakeInterruptStates +FxWakeInterruptMachine::Waking( + __in FxWakeInterruptMachine* This + ) +{ + This->m_PkgPnp->PowerPolicyProcessEvent(PwrPolWakeInterruptFired); + + return WakeInterruptMax; +} + +FxWakeInterruptStates +FxWakeInterruptMachine::Dx( + __in FxWakeInterruptMachine* This + ) +{ + // + // Flush queued callbacks so that we know that nobody is still trying to + // synchronize against this interrupt. For KMDF this will flush DPCs and + // for UMDF this will send a message to reflector to flush queued DPCs. + // + This->m_Interrupt->FlushQueuedDpcs(); + +#if FX_IS_KERNEL_MODE + // + // Rundown the workitem if present (passive-level interrupt support or KMDF). + // Not needed for UMDF since reflector doesn't use workitem for isr. + // + This->m_Interrupt->FlushQueuedWorkitem(); + +#endif + + This->m_PkgPnp->AckPendingWakeInterruptOperation(FALSE); + + return WakeInterruptMax; +} + +FxWakeInterruptStates +FxWakeInterruptMachine::DxNotArmedForWake( + __in FxWakeInterruptMachine* This + ) +{ + // + // Ask power state machine to process the acknowledgement event + // on a different thread as we could be running the state machine's + // engine in the context of a wake ISR, and the power + // state machine will attempt to disconnect this interrupt when + // it processes the acknowledgement event. + // + This->m_PkgPnp->AckPendingWakeInterruptOperation(TRUE); + + return WakeInterruptMax; +} + + +FxWakeInterruptStates +FxWakeInterruptMachine::InvokingEvtIsrInDxNotArmedForWake( + __in FxWakeInterruptMachine* This + ) +{ + This->m_Interrupt->InvokeWakeInterruptEvtIsr(); + + This->m_IsrEvent.Set(); + + return WakeInterruptDxNotArmedForWake; +} + +FxWakeInterruptStates +FxWakeInterruptMachine::InvokingEvtIsrPostWake( + __in FxWakeInterruptMachine* This + ) +{ + This->m_Interrupt->InvokeWakeInterruptEvtIsr(); + + This->m_IsrEvent.Set(); + + return WakeInterruptCompletingD0; +} + +FxWakeInterruptStates +FxWakeInterruptMachine::CompletingD0( + __in FxWakeInterruptMachine* This + ) +{ + This->m_PkgPnp->AckPendingWakeInterruptOperation(FALSE); + + return WakeInterruptD0; +} + +FxWakeInterruptStates +FxWakeInterruptMachine::InvokingEvtIsrInD0( + __in FxWakeInterruptMachine* This + ) +{ + This->m_Interrupt->InvokeWakeInterruptEvtIsr(); + + This->m_IsrEvent.Set(); + + return WakeInterruptD0; +} + +FxWakeInterruptStates +FxWakeInterruptMachine::Failed( + __in FxWakeInterruptMachine* This + ) +{ + // + // Device failed to power up and we are not invoking the + // client driver's callback. So we cannot claim the + // interrupt + // + This->m_Claimed = FALSE; + + This->m_IsrEvent.Set(); + + return WakeInterruptMax; +} + + diff --git a/sdk/lib/drivers/wdf/shared/object/dbgtrace.cpp b/sdk/lib/drivers/wdf/shared/object/dbgtrace.cpp new file mode 100644 index 00000000000..95bb4849237 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/dbgtrace.cpp @@ -0,0 +1,130 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + DbgTrace.cpp + +Abstract: + + Temporary file to be used until ETW can be used + for UM + +Author: + + + +Revision History: + + + +--*/ + +#include "fxobjectpch.hpp" + +#if FX_CORE_MODE==FX_CORE_USER_MODE +#include "strsafe.h" +#endif + +#if !defined(EVENT_TRACING) + +VOID +__cdecl +DoTraceLevelMessage( + __in PVOID FxDriverGlobals, + __in ULONG DebugPrintLevel, + __in ULONG DebugPrintFlag, + __drv_formatString(FormatMessage) + __in PCSTR DebugMessage, + ... + ) + +/*++ + +Routine Description: + + Print the trace message to debugger. + +Arguments: + + TraceEventsLevel - print level between 0 and 3, with 3 the most verbose + +Return Value: + + None. + + --*/ + { +#if DBG + UNREFERENCED_PARAMETER(FxDriverGlobals); + +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); +#else + HRESULT hr; + hr = StringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + + + if (HRESULT_FACILITY(hr) == FACILITY_WIN32) + { + status = WinErrorToNtStatus(HRESULT_CODE(hr)); + } + else + { + status = SUCCEEDED(hr) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + } +#endif + if(!NT_SUCCESS(status)) { + +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE + DbgPrint ("WDFTrace: RtlStringCbVPrintfA failed 0x%x\n", status); +#else + OutputDebugString("WDFTrace: Unable to expand: "); + OutputDebugString(DebugMessage); +#endif + return; + } + if (DebugPrintLevel <= TRACE_LEVEL_ERROR || + (DebugPrintLevel <= DebugLevel && + ((DebugPrintFlag & DebugFlag) == DebugPrintFlag))) { +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE + DbgPrint("WDFTrace: %s", debugMessageBuffer); +#else + OutputDebugString("WDFTrace: "); + OutputDebugString(DebugMessage); +#endif + } + } + va_end(list); + + return; +#else + UNREFERENCED_PARAMETER(FxDriverGlobals); + UNREFERENCED_PARAMETER(DebugPrintLevel); + UNREFERENCED_PARAMETER(DebugPrintFlag); + UNREFERENCED_PARAMETER(DebugMessage); +#endif +} + +#endif diff --git a/sdk/lib/drivers/wdf/shared/object/fxobject.cpp b/sdk/lib/drivers/wdf/shared/object/fxobject.cpp new file mode 100644 index 00000000000..25348b9b86a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxobject.cpp @@ -0,0 +1,1137 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObject.cpp + +Abstract: + + This module contains the implementation of the base object + +Author: + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + + + + + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxObject.tmh" +#else +ULONG DebugLevel = TRACE_LEVEL_INFORMATION; +ULONG DebugFlag = 0xff; +#endif + +} + +FxObject::FxObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + m_Type(Type), + m_ObjectSize((USHORT) WDF_ALIGN_SIZE_UP(Size, MEMORY_ALLOCATION_ALIGNMENT)), + m_Globals(FxDriverGlobals) +#if FX_CORE_MODE==FX_CORE_USER_MODE +#ifndef INLINE_WRAPPER_ALLOCATION + ,m_COMWrapper(NULL) +#endif +#endif +{ + ASSERT((((ULONG_PTR) this) & FxHandleFlagMask) == 0x0); + + Construct(FALSE); +} + +FxObject::FxObject( + __in WDFTYPE Type, + __in USHORT Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObjectType ObjectType + ) : + m_Type(Type), + m_ObjectSize((USHORT) WDF_ALIGN_SIZE_UP(Size, MEMORY_ALLOCATION_ALIGNMENT)), + m_Globals(FxDriverGlobals) +{ + if (ObjectType != FxObjectTypeEmbedded) { + // + // only for non embedded objects + // + ASSERT((((ULONG_PTR) this) & FxHandleFlagMask) == 0x0); + } + + Construct(ObjectType == FxObjectTypeEmbedded ? TRUE : FALSE); +} + +FxObject::~FxObject() +{ + FxTagTracker *pTagTracker; + + + + + + + + pTagTracker = GetTagTracker(); + + if (pTagTracker != NULL) { + delete pTagTracker; + } + + ASSERT(m_DisposeSingleEntry.Next == NULL); + + // + // We need to ensure there are no leaked child objects, or + // parent associations. + // + // This can occur if someone calls the C++ operator delete, + // or Release() to destroy the object. + // + // This is generally invalid in the framework, though certain + // objects may understand the underlying contract, but must + // make sure there are no left over un-Disposed associations. + // + // Embedded FxObject's also don't have delete called on them, + // and have to manually manage any child associations when + // their parent object disposes by calling PerformEarlyDispose. + // + // They don't have an associated lifetime parent since they + // are embedded. + // + if (m_ParentObject != NULL || + !IsListEmpty(&m_ChildListHead) || !IsListEmpty(&m_ChildEntry)) { + PCSTR pHandleName; + + pHandleName = FxObjectTypeToHandleName(m_Type); + if (pHandleName == NULL) { + pHandleName = "WDFOBJECT"; + } + + ASSERTMSG( + "Object was freed using WdfObjectDereference, not WdfObjectDelete\n", + m_ParentObject == NULL && + IsListEmpty(&m_ChildEntry) && + IsListEmpty(&m_ChildListHead) + ); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_FATAL, TRACINGOBJECT, + "Handle %s %p (raw object %p) was freed using " + "WdfObjectDereference(), not WdfObjectDelete()", + pHandleName, GetObjectHandleUnchecked(), this); + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_OBJECT_ERROR, + (ULONG_PTR) GetObjectHandleUnchecked(), + (ULONG_PTR) this); + } + + // + // This is called when the reference count goes to zero + // + SetObjectStateLocked(FxObjectStateDestroyed); +} + + +VOID +FX_VF_METHOD(FxObject, VerifyConstruct) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ BOOLEAN Embedded + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + PAGED_CODE_LOCKED(); +#endif + + ASSERTMSG( + "this object's type is not listed in FxObjectsInfo\n", + FxVerifyObjectTypeInTable(m_Type)); + + // + // If this is an embedded object, there is no possibility of having + // a debug extension, so do not set FXOBJECT_FLAGS_HAS_DEBUG *ever* + // in this case. + // + if (m_Globals->IsObjectDebugOn() && Embedded == FALSE) { + FxObjectDebugExtension* pExtension; + + m_ObjectFlags |= FXOBJECT_FLAGS_HAS_DEBUG; + + pExtension = GetDebugExtension(); + ASSERT(pExtension->Signature == FxObjectDebugExtensionSignature); + + // + // Assume that zero is an invalid state. + // + WDFCASSERT(FxObjectStateInvalid == 0x0); + RtlZeroMemory(&pExtension->StateHistory[0], + ARRAY_SIZE(pExtension->StateHistory)); + pExtension->StateHistoryIndex = 0; + + // + // Setup the first slot to our new state. + // + pExtension->StateHistory[0] = FxObjectStateCreated; + + AllocateTagTracker(m_Type); + } +} + + +VOID +FxObject::FinalRelease( + VOID + ) +{ + + + + + + + + + + + + + // + // No other access, OK to test flag without grabbing spinlock + // since it can only be set at create. + // + if (ShouldDeferDisposeLocked()) { + // + // If this is a passive level only object, ensure we only destroy + // it from passive level. No need to hold the object lock when + // changing to this state since no other thread can change our + // state. + // + SetObjectStateLocked(FxObjectStateDeferedDestroy); + + // + // Note, we cannot be holding a lock while making this call b/c by + // the time it returns, it could have freed the object and the + // KeReleaseSpinLock call would have touched freed pool. + // + + //FxToObjectItf::FxAddToDriverDisposeList(m_Globals, this); + + + m_Globals->Driver->GetDisposeList()->Add(this); + + } + else { + ProcessDestroy(); + } +} + +_Must_inspect_result_ +NTSTATUS +FxObject::QueryInterface( + __in FxQueryInterfaceParams* Params + ) +{ + NTSTATUS status; + + if (Params->Type == FX_TYPE_OBJECT) { + *Params->Object = this; + status = STATUS_SUCCESS; + } + else { + status = STATUS_NOINTERFACE; + } + + return status; +} + +VOID +FxObject::AllocateTagTracker( + __in WDFTYPE Type + ) +{ + ASSERT(IsDebug()); + + if (m_Globals->DebugExtension != NULL && + m_Globals->DebugExtension->ObjectDebugInfo != NULL && + FxVerifierGetTrackReferences( + m_Globals->DebugExtension->ObjectDebugInfo, + Type)) { + // + // Failure to CreateAndInitialize a tag tracker is no big deal, we just + // don't track references. + // + + (void) FxTagTracker::CreateAndInitialize( + &GetDebugExtension()->TagTracker, + m_Globals, + FxTagTrackerTypeHandle, + FALSE, + this + ); + + // + // For now we overload the requirement of a tag tracker as also tracing + // state changes. + // + m_ObjectFlags |= FXOBJECT_FLAGS_TRACE_STATE; + } +} + +VOID +FxObject::operator delete( + __in PVOID Memory + ) +{ + ASSERT(Memory != NULL); + + + + + + + + + + + + + + FxPoolFree(_GetBase((FxObject*) Memory)); +} + +VOID +FxObject::CallCleanupCallbacks( + VOID + ) +{ + FxContextHeader* pHeader; + WDFOBJECT h; + + // + // Deleted before Commit or it is an internal object + // + if (IsCommitted() == FALSE) { + return; + } + + // + // We only should have an object handle when we have an external object + // + h = GetObjectHandle(); + + for (pHeader = GetContextHeader(); + pHeader != NULL; + pHeader = pHeader->NextHeader) { + if (pHeader->EvtCleanupCallback != NULL) { + pHeader->EvtCleanupCallback(h); + pHeader->EvtCleanupCallback = NULL; + } + } + + m_ObjectFlags &= ~FXOBJECT_FLAGS_HAS_CLEANUP; +} + +VOID +FxObject::ClearEvtCallbacks( + VOID + ) +/*++ + +Routine Description: + + Clears out any assigned callbacks on the object. + +Arguments: + None + +Return Value: + None + + --*/ +{ + FxContextHeader *pHeader; + + for (pHeader = GetContextHeader(); + pHeader != NULL; + pHeader = pHeader->NextHeader) { + + pHeader->EvtDestroyCallback = NULL; + pHeader->EvtCleanupCallback = NULL; + } + + m_ObjectFlags &= ~FXOBJECT_FLAGS_HAS_CLEANUP; +} + +VOID +FxObject::DeleteFromFailedCreate( + VOID + ) +/*++ + +Routine Description: + Clears out any assigned callbacks on the object and then deletes it. Clearing + out the callbacks are necessary so that the driver's callbacks are not called + on a buffer that they didn't initialize. + +Arguments: + None + +Return Value: + None + + --*/ +{ + ClearEvtCallbacks(); + + // + // After this call returns "this" is destroyed is not a valid pointer! + // + DeleteObject(); + + // + // "this" is now freed memory, do not touch it! + // +} + +// +// FxObject Parent/Child Rules: +// +// The FxObject state machine protects state transitions when +// objects are being associated with each other, and races +// that can occur when a child and parent object are being +// deleted at the same time. This provides the backbone of +// assurance on the objects state. +// +// While transiting object states, the following must be taken +// into consideration: +// +// Reference counts: +// +// When an object is created with operator new(), it has a reference count +// of one. +// +// When a DeleteObject is done on it, the reference count is decremented +// after delete processing is done (which can include disposing children), +// and this results in the objects destruction. +// +// When an object is created by operator new() and immediately associated +// with a parent object, its reference count remains one. +// +// When either the DeleteObject() method is invoked, or the parent object +// disposes the child object with ParentDeleteEvent(), eventually the +// object will dereference itself after delete processing is done only +// once. +// +// Even in the face of race conditions, the object state machine ensures that +// only one set of the proper delete conditions occur (dispose children, invoke +// driver and class dispose callbacks, dereference object). +// +// An object is responsible for releasing its own reference count on its +// self when it goes into the FxObjectStateDeletedAndDisposed. +// +// This has been *carefully* designed so that only the original object +// references are required for this automatic lifetime case to avoid +// extra interlocked operations in AddRef and Release frequently. These +// extra interlocked operations can have a big performance impact on +// the WDF main I/O paths, in which object relationship's are being used. +// +// A simpler implementation may try and have the parent add a reference +// to the child, and the child add a reference to the parent, but this +// is a tightly coupled implementation controlled by the object state +// machine. A circular reference pattern is OK for objects that +// do not have a formal designed in relationship that can be expressed +// in the complex tear down contract implemented in the state machine. +// +// SpinLocks: +// +// The m_SpinLock field protects each indivdual objects m_ObjectState +// variable, the list of child objects that it has, and the m_ParentObject +// field. +// +// In addition, if any object associates itself with a parent object, +// it effectively "lends" its m_ChildEntry field to the parent object, +// and these are manipulated and protected by the parent objects m_SpinLock. +// +// Lock Order: +// +// Currently the lock order is Child -> Parent, meaning a child +// can call the AddChildObjectInternal, RemoveChildObjectInternal, methods with +// the child lock held. +// +// The parent object will not invoke any child object ParentDeleteEvent() +// while holding the parents m_SpinLock. +// +// This order allows potential races between child DeleteObject and parent +// Dispose to be resolved without extra reference counts and multiple +// acquires and releases of the spinlocks in the normal cases. +// +// +// AddChildObjectInternal/RemoveChildObjectInternal: +// +// When a child object is added to the parent, the parent can delete +// the child object at any time when the parent object is deleted +// or disposed. +// +// If a call to RemoveChildObjectInternal is made, the caller may not "win" +// the inherent race with a parent object Dispose() occuring. This +// is similar to the WDM IRP cancel race, and is handled in exactly +// the same fashion. +// +// If an object is associated with a parent, and later removal +// is desired, the return status of RemoveChildObjectInternal must be +// tested, and if not success, the caller should not delete the +// child object itself, since the parent is in the process +// of doing so. The caller "lost the Dispose race". +// +// +// m_ParentObject field: +// +// This field is set by the child object after it successfully +// adds a parent object, and clear it when it is disposed by +// the parent, or removes the parent association. +// +// It is protected by the childs m_SpinLock field. +// + + + + + + + +_Must_inspect_result_ +NTSTATUS +FxObject::AssignParentObject( + __in FxObject* ParentObject + ) +/*++ + +Routine Description: + Assign a parent to the current object. The parent can not be the same + object. + +Arguments: + ParentObject - Object to become the parent for this object + +Returns: + +Comments: + + The caller "passes" its initial object reference to us, so we + do not take an additional reference on the object. + + If we are deleted, Dispose() will be invoked on the object, and + its reference will be released. + + This provides automatic deletion of associated child objects if + the object does not keep any extra references. + +--*/ +{ + KIRQL oldIrql; + NTSTATUS status; + + m_SpinLock.Acquire(&oldIrql); + + // + // Can't add a parent if the current object is being deleted + // + if (m_ObjectState != FxObjectStateCreated) { + TraceDroppedEvent(FxObjectDroppedEventAssignParentObject); + m_SpinLock.Release(oldIrql); + return STATUS_DELETE_PENDING; + } + + // + // Current Object can't already have a parent, and can't + // be its own parent. + // + if (m_ParentObject != NULL) { + m_SpinLock.Release(oldIrql); + return STATUS_WDF_PARENT_ALREADY_ASSIGNED; + } + + if (m_ParentObject == this) { + m_SpinLock.Release(oldIrql); + return STATUS_WDF_PARENT_IS_SELF; + } + + // + // We don't allow a parent object to be assigned after + // FxObject::Commit(). + // + ASSERTMSG("Parent object can not be assigned after Commit()\n", !IsCommitted()); + + ASSERT(IsListEmpty(&this->m_ChildEntry)); + + status = ParentObject->AddChildObjectInternal(this); + + if (NT_SUCCESS(status)) { + m_ParentObject = ParentObject; + } + + m_SpinLock.Release(oldIrql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxObject::AddContext( + __in FxContextHeader *Header, + __in PVOID* Context, + __in PWDF_OBJECT_ATTRIBUTES Attributes + ) +{ + FxContextHeader *pCur, **ppLast; + NTSTATUS status; + KIRQL irql; + + status = STATUS_UNSUCCESSFUL; + + pCur = GetContextHeader(); + + // + // This should never happen since all outward facing objects have a + // context header; framework never calls this function on internal + // objects. + // + ASSERT(pCur != NULL); + + // + // Acquire the lock to lock the object's state. A side affect of grabbing + // the lock is that all updaters who want to add a context are serialized. + // All callers who want to find a context do not need to acquire the lock + // becuase they are not going to update the list, just read from it. + // + // Once a context has been added, it will not be removed until the object + // has been deleted. + // + m_SpinLock.Acquire(&irql); + + if (m_ObjectState == FxObjectStateCreated && pCur != NULL) { + // + // Iterate over the list of contexts already on this object and see if + // this type already is attached. + // + for (ppLast = &pCur->NextHeader; + pCur != NULL; + ppLast = &pCur->NextHeader, pCur = pCur->NextHeader) { + + if (pCur->ContextTypeInfo == Header->ContextTypeInfo) { + // + // Dupe found, return error but give the caller the context + // pointer + // + if (Context != NULL) { + *Context = &pCur->Context[0]; + } + + status = STATUS_OBJECT_NAME_EXISTS; + break; + } + } + + if (pCur == NULL) { + // + // By using the interlocked to update, we don't need to use a lock + // when walking the list to find the context. The only reason + // we are holding the object lock is to lock the current state + // (m_ObjectState) of the object. + // + InterlockedExchangePointer((PVOID*) ppLast, Header); + status = STATUS_SUCCESS; + + if (Context != NULL) { + *Context = &Header->Context[0]; + } + + // + // FxContextHeaderInit does not set these callbacks. If this were + // the creation of the object itself, FxObject::Commit would have done + // this assignment. + // + Header->EvtDestroyCallback = Attributes->EvtDestroyCallback; + + if (Attributes->EvtCleanupCallback != NULL) { + Header->EvtCleanupCallback = Attributes->EvtCleanupCallback; + m_ObjectFlags |= FXOBJECT_FLAGS_HAS_CLEANUP; + } + + } + } + else { + // + // Object is being torn down, adding a context is a bad idea because we + // cannot guarantee that the cleanup or destroy routines will be called + // + status = STATUS_DELETE_PENDING; + } + + m_SpinLock.Release(irql); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxObject::AddChildObjectInternal( + __in FxObject* ChildObject + ) + +/*++ + +Routine Description: + Called by an object to be added to this objects child list + +Arguments: + ChildObject - Object to add this this objects child list + +Returns: + NTSTATUS + +Comments: + The caller "passes" its initial object reference to us, so we + do not take an additional reference on the object. + + If we are deleted, Dispose() will be invoked on the object, and + its reference will be released. + + This provides automatic deletion of associated child objects if + the object does not keep any extra references. + +--*/ +{ + KIRQL oldIrql; + + m_SpinLock.Acquire(&oldIrql); + + // + // Can't add child if the current object is being deleted + // + if (m_ObjectState != FxObjectStateCreated) { + TraceDroppedEvent(FxObjectDroppedEventAddChildObjectInternal); + m_SpinLock.Release(oldIrql); + return STATUS_DELETE_PENDING; + } + + // + // ChildObject can't already have a parent, and can't + // be its own parent. + // + ASSERT(ChildObject->m_ParentObject == NULL); + ASSERT(IsListEmpty(&ChildObject->m_ChildEntry)); + ASSERT(ChildObject != this); + + // + // Add to our m_ChildList + // + InsertTailList(&m_ChildListHead, &ChildObject->m_ChildEntry); + + if (ChildObject->GetDeviceBase() == NULL) { + // + // Propagate the device base downward to the child + // + ChildObject->SetDeviceBase(GetDeviceBase()); + } + + m_SpinLock.Release(oldIrql); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxObject::RemoveChildObjectInternal( + __in FxObject* ChildObject + ) +/*++ + +Routine Description: + + Remove a ChildObject from our child associations list. + + The ChildObject must exist in our list if we are not + otherwise disposing or deleting ourselves. + + If we are not disposing, the child is removed from the list + and its reference count is unmodified. + + If we are disposing, a failure is returned so that the caller + does not delete or dereference the child object itself, since + this is similar to a cancel IRP race condition. + +Arguments: + ChildObject - the object to remove this object's list of children + +Returns: + + STATUS_SUCCESS - Child was removed from the list, no parent Dispose() + can occur. + + !STATUS_SUCCESS - Child can not be removed from the list, and is being + Disposed by the parent. The caller must *not* delete + the object itself. + +--*/ + +{ + KIRQL oldIrql; + + m_SpinLock.Acquire(&oldIrql); + + // + // Object is already being deleted, this object will be removed as a child + // by the parents Dispose() + // + if (m_ObjectState != FxObjectStateCreated) { + TraceDroppedEvent(FxObjectDroppedEventRemoveChildObjectInternal); + m_SpinLock.Release(oldIrql); + return STATUS_DELETE_PENDING; + } + + // + // We should be the child object's parent + // + ASSERT(ChildObject->m_ParentObject == this); + + // + // Child should be on our list + // + ASSERT(!IsListEmpty(&ChildObject->m_ChildEntry)); + + // + // We should have entries if someone wants to remove from our list + // + ASSERT(!IsListEmpty(&m_ChildListHead)); + + RemoveEntryList(&ChildObject->m_ChildEntry); + + // + // Mark it removed + // + InitializeListHead(&ChildObject->m_ChildEntry); + + // + // We did not take a reference on the child object when it + // was added to the list, so we do not dereference it + // on the remove call. + // + // Note: We only dereference child objects when we are deleted + // ourselves, not when the child object manually breaks the + // association by calling this method. + // + m_SpinLock.Release(oldIrql); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +FxObject* +FxObject::GetParentObjectReferenced( + __in PVOID Tag + ) + +/*++ + +Routine Description: + Return this objects parent, which could be NULL if + the object is not part of an association, or this or + the parent object is deleting. + + An extra reference is taken on the parent object which + must eventually be released by the caller. + +Arguments: + Tag - Tag to use when referencing the parent + +Returns: + + Parent object, otherwise NULL if no parent for this object + +--*/ + +{ + KIRQL oldIrql; + FxObject* parentObject; + + m_SpinLock.Acquire(&oldIrql); + + if (m_ObjectState == FxObjectStateCreated) { + parentObject = m_ParentObject; + } + else { + // Parent is disposing us, or we are being disposed + parentObject = NULL; + } + + if (parentObject != NULL) { + parentObject->ADDREF(Tag); + } + + m_SpinLock.Release(oldIrql); + + return parentObject; +} + +_Must_inspect_result_ +NTSTATUS +FxObject::Commit( + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out_opt WDFOBJECT* ObjectHandle, + __in_opt FxObject* Parent, + __in BOOLEAN AssignDriverAsDefaultParent + ) +/*++ + +Routine Description: + Commit the object before returning the handle to the caller. + +Arguments: + Attributes - PWDF_OBJECT_ATTRIBUTES to assign to this object + + ObjectHandle - Location to return the objects handle + +Returns: + NTSTATUS of the result. STATUS_SUCCESS if success. + + Returns WDFOBJECT handle if success. + +--*/ +{ + NTSTATUS status; + WDFOBJECT object; + FxObject* parent; + + parent = NULL; + + if (m_ObjectSize == 0) { + ASSERTMSG("Only external objects can call Commit()\n", + m_ObjectSize != 0); + return STATUS_INVALID_HANDLE; + } + + // + // For an object to be committed into a handle, it needs to have an object + // size. Internal objects set their size to zero as the indication they + // are internal and will not be converted into handles. + // + ASSERT(m_ObjectSize != 0); + + // + // Caller has already validated basic WDF_OBJECT_ATTRIBUTES + // with FxValidateObjectAttributes + // + + // + // Set object execution level constraint if specified + // + if (Attributes != NULL && + Attributes->ExecutionLevel == WdfExecutionLevelPassive) { + MarkPassiveCallbacks(); + } + + // + // Assign parent if supplied + // + if (Parent != NULL) { + parent = Parent; + } + else if (Attributes != NULL && Attributes->ParentObject != NULL) { + FxObjectHandleGetPtr( + m_Globals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&parent + ); + } + else { + + // + // If the object already does not have a parent, and + // one has not been specified we default it to FxDriver. + // + // We check to ensure we are not FxDriver being created. + // + if (AssignDriverAsDefaultParent && + m_ParentObject == NULL) { + + //parent = FxToObjectItf::FxGetDriverAsDefaultParent(m_Globals, this); + + + if (m_Globals->Driver != this) { + parent = m_Globals->Driver; + } + + } + } + + ASSERT(parent != this); + + if (parent != NULL) { + // + // Make it the parent of this object + // + status = AssignParentObject(parent); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + // + // Now assign the optional EvtObjectCleanup, EvtObjectDestroy callbacks + // + if (Attributes != NULL) { + FxContextHeader* pHeader; + + pHeader = GetContextHeader(); + + if (Attributes->EvtDestroyCallback != NULL) { + pHeader->EvtDestroyCallback = Attributes->EvtDestroyCallback; + } + + if (Attributes->EvtCleanupCallback != NULL) { + pHeader->EvtCleanupCallback = Attributes->EvtCleanupCallback; + m_ObjectFlags |= FXOBJECT_FLAGS_HAS_CLEANUP; + } + } + + // + // We mark the handle as committed so that we can create the handle. + // + MarkCommitted(); + + // + // Create the object handle, assign EvtObjectCleanup, EvtObjectDestroy + // + FxObjectHandleCreate(this, &object); + + if (ObjectHandle != NULL) { + *ObjectHandle = object; + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxObject::_GetEffectiveLock( + __in FxObject* Object, + __in_opt IFxHasCallbacks* Callbacks, + __in BOOLEAN AutomaticLocking, + __in BOOLEAN PassiveCallbacks, + __out FxCallbackLock** CallbackLock, + __out_opt FxObject** CallbackLockObject + ) +/*++ + +Routine Description: + + This gets the effective lock based on the callback constraints + configuration of the supplied object. + + This is a common routine shared by all FxObject's that utilize + DPC's. Currently, this is FxDpc, FxTimer, and FxInterrupt. + + This contains the common serialization configuration logic for these + objects. + +Arguments: + + Object - Object to serialize with + + Callbacks - Optional interface for acquiring constraints and locking pointers + + AutomaticLocking - TRUE if automatic serialization with Object is required + + PassiveCallbacks - TRUE if the caller requires passive level callback, FALSE + if the + CallbackLock - Lock that is in effect for Object + + CallbackLockOjbect - FxObject that contains the callback lock + +Returns: + + NTSTATUS + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_EXECUTION_LEVEL parentLevel; + WDF_SYNCHRONIZATION_SCOPE parentScope; + + pFxDriverGlobals = Object->GetDriverGlobals(); + *CallbackLock = NULL; + *CallbackLockObject = NULL; + + // + // No automatic locking, nothing to do + // + if (AutomaticLocking == FALSE) { + return STATUS_SUCCESS; + } + + // + // Objects that have callback locks must support this interface. + // + if (Callbacks == NULL) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Get the callback constraints in effect for the object + // + Callbacks->GetConstraints(&parentLevel, &parentScope); + + if (parentScope == WdfSynchronizationScopeInheritFromParent || + parentScope == WdfSynchronizationScopeNone) { + // + // Do nothing, no synchronization specified + // + DO_NOTHING(); + } + else { + // + // If the caller wants passive callbacks and the object does not support + // it, failure. + // + // If the caller wants non passive callbacks and the object supports + // passive only callbacks, failure. + // + if ((PassiveCallbacks && Object->IsPassiveCallbacks() == FALSE) || + (PassiveCallbacks == FALSE && Object->IsPassiveCallbacks())) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL; + } + + *CallbackLock = Callbacks->GetCallbackLockPtr(CallbackLockObject); + } + + return STATUS_SUCCESS; +} diff --git a/sdk/lib/drivers/wdf/shared/object/fxobjectapi.cpp b/sdk/lib/drivers/wdf/shared/object/fxobjectapi.cpp new file mode 100644 index 00000000000..004b48eacbc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxobjectapi.cpp @@ -0,0 +1,383 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObjectApi.cpp + +Abstract: + + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxObjectAPI.tmh" +#endif + +} + + +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectReferenceActual)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFOBJECT Object, + __in_opt + PVOID Tag, + __in + LONG Line, + __in + PSTR File + ) +/*++ + +Routine Description: + Adds an explicit reference that was taken on an object. + +Arguments: + Object - the object to reference + Tag - The tag used to track this reference. If not matched on dereference, + a breakpoint is hit. Tags are only tracked when enabled via the + registry or WDF verifier. + Line - the caller's line number making the call + File - the caller's file name making the call + +Return Value: + None. We do not return the current reference count. + + --*/ +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Object); + + FxObject::_ReferenceActual( + Object, + Tag, + Line, + File + ); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectDereferenceActual)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFOBJECT Object, + __in_opt + PVOID Tag, + __in + LONG Line, + __in + PSTR File + ) +/*++ + +Routine Description: + Removes an explicit reference that was taken on an object. + +Arguments: + Object - the object to dereference + Tag - The tag used when referencing the Object, if not matched, a breakpoint + is hit. Tags are only tracked when enabled via the registry or + WDF verifier. + Line - the caller's line number making the call + File - the caller's file name making the call + +Return Value: + None. We do not return the current reference count. + + --*/ +{ + DDI_ENTRY(); + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Object); + + FxObject::_DereferenceActual( + Object, + Tag, + Line, + File + ); +} + +FxCallbackLock* +FxGetCallbackLock( + FxObject* Object + ) + +/*++ + +Routine Description: + + This returns the proper FxCallbackLock pointer + for the object. + + It returns NULL if an FxCallbackLock is not valid + for the object. + +Arguments: + + Object - Pointer to object to retrieve the callback lock pointer for + +Returns: + + FxCallbackLock* + +--*/ + +{ + NTSTATUS status; + IFxHasCallbacks* ihcb; + FxQueryInterfaceParams params = { (PVOID*) &ihcb, FX_TYPE_IHASCALLBACKS, 0 }; + + ihcb = NULL; + + // + // Query the object for the IFxHasCallbacks interface. Objects that + // have callback locks must support this interface. + // + status = Object->QueryInterface(¶ms); + if (!NT_SUCCESS(status)) { + return NULL; + } + + return ihcb->GetCallbackLockPtr(NULL); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectAcquireLock)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ) +{ + DDI_ENTRY(); + + FxObject* pObject; + FxCallbackLock* pLock; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + KIRQL irql; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Object, + FX_TYPE_OBJECT, + (PVOID*)&pObject, + &pFxDriverGlobals); + + // + // If Lock Verifier on, validate whether its correct to + // make this call + // + if (pFxDriverGlobals->FxVerifierLock) { + // + // Check IRQL Level, etc. + // + } + + // + // Get the CallbackLock for the object + // + pLock = FxGetCallbackLock(pObject); + + if (pLock == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid to call on WDFOBJECT 0x%p", Object); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + FxVerifierBugCheck(pFxDriverGlobals, + WDF_INVALID_LOCK_OPERATION, + (ULONG_PTR)Object, + (ULONG_PTR)NULL + ); + return; + } + + pLock->Lock(&irql); + pLock->m_PreviousIrql = irql; + + return; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectReleaseLock)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxObject* pObject; + FxCallbackLock* pLock; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Object, + FX_TYPE_OBJECT, + (PVOID*)&pObject, + &pFxDriverGlobals); + + // + // If Lock Verifier on, validate whether its correct to + // make this call + // + if (pFxDriverGlobals->FxVerifierLock) { + // + // Check IRQL Level, etc. + // + } + + // + // Get the CallbackLock for the object + // + pLock = FxGetCallbackLock(pObject); + if (pLock == NULL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Invalid to call on WDFOBJECT 0x%p",Object); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + FxVerifierBugCheck(pFxDriverGlobals, + WDF_INVALID_LOCK_OPERATION, + (ULONG_PTR)Object, + (ULONG_PTR)NULL + ); + return; + } + + pLock->Unlock(pLock->m_PreviousIrql); + + return; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectDelete)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFOBJECT Object + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxObject* pObject; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Object, + FX_TYPE_OBJECT, + (PVOID*)&pObject, + &pFxDriverGlobals); + + // + // The object may not allow the Delete DDI + // + if (pObject->IsNoDeleteDDI()) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Attempt to Delete an Object Which does not allow WdfDeleteObject " + "Handle 0x%p, %!STATUS!", + Object, STATUS_CANNOT_DELETE); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + else { + pObject->DeleteObject(); + } +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectQuery)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFOBJECT Object, + __in + CONST GUID* Guid, + __in + ULONG QueryBufferLength, + __out_bcount(QueryBufferLength) + PVOID QueryBuffer + ) + +/*++ + +Routine Description: + + Query the object handle for specific information + + This allows dynamic extensions to DDI's. + + Currently, it is used to allow test hooks for verification + which are not available in a production release. + +Arguments: + + Object - Handle to object for the query + + Guid - GUID to represent the information/DDI to query for + + QueryBufferLength - Length of QueryBuffer to return data in + + QueryBuffer - Pointer to QueryBuffer + +Returns: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + FxObject* p; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Object, + FX_TYPE_OBJECT, + (PVOID*)&p); + + return FxObject::_ObjectQuery(p, + Guid, + QueryBufferLength, + QueryBuffer); +} + +} // extern "C" for all functions + + diff --git a/sdk/lib/drivers/wdf/shared/object/fxobjectpch.hpp b/sdk/lib/drivers/wdf/shared/object/fxobjectpch.hpp new file mode 100644 index 00000000000..76d82ce2b16 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxobjectpch.hpp @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxobjectpch.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in shared\object + +Author: + +Environment: + Both kernel and user mode + +Revision History: + +--*/ + +#ifndef __FX_CORE_PCH_H__ +#define __FX_CORE_PCH_H__ + +#include "objectpriv.hpp" +#include "fxmin.hpp" +#include "FxToObjectItf.hpp" + +#endif // __FX_CORE_PCH_H__ diff --git a/sdk/lib/drivers/wdf/shared/object/fxobjectstatemachine.cpp b/sdk/lib/drivers/wdf/shared/object/fxobjectstatemachine.cpp new file mode 100644 index 00000000000..30cf6e7901b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxobjectstatemachine.cpp @@ -0,0 +1,1217 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObjectStateMachine.cpp + +Abstract: + + This module contains the implementation of the base object's state machine. + +Author: + + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + + + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxObjectStateMachine.tmh" +#endif + +} + +VOID +FxObject::DeleteObject( + VOID + ) +/*++ + +Routine Description: + This is a public method that is called on an object to request that it Delete. + +Arguments: + None + +Returns: + NTSTATUS + +--*/ +{ + NTSTATUS status; + KIRQL oldIrql; + BOOLEAN result; + + m_SpinLock.Acquire(&oldIrql); + + result = MarkDeleteCalledLocked(); + + // This method should only be called once per object + ASSERT(result); + UNREFERENCED_PARAMETER(result); //for fre build + + // + // Perform the right action based on the objects current state + // + switch(m_ObjectState) { + case FxObjectStateCreated: + // + // If we have a parent object, notify it of our deletion + // + if (m_ParentObject != NULL) { + // + // We call this holding our spinlock, the hierachy is child->parent + // when the lock is held across calls + // + status = m_ParentObject->RemoveChildObjectInternal(this); + + if (status == STATUS_DELETE_PENDING) { + + // + // We won the race to ourselves (still FxObjectStateCreated), + // but lost the race on the parent who is going to try and + // dispose us through the ParentDeleteEvent(). + // + // This is OK since the state machine protects us from + // doing improper actions, but we must not rundown and + // release our reference count till the parent object + // eventually calls our ParentDeleteEvent(). + // + // So we note the state, and return waiting for the + // parent to dispose us. + // + + // + // Wait for our parent to come in and dispose us through + // the ParentDeleteEvent(). + // + SetObjectStateLocked(FxObjectStateWaitingForEarlyDispose); + m_SpinLock.Release(oldIrql); + break; + } + else { + // + // We no longer have a parent object + // + m_ParentObject = NULL; + } + } + + // + // Start Dispose, do delete state machine + // returns with m_SpinLock released + // + DeleteWorkerAndUnlock(oldIrql, TRUE); + break; + + case FxObjectStateDisposed: + + if (m_ParentObject != NULL) { + status = m_ParentObject->RemoveChildObjectInternal(this); + + if (status == STATUS_DELETE_PENDING) { + SetObjectStateLocked(FxObjectStateWaitingForParentDeleteAndDisposed); + m_SpinLock.Release(oldIrql); + break; + } + else { + // + // We no longer have a parent object + // + m_ParentObject = NULL; + } + } + + // + // This will release the spinlock + // + DeletedAndDisposedWorkerLocked(oldIrql); + break; + + case FxObjectStateDisposingDisposeChildren: + case FxObjectStateWaitingForEarlyDispose: + case FxObjectStateDeletedDisposing: // Do nothing, workitem will move into disposed and deleted + case FxObjectStateDeletedAndDisposed: // Do nothing, already deleted + TraceDroppedEvent(FxObjectDroppedEventDeleteObject); + m_SpinLock.Release(oldIrql); + break; + + // These are bad states for this event + case FxObjectStateInvalid: + case FxObjectStateDestroyed: + case FxObjectStateWaitingForParentDeleteAndDisposed: + default: + TraceDroppedEvent(FxObjectDroppedEventDeleteObject); + // Bad state + ASSERT(FALSE); + m_SpinLock.Release(oldIrql); + } +} + +VOID +FxObject::DeleteEarlyDisposedObject( + VOID + ) +/*++ + +Routine Description: + Deletes an object which has already been explicitly early disposed. + +Arguments: + None + +Return Value: + None + + --*/ +{ + BOOLEAN result; + + ASSERT(m_ObjectFlags & FXOBJECT_FLAGS_EARLY_DISPOSED_EXT); + ASSERT(m_ObjectState == FxObjectStateDisposed); + + result = MarkDeleteCalledLocked(); + ASSERT(result); + UNREFERENCED_PARAMETER(result); //for fre build + + if (m_ParentObject != NULL) { + NTSTATUS status; + KIRQL irql; + + m_SpinLock.Acquire(&irql); + + if (m_ParentObject != NULL) { + status = m_ParentObject->RemoveChildObjectInternal(this); + + if (status == STATUS_DELETE_PENDING) { + SetObjectStateLocked(FxObjectStateWaitingForParentDeleteAndDisposed); + m_SpinLock.Release(irql); + return; + } + else { + // + // We no longer have a parent object + // + m_ParentObject = NULL; + } + } + + m_SpinLock.Release(irql); + } + + // + // This will release the spinlock + // + DeletedAndDisposedWorkerLocked(PASSIVE_LEVEL, FALSE); +} + +BOOLEAN +FxObject::Dispose( + VOID + ) +/*++ + +Routine Description: + This is a virtual function overriden by sub-classes if they want + Dispose notifications. + +Arguments: + None + +Returns: + TRUE if the registered cleanup routines on this object should be called + when this funciton returns + +--*/ +{ + return TRUE; +} + +VOID +FxObject::ProcessDestroy( + VOID + ) +{ + FxTagTracker* pTagTracker; + + // + // Set the debug info to NULL so that we don't use it after the + // SelfDestruct call. Setting the DestroyFunction to NULL + // will also prevent reuse of the REF_OBJ after it has been destroyed. + // + pTagTracker = GetTagTracker(); + + // + // We will free debug info later. It useful to hang on to the debug + // info after the destructor has been called for debugging purposes. + // + if (pTagTracker != NULL) { + pTagTracker->CheckForAbandondedTags(); + } + + // + // Call the destroy callback *before* any desctructor is called. This + // way the callback has access to a full fledged object that hasn't been + // cleaned up yet. + // + // We only do this for committed objects. A non committed object will + // *NOT* have additional contexts to free. + // + if (m_ObjectSize > 0 && IsCommitted()) { + FxContextHeader* pHeader, *pNext; + WDFOBJECT h; + BOOLEAN first; + + // + // We are getting the object handle when the ref count is zero. We + // don't want to ASSERT in this case. + // + h = GetObjectHandleUnchecked(); + + + + + + + + + + + + + + for (pHeader = GetContextHeader(); + pHeader != NULL; + pHeader = pHeader->NextHeader) { + + // + // Cleanup *may* have been called earlier in the objects + // destruction, and in this case the EvtCleanupCallback will + // be set to NULL. Ensuring its always called provides + // symmetry to the framework. + // + + // + // No need to interlockexchange out the value of + // EvtCleanupCallback because any codepath that might be calling + // CallCleanup must have a valid reference and no longer have + // any outstanding references + // + if (pHeader->EvtCleanupCallback != NULL) { + pHeader->EvtCleanupCallback(h); + pHeader->EvtCleanupCallback = NULL; + } + + if (pHeader->EvtDestroyCallback != NULL) { + pHeader->EvtDestroyCallback(h); + pHeader->EvtDestroyCallback = NULL; + } + } + + first = TRUE; + for (pHeader = GetContextHeader(); pHeader != NULL; pHeader = pNext) { + + pNext = pHeader->NextHeader; + + // + // The first header is embedded, so it will be freed with the + // object + // + if (first == FALSE) { + FxPoolFree(pHeader); + } + + first = FALSE; + } + } + + + + + + + + + + + // + // NOTE: The delete of the tag tracker *MUST* occur before the SelfDestruct() + // of this object. The tag tracker has a back pointer to this object which + // it dereferences in its own destructor. If SelfDestruct() is called + // first, then ~FxTagTracker will touch freed pool and bugcheck. + // + if (pTagTracker != NULL) { + GetDebugExtension()->TagTracker = NULL; + delete pTagTracker; + } + + // + // See NOTE above. + // + SelfDestruct(); +} + +BOOLEAN +FxObject::EarlyDispose( + VOID + ) +/*++ + +Routine Description: + Public early dipose functionality. Removes the object from the parent's + list of children. This assumes the caller or someone else will eventually + invoke DeleteObject() on this object. + +Arguments: + None + +Return Value: + BOOLEAN - same semantic as DisposeChildrenWorker. + TRUE - dispose of this object and its children occurred synchronously in + this call + FALSE - the dispose was pended to a work item + + --*/ +{ + NTSTATUS status; + KIRQL oldIrql; + BOOLEAN result; + + // + // By default, we assume a synchronous diposal + // + result = TRUE; + + m_SpinLock.Acquire(&oldIrql); + + switch(m_ObjectState) { + case FxObjectStateCreated: + // + // If we have a parent object, notify it of our deletion + // + if (m_ParentObject != NULL) { + // + // We call this holding our spinlock, the hierachy is child->parent + // when the lock is held across calls + // + status = m_ParentObject->RemoveChildObjectInternal(this); + + if (status == STATUS_DELETE_PENDING) { + + // + // We won the race to ourselves (still FxObjectStateCreated), + // but lost the race on the parent who is going to try and + // dispose us through the PerformEarlyDipose(). + // + // This is OK since the state machine protects us from + // doing improper actions, but we must not rundown and + // release our reference count till the parent object + // eventually calls our ParentDeleteEvent(). + // + // So we note the state, and return waiting for the + // parent to dispose us. + // + + // + // Wait for our parent to come in and dispose us through + // the PerformEarlyDipose(). + // + SetObjectStateLocked(FxObjectStateWaitingForEarlyDispose); + m_SpinLock.Release(oldIrql); + + return FALSE; + } + else { + // + // We no longer have a parent object + // + m_ParentObject = NULL; + } + } + + // + // Mark that this object was early disposed externally wrt the + // state machine. + // + m_ObjectFlags |= FXOBJECT_FLAGS_EARLY_DISPOSED_EXT; + + // + // Start the dispose path. This call will release the spinlock. + // + result = PerformEarlyDisposeWorkerAndUnlock(oldIrql, TRUE); + break; + + default: + // + // Not in the right state for an early dispose + // + result = FALSE; + m_SpinLock.Release(oldIrql); + } + + return result; +} + +BOOLEAN +FxObject::PerformEarlyDispose( + VOID + ) +/*++ + +Routine Description: + Allows Dispose() processing on an object to occur before calling DeleteObject(). + +Arguments: + CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are + incorrect. If FALSE, the caller has guaranteed that we are at + the correct IRQL + +Returns: + None + +--*/ +{ + KIRQL oldIrql; + BOOLEAN result; + + // + // By default we assume that the dispose was synchronous + // + result = TRUE; + + + // + // It's OK for an object to already be disposing due to + // a parent delete call. + // + // To check for verifier errors in which two calls to + // PerformEarlyDispose() occur, a separate flag is used + // rather than complicating the state machine. + // + m_SpinLock.Acquire(&oldIrql); + + // + // Perform the right action based on the objects current state + // + switch(m_ObjectState) { + case FxObjectStateCreated: + // + // Start dispose, move into Disposing state + // returns with m_SpinLock released + // + result = PerformEarlyDisposeWorkerAndUnlock(oldIrql, FALSE); + break; + + case FxObjectStateWaitingForEarlyDispose: + // + // Start the dispose path. + // + result = PerformEarlyDisposeWorkerAndUnlock(oldIrql, FALSE); + break; + + case FxObjectStateDeferedDisposing: + // + // We should only get an early dispose in this state once we have thunked + // to passive level via the dispose list. + // + result = PerformDisposingDisposeChildrenLocked(oldIrql, FALSE); + break; + + case FxObjectStateWaitingForParentDeleteAndDisposed: // Do nothing, parent object will delete and dispose + case FxObjectStateDisposed: // Do nothing + case FxObjectStateDisposingEarly: // Do nothing + case FxObjectStateDeletedDisposing: // Do nothing, workitem will moved into disposed + case FxObjectStateDeletedAndDisposed: + TraceDroppedEvent(FxObjectDroppedEventPerformEarlyDispose); + m_SpinLock.Release(oldIrql); + break; + + // These are bad states for this event + case FxObjectStateInvalid: + case FxObjectStateDestroyed: + + default: + TraceDroppedEvent(FxObjectDroppedEventPerformEarlyDispose); + // Bad state + ASSERT(FALSE); + m_SpinLock.Release(oldIrql); + break; + } + + return result; +} + +_Must_inspect_result_ +NTSTATUS +FxObject::RemoveParentAssignment( + VOID + ) +/*++ + +Routine Description: + Remove the current objects ParentObject. + +Arguments: + None + +Returns: + NTSTATUS of action + +--*/ +{ + KIRQL oldIrql; + NTSTATUS status; + + m_SpinLock.Acquire(&oldIrql); + + // + // Object is already being deleted, this object will be removed as a child + // by the parents Dispose() + // + if (m_ObjectState != FxObjectStateCreated) { + TraceDroppedEvent(FxObjectDroppedEventRemoveParentAssignment); + m_SpinLock.Release(oldIrql); + return STATUS_DELETE_PENDING; + } + + // We should have a parent + ASSERT(m_ParentObject != NULL); + + status = m_ParentObject->RemoveChildObjectInternal(this); + if (NT_SUCCESS(status)) { + m_ParentObject = NULL; + } + + m_SpinLock.Release(oldIrql); + + return status; +} + +VOID +FxObject::ParentDeleteEvent( + VOID + ) +/*++ + +Routine Description: + + This is invoked by the parent object when it is Dispose()'ing us. + +Arguments: + None + +Returns: + None + +--*/ +{ + KIRQL oldIrql; + + // + // Note: It's ok for an object to already be in the delete + // state since there can be an allowed race between + // parent disposing an object, and the DeleteObject() + // call on the object itself. + // + m_SpinLock.Acquire(&oldIrql); + + // + // We no longer have a parent object + // + m_ParentObject = NULL; + + // + // Perform the right action based on the objects current state + // + switch(m_ObjectState) { + case FxObjectStateWaitingForParentDeleteAndDisposed: + case FxObjectStateDisposed: + // + // This will release the spinlock + // + DeletedAndDisposedWorkerLocked(oldIrql, TRUE); + break; + + case FxObjectStateDeletedDisposing: + // + // Do nothing, workitem will move into disposed + // + TraceDroppedEvent(FxObjectDroppedEventParentDeleteEvent); + m_SpinLock.Release(oldIrql); + break; + + case FxObjectStateDeletedAndDisposed: // Do nothing, already deleted + m_SpinLock.Release(oldIrql); + break; + + case FxObjectStateDisposingDisposeChildren: + // + // In the process of deleting, ignore it + // + m_SpinLock.Release(oldIrql); + break; + + // These are bad states for this event + + + + + + case FxObjectStateCreated: + case FxObjectStateWaitingForEarlyDispose: + + case FxObjectStateInvalid: + case FxObjectStateDestroyed: + default: + // + // Bad state + // + ASSERT(FALSE); + m_SpinLock.Release(oldIrql); + break; + } +} + +VOID +FxObject::DeferredDisposeWorkItem( + VOID + ) +/*++ + +Routine Description: + Invoked by deferred dispose workitem. This is invoked at PASSIVE_LEVEL, + and returns at PASSIVE_LEVEL + +Arguments: + None + +Return Value: + None + + --*/ +{ + KIRQL oldIrql; + BOOLEAN result, destroy; + + destroy = FALSE; + + m_SpinLock.Acquire(&oldIrql); + + ASSERT(oldIrql == PASSIVE_LEVEL); + + // + // Perform the right action based on the objects current state + // + // DisposeChildrenWorker return result can be ignored because we are + // guaranteed to be calling it at PASSIVE. + // + switch (m_ObjectState) { + case FxObjectStateDeferedDisposing: + // + // This will drop the spinlock and move the object to the right state + // before returning. + // + result = PerformDisposingDisposeChildrenLocked(oldIrql, FALSE); + + // + // The substree should never defer to the dispose list if we pass FALSE. + // + ASSERT(result); + UNREFERENCED_PARAMETER(result); //for fre build + + return; + + case FxObjectStateDeferedDeleting: + SetObjectStateLocked(FxObjectStateDeletedDisposing); + result = DisposeChildrenWorker(FxObjectStateDeferedDeleting, oldIrql, FALSE); + ASSERT(result); + UNREFERENCED_PARAMETER(result); //for fre build + + // + // This will release the spinlock + // + DeletedAndDisposedWorkerLocked(oldIrql, FALSE); + return; + + case FxObjectStateDeferedDestroy: + // Perform final destroy actions now that we are at passive level + destroy = TRUE; + break; + + // These are bad states for this event + case FxObjectStateDeletedAndDisposed: // Do nothing + case FxObjectStateDisposed: + case FxObjectStateWaitingForParentDeleteAndDisposed: // Do nothing + case FxObjectStateCreated: + case FxObjectStateWaitingForEarlyDispose: + case FxObjectStateInvalid: + case FxObjectStateDestroyed: + + default: + // Bad state + ASSERT(FALSE); + break; + } + + m_SpinLock.Release(oldIrql); + + if (destroy) { + ProcessDestroy(); + } +} + +_Releases_lock_(this->m_SpinLock.m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxObject::PerformDisposingDisposeChildrenLocked( + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ) +/*++ + +Routine Description: + This is entered with m_SpinLock held, and returns with it released. + +Arguments: + OldIrql - the IRQL before m_SpinLock was acquired + + CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are + incorrect. If FALSE, the caller has guaranteed that we are at + the correct IRQL + +Return Value: + BOOLEAN - same semantic as DisposeChildrenWorker. + TRUE - delete of this object and its children occurred synchronously in + this call + FALSE - the delete was pended to a work item + + --*/ +{ + static const USHORT edFlags = (FXOBJECT_FLAGS_DELETECALLED | + FXOBJECT_FLAGS_EARLY_DISPOSED_EXT); + + SetObjectStateLocked(FxObjectStateDisposingDisposeChildren); + + if (DisposeChildrenWorker(FxObjectStateDeferedDisposing, OldIrql, CanDefer)) { + // + // Upon returning TRUE, the lock is still held + // + + // + // If this object was early disposed externally, destroy the children + // immediately (FxRequest relies on this so that the WDFMEMORYs created + // for probed and locked buffers are freed before the request is + // completed.) + // + // Otherwise, wait for DeleteObject or ParentDeleteEvent() to occur. + // + if ((m_ObjectFlags & edFlags) == edFlags) { + // + // This will drop the lock + // + DeletedAndDisposedWorkerLocked(OldIrql, FALSE); + } + else { + // + // Will wait for the parent deleted event + // + SetObjectStateLocked(FxObjectStateDisposed); + } + + return TRUE; + } + else { + // + // Upon return FALSE, the lock was released and a work item was + // queued to dispose of children at passive level + // + DO_NOTHING(); + + return FALSE; + } +} + +_Releases_lock_(this->m_SpinLock.m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxObject::PerformEarlyDisposeWorkerAndUnlock( + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ) +/*++ + +Routine Description: + This is entered with m_SpinLock held, and returns with it released. + +Arguments: + OldIrql - the previous IRQL before the object lock was acquired + + CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are + incorrect. If FALSE, the caller has guaranteed that we are at + the correct IRQL + +Return Value: + BOOLEAN - same semantic as DisposeChildrenWorker. + TRUE - delete of this object and its children occurred synchronously in + this call + FALSE - the delete was pended to a work item + + --*/ +{ + ASSERT(m_ObjectState == FxObjectStateCreated || + m_ObjectState == FxObjectStateWaitingForEarlyDispose); + + SetObjectStateLocked(FxObjectStateDisposingEarly); + + if (CanDefer && ShouldDeferDisposeLocked(&OldIrql)) { + QueueDeferredDisposeLocked(FxObjectStateDeferedDisposing); + m_SpinLock.Release(OldIrql); + + return FALSE; + } + else { + return PerformDisposingDisposeChildrenLocked(OldIrql, CanDefer); + } +} + +_Releases_lock_(this->m_SpinLock.m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxObject::DeleteWorkerAndUnlock( + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ) +/*++ + +Routine Description: + This is entered with m_SpinLock held, and returns with it released. + + +Arguments: + OldIrql - the IRQL before m_SpinLock was acquired + + CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are + incorrect. If FALSE, the caller has guaranteed that we are at + the correct IRQL + +Return Value: + BOOLEAN - same semantic as DisposeChildrenWorker. + TRUE - delete of this object and its children occurred synchronously in + this call + FALSE - the delete was pended to a work item + + --*/ +{ + ASSERT(m_ObjectState == FxObjectStateCreated); + // m_ObjectState == FxObjectStateWaitingForParentDelete); + + if (CanDefer && ShouldDeferDisposeLocked(&OldIrql)) { + QueueDeferredDisposeLocked(FxObjectStateDeferedDeleting); + m_SpinLock.Release(OldIrql); + + return FALSE; + } + else { + SetObjectStateLocked(FxObjectStateDeletedDisposing); + + if (DisposeChildrenWorker(FxObjectStateDeferedDeleting, OldIrql, CanDefer)) { + // + // This will release the spinlock + // + DeletedAndDisposedWorkerLocked(OldIrql, FALSE); + + return TRUE; + } + else { + // + // Upon return FALSE, the lock was released and a work item was + // queued to dispose of children at passive level + // + DO_NOTHING(); + + return FALSE; + } + } +} + +VOID +FxObject::QueueDeferredDisposeLocked( + __in FxObjectState NewDeferedState + ) +/*++ + +Routine Description: + Queues this object onto a work item list which will dispose it at passive + level. The work item will be owned by the parent device or driver. + + This is called with the object's m_SpinLock held. + + NOTE: This function only looks at this object and the parent to attempt to + find the owning FxDeviceBase*. If this is a deeper hierarchy, the deeply + rooted FxDeviceBase will not be used. + +Arguments: + Parent - the parent of this objec (it may have already been removed from + m_ParentObject, so we can't use that field + +Return Value: + None + + --*/ +{ + // + // Queue workitem, which will run DisposeChildrenWorker() + // + ASSERT(m_Globals != NULL); + ASSERT(m_Globals->Driver != NULL); + + SetObjectStateLocked(NewDeferedState); + + //FxToObjectItf::FxAddToDisposeList(m_DeviceBase, m_Globals, this); + if (m_DeviceBase != NULL) { + m_DeviceBase->AddToDisposeList(this); + } + else { + m_Globals->Driver->GetDisposeList()->Add(this); + } +} + +_Releases_lock_(this->m_SpinLock.m_Lock) +__drv_requiresIRQL(DISPATCH_LEVEL) +BOOLEAN +FxObject::DisposeChildrenWorker( + __in FxObjectState NewDeferedState, + __in __drv_restoresIRQL KIRQL OldIrql, + __in BOOLEAN CanDefer + ) + +/*++ + +Routine Description: + + Rundown list of child objects removing their entries and invoking + their ParentDeleteEvent() on them. + + This is called with the m_SpinLock held and upon returning the lock is + released. + +Arguments: + NewDeferedState - If the state transition requires defering to a dispose + list, this is the new state to move to + + OldIrql - the previous IRQL when the caller acquired the object's lock + + CanDefer - if TRUE, can defer to a dispose list if IRQL requirements are + incorrect. If FALSE, the caller has guaranteed that we are at + the correct IRQL + +Returns: + TRUE: Dispose is completed in this function. + FALSE: Dispose is deferred either to a workitem (if CanDefer is TRUE) or will + be done later in the current thread (if CanDefer is FALSE). + + In either case lock is released. + + If the OldIrql == PASSIVE_LEVEL, TRUE is guaranteed to be returned + +Comments: + + This routine is entered with the spinlock held, and may return with it released. + + The state machine ensures that this is only invoked once in + an objects lifetime, regardless of races between PerformEarlyDispose, + DeleteObject, or a ParentDeleteEvent. If there are requirements for passive + level dispose and the previous IRQL is != PASSIVE, this function will be + called twice, the first at IRQL > PASSIVE, the second at PASSIVE. + + Top level code has ensured this is invoked under the right IRQL level + for the object to perform the Dispose() callbacks. + +--*/ +{ + LIST_ENTRY *ple; + FxObject* childObject; + + // + // Called from: + // + // DeferredDisposeWorkItem (will complete, and release in current thread) + // PerformDisposeWorkerAndUnlock(PerformEarlyDispose), no release, but possible thread deferral + // DeleteWorkerAndUnlock (will release, but may defer, its logic must change!) + // + + ASSERT((m_ObjectState == FxObjectStateDisposingDisposeChildren) || + (m_ObjectState == FxObjectStateDeletedDisposing)); + + // + // This routine will attempt to dispose as many children as possible + // in the current thread. It may have to stop if the thread is + // not at PASSIVE_LEVEL when the object spinlock was acquired, and + // a child object is marked as a passive level object. + // + // If this occurs, dispose processing is suspended and resumed in + // a passive level workitem, which calls this routine back to + // complete the processing. + // + // Once all child object's Dispose() callback has returned, we then + // can call Dispose() on the parent object. + // + // This must be done in this order to guarantee the contract with the + // device driver (and internal object system) that all child + // EvtObjectCleanup callbacks have returned before their parents + // EvtObjectCleanup event. + // + // This is important to avoid extra references + // when child objects expect their parent object to be valid until + // EvtObjectCleanup is called. + // + + // Rundown list removing entries and calling Dispose on child objects + + // + // If this object requires being forced onto the dispose thread, do it now + // + if (IsForceDisposeThreadLocked() && OldIrql != PASSIVE_LEVEL) { + // + // Workitem will re-run this function at PASSIVE_LEVEL + // + if (CanDefer) { + QueueDeferredDisposeLocked(NewDeferedState); + } + else { + SetObjectStateLocked(NewDeferedState); + } + + m_SpinLock.Release(OldIrql); + + return FALSE; + } + + for (ple = m_ChildListHead.Flink; + ple != &m_ChildListHead; + ple = ple->Flink) { + // + // Before removing the child object, we need to see if we need to defer + // to a work item to dispose the child. + // + childObject = CONTAINING_RECORD(ple, FxObject, m_ChildEntry); + + // + // Should not associate with self + // + ASSERT(childObject != this); + + // + // If current threads IRQL before acquiring the spinlock is not + // passive, and the child object is passive constrained, we must + // defer the current disposal processing to a workitem. + // + // We stay in the Disposing state, which this routine will continue + // processing when called back from the workitem. + // + // This code is re-entered at the proper passive_level to complete + // processing where it left off (at the head of the m_ChildListHead). + // + if (OldIrql != PASSIVE_LEVEL && childObject->IsPassiveDisposeLocked()) { + // + // Workitem will re-run this function at PASSIVE_LEVEL + // + if (CanDefer) { + QueueDeferredDisposeLocked(NewDeferedState); + } + else { + SetObjectStateLocked(NewDeferedState); + } + m_SpinLock.Release(OldIrql); + + return FALSE; + } + } + + m_SpinLock.Release(OldIrql); + + for (ple = m_ChildListHead.Flink; ple != &m_ChildListHead; ple = ple->Flink) { + childObject = CONTAINING_RECORD(ple, FxObject, m_ChildEntry); + + // + // Inform child object of disposal. We will release the reference on + // the child only after we have disposed ourself. + // + if (childObject->PerformEarlyDispose() == FALSE) { + + m_SpinLock.Acquire(&OldIrql); + if (CanDefer) { + QueueDeferredDisposeLocked(NewDeferedState); + } + else { + SetObjectStateLocked(NewDeferedState); + } + m_SpinLock.Release(OldIrql); + + return FALSE; + } + + ASSERT(childObject->GetRefCnt() > 0); + } + + // + // Call Dispose virtual callback on ourselves for benefit + // of sub-classes if it is overridden. + // + if ((m_ObjectFlags & FXOBJECT_FLAGS_DISPOSE_OVERRIDE) == 0x00 || Dispose()) { + // + // Now call Cleanup on any handle context's exposed + // to the device driver. + // + CallCleanup(); + } + + return TRUE; +} + +// +// Despite the name this function may not always be called with lock held +// but if Unlock is TRUE, lock must be held. +// +_When_(Unlock, _Releases_lock_(this->m_SpinLock.m_Lock)) +__drv_when(Unlock, __drv_requiresIRQL(DISPATCH_LEVEL)) +VOID +FxObject::DeletedAndDisposedWorkerLocked( + __in __drv_when(Unlock, __drv_restoresIRQL) KIRQL OldIrql, + __in BOOLEAN Unlock + ) +{ + SetObjectStateLocked(FxObjectStateDeletedAndDisposed); + + if (Unlock) { + m_SpinLock.Release(OldIrql); + } + + DestroyChildren(); + + // + // Release the final reference on the object + // + RELEASE(NULL); +} + diff --git a/sdk/lib/drivers/wdf/shared/object/fxtagtracker.cpp b/sdk/lib/drivers/wdf/shared/object/fxtagtracker.cpp new file mode 100644 index 00000000000..fb301e67c4d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxtagtracker.cpp @@ -0,0 +1,382 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTagTracker.cpp + +Abstract: + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "fxtagtracker.tmh" +#endif + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +// +// rtlsupportapi.h causes problems in AMD64 and ARM builds. +// +extern +_Success_(return != 0) +USHORT +RtlCaptureStackBackTrace( + _In_ ULONG FramesToSkip, + _In_ ULONG FramesToCapture, + _Out_writes_to_(FramesToCapture, return) PVOID * BackTrace, + _Out_opt_ PULONG BackTraceHash + ); +#endif + +} + +FxTagTracker::~FxTagTracker() +/*++ + +Routine Description: + Destructor for this object. Will verify that the object is being freed + without any outstanding tags. + +Arguments: + None + +Return Value: + None + + --*/ +{ + KIRQL irql; + FxTagTrackingBlock *current, *next; + + if (m_TrackerType == FxTagTrackerTypeHandle) { + FxDriverGlobalsDebugExtension* pExtension; + + CheckForAbandondedTags(); + + pExtension = GetDriverGlobals()->DebugExtension; + + // + // Remove this tracker from the list of allocated trackers + // + pExtension->AllocatedTagTrackersLock.Acquire(&irql); + RemoveEntryList(&m_TrackerEntry); + pExtension->AllocatedTagTrackersLock.Release(irql); + } else { + ASSERT(m_TrackerType == FxTagTrackerTypePower); + } + + // + // Delete any outstanding tracking blocks. + // + m_SpinLock.Acquire(&irql); + + current = m_Next; + m_Next = NULL; + + while (current != NULL) { + next = current->Next; + delete current; + current = next; + } + + m_SpinLock.Release(irql); +} + +VOID +FxTagTracker::CopyStackFrames( + _Inout_ FxTagTrackingStackFrames** StackFrames, + _In_ USHORT NumFrames, + _In_reads_(NumFrames) PVOID* Frames + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxTagTrackingStackFrames* stackFrames; + + // + // FxTagHistory structs are stored in a circular buffer and reused, + // so we also reuse the FxTagTrackingStackFrames that each allocates. + // + stackFrames = *StackFrames; + if (stackFrames == NULL) { + pFxDriverGlobals = GetDriverGlobals(); + stackFrames = new(pFxDriverGlobals) FxTagTrackingStackFrames; + if (stackFrames == NULL) { + return; + } + + *StackFrames = stackFrames; + } + + stackFrames->NumFrames = NumFrames; + + for (int i = 0; i < NumFrames; i++) { + stackFrames->Frames[i] = (ULONG64)Frames[i]; + } +} + +VOID +FxTagTracker::UpdateTagHistory( + __in PVOID Tag, + __in LONG Line, + __in_opt PSTR File, + __in FxTagRefType RefType, + __in ULONG RefCount + ) +/*++ + +Routine Description: + Update tag history and either create or free an existing tag tracking block. + +Arguments: + + Tag - Unique tag associated with the reference + + Line - Line where the reference is referenced/released + + File - Buffer containing the file name + + RefType - Enumerated type ( AddRef or Release ) + + RefCount - Approximate current reference count (see FxTagHistory.RefCount comment) + +Return Value: + + VOID + +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxTagHistory* pTagHistory; + FxTagTrackingBlock* pBlock; + LONG pos; + KIRQL irql; + USHORT numFrames = 0; + PVOID frames[FRAMES_TO_CAPTURE]; + + pFxDriverGlobals = GetDriverGlobals(); + + pos = InterlockedIncrement(&m_CurRefHistory) - 1; + pos %= TAG_HISTORY_DEPTH; + + // + // Prefast reports that m_CurRefHistory can be negative which can lead to + // underflow. But we know that m_CurRefHistory would never be negative. + // Hence we assert for the condition below and assume that it would be true. + // + FX_ASSERT_AND_ASSUME_FOR_PREFAST(pos >= 0 && pos < TAG_HISTORY_DEPTH); + + pTagHistory = m_TagHistory + pos; + + pTagHistory->RefType = RefType; + pTagHistory->RefCount = RefCount; + pTagHistory->Line = Line; + pTagHistory->Tag = Tag; + pTagHistory->File = File; + + if (m_CaptureStack) { + numFrames = RtlCaptureStackBackTrace(FRAMES_TO_SKIP, + FRAMES_TO_CAPTURE, + frames, + NULL); + if (numFrames > 0) { + CopyStackFrames(&pTagHistory->StackFrames, numFrames, frames); + } + } + + // + // We use the perf counter here and the tick count in the tracking block. + // Use the tick count here as well until we decide that correlating the + // perf counter to system time is not important. + // + // pTagHistory->Time = KeQueryPerformanceCounter(NULL); + Mx::MxQueryTickCount(&pTagHistory->Time); + + if (RefType == TagAddRef) { + + // + // Try to allocate some memory for the new block. If unsuccessful, + // fallback to a failed count increment. + // + pBlock = new(pFxDriverGlobals) FxTagTrackingBlock(Tag, Line, File); + + if (pBlock == NULL) { + InterlockedIncrement(&m_FailedCount); + } + else { + m_SpinLock.Acquire(&irql); + pBlock->Next = m_Next; + m_Next = pBlock; + m_SpinLock.Release(irql); + + if (m_CaptureStack && numFrames > 0) { + CopyStackFrames(&pBlock->StackFrames, numFrames, frames); + } + } + } + else { + FxTagTrackingBlock **prev; + + // + // Walk the list of current blocks and attempt to find the tag being + // released. If not found, decrement the failed count. If no failed + // tags exists, ASSERT immediately. + // + + m_SpinLock.Acquire(&irql); + prev = &m_Next; + pBlock = *prev; + + while (pBlock != NULL) { + if (pBlock->Tag == Tag) { + *prev = pBlock->Next; + break; + } + + prev = &pBlock->Next; + pBlock = pBlock->Next; + } + + m_SpinLock.Release(irql); + + if (pBlock == NULL) { + // + // Check to see if we have any credits in our Low Memory Count. + // In this fassion we can tell if we have acquired any locks without + // the memory for adding tracking blocks. + // + if (InterlockedDecrement(&m_FailedCount) < 0) { + // + // We have just released a lock that neither had a corresponding + // tracking block, nor a credit in LowMemoryCount. + // + InterlockedIncrement(&m_FailedCount); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "releasing %s %p on object %p that was not acquired, !wdftagtracker %p", + m_TrackerType == FxTagTrackerTypePower ? "power tag" : "tag", + Tag, + m_OwningObject, + this); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + else { + delete pBlock; + pBlock = NULL; + } + } +} + +VOID +FxTagTracker::CheckForAbandondedTags( + VOID + ) +/*++ + +Routine Description: + Iterates over any existing tags, dumping any existing tags to the debugger. + Will assert if there any outstanding tags (assumes that the caller wants + no current tags). + +Arguments: + None + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxTagTrackingBlock *current, *next; + LONG abandoned; + KIRQL irql; + BOOLEAN committed; + + pFxDriverGlobals = GetDriverGlobals(); + + committed = m_OwningObject->IsCommitted(); + + // + // If the object was not committed, then it was an FxObject derived + // class that was *embedded* as a field in another structure or class. + // As such, we are allowing one outstanding reference at this time. We will + // catch > 1 outstanding references below in the while loop. + // + if (committed) { + if (m_Next != NULL || m_FailedCount != 0) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Dropped references on a tag tracker, " + "show references with: !wdftagtracker %p", this); + // + // If this ASSERT fails, look in the history .. you'll + // likely find that you released more references than you had + // + ASSERT(m_Next == NULL && m_FailedCount == 0); + } + } + + m_SpinLock.Acquire(&irql); + + current = m_Next; + abandoned = 0; + + while (current != NULL) { + next = current->Next; + + if (committed) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Abandonded ref on object %p tag %p (%s @ %d)", + m_OwningObject, current->Tag, current->File, current->Line); + abandoned++; + } + + if (committed == FALSE) { + // + // The next time we encounter an abandoned reference, we will complain + // about it...we have used up our allowance of one leaked reference + // because the object is an embedded object. + // + // NOTE: we might be eating the real outstanding reference here + // and not tracing it and then tracing the initial creation + // reference as the leaked reference which will be confusing. + // This is b/c there is no way to distinguish what is the + // tracking block used to track the creatio of the object. + // + committed = TRUE; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDEVICE, + "Possibly Abandonded ref on object %p tag %p (%s @ %d). " + "Is benign unless there are other outstanding leaked references.", + m_OwningObject, current->Tag, current->File, current->Line); + } + + current = next; + } + + m_SpinLock.Release(irql); + + ASSERTMSG("Abandoned tags on ref\n", abandoned == 0); +} + + diff --git a/sdk/lib/drivers/wdf/shared/object/fxuserobject.cpp b/sdk/lib/drivers/wdf/shared/object/fxuserobject.cpp new file mode 100644 index 00000000000..0d9f7963efa --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxuserobject.cpp @@ -0,0 +1,106 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUserObject.cpp + +Abstract: + + This module implements the user object that device + driver writers can use to take advantage of the + driver frameworks infrastructure. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + +--*/ + +#include "fxobjectpch.hpp" + +#include "FxUserObject.hpp" + +// Tracing support +extern "C" { +#if defined(EVENT_TRACING) +#include "FxUserObject.tmh" +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxUserObject::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out FxUserObject** pUserObject + ) +{ + FxUserObject* pObject = NULL; + NTSTATUS status; + USHORT wrapperSize = 0; + WDFOBJECT handle; + +#ifdef INLINE_WRAPPER_ALLOCATION +#if FX_CORE_MODE==FX_CORE_USER_MODE + wrapperSize = FxUserObject::GetWrapperSize(); +#endif +#endif + + pObject = new(FxDriverGlobals, Attributes, wrapperSize) + FxUserObject(FxDriverGlobals); + + + if (pObject == NULL) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGOBJECT, + "Memory allocation failed"); + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pObject->Commit(Attributes, &handle); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, + TRACINGOBJECT, + "FxObject::Commit failed %!STATUS!", status); + } + + if (NT_SUCCESS(status)) { + *pUserObject = pObject; + } + else { + pObject->DeleteFromFailedCreate(); + } + + return status; +} + +// +// Public constructors +// + +FxUserObject::FxUserObject( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : +#ifdef INLINE_WRAPPER_ALLOCATION + FxNonPagedObject(FX_TYPE_USEROBJECT, sizeof(FxUserObject) + GetWrapperSize(), FxDriverGlobals) +#else + FxNonPagedObject(FX_TYPE_USEROBJECT, sizeof(FxUserObject), FxDriverGlobals) +#endif +{ + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/object/fxuserobjectapi.cpp b/sdk/lib/drivers/wdf/shared/object/fxuserobjectapi.cpp new file mode 100644 index 00000000000..85eea814685 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxuserobjectapi.cpp @@ -0,0 +1,145 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUserObjectApi.cpp + +Abstract: + + This modules implements the C API's for the FxUserObject. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "fxobjectpch.hpp" + +#include "FxUserObject.hpp" + +// Tracing support +extern "C" { +#if defined(EVENT_TRACING) +#include "FxUserObjectApi.tmh" +#endif +} + + +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfObjectCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFOBJECT* Object + ) + +/*++ + +Routine Description: + + This creates a general WDF object for use by the device driver. + + It participates in general framework object contracts in that it: + + - Has a handle and a reference count + - Has Cleanup and Destroy callbacks + - Supports driver context memory and type + - Can have child objects + - Can optionally have a parent object and automatically delete with it + + It is intended to allow a WDF device driver to use this object to + create its own structures that can participate in frameworks lifetime + management. + + The device driver can use the objects context memory and type to + represent its own internal data structures, and can further assign + device driver specific resources and release them by registering + for EvtObjectCleanup, and EvtObjectDestroy callbacks. + + The object may be deleted by using the WdfObjectDelete API. + + Since the object is represented by a frameworks handle, it can be + reference counted, and validated. + + Class drivers may use this object to define framework object handles + for their types. + +Arguments: + + Attributes - WDF_OBJECT_ATTRIBUTES to define a parent object, context memory, + Cleanup and Destroy handlers. + +Return Value: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + NTSTATUS status; + WDFOBJECT handle; + FxUserObject* pUserObject; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pUserObject = NULL; + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + Attributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, Object); + + status = FxValidateObjectAttributes(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED + ); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Create the FxObject. + // + status = FxUserObject::_Create(pFxDriverGlobals, Attributes, &pUserObject); + if (NT_SUCCESS(status)) { + handle = pUserObject->GetHandle(); + *Object = handle; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, + TRACINGUSEROBJECT, + "Created UserObject Handle 0x%p", + handle); + } + + return status; +} + +} // extern "C" the entire file diff --git a/sdk/lib/drivers/wdf/shared/object/fxvalidatefunctions.cpp b/sdk/lib/drivers/wdf/shared/object/fxvalidatefunctions.cpp new file mode 100644 index 00000000000..9f62cbbacb4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxvalidatefunctions.cpp @@ -0,0 +1,220 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxValidateFunctions.cpp + +Abstract: + + Functions which validate external WDF data structures + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + + + + + +--*/ + +#include "fxobjectpch.hpp" + +// We use DoTraceMessage +extern "C" { +#if defined(EVENT_TRACING) +#include "FxValidateFunctions.tmh" +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxValidateObjectAttributes( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in ULONG Flags + ) +{ + if (Attributes == NULL) { + if (Flags & FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "WDF_OBJECT_ATTRIBUTES required, %!STATUS!", + (ULONG) STATUS_WDF_PARENT_NOT_SPECIFIED); + + return STATUS_WDF_PARENT_NOT_SPECIFIED; + } + else { + return STATUS_SUCCESS; + } + } + + if (Attributes->Size != sizeof(WDF_OBJECT_ATTRIBUTES)) { + // + // Size is wrong, bail out + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p Size incorrect, expected %d, got %d, %!STATUS!", + Attributes, sizeof(WDF_OBJECT_ATTRIBUTES), + Attributes->Size, STATUS_INFO_LENGTH_MISMATCH); + + return STATUS_INFO_LENGTH_MISMATCH; + } + + if (Attributes->ContextTypeInfo != NULL) { +#pragma prefast(suppress:__WARNING_REDUNDANTTEST, "different structs of the same size") + if (Attributes->ContextTypeInfo->Size != + sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO) && + Attributes->ContextTypeInfo->Size != + sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO_V1_0)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p ContextTypeInfo %p Size %d incorrect, expected %d, %!STATUS!", + Attributes, Attributes->ContextTypeInfo, + Attributes->ContextTypeInfo->Size, + sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO), STATUS_INFO_LENGTH_MISMATCH); + + return STATUS_INFO_LENGTH_MISMATCH; + } + + // + // A ContextName != NULL and a ContextSize of 0 is allowed + // + if (Attributes->ContextTypeInfo->ContextSize > 0 && + Attributes->ContextTypeInfo->ContextName == NULL) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p ContextTypeInfo %p ContextSize %I64d is not zero, " + "but ContextName is NULL, %!STATUS!", + Attributes, Attributes->ContextTypeInfo, + Attributes->ContextTypeInfo->ContextSize, + STATUS_WDF_OBJECT_ATTRIBUTES_INVALID); + + return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + } + } + + if (Attributes->ContextSizeOverride > 0) { + if (Attributes->ContextTypeInfo == NULL) { + // + // Can't specify additional size without a type + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p ContextSizeOverride of %I64d specified, but no type " + "information, %!STATUS!", + Attributes, Attributes->ContextSizeOverride, + STATUS_WDF_OBJECT_ATTRIBUTES_INVALID); + + return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + } + else if (Attributes->ContextSizeOverride < + Attributes->ContextTypeInfo->ContextSize) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p ContextSizeOverride %I64d < " + "ContextTypeInfo->ContextSize %I64d, %!STATUS!", + Attributes, Attributes->ContextSizeOverride, + Attributes->ContextTypeInfo->ContextSize, + STATUS_WDF_OBJECT_ATTRIBUTES_INVALID); + + return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + } + } + + if (Flags & FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED) { + if (Attributes->ParentObject != NULL) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p does not allow a parent object to be set, set to " + "%p, %!STATUS!", Attributes, Attributes->ParentObject, + STATUS_WDF_PARENT_ASSIGNMENT_NOT_ALLOWED); + + return STATUS_WDF_PARENT_ASSIGNMENT_NOT_ALLOWED; + } + } + else if ((Flags & FX_VALIDATE_OPTION_PARENT_REQUIRED_FLAG) && + Attributes->ParentObject == NULL) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "ParentObject required in WDF_OBJECT_ATTRIBUTES %p, %!STATUS!", + Attributes, STATUS_WDF_PARENT_NOT_SPECIFIED); + + return STATUS_WDF_PARENT_NOT_SPECIFIED; + } + + // Enum range checks + if ((Attributes->ExecutionLevel == WdfExecutionLevelInvalid) || + (Attributes->ExecutionLevel > WdfExecutionLevelDispatch)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p execution level set to %d, out of range, %!STATUS!", + Attributes, Attributes->ExecutionLevel, + STATUS_WDF_OBJECT_ATTRIBUTES_INVALID); + return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + } + + if ((Attributes->SynchronizationScope == WdfSynchronizationScopeInvalid) || + (Attributes->SynchronizationScope > WdfSynchronizationScopeNone)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p synchronization scope set to %d, out of range, %!STATUS!", + Attributes, Attributes->SynchronizationScope, + STATUS_WDF_OBJECT_ATTRIBUTES_INVALID); + return STATUS_WDF_OBJECT_ATTRIBUTES_INVALID; + } + + if ((Flags & FX_VALIDATE_OPTION_SYNCHRONIZATION_SCOPE_ALLOWED) == 0) { + + // + // If synchronization is not allowed for this object, + // check the requested level to ensure none was specified. + // + if ((Attributes->SynchronizationScope != WdfSynchronizationScopeInheritFromParent) && + (Attributes->SynchronizationScope != WdfSynchronizationScopeNone)) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p does not allow synchronization scope too be set, " + "but was set to %!WDF_SYNCHRONIZATION_SCOPE!, %!STATUS!", + Attributes, Attributes->SynchronizationScope, + STATUS_WDF_SYNCHRONIZATION_SCOPE_INVALID); + + return STATUS_WDF_SYNCHRONIZATION_SCOPE_INVALID; + } + } + + if ((Flags & FX_VALIDATE_OPTION_EXECUTION_LEVEL_ALLOWED) == 0) { + + // + // If execution level restrictions are not allowed for this object, + // check the requested level to ensure none was specified. + // + if (Attributes->ExecutionLevel != WdfExecutionLevelInheritFromParent) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Attributes %p does not allow execution level to be set, but was" + " set to %!WDF_EXECUTION_LEVEL!, %!STATUS!", + Attributes, Attributes->ExecutionLevel, + STATUS_WDF_EXECUTION_LEVEL_INVALID); + + return STATUS_WDF_EXECUTION_LEVEL_INVALID; + } + } + + return STATUS_SUCCESS; +} diff --git a/sdk/lib/drivers/wdf/shared/object/fxverifierbugcheck.cpp b/sdk/lib/drivers/wdf/shared/object/fxverifierbugcheck.cpp new file mode 100644 index 00000000000..2fcffcbd0c4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxverifierbugcheck.cpp @@ -0,0 +1,107 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxVerifierBugcheck.cpp + +Abstract: + + This file contains definitions of verifier bugcheck functions + These definitions are split from tracing.cpp in kmdf\src\core + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "fxobjectpch.hpp" + +// We use DoTraceMessage +extern "C" { +#if defined(EVENT_TRACING) +#include "FxVerifierBugcheck.tmh" +#endif +} + +//============================================================================= +// +//============================================================================= + + +VOID +__declspec(noreturn) +FxVerifierBugCheckWorker( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDF_BUGCHECK_CODES WdfBugCheckCode, + __in_opt ULONG_PTR BugCheckParameter2, + __in_opt ULONG_PTR BugCheckParameter3 + ) +/*++ + +Routine Description: + Wrapper for system BugCheck. + + Note this functions is marked "__declspec(noreturn)" + +Arguments: + +Returns: + +--*/ +{ + // + // Indicate to the BugCheck callback filter which IFR to dump. + // + FxDriverGlobals->FxForceLogsInMiniDump = TRUE; + + Mx::MxBugCheckEx(WDF_VIOLATION, + WdfBugCheckCode, + BugCheckParameter2, + BugCheckParameter3, + (ULONG_PTR) FxDriverGlobals ); +} + +VOID +__declspec(noreturn) +FxVerifierNullBugCheck( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID ReturnAddress + ) +/*++ + +Routine Description: + + Calls KeBugCheckEx indicating a WDF DDI was passed a NULL parameter. + + Note this functions is marked "__declspec(noreturn)" + +Arguments: + +Returns: + +--*/ +{ + + DoTraceLevelMessage( FxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGERROR, + "NULL Required Parameter Passed to a DDI\n" + "FxDriverGlobals 0x%p", + FxDriverGlobals + ); + + FxVerifierBugCheck(FxDriverGlobals, + WDF_REQUIRED_PARAMETER_IS_NULL, // Bugcheck code. + 0, // Parameter 2 + (ULONG_PTR)ReturnAddress // Parameter 3 + ); +} diff --git a/sdk/lib/drivers/wdf/shared/object/fxverifierlock.cpp b/sdk/lib/drivers/wdf/shared/object/fxverifierlock.cpp new file mode 100644 index 00000000000..1ab7a401f8e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/fxverifierlock.cpp @@ -0,0 +1,1050 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxVerifierLock.cpp + +Abstract: + + This module contains the implementation of the verifier lock + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxVerifierLock.tmh" +#endif +} + +// +// Mapping table structure between Fx object types and lock orders +// +FxVerifierOrderMapping FxVerifierOrderTable[] = { + + // Table is defined in fx\inc\FxVerifierLock.hpp + FX_VERIFIER_LOCK_ENTRIES() +}; + +FxVerifierOrderMapping FxVerifierCallbackOrderTable[] = { + + // Table is defined in fx\inc\FxVerifierLock.hpp + FX_VERIFIER_CALLBACKLOCK_ENTRIES() +}; + +// +// Organization of verifier lock structures +// +// As locks are acquired, they are added to the head of a list of locks held +// by the current thread if equal, or higher than the lock +// at the current list head. +// +// The hierachy of locks acquired by a thread is seperate for dispatch level +// (spinlock) and passive level (mutex) locks. These locks can not be mixed +// since holding a mutex lock does not prevent a DPC from interrupting the +// thread and properly acquiring a spinlock, which could appear to be +// of an improper level, giving a false report. +// +// In order to prevent memory allocations (which can fail) when locks are +// acquired, each FxVerifierLock structure contains members required to chain +// locks that are held on a per thread basis. (m_OwnedLink) +// +// Since we have no way of knowing the number of unique PETHREADS that may +// be holding locks at any time, a fixed size hash table is allocated +// and PETHREAD values are hashed into it, with chaining allowed on +// each entry due to overflows and collisions. The storage required for +// the hash table entry and chain is also allocated as member fields +// of the FxVerifierLock class. (m_ThreadTableEntry) +// +// The hash table and its chained entries (m_ThreadTableEntry) is protected +// by a global spinlock, FxDriverGlobals->ThreadTableLock. +// +// When a lock is acquired, the current threads address is used to look up +// a FxVerifierThreadTableEntry for it in the hash table. +// +// If one does not exist, this is the start of a new chain of locks for this +// ETHREAD, and the m_ThreadTableEntry of the current lock being acquired +// is inserted into the hash table, and the new lock chain is started using +// either the +// FxVerifierThreadTableEntry::PerThreadPassiveLockList, or +// FxVerifierThreadTableEntry::PerThreadDispatchLockList. +// +// If an entry does exist, the current lock is added to the head of +// the list in the existing entry. +// +// On lock release, the lock is identified in the list of held locks, +// which may not be the head if release was out of order (this is allowed), +// and removed from the list. +// +// If the list of locks held by the current thread is NULL for both +// the passive and dispatch lists, the threads entry is removed from +// the hash table since the thread no longer holds any locks. +// +// If either of these lists is not NULL, then the entries in the +// current locks FxVerifierThreadTableEntry is copied into one +// of the other locks on the new list head and the hash table +// is updated to point to the new entry. +// +// This is because the released FxVerifierLock entry may be freed +// as a result of its containing data structure being run down. +// + +// +// Method Definitions +// + +// +// Called at Driver Frameworks init time +// +extern "C" +void +FxVerifierLockInitialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if( FxDriverGlobals->FxVerifierLock ) { + + FxDriverGlobals->ThreadTableLock.Initialize(); + + FxVerifierLock::AllocateThreadTable(FxDriverGlobals); + } + + return; +} + +// +// Called at Driver Frameworks is unloading +// +extern "C" +void +FxVerifierLockDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if( FxDriverGlobals->FxVerifierLock ) { + FxVerifierLock::FreeThreadTable(FxDriverGlobals); + + FxDriverGlobals->ThreadTableLock.Uninitialize(); + } + + return; +} + +VOID +FxVerifierLock::Lock( + __out PKIRQL PreviousIrql, + __in BOOLEAN AtDpc + ) +{ + MxThread curThread; + FxVerifierLock* head; + pFxVerifierThreadTableEntry perThreadList; + KIRQL oldIrql = PASSIVE_LEVEL; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + curThread = Mx::MxGetCurrentThread(); + + // + // First check to see if the lock is already + // owned. + // + // This check is race free since this can only be set + // to our thread from under the spinlock, and is cleared + // before release. + // + + if( m_OwningThread == curThread ) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGDEVICE, + "Thread 0x%p already owns lock 0x%p for object 0x%p, WDFOBJECT 0x%p", + curThread, this, m_ParentObject, m_ParentObject->GetObjectHandle()); + + FxVerifierBugCheck( FxDriverGlobals, + WDF_RECURSIVE_LOCK, + (ULONG_PTR) m_ParentObject->GetObjectHandle(), + (ULONG_PTR) this); + } + + if( m_UseMutex ) { + // Get the Mutex + Mx::MxEnterCriticalRegion(); + m_Mutex.AcquireUnsafe(); + + *PreviousIrql = Mx::MxGetCurrentIrql(); + } + else if (AtDpc) { + // Get the spinlock + m_Lock.AcquireAtDpcLevel(); + m_OldIrql = DISPATCH_LEVEL; + + *PreviousIrql = m_OldIrql; + } + else { + // Try to force a thread switch to catch synchronization errors + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + LARGE_INTEGER sleepTime; + + sleepTime.QuadPart = 0; + Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); + } + + // Get the spinlock using a local since KeAcquireSpinLock might use this + // var as temp space while spinning and we would then corrupt it if + // the owning thread used it in the middle of the spin. + // + m_Lock.Acquire(PreviousIrql); + m_OldIrql = *PreviousIrql; + } + + // Lock the verifier lists + if (m_UseMutex) { + FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); + } + else { + FxDriverGlobals->ThreadTableLock.AcquireAtDpcLevel(); + } + + m_OwningThread = curThread; + + // Get our per thread list from the thread table + perThreadList = FxVerifierLock::GetThreadTableEntry(curThread, this, FALSE); + if( perThreadList == NULL ) { + + if (m_UseMutex) { + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + } + else { + FxDriverGlobals->ThreadTableLock.ReleaseFromDpcLevel(); + } + + // Can't get an entry, so return + return; + } + + // + // There are seperately sorted lists for passive and dispatch + // level locks since dispatch level locks of a lower level can interrupt a + // higher passive level lock, giving a false report. + // + if( m_UseMutex ) { + head = perThreadList->PerThreadPassiveLockList; + } + else { + head = perThreadList->PerThreadDispatchLockList; + } + + if( head != NULL ) { + + // Validate current is > head + if( m_Order > head->m_Order ) { + m_OwnedLink = head; + //perThreadList->PerThreadLockList = this; + } + else if( m_Order == head->m_Order ) { + + // Place at head if the same lock level as current head + m_OwnedLink = head; + //perThreadList->PerThreadLockList = this; + } + else { + + // Lock violation, m_Order < head->m_Order + FxVerifierLock::DumpDetails(this, curThread, head); + + // + // Caller is feeling lucky and resumed so place it at the head + // to keep our lists intact + // + m_OwnedLink = head; + //perThreadList->PerThreadLockList = this; + } + } + else { + this->m_OwnedLink = NULL; + //perThreadList->PerThreadLockList = this; + } + + // + // Update to the next list head + // + if (m_UseMutex) { + perThreadList->PerThreadPassiveLockList = this; + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + } + else { + perThreadList->PerThreadDispatchLockList = this; + FxDriverGlobals->ThreadTableLock.ReleaseFromDpcLevel(); + } + + return; +} + +void +FxVerifierLock::Unlock( + __in KIRQL PreviousIrql, + __in BOOLEAN AtDpc + ) +{ + MxThread curThread; + pFxVerifierThreadTableEntry perThreadList; + KIRQL oldIrql; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + // Only from DISPATCH_LEVEL or below + curThread = Mx::MxGetCurrentThread(); + + if( curThread != m_OwningThread ) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Thread 0x%p Is Attempting to release a Lock 0x%p " + "for Object 0x%p it does not own!", + curThread,this,m_ParentObject); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return; + } + + // Lock the verifier lists + FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); + + // Get our per thread list from the thread table + perThreadList = FxVerifierLock::GetThreadTableEntry(m_OwningThread, this, TRUE); + if( perThreadList == NULL ) { + + // Can't get our entry, so release the spinlock and return + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Unlock: Can't get per thread entry for thread %p", + curThread); + + m_OwningThread = NULL; + + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + + if (m_UseMutex) { + m_Mutex.ReleaseUnsafe(); + Mx::MxLeaveCriticalRegion(); + } + else if (AtDpc) { + m_Lock.ReleaseFromDpcLevel(); + } + else { + m_Lock.Release(PreviousIrql); + + // Try to force a thread switch to catch synchronization errors + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + LARGE_INTEGER sleepTime; + + sleepTime.QuadPart = 0; + Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); + } + } + return; + } + + if( m_UseMutex ) { + if( perThreadList->PerThreadPassiveLockList == NULL ) { + // Problem with verifier + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Thread has entry, but no locks recorded as " + "held for passive!"); + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "this 0x%p, perThreadList 0x%p", + this, perThreadList); + FxVerifierDbgBreakPoint(FxDriverGlobals); + + m_OwningThread = NULL; + + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + + m_Mutex.ReleaseUnsafe(); + Mx::MxLeaveCriticalRegion(); + + return; + } + } + else { + if( perThreadList->PerThreadDispatchLockList == NULL ) { + // Problem with verifier + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Thread has entry, but no locks recorded as held " + "for dispatch!"); + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "this 0x%p, perThreadList 0x%p", + this, perThreadList); + FxVerifierDbgBreakPoint(FxDriverGlobals); + + m_OwningThread = NULL; + + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + + if (AtDpc) { + m_Lock.ReleaseFromDpcLevel(); + } + else { + m_Lock.Release(PreviousIrql); + + // Try to force a thread switch to catch synchronization errors + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + LARGE_INTEGER sleepTime; + + sleepTime.QuadPart = 0; + Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); + } + } + + return; + } + } + + if( m_UseMutex ) { + + // Common case is a nested release + if( perThreadList->PerThreadPassiveLockList == this ) { + + perThreadList->PerThreadPassiveLockList = this->m_OwnedLink; + m_OwnedLink = NULL; + + ReleaseOrReplaceThreadTableEntry(curThread, this); + + + + + + + + + + + + + + + + + + + + + + + } + else { + // + // Releasing out of order does not deadlock as + // long as all acquires are in order, but its + // not commmon + // + FxVerifierLock* next; + FxVerifierLock* prev = NULL; + + // Skip the first entry checked by the above if + prev = perThreadList->PerThreadPassiveLockList; + next = perThreadList->PerThreadPassiveLockList->m_OwnedLink; + + while( next != NULL ) { + + if( next == this ) { + prev->m_OwnedLink = m_OwnedLink; + m_OwnedLink = NULL; + + // + // The perThreadList entry may, or may not be the + // data structure in this lock. Sinse we are releasing + // the lock, this entry can no longer be referenced if + // so. + // + ReleaseOrReplaceThreadTableEntry(curThread, this); + +// FxVerifierLock::ReplaceThreadTableEntry(curThread, this, perThreadList->PerThreadPassiveLockList); + + break; + } + + prev = next; + next = next->m_OwnedLink; + } + + if( next == NULL ) { + // Somehow the entry is gone + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Record entry for VerifierLock 0x%p is missing " + "on list 0x%p for Thread 0x%p", + this,perThreadList,m_OwningThread); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + } + } + else { + + // Common case is a nested release + if( perThreadList->PerThreadDispatchLockList == this ) { + + perThreadList->PerThreadDispatchLockList = this->m_OwnedLink; + m_OwnedLink = NULL; + + ReleaseOrReplaceThreadTableEntry(curThread, this); + + + + + + + + + + + + + + + + + + + + + + + } + else { + // + // Releasing out of order does not deadlock as + // long as all acquires are in order, but its + // not commmon + // + FxVerifierLock* next; + FxVerifierLock* prev = NULL; + + // Skip the first entry checked by the above if + prev = perThreadList->PerThreadDispatchLockList; + next = perThreadList->PerThreadDispatchLockList->m_OwnedLink; + + while( next != NULL ) { + + if( next == this ) { + prev->m_OwnedLink = m_OwnedLink; + m_OwnedLink = NULL; + + // + // The perThreadList entry may, or may not be the + // data structure in this lock. Sinse we are releasing + // the lock, this entry can no longer be referenced if + // so. + // + ReleaseOrReplaceThreadTableEntry(curThread, this); + +// FxVerifierLock::ReplaceThreadTableEntry(curThread, this, perThreadList->PerThreadDispatchLockList); + + break; + } + + prev = next; + next = next->m_OwnedLink; + } + + if( next == NULL ) { + // Somehow the entry is gone + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Record entry for VerifierLock 0x%p is missing " + "on list 0x%p for Thread 0x%p", + this,perThreadList,m_OwningThread); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + } + + } + + m_OwningThread = NULL; + + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + + if (m_UseMutex) { + m_Mutex.ReleaseUnsafe(); + Mx::MxLeaveCriticalRegion(); + } + else if (AtDpc) { + m_Lock.ReleaseFromDpcLevel(); + } + else { + m_Lock.Release(PreviousIrql); + + // Try to force a thread switch to catch synchronization errors + if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { + LARGE_INTEGER sleepTime; + + sleepTime.QuadPart = 0; + Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); + } + } + + return; +} + +KIRQL +FxVerifierLock::GetLockPreviousIrql() +{ + return m_OldIrql; +} + +void +FxVerifierLock::InitializeLockOrder() +{ + USHORT ObjectType; + pFxVerifierOrderMapping p; + + PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); + + ObjectType = m_ParentObject->GetType(); + + if( m_CallbackLock ) { + p = FxVerifierCallbackOrderTable; + } + else { + p = FxVerifierOrderTable; + } + + while( p->ObjectType != 0 ) { + + if( p->ObjectType == ObjectType ) { + m_Order = p->ObjectLockOrder; + return; + } + + p++; + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Object Type 0x%x does not have a lock order " + "defined in fx\\inc\\FxVerifierLock.hpp", + ObjectType); + + m_Order = FX_LOCK_ORDER_UNKNOWN; + + return; +} + +// +// This looks up the supplied thread in the table, and if +// found returns it. +// +// If no entry for the thread is found, create one using the +// m_ThreadTableEntry for the lock. +// +pFxVerifierThreadTableEntry +FxVerifierLock::GetThreadTableEntry( + __in MxThread curThread, + __in FxVerifierLock* pLock, + __in BOOLEAN LookupOnly + ) +{ + ULONG Hash, Index; + PLIST_ENTRY head, next; + FxVerifierLock* entry; + + PFX_DRIVER_GLOBALS FxDriverGlobals = pLock->GetDriverGlobals(); + + // Verifier is off, or an early memory allocation failure + if( FxDriverGlobals->ThreadTable == NULL ) { + return NULL; + } + + // + // Hash the KeCurrentThread() information into an table + // index. + // + // Hash takes into account that NT pool items don't use + // the lower 4 bits (16 byte boundries) + // + + Hash = (ULONG)((ULONG_PTR)curThread >> 4); + Hash = ((Hash >> 16) & 0x0000FFFF) ^ (Hash & 0x0000FFFF); + + // + // Hash table is maintained as a power of two + // + Index = Hash & (VERIFIER_THREAD_HASHTABLE_SIZE-1); + + head = &FxDriverGlobals->ThreadTable[Index]; + + // + // Walk the list to see if our thread has an entry + // + next = head->Flink; + while( next != head ) { + entry = CONTAINING_RECORD(next, FxVerifierLock, m_ThreadTableEntry.HashChain); + + if( entry->m_ThreadTableEntry.Thread == curThread ) { + + //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + // "Returning existing Entry 0x%p for Thread 0x%p, " + // "Lock 0x%p", + // &entry->m_ThreadTableEntry, curThread, pLock); + + return &entry->m_ThreadTableEntry; + } + + next = next->Flink; + } + + if( LookupOnly ) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Thread 0x%p does not have an entry",curThread); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return NULL; + } + + // + // The current ETHREAD has no locks it currently holds, so it has + // no entry in the hash table. + // + // Use the supplied locks m_ThreadTableEntry to create an entry + // for this ETHREAD and the start of a new list of held locks. + // + pLock->m_ThreadTableEntry.Thread = curThread; + pLock->m_ThreadTableEntry.PerThreadPassiveLockList = NULL; + pLock->m_ThreadTableEntry.PerThreadDispatchLockList = NULL; + + InsertTailList(head, &pLock->m_ThreadTableEntry.HashChain); + +// DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, +// "Returning new Entry 0x%p for Thread 0x%p, Lock 0x%p", +// &pLock->m_ThreadTableEntry, curThread, pLock); + + return &pLock->m_ThreadTableEntry; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void +FxVerifierLock::ReleaseOrReplaceThreadTableEntry( + __in MxThread curThread, + __in FxVerifierLock* pLock + ) + +/*++ + +Routine Description: + + Removes the use of the supplied locks m_ThreadTableEntry by + either releasing it if the ETHREAD is holding no more locks, + or by copying it to the m_ThreadTableEntry of another lock + held by the thread. + +Arguments: + + curThread - Thread who is holding lock + + pLock - Lock whose m_ThreadTableEntry is to be released + +Returns: + + +Comments: + + This is called with the verifier hash table lock held + FxDriverGlobals->ThreadTableLock. + + The pLock has already been removed from the held locks chain, + so the lock at the head of the list can be used for the new hash + table entry. + +--*/ + +{ + ULONG Hash, Index; + PLIST_ENTRY head; + FxVerifierLock* pNewLock = NULL; + + PFX_DRIVER_GLOBALS FxDriverGlobals = pLock->GetDriverGlobals(); + + if( pLock->m_ThreadTableEntry.Thread == NULL ) { + + // This locks entry is not used for hash chaining + //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + // "Entry 0x%p Not currently part of the hash chain", + // pLock); + + return; + } + + // It should be the current thread + if( pLock->m_ThreadTableEntry.Thread != curThread ) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "OldEntry Thread 0x%p not Current! 0x%p", + pLock,curThread); + FxVerifierDbgBreakPoint(FxDriverGlobals); + } + + Hash = (ULONG)((ULONG_PTR)curThread >> 4); + Hash = ((Hash >> 16) & 0x0000FFFF) ^ (Hash & 0x0000FFFF); + + Index = Hash & (VERIFIER_THREAD_HASHTABLE_SIZE-1); + + head = &FxDriverGlobals->ThreadTable[Index]; + + // Remove old entry + RemoveEntryList(&pLock->m_ThreadTableEntry.HashChain); + + // + // If both lock lists are NULL, we can just release the entry + // + if( (pLock->m_ThreadTableEntry.PerThreadPassiveLockList == NULL) && + (pLock->m_ThreadTableEntry.PerThreadDispatchLockList == NULL) ) { + + //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + // "Releasing entry for lock 0x%p for Thread 0x%p", + // pLock, curThread); + + // This is now an unused entry + pLock->m_ThreadTableEntry.Thread = NULL; + pLock->m_ThreadTableEntry.PerThreadPassiveLockList = NULL; + pLock->m_ThreadTableEntry.PerThreadDispatchLockList = NULL; + + return; + } + + //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + // "Replacing Lock 0x%p, for Thread 0x%p", + // pLock, curThread); + if( pLock->m_ThreadTableEntry.PerThreadPassiveLockList != NULL ) { + pNewLock = pLock->m_ThreadTableEntry.PerThreadPassiveLockList; + } + else { + pNewLock = pLock->m_ThreadTableEntry.PerThreadDispatchLockList; + } + + ASSERT(pNewLock != NULL); + ASSERT(pNewLock->m_ThreadTableEntry.Thread == NULL); + ASSERT(pNewLock->m_ThreadTableEntry.PerThreadPassiveLockList == NULL); + ASSERT(pNewLock->m_ThreadTableEntry.PerThreadDispatchLockList == NULL); + + // Copy the old lock structures table to the next one + pNewLock->m_ThreadTableEntry.Thread = pLock->m_ThreadTableEntry.Thread; + pNewLock->m_ThreadTableEntry.PerThreadPassiveLockList = pLock->m_ThreadTableEntry.PerThreadPassiveLockList; + pNewLock->m_ThreadTableEntry.PerThreadDispatchLockList = pLock->m_ThreadTableEntry.PerThreadDispatchLockList; + + // Insert new entry at the end of thelist + InsertTailList(head, &pNewLock->m_ThreadTableEntry.HashChain); + + return; +} + +void +FxVerifierLock::AllocateThreadTable( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + KIRQL oldIrql; + ULONG newEntries; + PLIST_ENTRY newTable; + + FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); + + if( FxDriverGlobals->ThreadTable != NULL ) { + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + return; + } + + // Table must be kept as a power of 2 for hash algorithm + newEntries = VERIFIER_THREAD_HASHTABLE_SIZE; + + newTable = (PLIST_ENTRY) FxPoolAllocateWithTag( + FxDriverGlobals, + NonPagedPool, + sizeof(LIST_ENTRY) * newEntries, + FxDriverGlobals->Tag); + + if( newTable == NULL ) { + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "No Memory to allocate thread table"); + return; + } + + for(ULONG index=0; index < newEntries; index++ ) { + InitializeListHead(&newTable[index]); + } + + FxDriverGlobals->ThreadTable = newTable; + + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + + return; +} + +void +FxVerifierLock::FreeThreadTable( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + KIRQL oldIrql; + + UNREFERENCED_PARAMETER(FxDriverGlobals); + + FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); + + if( FxDriverGlobals->ThreadTable == NULL ) { + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + return; + } + + FxPoolFree(FxDriverGlobals->ThreadTable); + + FxDriverGlobals->ThreadTable = NULL; + + FxDriverGlobals->ThreadTableLock.Release(oldIrql); + + return; +} + +void +FxVerifierLock::DumpDetails( + __in FxVerifierLock* Lock, + __in MxThread curThread, + __in FxVerifierLock* PerThreadList + ) +{ + PFX_DRIVER_GLOBALS FxDriverGlobals = Lock->GetDriverGlobals(); + + FxVerifierLock* next; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Thread 0x%p Attempted to acquire lock on Object 0x%p, " + "ObjectType 0x%x, at Level 0x%x out of sequence.", + curThread,Lock->m_ParentObject, + Lock->m_ParentObject->GetType(), + Lock->m_Order); + + next = PerThreadList; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Highest Lock Currently held is level 0x%x for " + "Object 0x%p, ObjectType 0x%x", + next->m_Order, + next->m_ParentObject, + next->m_ParentObject->GetType()); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "List of Already Acquired Locks and Objects:"); + + while( next != NULL ) { + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Object 0x%p, ObjectType 0x%x, LockLevel 0x%x", + next->m_ParentObject, + next->m_ParentObject->GetType(), + next->m_Order); + + next = next->m_OwnedLink; + } + + FxVerifierDbgBreakPoint(FxDriverGlobals); + + return; +} + + diff --git a/sdk/lib/drivers/wdf/shared/object/globals.cpp b/sdk/lib/drivers/wdf/shared/object/globals.cpp new file mode 100644 index 00000000000..fcc0815be17 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/globals.cpp @@ -0,0 +1,1740 @@ + +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + globals.cpp + +Abstract: + + This contains all Driver Frameworks configuration globals. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + + + + + + + + +--*/ + + +#include "fxobjectpch.hpp" + +// Tracing support +extern "C" { +#if defined(EVENT_TRACING) +#include "globals.tmh" +#endif +} + +extern "C" { + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +VOID +VerifierPageLockHandle ( + VOID + ); +#ifdef ALLOC_PRAGMA +#pragma alloc_text(WDF_FX_VF_SECTION_NAME, VerifierPageLockHandle) +#endif +#endif + +// +// Private methods. +// + +VOID +FxLibraryGlobalsQueryRegistrySettings( + VOID + ); + +VOID +FxRegistrySettingsInitialize( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath, + __in BOOLEAN WindowsVerifierOn + ); + +_Must_inspect_result_ +FxObjectDebugInfo* +FxVerifierGetObjectDebugInfo( + __in HANDLE Key, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); + +VOID +FxVerifierQueryTrackPower( + __in HANDLE Key, + __out FxTrackPowerOption* TrackPower + ); + +// +// Global allocation tracker +// +FX_POOL FxPoolFrameworks; + +FxLibraryGlobalsType FxLibraryGlobals = { 0 }; + +// +// These are defined in FxObjectInfo.cpp to account for the facts that +// 1. FxObjectInfo array is different for UMDF and KMDF, +// 2. and not all the types are available in the common code +// +extern const FX_OBJECT_INFO FxObjectsInfo[]; +extern ULONG FxObjectsInfoCount; + +// +// Prevent compiler/linker/BBT from optimizing the global variable away +// +#if defined(_M_IX86) +#pragma comment(linker, "/include:_FxObjectsInfoCount") +#else +#pragma comment(linker, "/include:FxObjectsInfoCount") +#endif + + +_Must_inspect_result_ +BOOLEAN +FxVerifyObjectTypeInTable( + __in USHORT ObjectType + ) +{ + ULONG i; + + for (i = 0; i < FxObjectsInfoCount; i++) { + if (ObjectType == FxObjectsInfo[i].ObjectType) { + return TRUE; + } + else if (ObjectType > FxObjectsInfo[i].ObjectType) { + continue; + } + + return FALSE; + } + + return FALSE; +} + +_Must_inspect_result_ +FxObjectDebugInfo* +FxVerifyAllocateDebugInfo( + __in LPWSTR HandleNameList, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + +/*++ + +Routine Description: + Allocates an array of FxObjectDebugInfo's. The length of this array is the + same length as FxObjectsInfo. The array is sorted the same as + FxObjectDebugInfo, ObjectInfo is ascending in the list. + + If HandleNameList's first string is "*", we treat this as a wildcard and + track all external handles. + +Arguments: + HandleNameList - a multi-sz of handle names. It is assumed the multi sz is + well formed. + +Return Value: + a pointer allocated by ExAllocatePoolWithTag. The caller is responsible for + eventually freeing the pointer by calling ExFreePool. + +--*/ + +{ + FxObjectDebugInfo* pInfo; + PWCHAR pCur; + ULONG i, length; + BOOLEAN all; + + // + // check to see if the multi sz is empty + // + if (*HandleNameList == NULL) { + return NULL; + } + + length = sizeof(FxObjectDebugInfo) * FxObjectsInfoCount; + + // + // Freed with ExFreePool in FxFreeDriverGlobals. Must be non paged because + // objects can be allocated at IRQL > PASSIVE_LEVEL. + // + pInfo = (FxObjectDebugInfo*) MxMemory::MxAllocatePoolWithTag(NonPagedPool, + length, + FxDriverGlobals->Tag); + + if (pInfo == NULL) { + return NULL; + } + + all = *HandleNameList == L'*' ? TRUE : FALSE; + + RtlZeroMemory(pInfo, length); + + // + // Iterate over all of the objects in our internal array. We iterate over + // this array instead of the multi sz list b/c this way we only convert + // each ANSI string to UNICODE once. + // + for (i = 0; i < FxObjectsInfoCount; i++) { + UNICODE_STRING objectName; + WCHAR ubuffer[40]; + STRING string; + + pInfo[i].ObjectType = FxObjectsInfo[i].ObjectType; + + // + // If this is an internal object, just continue past it + // + if (FxObjectsInfo[i].HandleName == NULL) { + continue; + } + + // + // Short circuit if we are wildcarding + // + if (all) { + pInfo[i].u.DebugFlags |= FxObjectDebugTrackReferences; + continue; + } + + RtlInitAnsiString(&string, FxObjectsInfo[i].HandleName); + + RtlZeroMemory(ubuffer, sizeof(ubuffer)); + objectName.Buffer = ubuffer; + objectName.Length = 0; + objectName.MaximumLength = sizeof(ubuffer); + + // + // Conversion failed, just continue. Failure is not critical to + // returning the list. + // + if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&objectName, + &string, + FALSE))) { + continue; + } + + // + // Now iterate over the multi sz list, comparing handle strings in the + // list against the current object name. + // + pCur = HandleNameList; + + while (*pCur != UNICODE_NULL) { + UNICODE_STRING handleName; + + RtlInitUnicodeString(&handleName, pCur); + + // + // Increment to the next string now. Add one so that we skip past + // terminating null for this sz as well. + // Length is the number of bytes, not the number of characters. + // + pCur += handleName.Length / sizeof(WCHAR) + 1; + + // + // Case insensitive compare + // + if (RtlCompareUnicodeString(&handleName, &objectName, TRUE) == 0) { + pInfo[i].u.DebugFlags |= FxObjectDebugTrackReferences; + break; + } + } + } + + return pInfo; +} + +VOID +FxDriverGlobalsInitializeDebugExtension( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt HANDLE Key + ) +{ + FxDriverGlobalsDebugExtension* pExtension; + + // + // The wdf subkey may not be present for inbox drivers that do not use inf. + // Since Mdl tracking doen't need regsitry info we go ahead and allocate + // debug extension for use in Mdl tracking. Tag tracker depends on registry + // info and it won't be available if registry info is not present. + // + + pExtension = (FxDriverGlobalsDebugExtension*) MxMemory::MxAllocatePoolWithTag( + NonPagedPool, sizeof(FxDriverGlobalsDebugExtension), FxDriverGlobals->Tag); + + if (pExtension == NULL) { + return; + } + + RtlZeroMemory(pExtension, sizeof(*pExtension)); + + pExtension->AllocatedTagTrackersLock.Initialize(); + + InitializeListHead(&pExtension->AllocatedTagTrackersListHead); + + pExtension->TrackPower = FxTrackPowerNone; + + FxDriverGlobals->DebugExtension = pExtension; + + if (Key != NULL) { + pExtension->ObjectDebugInfo = FxVerifierGetObjectDebugInfo( + Key, + FxDriverGlobals + ); + FxVerifierQueryTrackPower(Key, &pExtension->TrackPower); + } + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + KeInitializeSpinLock(&pExtension->AllocatedMdlsLock); +#endif +} + +PCSTR +FxObjectTypeToHandleName( + __in WDFTYPE ObjectType + ) +{ + ULONG i; + + for (i = 0; i < FxObjectsInfoCount; i++) { + if (ObjectType == FxObjectsInfo[i].ObjectType) { + return FxObjectsInfo[i].HandleName; + } + else if (ObjectType > FxObjectsInfo[i].ObjectType) { + continue; + } + + return NULL; + } + + return NULL; +} + +_Must_inspect_result_ +BOOLEAN +FxVerifierGetTrackReferences( + __in FxObjectDebugInfo* DebugInfo, + __in WDFTYPE ObjectType + ) + +/*++ + +Routine Description: + For a given object type, returns to the caller if it should track references + to the object. + +Arguments: + DebugInfo - array of object debug info to search through + ObjectType - the type of the object to check + +Return Value: + TRUE if references should be tracked, FALSE otherwise + +--*/ + +{ + ULONG i; + + // + // Array size of DebugInfo is the same size as FxObjectsInfo + // + for (i = 0; i < FxObjectsInfoCount; i++) { + if (ObjectType == DebugInfo[i].ObjectType) { + return FLAG_TO_BOOL(DebugInfo[i].u.DebugFlags, + FxObjectDebugTrackReferences); + } + else if (ObjectType > FxObjectsInfo[i].ObjectType) { + continue; + } + + return FALSE; + } + + return FALSE; +} + + +VOID +FxVerifyObjectTableIsSorted( + VOID + ) +{ + ULONG i; + USHORT prevType; + + prevType = FxObjectsInfo[0].ObjectType; + + for (i = 1; i < FxObjectsInfoCount; i++) { + if (prevType >= FxObjectsInfo[i].ObjectType) { + ASSERTMSG("FxObjectsInfo table is not in sorted order\n", + prevType < FxObjectsInfo[i].ObjectType); + } + + prevType = FxObjectsInfo[i].ObjectType; + } +} + +typedef +NTSTATUS +(*PFN_RTL_GET_VERSION)( + __out PRTL_OSVERSIONINFOW VersionInformation + ); + +typedef +NTSTATUS +(*PFN_RTL_VERIFY_VERSION_INFO)( + __in PRTL_OSVERSIONINFOEXW VersionInfo, + __in ULONG TypeMask, + __in ULONGLONG ConditionMask + ); + +typedef +ULONGLONG +(*PFN_VER_SET_CONDITION_MASK)( + __in ULONGLONG ConditionMask, + __in ULONG TypeMask, + __in UCHAR Condition + ); + +VOID +FxLibraryGlobalsVerifyVersion( + VOID + ) +{ + RTL_OSVERSIONINFOEXW info; + PFN_RTL_VERIFY_VERSION_INFO pRtlVerifyVersionInfo; + PFN_VER_SET_CONDITION_MASK pVerSetConditionMask; + ULONGLONG condition; + NTSTATUS status; + + pRtlVerifyVersionInfo = (PFN_RTL_VERIFY_VERSION_INFO) + Mx::MxGetSystemRoutineAddress(MAKE_MX_FUNC_NAME("RtlVerifyVersionInfo")); + + if (pRtlVerifyVersionInfo == NULL) { + return; + } + + pVerSetConditionMask = (PFN_VER_SET_CONDITION_MASK) + Mx::MxGetSystemRoutineAddress(MAKE_MX_FUNC_NAME("VerSetConditionMask")); + + // + // Check for Win8 (6.2) and later for passive-level interrupt support. + // + RtlZeroMemory(&info, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); + info.dwMajorVersion = 6; + info.dwMinorVersion = 2; + + condition = 0; + condition = pVerSetConditionMask(condition, VER_MAJORVERSION, VER_GREATER_EQUAL); + condition = pVerSetConditionMask(condition, VER_MINORVERSION, VER_GREATER_EQUAL); + + status = pRtlVerifyVersionInfo(&info, + VER_MAJORVERSION | VER_MINORVERSION, + condition); + if (NT_SUCCESS(status)) { + FxLibraryGlobals.PassiveLevelInterruptSupport = TRUE; + } +} + +VOID +FxLibraryGlobalsQueryRegistrySettings( + VOID + ) +{ + FxAutoRegKey hWdf; + NTSTATUS status = STATUS_SUCCESS; + DECLARE_CONST_UNICODE_STRING(path, WDF_REGISTRY_BASE_PATH); + DECLARE_CONST_UNICODE_STRING(ifrDisabledName, WDF_GLOBAL_VALUE_IFRDISABLED); + ULONG ifrDisabled = 0; + + status = FxRegKey::_OpenKey(NULL, &path, &hWdf.m_Key, KEY_READ); + if (!NT_SUCCESS(status)) { + goto exit; + } + + status = FxRegKey::_QueryULong(hWdf.m_Key, &ifrDisabledName, &ifrDisabled); + if (!NT_SUCCESS(status)) { + goto exit; + } + + if (ifrDisabled == 1) { + FxLibraryGlobals.IfrDisabled = TRUE; + } + +exit: + return; +} + +_Must_inspect_result_ +NTSTATUS +FxLibraryGlobalsCommission( + VOID + ) +{ + PFN_RTL_GET_VERSION pRtlGetVersion; + NTSTATUS status; + + // + // Global initialization for mode-agnostic primitives library + // + Mx::MxGlobalInit(); + + + + + + + + + + + + + + + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + FxLibraryGlobals.IsUserModeFramework = FALSE; +#else + FxLibraryGlobals.IsUserModeFramework = TRUE; +#endif + + // + // IFR is enabled by default + // + FxLibraryGlobals.IfrDisabled = FALSE; + + // + // Query global WDF settings (both KMDF and UMDF). + // + FxLibraryGlobalsQueryRegistrySettings(); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + UNICODE_STRING funcName; + + // For DSF support. + RtlInitUnicodeString(&funcName, L"IoConnectInterruptEx"); + FxLibraryGlobals.IoConnectInterruptEx = (PFN_IO_CONNECT_INTERRUPT_EX) + MmGetSystemRoutineAddress(&funcName); + + RtlInitUnicodeString(&funcName, L"IoDisconnectInterruptEx"); + FxLibraryGlobals.IoDisconnectInterruptEx = (PFN_IO_DISCONNECT_INTERRUPT_EX) + MmGetSystemRoutineAddress(&funcName); + + // 32 bit: W2k and forward. + // 64 bit: W2k -> Windows Server 2008 (obsolete otherwise). + RtlInitUnicodeString(&funcName, L"KeQueryActiveProcessors"); + FxLibraryGlobals.KeQueryActiveProcessors = (PFN_KE_QUERY_ACTIVE_PROCESSORS) + MmGetSystemRoutineAddress(&funcName); + + RtlInitUnicodeString(&funcName, L"KeSetTargetProcessorDpc"); + FxLibraryGlobals.KeSetTargetProcessorDpc = (PFN_KE_SET_TARGET_PROCESSOR_DPC) + MmGetSystemRoutineAddress(&funcName); + + // These should always be there (obsolete in 64 bit Win 7 and forward). + ASSERT(FxLibraryGlobals.KeQueryActiveProcessors != NULL && + FxLibraryGlobals.KeSetTargetProcessorDpc != NULL); + + // Win 7 and forward. + RtlInitUnicodeString(&funcName, L"KeQueryActiveGroupCount"); + if (MmGetSystemRoutineAddress(&funcName) != NULL) { + FxLibraryGlobals.ProcessorGroupSupport = TRUE; + } + + // Win 7 and forward. + RtlInitUnicodeString(&funcName, L"KeSetCoalescableTimer"); + FxLibraryGlobals.KeSetCoalescableTimer = (PFN_KE_SET_COALESCABLE_TIMER) + MmGetSystemRoutineAddress(&funcName); + + // Win 7 and forward. + RtlInitUnicodeString(&funcName, L"IoUnregisterPlugPlayNotificationEx"); + FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx = (PFN_IO_UNREGISTER_PLUGPLAY_NOTIFICATION_EX) + MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxRegisterDevice"); + FxLibraryGlobals.PoxRegisterDevice = + (PFN_POX_REGISTER_DEVICE) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxStartDevicePowerManagement"); + FxLibraryGlobals.PoxStartDevicePowerManagement = + (PFN_POX_START_DEVICE_POWER_MANAGEMENT) + MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxUnregisterDevice"); + FxLibraryGlobals.PoxUnregisterDevice = + (PFN_POX_UNREGISTER_DEVICE) + MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxActivateComponent"); + FxLibraryGlobals.PoxActivateComponent = (PFN_POX_ACTIVATE_COMPONENT) + MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxIdleComponent"); + FxLibraryGlobals.PoxIdleComponent = (PFN_POX_IDLE_COMPONENT) + MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxReportDevicePoweredOn"); + FxLibraryGlobals.PoxReportDevicePoweredOn = + (PFN_POX_REPORT_DEVICE_POWERED_ON) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxCompleteIdleState"); + FxLibraryGlobals.PoxCompleteIdleState = + (PFN_POX_COMPLETE_IDLE_STATE) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxCompleteIdleCondition"); + FxLibraryGlobals.PoxCompleteIdleCondition = + (PFN_POX_COMPLETE_IDLE_CONDITION) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxCompleteDevicePowerNotRequired"); + FxLibraryGlobals.PoxCompleteDevicePowerNotRequired = + (PFN_POX_COMPLETE_DEVICE_POWER_NOT_REQUIRED) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"PoFxSetDeviceIdleTimeout"); + FxLibraryGlobals.PoxSetDeviceIdleTimeout = + (PFN_POX_SET_DEVICE_IDLE_TIMEOUT) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"IoReportInterruptActive"); + FxLibraryGlobals.IoReportInterruptActive = + (PFN_IO_REPORT_INTERRUPT_ACTIVE) MmGetSystemRoutineAddress(&funcName); + + // Win 8 and forward + RtlInitUnicodeString(&funcName, L"IoReportInterruptInactive"); + FxLibraryGlobals.IoReportInterruptInactive = + (PFN_IO_REPORT_INTERRUPT_INACTIVE) MmGetSystemRoutineAddress(&funcName); + + // Win 8.2 and forward + RtlInitUnicodeString(&funcName, L"VfCheckNxPoolType"); + FxLibraryGlobals.VfCheckNxPoolType = + (PFN_VF_CHECK_NX_POOL_TYPE) MmGetSystemRoutineAddress(&funcName); + +#endif //((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + + FxLibraryGlobals.OsVersionInfo.dwOSVersionInfoSize = sizeof(FxLibraryGlobals.OsVersionInfo); + + // User/Kernel agnostic. + + pRtlGetVersion = (PFN_RTL_GET_VERSION) + Mx::MxGetSystemRoutineAddress(MAKE_MX_FUNC_NAME("RtlGetVersion")); + + ASSERT(pRtlGetVersion != NULL); + pRtlGetVersion((PRTL_OSVERSIONINFOW) &FxLibraryGlobals.OsVersionInfo); + FxLibraryGlobalsVerifyVersion(); + + // + // Initialize power management-related stuff. + // + RtlZeroMemory(&FxLibraryGlobals.MachineSleepStates[0], + sizeof(FxLibraryGlobals.MachineSleepStates)); + + // + // Insure that the FxObject is layed-up correctly. + // + FxVerifyObjectTableIsSorted(); + + // + // Initialize the list of FxDriverGlobals. + // This is essentially the list of drivers on this WDF version. + // + InitializeListHead(&FxLibraryGlobals.FxDriverGlobalsList); + FxLibraryGlobals.FxDriverGlobalsListLock.Initialize(); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // Register for the global (library) bugcheck callbacks. + // + FxInitializeBugCheckDriverInfo(); + + // + // Init driver usage tracker. This tracker is used by the debug dump + // callback routines for finding the driver's dump log file to write + // in the minidump. Ignore any tracker's errors. + // + (VOID)FxLibraryGlobals.DriverTracker.Initialize(); + + // + // Initialize enhanced-verifier section handle + // + FxLibraryGlobals.VerifierSectionHandle = NULL; + FxLibraryGlobals.VerifierSectionHandleRefCount = 0; + + // + // Retrieve a pointer to the data structure that cotains trace routines + // corresponding to WdfNotifyRoutinesClass from the SystemTraceProvider + // that we'll use for perf tracing of WDF operations. The trace + // routines inside the structuyre are present only when tracing is enabled + // by some trace client (e.g. tracelog or xperf) for WDF specific perf + // groups. Note that no unregistration is necessary. + // + status = WmiQueryTraceInformation(WdfNotifyRoutinesClass, + &FxLibraryGlobals.PerfTraceRoutines, + sizeof(PWMI_WDF_NOTIFY_ROUTINES), + NULL, + NULL); + + if (!NT_SUCCESS(status)) { + // + // WDF trace routines are available only on win8+, so failure is + // expected on pre-Win8 OS. Use the dummy routines on failure. + // + RtlZeroMemory(&FxLibraryGlobals.DummyPerfTraceRoutines, + sizeof(WMI_WDF_NOTIFY_ROUTINES)); + FxLibraryGlobals.DummyPerfTraceRoutines.Size = + sizeof(WMI_WDF_NOTIFY_ROUTINES); + FxLibraryGlobals.PerfTraceRoutines = + &FxLibraryGlobals.DummyPerfTraceRoutines; + status = STATUS_SUCCESS; + } + + // + // The Size member of WMI_WDF_NOTIFY_ROUTINES allows versioning. When + // the WMI_WDF_NOTIFY_ROUTINES structure is revised with additional + // members in future OS versions, the Size member will allow validating + // the various versions, and initializeing the structure correctly. + // + ASSERT(FxLibraryGlobals.PerfTraceRoutines->Size >= + sizeof(WMI_WDF_NOTIFY_ROUTINES)); + +#else + status = STATUS_SUCCESS; +#endif + + return status; +} + +VOID +FxLibraryGlobalsDecommission( + VOID + ) +{ + // + // Assure the all driver's FxDriverGlobals have been freed. + // + ASSERT(IsListEmpty(&FxLibraryGlobals.FxDriverGlobalsList)); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // Cleanup for the driver usage tracker. + // + FxLibraryGlobals.DriverTracker.Uninitialize(); + + // + // Deregister from the global (library) bugcheck callbacks. + // + FxUninitializeBugCheckDriverInfo(); +#endif + + FxLibraryGlobals.FxDriverGlobalsListLock.Uninitialize(); + + return; +} + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +// +// This function is only used to lock down verifier section code in memory. +// It uses the #pragma alloc_text(...) style for paging. +// +VOID +VerifierPageLockHandle ( + VOID + ) +{ + PAGED_CODE_LOCKED(); + DO_NOTHING(); +} + +VOID +LockVerifierSection( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ PCUNICODE_STRING RegistryPath + ) +{ + LONG count; + + // + // This asserts makes sure the struct is not pack(1) and the counter + // is correctly aligned on a 32 bit boundary. + // + C_ASSERT((FIELD_OFFSET(FxLibraryGlobalsType, VerifierSectionHandleRefCount) + % __alignof(LONG)) == 0); + + count = InterlockedIncrement(&FxLibraryGlobals.VerifierSectionHandleRefCount); + ASSERT(count > 0); + + // + // If verifier section is unlocked, lock it in. + // + if(FxLibraryGlobals.VerifierSectionHandle == NULL) { + // + //First time verifier section is being locked. + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "First time Locking (%d) in Verifier Paged Memory " + "from %!wZ! from driver globals %p", + count, RegistryPath, FxDriverGlobals); + // + // VerifierLockHandle is a function that we use to lock in all the code from it's section + // since all the verifier code is in the same section as VerifierLockHandle. + // + FxLibraryGlobals.VerifierSectionHandle = MmLockPagableCodeSection(VerifierPageLockHandle); + } + else { + MmLockPagableSectionByHandle(FxLibraryGlobals.VerifierSectionHandle); + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "Increment Lock counter (%d) for Verifier Paged Memory " + "from %!wZ! from driver globals %p", + count, RegistryPath, FxDriverGlobals); + } +} + +VOID +UnlockVerifierSection( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + if( FxLibraryGlobals.VerifierSectionHandle != NULL) { + LONG count; + + count = InterlockedDecrement(&FxLibraryGlobals.VerifierSectionHandleRefCount); + ASSERT(count >= 0); + + MmUnlockPagableImageSection(FxLibraryGlobals.VerifierSectionHandle); + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "Decrement UnLock counter (%d) for Verifier Paged Memory " + "with driver globals %p", + count, FxDriverGlobals); + } +} +#endif + +_Must_inspect_result_ +NTSTATUS +FxInitialize( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in MdDriverObject DriverObject, + __in PCUNICODE_STRING RegistryPath, + __in_opt PWDF_DRIVER_CONFIG DriverConfig + ) + +/*++ + +Routine Description: + + This is the global framework initialization routine. + + This is called when the framework is loaded, and by + any drivers that use the framework. + + It is safe to call if already initialized, to handle + cases where multiple drivers are sharing a common + kernel DLL. + + This method is used instead of relying on C++ static class + constructors in kernel mode. + +Arguments: + + +Returns: + + NTSTATUS + +--*/ + +{ + NTSTATUS status; + BOOLEAN windowsVerifierOn = FALSE; + + UNREFERENCED_PARAMETER(DriverConfig); + + // + // Check if windows driver verifier is on for this driver + // We need this when initializing wdf verifier + // + windowsVerifierOn = IsWindowsVerifierOn(DriverObject); + + // + // Get registry values first since these effect the + // rest of initialization + // + FxRegistrySettingsInitialize(FxDriverGlobals, + RegistryPath, + windowsVerifierOn); + + // + // Initialize IFR logging + // + FxIFRStart(FxDriverGlobals, RegistryPath, DriverObject); + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Initialize globals for %!wZ!", RegistryPath); + + // + // Only first one initializes the frameworks globals + // + status = FxPoolPackageInitialize(FxDriverGlobals); + if (!NT_SUCCESS(status)) { + // + // FxPoolPackageInitialize logs a message in case of failure so + // we don't need to log failure here. + // + FxIFRStop(FxDriverGlobals); + return status; + } + + // + // Lock verifier package + // + FxVerifierLockInitialize(FxDriverGlobals); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // Cache driver info for bugcheck callback. + // + FxCacheBugCheckDriverInfo(FxDriverGlobals); + + // + // Register for bugcheck callbacks. + // + FxRegisterBugCheckCallback(FxDriverGlobals, DriverObject); +#endif + + if (NULL != RegistryPath) { + if (FALSE == FxDriverGlobals->IsCorrectVersionRegistered(RegistryPath)) + FxDriverGlobals->RegisterClientVersion(RegistryPath); + } + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + if(FxDriverGlobals->FxVerifierOn){ + LockVerifierSection(FxDriverGlobals, RegistryPath); + } +#endif + + return STATUS_SUCCESS; +} + +BOOLEAN +IsWindowsVerifierOn( + _In_ MdDriverObject DriverObject + ) +{ + BOOLEAN windowsVerifierOn = FALSE; + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // Check if windows driver verifier is on for this driver + // We need this when initializing wdf verifier + // + windowsVerifierOn = MmIsDriverVerifying(DriverObject) ? TRUE: FALSE; + +#else + UNREFERENCED_PARAMETER(DriverObject); + + // + // For user-mode we check if app verifier's verifier.dll is loaded in this + // process (since app verifier doesn't provide any other way to detect its + // presence). + // + windowsVerifierOn = (GetModuleHandleW(L"verifier.dll") == NULL ? FALSE : TRUE); +#endif + + return windowsVerifierOn; +} + +VOID +FxDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + +/*++ + +Routine Description: + + This is the global framework uninitialization routine. + + It is here for symmetry, and to allow a shared DLL based frameworks + to unload safely. + +Arguments: + + +Returns: + + NTSTATUS + +--*/ + +{ + // + // Release the last reference. + // + FxDriverGlobals->RELEASE(FxDestroy); + + // + // Wait for everyone else to be done. + // + Mx::MxEnterCriticalRegion(); + FxDriverGlobals->DestroyEvent.WaitFor(Executive, KernelMode, FALSE, NULL); + Mx::MxLeaveCriticalRegion(); + + // + // Lock verifier package + // + FxVerifierLockDestroy(FxDriverGlobals); + + // + // Cleanup frameworks structures + // + FxPoolPackageDestroy(FxDriverGlobals); + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // Deregister from the bugcheck callbacks. + // + FxUnregisterBugCheckCallback(FxDriverGlobals); + + // + // Purge driver info from bugcheck data. + // + FxPurgeBugCheckDriverInfo(FxDriverGlobals); +#endif + +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + // + // unlock verifier image sections + // + if(FxDriverGlobals->FxVerifierOn){ + UnlockVerifierSection(FxDriverGlobals); + } +#endif + + return; +} + +_Must_inspect_result_ +PWDF_DRIVER_GLOBALS +FxAllocateDriverGlobals( + VOID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + KIRQL irql; + NTSTATUS status; + + pFxDriverGlobals = (PFX_DRIVER_GLOBALS) + MxMemory::MxAllocatePoolWithTag(NonPagedPool, sizeof(FX_DRIVER_GLOBALS), FX_TAG); + + if (pFxDriverGlobals == NULL) { + return NULL; + } + + RtlZeroMemory(pFxDriverGlobals, sizeof(FX_DRIVER_GLOBALS)); + + pFxDriverGlobals->Refcnt = 1; + + status = pFxDriverGlobals->DestroyEvent.Initialize(NotificationEvent, FALSE); +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + if (!NT_SUCCESS(status)) { + MxMemory::MxFreePool(pFxDriverGlobals); + return NULL; + } +#else + UNREFERENCED_PARAMETER(status); +#endif + + // + // Initialize this new FxDriverGlobals structure. + // + FxLibraryGlobals.FxDriverGlobalsListLock.Acquire(&irql); + InsertHeadList(&FxLibraryGlobals.FxDriverGlobalsList, + &pFxDriverGlobals->Linkage); + FxLibraryGlobals.FxDriverGlobalsListLock.Release(irql); + + pFxDriverGlobals->WdfHandleMask = FxHandleValueMask; + pFxDriverGlobals->WdfVerifierAllocateFailCount = (ULONG) -1; + pFxDriverGlobals->Driver = NULL; + pFxDriverGlobals->DebugExtension = NULL; + pFxDriverGlobals->LibraryGlobals = &FxLibraryGlobals; + pFxDriverGlobals->WdfLogHeader = NULL; + + // + // Verifier settings. Off by default. + // + pFxDriverGlobals->SetVerifierState(FALSE); + + // + // By default don't apply latest-version restricted verifier checks + // to downlevel version drivers. + // + pFxDriverGlobals->FxVerifyDownlevel = FALSE; + + // + // Verbose is separate knob + // + pFxDriverGlobals->FxVerboseOn = FALSE; + + // + // Do not parent queue presented requests. + // This performance optimization is on by default. + // + pFxDriverGlobals->FxRequestParentOptimizationOn = TRUE; + + // + // Enhanced verifier options. Off by default + // + pFxDriverGlobals->FxEnhancedVerifierOptions = 0; + + // + // If FxVerifierDbgBreakOnError is true, WaitForSignal interrupts the + // execution of the system after waiting for the specified number + // of seconds. Developer will have an opportunity to validate the state + // of the driver when breakpoint is hit. Developer can continue to wait + // by entering 'g' in the debugger. + // + pFxDriverGlobals->FxVerifierDbgWaitForSignalTimeoutInSec = 60; + + // + // Timeout used by the wake interrupt ISR in WaitForSignal to catch + // scenarios where the interrupt ISR is blocked because the device stack + // is taking too long to power up + // + pFxDriverGlobals->DbgWaitForWakeInterruptIsrTimeoutInSec = 60; + + // + // Minidump log related settings. + // + pFxDriverGlobals->FxForceLogsInMiniDump = FALSE; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + pFxDriverGlobals->FxTrackDriverForMiniDumpLog = TRUE; + pFxDriverGlobals->IsUserModeDriver = FALSE; +#else + pFxDriverGlobals->FxTrackDriverForMiniDumpLog = FALSE; + pFxDriverGlobals->IsUserModeDriver = TRUE; +#endif + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + // + // Minidump driver info related settings. + // + pFxDriverGlobals->BugCheckDriverInfoIndex = 0; +#endif + + // + // By default disable the support for device simulation framework (DSF). + // + pFxDriverGlobals->FxDsfOn = FALSE; + + // + // Allocate a telemetry context if a telemetry client is enabled, for any level/keyword. + // + pFxDriverGlobals->TelemetryContext = NULL; + if (TraceLoggingProviderEnabled(g_TelemetryProvider, 0 ,0)) { + AllocAndInitializeTelemetryContext(&(pFxDriverGlobals->TelemetryContext)); + } + + return &pFxDriverGlobals->Public; +} + +VOID +FxFreeDriverGlobals( + __in PWDF_DRIVER_GLOBALS DriverGlobals + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + KIRQL irql; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxLibraryGlobals.FxDriverGlobalsListLock.Acquire(&irql); + RemoveEntryList(&pFxDriverGlobals->Linkage); + InitializeListHead(&pFxDriverGlobals->Linkage); + FxLibraryGlobals.FxDriverGlobalsListLock.Release(irql); + + if (pFxDriverGlobals->DebugExtension != NULL) { + + FxFreeAllocatedMdlsDebugInfo(pFxDriverGlobals->DebugExtension); + + if (pFxDriverGlobals->DebugExtension->ObjectDebugInfo != NULL) { + MxMemory::MxFreePool(pFxDriverGlobals->DebugExtension->ObjectDebugInfo); + pFxDriverGlobals->DebugExtension->ObjectDebugInfo = NULL; + } + + pFxDriverGlobals->DebugExtension->AllocatedTagTrackersLock.Uninitialize(); + + MxMemory::MxFreePool(pFxDriverGlobals->DebugExtension); + pFxDriverGlobals->DebugExtension = NULL; + } + + // + // Cleanup event b/c d'tor is not called for MxAllocatePoolWithTag. + // + pFxDriverGlobals->DestroyEvent.Uninitialize(); + + if (NULL != pFxDriverGlobals->TelemetryContext) { + MxMemory::MxFreePool(pFxDriverGlobals->TelemetryContext); + pFxDriverGlobals->TelemetryContext = NULL; + } + + MxMemory::MxFreePool(pFxDriverGlobals); +} + +_Must_inspect_result_ +FxObjectDebugInfo* +FxVerifierGetObjectDebugInfo( + __in HANDLE Key, + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) + +/*++ + +Routine Description: + Attempts to open a value under the passed in key and create an array of + FxObjectDebugInfo. + +Arguments: + Key - Registry key to query the value for + +Return Value: + NULL or a pointer which should be freed by the caller using ExFreePool + +--*/ + +{ + FxObjectDebugInfo* pInfo; + PVOID dataBuffer; + NTSTATUS status; + ULONG length, type; + DECLARE_CONST_UNICODE_STRING(valueName, L"TrackHandles"); + + pInfo = NULL; + type = REG_MULTI_SZ; + length = 0; + + // + // Find out how big a buffer we need to allocate if the value is present + // + status = FxRegKey::_QueryValue(FxDriverGlobals, + Key, + &valueName, + length, + NULL, + &length, + &type); + + // + // We expect the list to be bigger then a standard partial, so if it is + // not, just bail now. + // + if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) { + return NULL; + } + + // + // Pool can be paged b/c we are running at PASSIVE_LEVEL and we are going + // to free it at the end of this function. + // + dataBuffer = MxMemory::MxAllocatePoolWithTag(PagedPool, length, FxDriverGlobals->Tag); + if (dataBuffer == NULL) { + return NULL; + } + + // + // Requery now that we have a big enough buffer + // + status = FxRegKey::_QueryValue(FxDriverGlobals, + Key, + &valueName, + length, + dataBuffer, + &length, + &type); + if (NT_SUCCESS(status)) { + // + // Verify that the data from the registry is a valid multi-sz string. + // + status = FxRegKey::_VerifyMultiSzString(FxDriverGlobals, + &valueName, + (PWCHAR) dataBuffer, + length); + } + + if (NT_SUCCESS(status)) { +#pragma prefast(push) +#pragma prefast(suppress:__WARNING_PRECONDITION_NULLTERMINATION_VIOLATION, "FxRegKey::_VerifyMultiSzString makes sure the string is NULL-terminated") + pInfo = FxVerifyAllocateDebugInfo((LPWSTR) dataBuffer, FxDriverGlobals); +#pragma prefast(pop) + + } + + MxMemory::MxFreePool(dataBuffer); + + return pInfo; +} + +VOID +FxVerifierQueryTrackPower( + __in HANDLE Key, + __out FxTrackPowerOption* TrackPower + ) +{ + NTSTATUS status; + ULONG value = 0; + DECLARE_CONST_UNICODE_STRING(valueName, L"TrackPower"); + + status = FxRegKey::_QueryULong(Key, &valueName, &value); + if (NT_SUCCESS(status) && value < FxTrackPowerMaxValue) { + *TrackPower = (FxTrackPowerOption)value; + } + else { + *TrackPower = FxTrackPowerNone; + } +} + +VOID +FxOverrideDefaultVerifierSettings( + __in HANDLE Key, + __in LPWSTR Name, + __out PBOOLEAN OverrideValue + ) +{ + UNICODE_STRING valueName; + ULONG value = 0; + + RtlInitUnicodeString(&valueName, Name); + + if (NT_SUCCESS(FxRegKey::_QueryULong(Key, + (PCUNICODE_STRING)&valueName, + &value))) { + if (value) { + *OverrideValue = TRUE; + } else { + *OverrideValue = FALSE; + } + } + +} + + +VOID +FxRegistrySettingsInitialize( + __inout PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath, + __in BOOLEAN WindowsVerifierOn + ) + +/*++ + +Routine Description: + + Initialize Driver Framework settings from the driver + specific registry settings under + + \REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\\Parameters\Wdf + +Arguments: + + RegistryPath - Registry path passed to DriverEntry + +--*/ + +{ + NTSTATUS status; + RTL_QUERY_REGISTRY_TABLE paramTable[10]; + ULONG verifierOnValue; + ULONG verifyDownlevelValue; + ULONG verboseValue; + ULONG allocateFailValue; + ULONG forceLogsInMiniDump; + ULONG trackDriverForMiniDumpLog; + ULONG requestParentOptimizationOn; + ULONG dsfValue; + ULONG removeLockOptionFlags; + ULONG zero = 0; + ULONG max = 0xFFFFFFFF; + ULONG defaultTrue = (ULONG) TRUE; + ULONG i; + ULONG timeoutValue = 0; + FxAutoRegKey hDriver, hWdf; + DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf"); + + typedef NTSTATUS NTAPI QUERYFN( + ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID); + + QUERYFN* queryFn; + +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + UNICODE_STRING FunctionName; +#endif + + // + // UMDF may not provide this registry path + // + if (NULL == RegistryPath) { + return; + } + + status = FxRegKey::_OpenKey(NULL, RegistryPath, &hDriver.m_Key, KEY_READ); + if (!NT_SUCCESS(status)) { + return; + } + + status = FxRegKey::_OpenKey(hDriver.m_Key, ¶metersPath, &hWdf.m_Key, KEY_READ); + if (!NT_SUCCESS(status)) { + // + // For version >= 1.9 we enable WDF verifier automatically when driver + // verifier or app verifier is enabled. Since inbox drivers may not have + // WDF subkey populated as they may not use INF, we need to enable + // verifier even if we fail to open wdf subkey (if DriverVerifier is on). + // + if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { + // + // Verifier settings are all or nothing. We currently do not support + // turning on individual sub-verifiers. + // + FxDriverGlobals->SetVerifierState(WindowsVerifierOn); + if (FxDriverGlobals->FxVerifierOn) { + FxDriverGlobalsInitializeDebugExtension(FxDriverGlobals, NULL); + } + } + + return; + } + + RtlZeroMemory (¶mTable[0], sizeof(paramTable)); + i = 0; + + verboseValue = 0; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"VerboseOn"; + paramTable[i].EntryContext = &verboseValue; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &zero; + paramTable[i].DefaultLength = sizeof(ULONG); + + allocateFailValue = (ULONG) -1; + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"VerifierAllocateFailCount"; + paramTable[i].EntryContext = &allocateFailValue; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &max; + paramTable[i].DefaultLength = sizeof(ULONG); + + verifierOnValue = 0; + + // + // If the client version is 1.9 or above, the defaut (i.e when + // the key is not present) VerifierOn state is tied to the + // driver verifier. + // + if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { + verifierOnValue = WindowsVerifierOn; + } + + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"VerifierOn"; + paramTable[i].EntryContext = &verifierOnValue; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &verifierOnValue; + paramTable[i].DefaultLength = sizeof(ULONG); + + verifyDownlevelValue = 0; + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"VerifyDownLevel"; + paramTable[i].EntryContext = &verifyDownlevelValue; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &zero; + paramTable[i].DefaultLength = sizeof(ULONG); + + forceLogsInMiniDump = 0; + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"ForceLogsInMiniDump"; + paramTable[i].EntryContext = &forceLogsInMiniDump; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &zero; + paramTable[i].DefaultLength = sizeof(ULONG); + + // + // Track driver for minidump log: + // Default for KMDF is on. + // Default for UMDF is off. + // +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + trackDriverForMiniDumpLog = (ULONG) TRUE; +#else + trackDriverForMiniDumpLog = 0; +#endif + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"TrackDriverForMiniDumpLog"; + paramTable[i].EntryContext = &trackDriverForMiniDumpLog; + paramTable[i].DefaultType = REG_DWORD; +#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE) + paramTable[i].DefaultData = &defaultTrue; +#else + paramTable[i].DefaultData = &zero; +#endif + paramTable[i].DefaultLength = sizeof(ULONG); + + requestParentOptimizationOn = (ULONG) TRUE; + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"RequestParentOptimizationOn"; + paramTable[i].EntryContext = &requestParentOptimizationOn; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &defaultTrue; + paramTable[i].DefaultLength = sizeof(ULONG); + + dsfValue = 0; + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"DsfOn"; + paramTable[i].EntryContext = &dsfValue; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &zero; + paramTable[i].DefaultLength = sizeof(ULONG); + + removeLockOptionFlags = 0; + i++; + + paramTable[i].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[i].Name = L"RemoveLockOptionFlags"; + paramTable[i].EntryContext = &removeLockOptionFlags; + paramTable[i].DefaultType = REG_DWORD; + paramTable[i].DefaultData = &zero; + paramTable[i].DefaultLength = sizeof(ULONG); + + ASSERT(i < sizeof(paramTable) / sizeof(paramTable[0])); + +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + + queryFn = (QUERYFN*) GetProcAddress( + GetModuleHandle(TEXT("ntdll.dll")), + "RtlQueryRegistryValuesEx" + ); + +#else + + RtlInitUnicodeString(&FunctionName, L"RtlQueryRegistryValuesEx"); + +#pragma warning(push) +#pragma warning(disable: 4055) + + queryFn = (QUERYFN*)MmGetSystemRoutineAddress(&FunctionName); + +#pragma warning(pop) + +#endif + + if (queryFn == NULL) { + queryFn = &RtlQueryRegistryValues; + } + + status = queryFn( + RTL_REGISTRY_OPTIONAL | RTL_REGISTRY_HANDLE, + (PWSTR) hWdf.m_Key, + ¶mTable[0], + NULL, + NULL + ); + + // + // Only examine key values on success + // + if (NT_SUCCESS(status)) { + + if (verboseValue) { + FxDriverGlobals->FxVerboseOn = TRUE; + } + else { + FxDriverGlobals->FxVerboseOn = FALSE; + } + + if (allocateFailValue != (ULONG) -1) { + FxDriverGlobals->WdfVerifierAllocateFailCount = (LONG) allocateFailValue; + } + else { + FxDriverGlobals->WdfVerifierAllocateFailCount = -1; + } + + // + // Verifier settings are all or nothing. We currently do not support + // turning on individual sub-verifiers. + // + FxDriverGlobals->SetVerifierState(verifierOnValue ? TRUE : FALSE); + + if (FxDriverGlobals->FxVerifierOn) { + FxDriverGlobalsInitializeDebugExtension(FxDriverGlobals, hWdf.m_Key); + } + + // + // Update FxVerifyDownLevel independent of FxVerifyOn because for UMDF + // verifer is always on so it does not consume FxVerifyOn value + // + if (verifyDownlevelValue) { + FxDriverGlobals->FxVerifyDownlevel = TRUE; + } + else { + FxDriverGlobals->FxVerifyDownlevel = FALSE; + } + + // + // See if there exists an override in the registry for WDFVERIFY state. + // We query for this separately so that we can establish a default state + // based on verifierOnValue, and then know if the value was present in + // the registry to override the default. + // + FxOverrideDefaultVerifierSettings(hWdf.m_Key, + L"VerifyOn", + &FxDriverGlobals->FxVerifyOn); + + if (FxDriverGlobals->FxVerifyOn) { + FxDriverGlobals->Public.DriverFlags |= WdfVerifyOn; + } + + FxOverrideDefaultVerifierSettings(hWdf.m_Key, + L"DbgBreakOnError", + &FxDriverGlobals->FxVerifierDbgBreakOnError); + + FxOverrideDefaultVerifierSettings(hWdf.m_Key, + L"DbgBreakOnDeviceStateError", + &FxDriverGlobals->FxVerifierDbgBreakOnDeviceStateError); + + if (FxDriverGlobals->FxVerifierDbgBreakOnError) { + timeoutValue = 0; + DECLARE_CONST_UNICODE_STRING(timeoutName, L"DbgWaitForSignalTimeoutInSec"); + + // + // Get the override value for the WaitForSignal's timeout if present. + // + if (NT_SUCCESS(FxRegKey::_QueryULong(hWdf.m_Key, + &timeoutName, + &timeoutValue))) { + + FxDriverGlobals->FxVerifierDbgWaitForSignalTimeoutInSec = timeoutValue; + } + } + + timeoutValue = 0; + DECLARE_CONST_UNICODE_STRING(timeoutName, L"DbgWaitForWakeInterruptIsrTimeoutInSec"); + + // + // Get the override value for the Wake Interrupt ISR timeout if present. + // Since the wake interrupt feature is only supported for 1.13 and higher, + // avoid querying the reg key for older versions + // + if (FxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) && + NT_SUCCESS(FxRegKey::_QueryULong(hWdf.m_Key, + &timeoutName, + &timeoutValue))) { + + FxDriverGlobals->DbgWaitForWakeInterruptIsrTimeoutInSec = timeoutValue; + } + + FxDriverGlobals->FxForceLogsInMiniDump = + (forceLogsInMiniDump) ? TRUE : FALSE; + + FxDriverGlobals->FxTrackDriverForMiniDumpLog = + (trackDriverForMiniDumpLog) ? TRUE : FALSE; + + FxDriverGlobals->FxRequestParentOptimizationOn = + (requestParentOptimizationOn) ? TRUE : FALSE; + + FxDriverGlobals->FxDsfOn = (dsfValue) ? TRUE : FALSE; + + FxDriverGlobals->RemoveLockOptionFlags = removeLockOptionFlags; + } + + return; +} + +VOID +FX_DRIVER_GLOBALS::WaitForSignal( + __in MxEvent* Event, + __in PCSTR ReasonForWaiting, + __in WDFOBJECT Handle, + __in ULONG WarningTimeoutInSec, + __in ULONG WaitSignalFlags + ) +{ + LARGE_INTEGER timeOut; + NTSTATUS status; + + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + timeOut.QuadPart = WDF_REL_TIMEOUT_IN_SEC(((ULONGLONG)WarningTimeoutInSec)); + + do { + status = Event->WaitFor(Executive, + KernelMode, + FALSE, // Non alertable + timeOut.QuadPart ? &timeOut : NULL); + + if(status == STATUS_TIMEOUT) { + DbgPrint("Thread 0x%p is %s 0x%p\n", + Mx::MxGetCurrentThread(), + ReasonForWaiting, + Handle); + + if ((WaitSignalFlags & WaitSignalAlwaysBreak) || + ((WaitSignalFlags & WaitSignalBreakUnderVerifier) && + FxVerifierDbgBreakOnError) || + ((WaitSignalFlags & WaitSignalBreakUnderDebugger) && + IsDebuggerAttached())) { + + DbgBreakPoint(); + } + } else { + ASSERT(NT_SUCCESS(status)); + break; + } + } WHILE(TRUE); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/object/handleapi.cpp b/sdk/lib/drivers/wdf/shared/object/handleapi.cpp new file mode 100644 index 00000000000..18db36b0d7f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/handleapi.cpp @@ -0,0 +1,702 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + HandleApi.cpp + +Abstract: + + This module implements the driver frameworks handle functions. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "HandleAPI.tmh" +#endif + +} + +size_t +FxGetContextSize( + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Get a context size from an object's attributes settings. + +Arguments: + Attributes - attributes which will describe the size requirements for the + associated context. + +Return Value: + Size requirements for the associated context. + + --*/ +{ + size_t contextSize = 0; + + if (Attributes != NULL) { + if (Attributes->ContextTypeInfo != NULL) { + if (Attributes->ContextSizeOverride != 0) { + contextSize = Attributes->ContextSizeOverride; + } + else { + contextSize = Attributes->ContextTypeInfo->ContextSize; + } + } + } + + return contextSize; +} + +_Must_inspect_result_ +NTSTATUS +FxCalculateObjectTotalSize2( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT RawObjectSize, + __in USHORT ExtraSize, + __in size_t ContextSize, + __out size_t* Total + ) +/*++ + +Routine Description: + Calculates the size of an allocation for an FxObject that will contain the + object, its initial context and any addtional headers. + +Arguments: + FxDriverGlobals - driver's globals + RawObjectSize - the size of the FxObject derived object + ExtraSize - additional size required by the derived object + ContextSize - Size requirements for the associated context (see FxGetContextSize() above). + Total - pointer which will receive the final size requirement + +Return Value: + NT_SUCCESS on success, !NT_SUCCESS on failure + + --*/ +{ + NTSTATUS status; + + *Total = 0; + + status = RtlSizeTAdd( + WDF_ALIGN_SIZE_UP(COMPUTE_OBJECT_SIZE(RawObjectSize, ExtraSize), MEMORY_ALLOCATION_ALIGNMENT), + FX_CONTEXT_HEADER_SIZE, + Total + ); + + if (NT_SUCCESS(status)) { + if (ContextSize != 0) { + size_t alignUp; + + alignUp = ALIGN_UP(ContextSize, PVOID); + + // + // overflow after aligning up to a pointer boundary; + // + if (alignUp < ContextSize) { + return STATUS_INTEGER_OVERFLOW; + } + + status = RtlSizeTAdd(*Total, alignUp, Total); + } + } + + if (NT_SUCCESS(status) && FxDriverGlobals->IsObjectDebugOn()) { + // + // Attempt to add in the debug extension + // + status = RtlSizeTAdd(*Total, + FxObjectDebugExtensionSize, + Total); + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGOBJECT, + "Size overflow, object size 0x%x, extra object size 0x%x, " + "context size 0x%I64x, %!STATUS!", + RawObjectSize, ExtraSize, ContextSize, status); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxCalculateObjectTotalSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT RawObjectSize, + __in USHORT ExtraSize, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __out size_t* Total + ) +{ + return FxCalculateObjectTotalSize2(FxDriverGlobals, + RawObjectSize, + ExtraSize, + FxGetContextSize(Attributes), + Total); +} + +PVOID +FxObjectHandleAlloc( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in POOL_TYPE PoolType, + __in size_t Size, + __in ULONG Tag, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in USHORT ExtraSize, + __in FxObjectType ObjectType + ) +/*++ + +Routine Description: + Allocates an FxObject derived object, it's associated context, and any + framework required headers and footers. + +Arguments: + FxDriverGlobals - caller's globals + PoolType - type of pool to be used in allocating the object's memory + Size - size of the object (as passed to operator new() by the compiler) + Tag - tag to use when allocating the object's memory + Attributes - attributes which describe the context to be associated with the + object + ExtraSize - any addtional storage required by the object itself + ObjectType - the type (internal or external) of object being allocated. An + internal object is a worker object which will never have an associated + type or be Commit()'ed into an external object handle that the client + driver will see. + +Return Value: + A valid pointer on success, NULL otherwise + + --*/ +{ + PVOID blob; + size_t totalSize; + NTSTATUS status; + + if (Tag == 0) { + Tag = FxDriverGlobals->Tag; + ASSERT(Tag != 0); + } + + if (ObjectType == FxObjectTypeInternal) { + // + // An internal object might need the debug extension size added to it, + // but that's it. No extra size, no FxContextHeader. + // + if (FxDriverGlobals->IsObjectDebugOn()) { + status = RtlSizeTAdd(Size, + FxObjectDebugExtensionSize, + &totalSize); + } + else { + totalSize = Size; + status = STATUS_SUCCESS; + } + } + else { + status = FxCalculateObjectTotalSize(FxDriverGlobals, + (USHORT) Size, + ExtraSize, + Attributes, + &totalSize); + } + + if (!NT_SUCCESS(status)) { + return NULL; + } + + blob = FxPoolAllocateWithTag(FxDriverGlobals, PoolType, totalSize, Tag); + + if (blob != NULL) { + blob = FxObjectAndHandleHeaderInit( + FxDriverGlobals, + blob, + COMPUTE_OBJECT_SIZE((USHORT) Size, ExtraSize), + Attributes, + ObjectType + ); + } + + return blob; +} + +VOID +FxContextHeaderInit( + __in FxContextHeader* Header, + __in FxObject* Object, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes + ) +/*++ + +Routine Description: + Initializes a context header which describes a typed context. + +Arguments: + Header - the header to initialize + Object - the object on which the context is being associated with + Attributes - description of the typed context + + --*/ +{ + RtlZeroMemory(Header, FX_CONTEXT_HEADER_SIZE); + + Header->Object = Object; + + if (Attributes != NULL) { + if (Attributes->ContextTypeInfo != NULL) { + size_t contextSize; + + if (Attributes->ContextSizeOverride != 0) { + contextSize = Attributes->ContextSizeOverride; + + } + else { + contextSize = Attributes->ContextTypeInfo->ContextSize; + } + + // + // Zero initialize the entire context + // + RtlZeroMemory(&Header->Context[0], ALIGN_UP(contextSize, PVOID)); + } + + Header->ContextTypeInfo = Attributes->ContextTypeInfo; + } +} + +PVOID +FxObjectAndHandleHeaderInit( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID AllocationStart, + __in USHORT ObjectSize, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in FxObjectType ObjectType + ) +/*++ + +Routine Description: + Initialize the object and its associated context. + +Arguments: + FxDriverGlobals - caller's globals + AllocationStart - start of the memory block allocated to represent the object. + This will not be the same as the pointer which represents the address of + the object itself in memory + ObjectSize - size of the object + Attributes - description of its context + ObjectType - type (internal or external) of object being initialized + +Return Value: + The address of the object withing AllocationStart + + --*/ + +{ + FxObject* pObject; + + if (FxDriverGlobals->IsObjectDebugOn()) { + FxObjectDebugExtension* pExtension; + + pExtension = (FxObjectDebugExtension*) AllocationStart; + + RtlZeroMemory(pExtension, FxObjectDebugExtensionSize); + pExtension->Signature = FxObjectDebugExtensionSignature; + + pObject = (FxObject*) &pExtension->AllocationStart[0]; + } + else { + pObject = (FxObject*) AllocationStart; + } + + if (ObjectType == FxObjectTypeExternal) { + FxContextHeaderInit( + (FxContextHeader*) WDF_PTR_ADD_OFFSET(pObject, ObjectSize), + pObject, + Attributes + ); + } + + return pObject; +} + +VOID +FxObjectHandleGetPtrQI( + __in FxObject* Object, + __out PVOID* PPObject, + __in WDFOBJECT Handle, + __in WDFTYPE Type, + __in WDFOBJECT_OFFSET Offset + ) +/*++ + +Routine Description: + Worker function for FxObjectHandleGetPtrXxx which will call + FxObject::QueryInterface when the Type does not match the object's built in + Type. + +Arguments: + Object - object to query + PPObject - pointer which will recieve the queried for object + Handle - handle which the caller passed to the framework + Type - required object type + Offset - offset of the handle within the object. Nearly all handles will have + a zero object. + + --*/ +{ + FxQueryInterfaceParams params = { PPObject, Type, Offset }; + NTSTATUS status; + + *PPObject = NULL; + + status = Object->QueryInterface(¶ms); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + Object->GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Object Type Mismatch, Handle 0x%p, Type 0x%x, " + "Obj 0x%p, SB 0x%x", + Handle, Type, Object, Object->GetType()); + + FxVerifierBugCheck(Object->GetDriverGlobals(), + WDF_INVALID_HANDLE, + (ULONG_PTR) Handle, + Type); + + /* NOTREACHED */ + return; + } +} + +_Must_inspect_result_ +NTSTATUS +FxObjectAllocateContext( + __in FxObject* Object, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in BOOLEAN AllowCallbacksOnly, + __deref_opt_out PVOID* Context + ) +/*++ + +Routine Description: + Allocates an additional context on the object if it is in the correct state. + +Arguments: + Object - object on which to add a context + Attributes - attributes which describe the type and size of the new context + AllowEmptyContext -TRUE to allow logic to allocate the context's header only. + Context - optional pointer which will recieve the new context + +Return Value: + STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type + is already attached to the handle, and !NT_SUCCESS on failure + + --*/ +{ + PFX_DRIVER_GLOBALS fxDriverGlobals; + NTSTATUS status; + FxContextHeader * header; + size_t size; + BOOLEAN relRef; + ULONG flags; + + fxDriverGlobals = Object->GetDriverGlobals(); + header = NULL; + relRef = FALSE; + + // + // Init validation flags. + // + flags = FX_VALIDATE_OPTION_ATTRIBUTES_REQUIRED; + if (fxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,11)) { + flags |= FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED; + } + + // + // Basic validations. + // + status = FxValidateObjectAttributes(fxDriverGlobals, Attributes, flags); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Check for context type! + // + if (Attributes->ContextTypeInfo == NULL && AllowCallbacksOnly == FALSE) { + status = STATUS_OBJECT_NAME_INVALID; + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE, + "Attributes %p ContextTypeInfo is NULL, %!STATUS!", + Attributes, status); + goto Done; + } + + Object->ADDREF(&status); + relRef = TRUE; + + // + // By passing 0's for raw object size and extra size, we can compute the + // size of only the header and its contents. + // + status = FxCalculateObjectTotalSize(fxDriverGlobals, 0, 0, Attributes, &size); + if (!NT_SUCCESS(status)) { + goto Done; + } + + header = (FxContextHeader*) + FxPoolAllocate(fxDriverGlobals, NonPagedPool, size); + + if (header == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + FxContextHeaderInit(header, Object, Attributes); + + status = Object->AddContext(header, Context, Attributes); + + // + // STATUS_OBJECT_NAME_EXISTS will not fail NT_SUCCESS, so check + // explicitly for STATUS_SUCCESS. + // + if (status != STATUS_SUCCESS) { + FxPoolFree(header); + } + +Done: + + if (relRef) { + Object->RELEASE(&status); + } + + return status; +} + +// extern "C" all APIs +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectAllocateContext)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFOBJECT Handle, + __in + PWDF_OBJECT_ATTRIBUTES Attributes, + __deref_opt_out + PVOID* Context + ) +/*++ + +Routine Description: + Allocates an additional context on the handle if the object is in the + correct state + +Arguments: + Handle - handle on which to add a context + Attributes - attributes which describe the type and size of the new context + Context - optional pointer which will recieve the new context + +Return Value: + STATUS_SUCCESS upon success, STATUS_OBJECT_NAME_EXISTS if the context type + is already attached to the handle, and !NT_SUCCESS on failure + + --*/ +{ + DDI_ENTRY_IMPERSONATION_OK(); + + NTSTATUS status; + FxObject* object; + WDFOBJECT_OFFSET offset; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle); + + // + // No need to call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because + // we assume that the object handle will point back to an FxObject. (The + // call to FxObjectHandleGetPtr will just make needless virtual call into + // FxObject anyways). + // + offset = 0; + object = FxObject::_GetObjectFromHandle(Handle, &offset); + + if (offset != 0) { + + + + status = STATUS_OBJECT_PATH_INVALID; + DoTraceLevelMessage( + object->GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGHANDLE, + "WDFHANDLE %p cannot have contexts added to it, %!STATUS!", + Handle, status); + goto Done; + } + + // + // Internal helper function does the rest of the work. + // + status = FxObjectAllocateContext(object, Attributes, FALSE, Context); + +Done: + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL+1) +WDFAPI +PVOID +FASTCALL +WDFEXPORT(WdfObjectGetTypedContextWorker)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFOBJECT Handle, + __in + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ) +/*++ + +Routine Description: + Retrieves the requested type from a handle + +Arguments: + Handle - the handle to retrieve the context from + TypeInfo - global constant pointer which describes the type. Since the pointer + value is unique in all of kernel space, we will perform a pointer compare + instead of a deep structure compare + +Return Value: + A valid context pointere or NULL. NULL is not a failure, querying for a type + not associated with the handle is a legitimate operation. + + --*/ +{ + DDI_ENTRY_IMPERSONATION_OK(); + + FxContextHeader* pHeader; + FxObject* pObject; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFOBJECT_OFFSET offset; + + FxPointerNotNull(GetFxDriverGlobals(DriverGlobals), Handle); + + // + // Do not call FxObjectHandleGetPtr( , , FX_TYPE_OBJECT) because this is a + // hot spot / workhorse function that should be as efficient as possible. + // + // A call to FxObjectHandleGetPtr would : + // 1) invoke a virtual call to QueryInterface + // + // 2) ASSERT that the ref count of the object is > zero. Since this is one + // of the few functions that can be called in EvtObjectDestroy where the + // ref count is zero, that is not a good side affect. + // + offset = 0; + pObject = FxObject::_GetObjectFromHandle(Handle, &offset); + + // + // Use the object's globals, not the caller's + // + pFxDriverGlobals = pObject->GetDriverGlobals(); + + FxPointerNotNull(pFxDriverGlobals, TypeInfo); + + pHeader = pObject->GetContextHeader(); + + for ( ; pHeader != NULL; pHeader = pHeader->NextHeader) { + if (pHeader->ContextTypeInfo == TypeInfo) { + return &pHeader->Context[0]; + } + } + + PCHAR pGivenName; + + if (TypeInfo->ContextName != NULL) { + pGivenName = TypeInfo->ContextName; + } + else { + pGivenName = ""; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGHANDLE, + "Attempting to get context type %s from WDFOBJECT 0x%p", + pGivenName, Handle); + + return NULL; +} + +__drv_maxIRQL(DISPATCH_LEVEL+1) +WDFAPI +WDFOBJECT +FASTCALL +WDFEXPORT(WdfObjectContextGetObject)( + __in + PWDF_DRIVER_GLOBALS, + __in + PVOID ContextPointer + ) +/*++ + +Routine Description: + Reverse of WdfObjectGetTypedContextWorker. Function will return the handle + associated with the provided context pointer. + +Arguments: + ContextPointer - context pointer from which to retrieve the owning handle + +Return Value: + A valid WDF handle + + --*/ +{ + DDI_ENTRY_IMPERSONATION_OK(); + + FxContextHeader* pHeader; + FxObject* pObject; + + // + // The context could be one of the chained contexts on the object and not + // the first one, so it is easiest to go back to the object and build the + // handle value from the FxObject*. + // + #pragma prefast(push); + + + #pragma prefast(disable:__WARNING_BUFFER_UNDERFLOW, "No way to express that passed in ptr is at an offset"); + + pHeader = CONTAINING_RECORD(ContextPointer, FxContextHeader, Context); + pObject = pHeader->Object; + + #pragma prefast(pop); + + return (WDFOBJECT) pObject->GetObjectHandle(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/object/km/fxobjectkm.cpp b/sdk/lib/drivers/wdf/shared/object/km/fxobjectkm.cpp new file mode 100644 index 00000000000..367b78fe796 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/km/fxobjectkm.cpp @@ -0,0 +1,120 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObjectKm.cpp + +Abstract: + + Kernel mode implementations of FxObject APIs + +Author: + + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxObjectKm.tmh" +#endif + +} + + +extern "C" { + +_Must_inspect_result_ +NTSTATUS +FxObject::_ObjectQuery( + _In_ FxObject* Object, + _In_ CONST GUID* Guid, + _In_ ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ) + +/*++ + +Routine Description: + + Query the object handle for specific information + + This allows dynamic extensions to DDI's. + + Currently, it is used to allow test hooks for verification + which are not available in a production release. + +Arguments: + + Object - Object to query + + Guid - GUID to represent the information/DDI to query for + + QueryBufferLength - Length of QueryBuffer to return data in + + QueryBuffer - Pointer to QueryBuffer + +Returns: + + NTSTATUS + +--*/ + +{ + // PFX_DRIVER_GLOBALS pFxDriverGlobals = Object->GetDriverGlobals(); + + // + // Design Note: This interface does not look strongly typed + // but it is. The GUID defines a specific strongly typed + // contract for QueryBuffer and QueryBufferLength. + // + +#if DBG + + // + // These operations are only available on checked builds for deep unit + // testing, code coverage analysis, and model verification. + + + + + + + + + + + + + + // + + // Add code based on the GUID + + // IsEqualGUID(guid1, guid2), DEFINE_GUID, INITGUID, inc\wnet\guiddef.h + UNREFERENCED_PARAMETER(Object); + UNREFERENCED_PARAMETER(Guid); + UNREFERENCED_PARAMETER(QueryBufferLength); + UNREFERENCED_PARAMETER(QueryBuffer); +#else + UNREFERENCED_PARAMETER(Object); + UNREFERENCED_PARAMETER(Guid); + UNREFERENCED_PARAMETER(QueryBufferLength); + UNREFERENCED_PARAMETER(QueryBuffer); +#endif + + return STATUS_NOT_FOUND; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/object/km/globalskm.cpp b/sdk/lib/drivers/wdf/shared/object/km/globalskm.cpp new file mode 100644 index 00000000000..41de43d0013 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/km/globalskm.cpp @@ -0,0 +1,254 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "fxobjectpch.hpp" + +// Tracing support +extern "C" { +#if defined(EVENT_TRACING) +#include "GlobalsKm.tmh" +#endif + +#include +#include + + +} +extern "C" { + +VOID +FxFreeAllocatedMdlsDebugInfo( + __in FxDriverGlobalsDebugExtension* DebugExtension + ) +{ + FxAllocatedMdls* pNext, *pCur; + + pNext = DebugExtension->AllocatedMdls.Next; + + // + // MDL leaks were already checked for in FxPoolDestroy, just free all + // the tables here. + // + while (pNext != NULL) { + pCur = pNext; + pNext = pCur->Next; + + ExFreePool(pCur); + } +} + +KDEFERRED_ROUTINE FxFlushDpc; + +__drv_functionClass(KDEFERRED_ROUTINE) +__drv_maxIRQL(DISPATCH_LEVEL) +__drv_minIRQL(DISPATCH_LEVEL) +__drv_requiresIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +VOID +FxFlushDpc ( + __in struct _KDPC *Dpc, + __in_opt PVOID DeferredContext, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) + +/*++ + +Routine Description: + + This DPC is called on a processor to assist in flushing previous DPC's + +Arguments: + + Dpc - Supplies a pointer to DPC object. + + DeferredContext - Supplies the deferred context (event object address). + + SystemArgument1 - Supplies the first system context parameter (not used). + + SystemArgument2 - Supplies the second system context parameter (not used). + +Return Value: + + None. + +--*/ + +{ + + UNREFERENCED_PARAMETER(Dpc); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + // + // Signal that this routine has been called. + // + ((FxCREvent*)DeferredContext)->Set(); +} + +_Must_inspect_result_ +BOOLEAN +FX_DRIVER_GLOBALS::IsVersionGreaterThanOrEqualTo( + __in ULONG Major, + __in ULONG Minor + ) +{ + if ((WdfBindInfo->Version.Major > Major) || + (WdfBindInfo->Version.Major == Major && + WdfBindInfo->Version.Minor >= Minor)) { + return TRUE; + } + else { + return FALSE; + } +} + +#define WDF_MAJOR_VERSION_VALUE L"WdfMajorVersion" +#define WDF_MINOR_VERSION_VALUE L"WdfMinorVersion" + +_Must_inspect_result_ +BOOLEAN +FX_DRIVER_GLOBALS::IsCorrectVersionRegistered( + _In_ PCUNICODE_STRING ServiceKeyName + ) +{ + FxAutoRegKey hDriver, hWdf; + DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf"); + DECLARE_CONST_UNICODE_STRING(wdfMajorValue, WDF_MAJOR_VERSION_VALUE); + DECLARE_CONST_UNICODE_STRING(wdfMinorValue, WDF_MINOR_VERSION_VALUE); + ULONG registeredMajor = 0, registeredMinor = 0; + NTSTATUS status; + + status = FxRegKey::_OpenKey(NULL, + ServiceKeyName, + &hDriver.m_Key, + KEY_READ + ); + if (!NT_SUCCESS(status)) { + return FALSE; + } + + status = FxRegKey::_OpenKey(hDriver.m_Key, + ¶metersPath, + &hWdf.m_Key, + KEY_READ + ); + if (!NT_SUCCESS(status)) { + return FALSE; + } + + status = FxRegKey::_QueryULong(hWdf.m_Key, + &wdfMajorValue, + ®isteredMajor); + + if (!NT_SUCCESS(status) || registeredMajor != WdfBindInfo->Version.Major) { + return FALSE; + } + + status = FxRegKey::_QueryULong(hWdf.m_Key, + &wdfMinorValue, + ®isteredMinor); + + if (!NT_SUCCESS(status) || registeredMinor != WdfBindInfo->Version.Minor){ + return FALSE; + } + else { + return TRUE; + } +} + +VOID +FX_DRIVER_GLOBALS::RegisterClientVersion( + _In_ PCUNICODE_STRING ServiceKeyName + ) +{ + FxAutoRegKey hDriver, hParameters, hWdf; + DECLARE_CONST_UNICODE_STRING(parametersPart, L"Parameters"); + DECLARE_CONST_UNICODE_STRING(wdfPart, L"Wdf"); + // + // Not defined with the macro because ZwSetValue doesn't use PCUNICODE_STRING + // + UNICODE_STRING wdfMajorValue; + UNICODE_STRING wdfMinorValue; + NTSTATUS status; + + RtlInitUnicodeString(&wdfMajorValue, WDF_MAJOR_VERSION_VALUE); + RtlInitUnicodeString(&wdfMinorValue, WDF_MINOR_VERSION_VALUE); + + status = FxRegKey::_OpenKey(NULL, + ServiceKeyName, + &hDriver.m_Key, + KEY_WRITE | KEY_READ + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Unable to open driver's service key, status %!STATUS!", status); + return; + } + // + // Key creation, unlike user mode, must happen one level at a time, since + // create will also open take both steps instead of trying open first + // + status = FxRegKey::_Create(hDriver.m_Key, + ¶metersPart, + &hParameters.m_Key, + KEY_WRITE | KEY_READ + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Unable to write Parameters key, status %!STATUS!", status); + return; + } + + status = FxRegKey::_Create(hParameters.m_Key, + &wdfPart, + &hWdf.m_Key, + KEY_WRITE | KEY_READ + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Unable to write Parameters key, status %!STATUS!", status); + return; + } + + // + // Using ZwSetValueKey here to avoid having to change the implementation + // in FxRegKey of SetValue to a static / thiscall pair + // + status = ZwSetValueKey(hWdf.m_Key, + &wdfMajorValue, + 0, + REG_DWORD, + &WdfBindInfo->Version.Major, + sizeof(WdfBindInfo->Version.Major) + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Failed to record driver major version value, status %!STATUS!", status); + } + + status = ZwSetValueKey(hWdf.m_Key, + &wdfMinorValue, + 0, + REG_DWORD, + &WdfBindInfo->Version.Minor, + sizeof(WdfBindInfo->Version.Minor) + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(this, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "Failed to record driver version value, status %!STATUS!", status); + } +} + +} // extern "C" + +_Must_inspect_result_ +BOOLEAN +FX_DRIVER_GLOBALS::IsDebuggerAttached( + VOID + ) +{ + return (FALSE == KdRefreshDebuggerNotPresent()); +} diff --git a/sdk/lib/drivers/wdf/shared/object/km/wdfpoolkm.cpp b/sdk/lib/drivers/wdf/shared/object/km/wdfpoolkm.cpp new file mode 100644 index 00000000000..8795026a03e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/km/wdfpoolkm.cpp @@ -0,0 +1,272 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + wdfpoolkm.cpp + +Abstract: + + This module implements the driver frameworks pool routines + functionality only applicable in kernel mode + +Author: + + + + +Environment: + + Kernel mode only + +Revision History: + + +--*/ + +#include "fxobjectpch.hpp" + +// We use DoTraceMessage +extern "C" { +#if defined(EVENT_TRACING) +#include "wdfpoolkm.tmh" +#endif +} + +// undo the previous masking +#undef IoAllocateMdl +#undef IoFreeMdl + +__drv_maxIRQL(DISPATCH_LEVEL) +NTKERNELAPI +PMDL +IoAllocateMdl( + __in_opt __drv_aliasesMem PVOID VirtualAddress, + __in ULONG Length, + __in BOOLEAN SecondaryBuffer, + __in BOOLEAN ChargeQuota, + __inout_opt PIRP Irp + ); + +__drv_maxIRQL(DISPATCH_LEVEL) +NTKERNELAPI +VOID +IoFreeMdl( + PMDL Mdl + ); + +// +// Windows Driver Framework Pool Tracking +// +// This module implements a generic pool tracking mechanism +// if pool verifier mode is enabled. +// +// There can be multiple pools, each represented by a FX_POOL header. +// +// When the framework is supplied as a DLL, there is a global +// pool that represents allocations for the framework DLL itself. These +// allocations are pool allocations and object allocations. +// +// The driver's pool allocations are not currently tracked. If the driver needs +// to use pool outside of the framework objects, it calls the WDM +// ExAllocatePoolWithTag and ExFreePool(WithTag) APIs. +// + + + +PMDL +FxMdlAllocateDebug( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject* Owner, + __in PVOID VirtualAddress, + __in ULONG Length, + __in BOOLEAN SecondaryBuffer, + __in BOOLEAN ChargeQuota, + __in PVOID CallersAddress + ) +{ + FxDriverGlobalsDebugExtension* pExtension; + FxAllocatedMdls* pAllocated, **ppNext; + ULONG i; + PMDL pMdl; + KIRQL irql; + + pExtension = FxDriverGlobals->DebugExtension; + if (pExtension == NULL) { + return IoAllocateMdl(VirtualAddress, + Length, + SecondaryBuffer, + ChargeQuota, + NULL); + } + + pAllocated = &pExtension->AllocatedMdls; + ppNext = NULL; + pMdl = NULL; + + KeAcquireSpinLock(&pExtension->AllocatedMdlsLock, &irql); + + while (pAllocated != NULL && pAllocated->Count == NUM_MDLS_IN_INFO) { + ppNext = &pAllocated->Next; + pAllocated = pAllocated->Next; + } + + if (pAllocated == NULL) { + // + // No more entries, allocate a new table + // + pAllocated = (FxAllocatedMdls*) ExAllocatePoolWithTag( + NonPagedPool, sizeof(FxAllocatedMdls), FxDriverGlobals->Tag); + + if (pAllocated != NULL) { + // + // Zero out the new buffer and link it in to the list + // + RtlZeroMemory(pAllocated, sizeof(*pAllocated)); + *ppNext = pAllocated; + } + else { + // + // Could not allocate a new table, return error + // + KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql); + + return NULL; + } + } + + for (i = 0; i < NUM_MDLS_IN_INFO; i++) { + if (pAllocated->Info[i].Mdl != NULL) { + continue; + } + + pMdl = IoAllocateMdl(VirtualAddress, + Length, + SecondaryBuffer, + ChargeQuota, + NULL); + + if (pMdl != NULL) { + pAllocated->Info[i].Mdl = pMdl; + pAllocated->Info[i].Owner = Owner; + pAllocated->Info[i].Caller = CallersAddress; + pAllocated->Count++; + } + break; + } + + KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql); + + return pMdl; +} + +VOID +FxMdlFreeDebug( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PMDL Mdl + ) +{ + FxDriverGlobalsDebugExtension* pExtension; + FxAllocatedMdls* pAllocated, **ppNext; + ULONG i; + KIRQL irql; + BOOLEAN found; + + pExtension = FxDriverGlobals->DebugExtension; + if (pExtension == NULL) { + IoFreeMdl(Mdl); + return; + } + + found = FALSE; + + pAllocated = &pExtension->AllocatedMdls; + ppNext = NULL; + + KeAcquireSpinLock(&pExtension->AllocatedMdlsLock, &irql); + + while (pAllocated != NULL) { + for (i = 0; i < NUM_MDLS_IN_INFO; i++) { + if (pAllocated->Info[i].Mdl != Mdl) { + continue; + } + + RtlZeroMemory(&pAllocated->Info[i], + sizeof(pAllocated->Info[i])); + + pAllocated->Count--; + + if (pAllocated->Count == 0 && + pAllocated != &pExtension->AllocatedMdls) { + // + // Remove the current table from the chain + // + *ppNext = pAllocated->Next; + + // + // And free it + // + ExFreePool(pAllocated); + } + + IoFreeMdl(Mdl); + found = TRUE; + break; + } + + if (found) { + break; + } + + ppNext = &pAllocated->Next; + pAllocated = pAllocated->Next; + } + + KeReleaseSpinLock(&pExtension->AllocatedMdlsLock, irql); + + if (found == FALSE) { + + + + FxVerifierDbgBreakPoint(FxDriverGlobals); + } +} + +VOID +FxMdlDump( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + FxAllocatedMdls *pCur; + BOOLEAN leak; + + if (FxDriverGlobals->DebugExtension == NULL) { + return; + } + + leak = FALSE; + + for (pCur = &FxDriverGlobals->DebugExtension->AllocatedMdls; + pCur != NULL; + pCur = pCur->Next) { + ULONG i; + + for (i = 0; i < NUM_MDLS_IN_INFO; i++) { + if (pCur->Info[i].Mdl != NULL) { + leak = TRUE; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "PMDL 0x%p leaked, FxObject owner %p, Callers Address %p", + pCur->Info[i].Mdl, pCur->Info[i].Owner, + pCur->Info[i].Caller); + } + } + } + + if (leak) { + FxVerifierDbgBreakPoint(FxDriverGlobals); + } +} + diff --git a/sdk/lib/drivers/wdf/shared/object/objectpriv.hpp b/sdk/lib/drivers/wdf/shared/object/objectpriv.hpp new file mode 100644 index 00000000000..ec62a5beafa --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/objectpriv.hpp @@ -0,0 +1,37 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + objectpriv.hpp + +Abstract: + + Private header file for shared\object directory + It is then included in objectpch.hpp + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + + +extern "C" { +#include "mx.h" +} + +// +// Root WDF key, for both UMDF and KMDF settings. +// +#define WDF_REGISTRY_BASE_PATH L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Wdf" + +#define WDF_GLOBAL_VALUE_IFRDISABLED L"WdfGlobalLogsDisabled" // REG_DWORD + diff --git a/sdk/lib/drivers/wdf/shared/object/um/fxobjectinfoum.cpp b/sdk/lib/drivers/wdf/shared/object/um/fxobjectinfoum.cpp new file mode 100644 index 00000000000..9af6f6da48f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/um/fxobjectinfoum.cpp @@ -0,0 +1,70 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "FxMin.hpp" +#include "fxobjectpch.hpp" + +#include "FxUserObject.hpp" +#include "pnppriv.hpp" + +// +// More object types should be added to this table as more objects +// are merged and incorporated in UMDF +// + +extern "C" { + +// +// Assumes sorted (by type) order! +// +FX_OBJECT_INFO FxObjectsInfo[] = { + FX_INTERNAL_OBJECT_INFO_ENTRY(FxObject, FX_TYPE_OBJECT), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDriver, FX_TYPE_DRIVER, WDFDRIVER), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxDevice, FX_TYPE_DEVICE, WDFDEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoQueue, FX_TYPE_QUEUE, WDFQUEUE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWmiProvider, FX_TYPE_WMI_PROVIDER, WDFWMIPROVIDER), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRegKey, FX_TYPE_REG_KEY, WDFKEY), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxString, FX_TYPE_STRING, WDFSTRING), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRequest, FX_TYPE_REQUEST, WDFREQUEST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxLookasideList, FX_TYPE_LOOKASIDE, WDFLOOKASIDE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMemoryObject, IFX_TYPE_MEMORY, WDFMEMORY), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxIrpQueue, FX_TYPE_IRPQUEUE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUserObject, FX_TYPE_USEROBJECT, WDFOBJECT), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCollection, FX_TYPE_COLLECTION, WDFCOLLECTION), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxVerifierLock, FX_TYPE_VERIFIERLOCK), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxSystemThread, FX_TYPE_SYSTEMTHREAD), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMpDevice, FX_TYPE_MP_DEVICE, WDFDEVICE), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxResourceIo, FX_TYPE_RESOURCE_IO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxResourceCm, FX_TYPE_RESOURCE_CM), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxFileObject, FX_TYPE_FILEOBJECT, WDFFILEOBJECT), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxRelatedDevice, FX_TYPE_RELATED_DEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxMemoryBufferPreallocated, FX_TYPE_MEMORY_PREALLOCATED, WDFMEMORY), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWaitLock, FX_TYPE_WAIT_LOCK, WDFWAITLOCK), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxSpinLock, FX_TYPE_SPIN_LOCK, WDFSPINLOCK), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxWorkItem, FX_TYPE_WORKITEM, WDFWORKITEM), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxInterrupt, FX_TYPE_INTERRUPT, WDFINTERRUPT), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxTimer, FX_TYPE_TIMER, WDFTIMER), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxChildList, FX_TYPE_CHILD_LIST, WDFCHILDLIST), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxSystemWorkItem, FX_TYPE_SYSTEMWORKITEM), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxRequestMemory, FX_TYPE_REQUEST_MEMORY, WDFMEMORY), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxDisposeList, FX_TYPE_DISPOSELIST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoResList, FX_TYPE_IO_RES_LIST, WDFIORESLIST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxCmResList, FX_TYPE_CM_RES_LIST, WDFCMRESLIST), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoResReqList, FX_TYPE_IO_RES_REQ_LIST, WDFIORESREQLIST), + + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgIo, FX_TYPE_PACKAGE_IO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgFdo, FX_TYPE_PACKAGE_FDO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgPdo, FX_TYPE_PACKAGE_PDO), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxPkgGeneral, FX_TYPE_PACKAGE_GENERAL), + FX_INTERNAL_OBJECT_INFO_ENTRY(FxDefaultIrpHandler, FX_TYPE_DEFAULT_IRP_HANDLER), + + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoTarget, FX_TYPE_IO_TARGET, WDFIOTARGET), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbDevice, FX_TYPE_IO_TARGET_USB_DEVICE, WDFUSBDEVICE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbPipe, FX_TYPE_IO_TARGET_USB_PIPE, WDFUSBPIPE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxUsbInterface, FX_TYPE_USB_INTERFACE, WDFUSBINTERFACE), + FX_EXTERNAL_OBJECT_INFO_ENTRY(FxIoTargetSelf, FX_TYPE_IO_TARGET_SELF, WDFIOTARGET), +}; + +ULONG FxObjectsInfoCount = sizeof(FxObjectsInfo)/sizeof(FX_OBJECT_INFO); + +} //extern "C" diff --git a/sdk/lib/drivers/wdf/shared/object/um/fxobjectum.cpp b/sdk/lib/drivers/wdf/shared/object/um/fxobjectum.cpp new file mode 100644 index 00000000000..9b3310e8120 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/um/fxobjectum.cpp @@ -0,0 +1,194 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxObjectUm.cpp + +Abstract: + + User mode implementations of FxObject APIs + +Author: + + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "fxobjectpch.hpp" + +extern "C" { + +#if defined(EVENT_TRACING) +#include "FxObjectUm.tmh" +#endif + +} + +extern "C" { + +#define INITGUID +#include + +#include + +// +// Function declarations for the WdfObjectQuery DDIs +// +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFileObjectIncrementProcessKeepAliveCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFileObjectDecrementProcessKeepAliveCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +} + + +extern "C" { + +_Must_inspect_result_ +NTSTATUS +FxObject::_ObjectQuery( + _In_ FxObject* Object, + _In_ CONST GUID* Guid, + _In_ ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ) + +/*++ + +Routine Description: + + Query the object handle for specific information + + This allows dynamic extensions to DDI's. + + Currently, it is used to allow test hooks for verification + which are not available in a production release. + +Arguments: + + Object - Object to query + + Guid - GUID to represent the information/DDI to query for + + QueryBufferLength - Length of QueryBuffer to return data in + + QueryBuffer - Pointer to QueryBuffer + +Returns: + + NTSTATUS + +--*/ + +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals = Object->GetDriverGlobals(); + + // + // Design Note: This interface does not look strongly typed + // but it is. The GUID defines a specific strongly typed + // contract for QueryBuffer and QueryBufferLength. + // + +#if DBG + + // + // These operations are only available on checked builds for deep unit + // testing, code coverage analysis, and model verification. + + + + + + + + + + + + + + // + + // Add code based on the GUID + + // IsEqualGUID(guid1, guid2), DEFINE_GUID, INITGUID, inc\wnet\guiddef.h +#endif + + if (IsEqualGUID(*Guid, GUID_WDFP_FILEOBJECT_INTERFACE)) { + + // + // Check the query buffer size before performing the cast + // + const ULONG RequiredBufferLength = sizeof(WDFP_FILEOBJECT_INTERFACE); + + if (QueryBufferLength < RequiredBufferLength) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Insufficient query buffer size for file object query " + "Required size %d, %!STATUS!", + RequiredBufferLength, + STATUS_BUFFER_TOO_SMALL); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_BUFFER_TOO_SMALL; + } + + if (nullptr == QueryBuffer) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "NULL query buffer for file object query, %!STATUS!", + STATUS_BUFFER_TOO_SMALL); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_INVALID_PARAMETER; + } + + PWDFP_FILEOBJECT_INTERFACE FileObjectInterface = + reinterpret_cast(QueryBuffer); + + // + // Check the struct version (require an exact match for a private DDI) + // + if (FileObjectInterface->Size != RequiredBufferLength) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Wrong struct version provided for file object query, " + "%!STATUS!", + STATUS_INVALID_PARAMETER); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_INVALID_PARAMETER; + } + + FileObjectInterface->WdfpFileObjectIncrementProcessKeepAliveCount = + WDFEXPORT(WdfFileObjectIncrementProcessKeepAliveCount); + FileObjectInterface->WdfpFileObjectDecrementProcessKeepAliveCount = + WDFEXPORT(WdfFileObjectDecrementProcessKeepAliveCount); + + return STATUS_SUCCESS; + } + + return STATUS_NOT_FOUND; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/object/um/globalsum.cpp b/sdk/lib/drivers/wdf/shared/object/um/globalsum.cpp new file mode 100644 index 00000000000..d36127425ad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/um/globalsum.cpp @@ -0,0 +1,67 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "fxobjectpch.hpp" +#include "fxldrum.h" + +extern "C" { + +VOID +FxFreeAllocatedMdlsDebugInfo( + __in FxDriverGlobalsDebugExtension* DebugExtension + ) +{ + UNREFERENCED_PARAMETER(DebugExtension); + + //DO_NOTHING() +} + +_Must_inspect_result_ +BOOLEAN +FX_DRIVER_GLOBALS::IsCorrectVersionRegistered( + _In_ PCUNICODE_STRING /*ServiceKeyName*/ + ) +{ + return TRUE; // Then it won't even call the next method +} + +VOID +FX_DRIVER_GLOBALS::RegisterClientVersion( + _In_ PCUNICODE_STRING ServiceKeyName + ) +{ + UNREFERENCED_PARAMETER(ServiceKeyName); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +_Must_inspect_result_ +BOOLEAN +FX_DRIVER_GLOBALS::IsVersionGreaterThanOrEqualTo( + __in ULONG Major, + __in ULONG Minor + ) +{ + if ((WdfBindInfo->Version.Major > Major) || + (WdfBindInfo->Version.Major == Major && + WdfBindInfo->Version.Minor >= Minor)) { + return TRUE; + } + else { + return FALSE; + } +} + +} + +_Must_inspect_result_ +BOOLEAN +FX_DRIVER_GLOBALS::IsDebuggerAttached( + VOID + ) +{ + // + // COnvert the returned BOOL into BOOLEAN + // + return (IsDebuggerPresent() != FALSE); +} diff --git a/sdk/lib/drivers/wdf/shared/object/wdfpool.cpp b/sdk/lib/drivers/wdf/shared/object/wdfpool.cpp new file mode 100644 index 00000000000..0c44b688e61 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/object/wdfpool.cpp @@ -0,0 +1,710 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + wdfpool.c + +Abstract: + + This module implements the driver frameworks pool routines. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + + + + + + +--*/ + +#include "fxobjectpch.hpp" + +// We use DoTraceMessage +extern "C" { + +#if defined(EVENT_TRACING) +#include "wdfpool.tmh" +#endif + +} + +BOOLEAN +FxIsPagedPoolType( + __in POOL_TYPE Type + ) +/*++ + +Routine Description: + + Return whether paged pool is specified by POOL_TYPE + +Arguments: + + Type - POOL_TYPE + +Returns: + TRUE - Paged Pool,FALSE - Non-Paged Pool + +--*/ +{ + // + // Cleaner than doing (Type & 0x01) + // + switch( Type & (~POOL_COLD_ALLOCATION) ) { + case PagedPool: + case PagedPoolCacheAligned: + return TRUE; + + default: + return FALSE; + } +} + + +PVOID +FxPoolAllocator( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool, + __in POOL_TYPE Type, + __in SIZE_T Size, + __in ULONG Tag, + __in PVOID Caller + ) +/*++ + +Routine Description: + + Allocates system pool tracked in a FX_POOL tracking object. + +Arguments: + + Pool - FX_POOL object for tracking allocations + + Type - POOL_TYPE from ntddk.h + + Size - Size in bytes of the allocation + + Tag - Caller specified additional tag value for debugging/tracing + + Caller - Caller's address + +Returns: + + NULL - Could not allocate pool + !NULL - Pointer to pool of minimum Size bytes + +Remarks: + + In kernel mode this routine conditionally adds header on top iff the + allocation size is < PAGE_SIZE. If the allocation size is >= PAGE_SIZE + the caller would expect a page aligned pointer, hence no header is added. + In addition, ExAllocatePool* functions guarantee that a buffer < PAGE_SIZE + doesn't straddle page boundary. This allows FxPoolFree to determine whether + a header is added to buffer or not based on whether the pointer passed in + is page aligned or not. (In addition, when pool tracking is ON, this + routine adds pool tracking header based on whether additional space for this + header will push the buffer size beyond PAGE_SIZE, which is an optimization.) + + Such guarantees are not available with user mode allocator, hence in case + of user mode we always add the header. (In user mode a buffer < PAGE_SIZE + can straddle page boundary and the pointer returned may happen to be page + aligned, causing FxPoolFree to free the wrong pointer.) + +--*/ +{ + PVOID ptr; + PCHAR pTrueBase; + PFX_POOL_TRACKER pTracker; + PFX_POOL_HEADER pHeader; + NTSTATUS status; + SIZE_T allocationSize; + + + ptr = NULL; + + // + // Allocations of a zero request size are invalid. + // + // Besides, with a zero request size, special pool could place us + // at the end of a page, and adding our header would give us a page + // aligned address, which is ambiguous with large allocations. + // + if (Size == 0) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL, + "Invalid Allocation Size of 0 requested"); + FxVerifierDbgBreakPoint(FxDriverGlobals); + return NULL; + } + + if (FxDriverGlobals->IsPoolTrackingOn()) { + + if (FxDriverGlobals->FxVerifierOn && + (FxDriverGlobals->WdfVerifierAllocateFailCount != 0xFFFFFFFF)) { + + // + // If the registry key VerifierAllocateFailCount is set, all allocations + // after the specified count are failed. + // + // This is a brutal test, but also ensures the framework can cleanup + // under low memory conditions as well. + // + if (FxDriverGlobals->WdfVerifierAllocateFailCount == 0) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL, + "Allocation Fail Count exceeded"); + return NULL; + } + + // Decrement the count + InterlockedDecrement(&FxDriverGlobals->WdfVerifierAllocateFailCount); + } + + // + // (Kernel mode only) PAGE_SIZE or greater allocations can not have our + // header since this would break the system allocators contract + // that PAGE_SIZE or greater allocations start on a whole page boundary + // + + // + // For allocations less than a page size that will not fit with our + // header, we round up to a non-tracked whole page allocation so + // we don't burn two pages for this boundary condition. + // + + // This if is the same as + // Size + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE >= PAGE_SIZE + // BUT with no integer overflow + if (Mx::IsKM() && + (Size >= PAGE_SIZE - sizeof(FX_POOL_TRACKER) - FX_POOL_HEADER_SIZE) + ) { + + // + // Ensure that we ask for at least a page to ensure the + // allocation starts on a whole page. + // + if (Size < PAGE_SIZE) { + Size = PAGE_SIZE; + } + + ptr = MxMemory::MxAllocatePoolWithTag(Type, Size, Tag); + + // + // The current system allocator returns paged aligned memory + // in this case, which we rely on to detect whether our header + // is present or not in FxPoolFree + // + ASSERT(((ULONG_PTR)ptr & (PAGE_SIZE-1)) == 0); + } + else { + + status = RtlSIZETAdd(Size, + sizeof(FX_POOL_TRACKER) + FX_POOL_HEADER_SIZE, + &allocationSize); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL, + "overflow: allocation tracker (%d) + header (%d) + pool " + "request (%I64d)", sizeof(FX_POOL_TRACKER), + FX_POOL_HEADER_SIZE, Size); + + return NULL; + } + + pTrueBase = (PCHAR) MxMemory::MxAllocatePoolWithTag( + Type, + allocationSize, + Tag + ); + + if (pTrueBase == NULL) { + return NULL; + } + + pTracker = (PFX_POOL_TRACKER) pTrueBase; + pHeader = WDF_PTR_ADD_OFFSET_TYPE(pTrueBase, + sizeof(FX_POOL_TRACKER), + PFX_POOL_HEADER); + pHeader->Base = pTrueBase; + pHeader->FxDriverGlobals = FxDriverGlobals; + + // + // Adjust the pointer to what we return to the driver + // + ptr = &pHeader->AllocationStart[0]; + + // + // Ensure the pointer we are returning is aligned on the proper + // boundary. + // + ASSERT( ((ULONG_PTR) ptr & (MEMORY_ALLOCATION_ALIGNMENT-1)) == 0); + + // + // Ensure the pointer is still not page aligned after + // our adjustment. Otherwise the pool free code will + // get confused and call ExFreePool on the wrong ptr. + // + if (Mx::IsKM()) { + ASSERT(((ULONG_PTR)ptr & (PAGE_SIZE-1)) != 0 ); + } + + // + // We must separate paged and non-paged pool since + // the lock held differs as to whether we can accept + // page faults and block in the allocator. + // + if (FxIsPagedPoolType(Type)) { + // + // Format and insert the Tracker in the PagedHeader list. + // + FxPoolInsertPagedAllocateTracker(Pool, + pTracker, + Size, + Tag, + Caller); + } + else { + // + // Format and insert the Tracker in the NonPagedHeader list. + // + FxPoolInsertNonPagedAllocateTracker(Pool, + pTracker, + Size, + Tag, + Caller); + } + } + } + else { + // + // No pool tracking... + // + + if ((Size < PAGE_SIZE) || Mx::IsUM()) + { + // + // (Kernel mode only) See if adding our header promotes us past a + // page boundary + // + status = RtlSIZETAdd(Size, + FX_POOL_HEADER_SIZE, + &allocationSize); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL, + "overflow: header + pool request (%I64d)", Size); + + return NULL; + } + + } + else { + // + // Is the raw request for alloc >= PAGE_SIZE ? Then just use it. + // + allocationSize = Size; + } + + // + // Is cooked size for alloc >= PAGE_SIZE ? Then just do it. + // + if (allocationSize >= PAGE_SIZE && Mx::IsKM()) + { + // + // Important to use allocationSize so that we get a page aligned + // allocation so that we know to just free the memory pointer as is + // when it is freed. + // + ptr = MxMemory::MxAllocatePoolWithTag(Type, allocationSize, Tag); + ASSERT(((ULONG_PTR)ptr & (PAGE_SIZE-1)) == 0); + } + else { + pTrueBase = (PCHAR) MxMemory::MxAllocatePoolWithTag(Type, + allocationSize, + Tag); + + if (pTrueBase != NULL) { + + pHeader = (PFX_POOL_HEADER) pTrueBase; + pHeader->Base = pTrueBase; + pHeader->FxDriverGlobals = FxDriverGlobals; + + ptr = &pHeader->AllocationStart[0]; + + if (Mx::IsKM()) { + // + // Ensure the pointer is still not page aligned after + // our adjustment. Otherwise the pool free code will + // get confused and call ExFreePool on the wrong ptr. + // + ASSERT( ((ULONG_PTR)ptr & (PAGE_SIZE-1)) != 0 ); + } + } + } + } + + return ptr; +} + +VOID +FxPoolFree( + __in_xcount(ptr is at an offset from AllocationStart) PVOID ptr + ) +/*++ + +Routine Description: + + Release tracked pool + +Arguments: + + Pool - FX_POOL object allocation is tracked in + + ptr - Pointer to pool to release + +Returns: + +Remarks: + In kernel mode the pointer passed in may or may not have a header before + it depending upon whether the pointer is page aligned or not. + + In user mode the pointer passed in always has a header before it. See + remarks for FxPoolAllocator. + +--*/ +{ + PFX_POOL_HEADER pHeader; + PVOID pTrueBase; + PFX_POOL_TRACKER pTracker; + + // + // Null pointers are always bad + // + if( ptr == NULL ) { + ASSERTMSG("NULL pointer freed\n", FALSE); + Mx::MxBugCheckEx(WDF_VIOLATION, + WDF_REQUIRED_PARAMETER_IS_NULL, + (ULONG_PTR)NULL, + (ULONG_PTR)_ReturnAddress(), + (ULONG_PTR)NULL + ); + } + + // + // (Kernel mode only) If ptr is aligned on page boundry (indicates + // it was > PAGE_SIZE allocation) + // then there will be no common header...just free the memory without + // further processing. + // + if( Mx::IsKM() && ( ((ULONG_PTR)ptr & (PAGE_SIZE-1)) == 0 ) ) { + MxMemory::MxFreePool(ptr); + return; + } + + // + // Ensure the pointer we are returning is aligned on the proper + // boundary. + // + ASSERT( ((ULONG_PTR) ptr & (MEMORY_ALLOCATION_ALIGNMENT-1)) == 0); + + // + // Dereference the Common header which all Base; + + // + // If PoolTracker is on then Base must point to it's header. + // This is currently the only option for this area...may change later. + // + if (pHeader->FxDriverGlobals->IsPoolTrackingOn()) { + + pTracker = (PFX_POOL_TRACKER) pTrueBase; + + if (FxIsPagedPoolType(pTracker->PoolType)) { + // + // Decommission this Paged Allocation tracker + // + FxPoolRemovePagedAllocateTracker(pTracker); + } + else { + // + // Decommission this NonPaged Allocation tracker + // + FxPoolRemoveNonPagedAllocateTracker(pTracker); + } + + // + // Scrub the pool to zeros to catch destructed objects + // by NULL'ing the v-table ptr + // + RtlZeroMemory(pTracker, pTracker->Size + sizeof(FX_POOL_TRACKER)); + } + + MxMemory::MxFreePool(pTrueBase); +} + +NTSTATUS +FxPoolDump( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool + ) +/*++ + +Routine Description: + + Dump the FX_POOL tracking object + +Arguments: + + Pool - FX_POOL object for tracking allocations + +Returns: + + STATUS_SUCCESS + +--*/ +{ + PFX_POOL_TRACKER pTracker; + PLIST_ENTRY ple; + KIRQL oldIrql; + BOOLEAN leak; + + // + // Dump usage information + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "FxPoolDump: " + "NonPagedBytes %I64d, PagedBytes %I64d, " + "NonPagedAllocations %d, PagedAllocations %d," + "PeakNonPagedBytes %I64d, PeakPagedBytes %I64d," + "FxPoolDump: PeakNonPagedAllocations %d, PeakPagedAllocations %d", + Pool->NonPagedBytes, Pool->PagedBytes, + Pool->NonPagedAllocations, Pool->PagedAllocations, + Pool->PeakNonPagedBytes, Pool->PeakPagedBytes, + Pool->PeakNonPagedAllocations, Pool->PeakPagedAllocations + ); + + leak = FALSE; + + // + // Check paged pool for leaks + // + Pool->PagedLock.Acquire(); + + for (ple = Pool->PagedHead.Flink; ple != &Pool->PagedHead; ple = ple->Flink) { + pTracker = CONTAINING_RECORD(ple, FX_POOL_TRACKER, Link); + + // Leaker + leak = TRUE; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "FX_POOL 0x%p leaked paged memory alloc 0x%p (tracking block %p)", + Pool, pTracker + 1, pTracker); + } + + Pool->PagedLock.Release(); + + // + // Check non-paged pool for leaks + // + + Pool->NonPagedLock.Acquire(&oldIrql); + + for (ple = Pool->NonPagedHead.Flink; + ple != &Pool->NonPagedHead; + ple = ple->Flink) { + pTracker = CONTAINING_RECORD(ple, FX_POOL_TRACKER, Link ); + + // Leaker + leak = TRUE; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "FX_POOL 0x%p leaked non-paged memory alloc 0x%p (tracking block %p)", + Pool, pTracker+1, pTracker); + } + + Pool->NonPagedLock.Release(oldIrql); + + if (leak) { + FxVerifierDbgBreakPoint(FxDriverGlobals); + return STATUS_MORE_ENTRIES; + } + else { + return STATUS_SUCCESS; + } +} + +_Must_inspect_result_ +NTSTATUS +FxPoolInitialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool + ) +/*++ + +Routine Description: + Initialize the FX_POOL tracking object + +Arguments: + Pool - FX_POOL object for tracking allocations + +Returns: + STATUS_SUCCESS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPOOL, + "Initializing Pool 0x%p, Tracking %d", + Pool, FxDriverGlobals->IsPoolTrackingOn()); + + Pool->NonPagedLock.Initialize(); + + InitializeListHead( &Pool->NonPagedHead ); + + status = Pool->PagedLock.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPOOL, + "Initializing paged lock failed for Pool 0x%p, " + "status %!STATUS!", + Pool, status); + goto exit; + } + + InitializeListHead( &Pool->PagedHead ); + + // Pool usage information + Pool->NonPagedBytes = 0; + Pool->PagedBytes = 0; + + Pool->NonPagedAllocations = 0; + Pool->PagedAllocations = 0; + + Pool->PeakNonPagedBytes = 0; + Pool->PeakPagedBytes = 0; + + Pool->PeakNonPagedAllocations = 0; + Pool->PeakPagedAllocations = 0; + +exit: + if (!NT_SUCCESS(status)) { + // + // We disable pool tracking if we could not initialize the locks needed + // + // If we don't do this we would need another flag to make FxPoolDestroy + // not access the locks + // + FxDriverGlobals->FxPoolTrackingOn = FALSE; + } + + // + // FxPoolDestroy will always be called even if we fail FxPoolInitialize + // + // FxPoolDestroy will uninitialize locks both in success and failure + // cases + // + + return status; +} + +VOID +FxPoolDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PFX_POOL Pool + ) +/*++ + +Routine Description: + Destroy the FX_POOL tracking object + +Arguments: + Pool - FX_POOL object for tracking allocations + +Returns: + STATUS_SUCCESS + +--*/ +{ + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPOOL, + "Destroying Pool 0x%p", Pool); + + if (FxDriverGlobals->IsPoolTrackingOn()) { + FxPoolDump(FxDriverGlobals, Pool); + +#if FX_CORE_MODE==FX_CORE_KERNEL_MODE + FxMdlDump(FxDriverGlobals); +#endif + // + // We don't automatically free memory items since we don't + // know what they contain, and who is still referencing them. + // + } + + Pool->PagedLock.Uninitialize(); + Pool->NonPagedLock.Uninitialize(); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxPoolPackageInitialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +/*++ + +Routine Description: + Initialize the pool support package at startup time. + + This must be called before the first allocation. + +Arguments: + FxDriverGlobals - DriverGlobals + +Returns: + STATUS_SUCCESS + +--*/ +{ + return FxPoolInitialize(FxDriverGlobals, &FxDriverGlobals->FxPoolFrameworks); +} + +VOID +FxPoolPackageDestroy( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +/*++ + +Routine Description: + Destroy the pool support package at unload time + + This must be after the last free + +Arguments: + FxDriverGlobals - Driver's globals + +Returns: + STATUS_SUCCESS + +--*/ +{ + FxPoolDestroy(FxDriverGlobals, &FxDriverGlobals->FxPoolFrameworks); + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/primitives/km/mxgeneralkm.cpp b/sdk/lib/drivers/wdf/shared/primitives/km/mxgeneralkm.cpp new file mode 100644 index 00000000000..4b609c9dbe1 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/km/mxgeneralkm.cpp @@ -0,0 +1,58 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "Mx.h" + +VOID +Mx::MxDbgPrint( + __drv_formatString(printf) + __in PCSTR DebugMessage, + ... + ) +{ +#if DBG + +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + NTSTATUS status; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + status = RtlStringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!NT_SUCCESS(status)) { + + DbgPrint ("WDF DbgPrint: Unable to expand: %s", DebugMessage); + } + else { + DbgPrint("%s", debugMessageBuffer); + } + } + va_end(list); + +#else + UNREFERENCED_PARAMETER(DebugMessage); +#endif + return; +} + + +VOID +Mx::MxGlobalInit( + VOID + ) +{ + // + // Global initialization for kernel-mode primitives + // +} diff --git a/sdk/lib/drivers/wdf/shared/primitives/um/errtostatus.cpp b/sdk/lib/drivers/wdf/shared/primitives/um/errtostatus.cpp new file mode 100644 index 00000000000..5c8dad3579a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/um/errtostatus.cpp @@ -0,0 +1,74 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "Mx.h" + +BOOL +ConvertWinErrorToNtstatus( + __in ULONG WinError, + __out NTSTATUS * Status + ) +{ + ULONG index = 0; + BOOL found = FALSE; + + *Status = INVALID_STATUS; + + for ( ULONG i = 0; i < ARRAYSIZE(ErrorBucketTable); i++ ) + { + if (WinError < ErrorBucketTable[i].BaseErrorCode) + { + // + // The error code falls between previous bucket end and current + // bucket begin, hence there is no mapping for it + // + break; + } + + if ( WinError < (ErrorBucketTable[i].BaseErrorCode + + ErrorBucketTable[i].RunLength) ) + { + // + // Index falls within the current bucket + // + index += (WinError - ErrorBucketTable[i].BaseErrorCode); + found = TRUE; + break; + } + else + { + // + // Index is beyond current bucket, continue search + // + index += ErrorBucketTable[i].RunLength; + } + } + + if (TRUE == found) + { + *Status = ErrorTable[index]; + if (INVALID_STATUS == (*Status)) + { + found = FALSE; + } + } + + return found; +} + +NTSTATUS +WinErrorToNtStatus( + __in ULONG WinError + ) +{ + NTSTATUS status; + + if (TRUE == ConvertWinErrorToNtstatus(WinError, &status)) + { + return status; + } + else + { + return STATUS_UNSUCCESSFUL; + } +} diff --git a/sdk/lib/drivers/wdf/shared/primitives/um/mxdeviceobjectum.cpp b/sdk/lib/drivers/wdf/shared/primitives/um/mxdeviceobjectum.cpp new file mode 100644 index 00000000000..0f75cca655a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/um/mxdeviceobjectum.cpp @@ -0,0 +1,206 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDeviceObjectUm.cpp + +Abstract: + + User Mode implementation of Device Object defined in MxDeviceObject.h + +--*/ + +#include "fxmin.hpp" + +CCHAR +MxDeviceObject::GetStackSize( + VOID + ) +{ + return (CCHAR) (static_cast(m_DeviceObject))->GetStackSize2(); +} + +VOID +MxDeviceObject::ReferenceObject( + ) +{ + m_DeviceObject->AddRef(); + + // + // We take a reference on device stack object as it is the reference on + // device stack object that keeps the driver loaded + // + m_DeviceObject->GetDeviceStackInterface()->AddRef(); +} + +MdDeviceObject +MxDeviceObject::GetAttachedDeviceReference( + VOID + ) +{ + FX_VERIFY(INTERNAL, TRAPMSG("MxDeviceObject::GetAttachedDeviceReference " + "not implemented for UMDF")); + return NULL; +} + +VOID +MxDeviceObject::DereferenceObject( + ) +{ + m_DeviceObject->Release(); + + // + // We also take a device stack reference (see ReferenceObject) + // release it now + // + m_DeviceObject->GetDeviceStackInterface()->Release(); +} + +ULONG +MxDeviceObject::GetFlags( + VOID + ) +{ + return m_DeviceObject->GetDeviceObjectWdmFlags(); +} + +POWER_STATE +MxDeviceObject::SetPowerState( + __in POWER_STATE_TYPE /*Type*/, + __in POWER_STATE State + ) +{ + ULONG oldState; + POWER_STATE oldStateEnum; + + m_DeviceObject->GetDeviceStackInterface()->SetPowerState( + State.DeviceState, + &oldState + ); + + oldStateEnum.DeviceState = (DEVICE_POWER_STATE) oldState; + + return oldStateEnum; +} + +VOID +MxDeviceObject::InvalidateDeviceRelations( + __in DEVICE_RELATION_TYPE Type + ) +{ + UNREFERENCED_PARAMETER(Type); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + //IoInvalidateDeviceRelations(DeviceObject, Type); +} + +VOID +MxDeviceObject::InvalidateDeviceState( + __in MdDeviceObject Fdo + ) +{ + // + // DO NOT use m_DeviceObject. That specifies PDO in this case which is + // currently NULL for UMDF. Use the passed in Fdo instead. + // + Fdo->GetDeviceStackInterface()->InvalidateDeviceState(); +} + +PVOID +MxDeviceObject::GetDeviceExtension( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return NULL; +} + +VOID +MxDeviceObject::SetDeviceExtension( + PVOID Value + ) +{ + // + // This will set the context + // + (static_cast(m_DeviceObject))->SetContext(Value); +} + +DEVICE_TYPE +MxDeviceObject::GetDeviceType( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return (DEVICE_TYPE) 0; +} + +ULONG +MxDeviceObject::GetCharacteristics( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return 0; +} + +VOID +MxDeviceObject::SetDeviceType( + DEVICE_TYPE /* Value */ + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +MxDeviceObject::SetCharacteristics( + ULONG /* Characteristics */ + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +VOID +MxDeviceObject::SetAlignmentRequirement( + _In_ ULONG /* Value */ + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +ULONG +MxDeviceObject::GetAlignmentRequirement( + VOID + ) +{ + ASSERTMSG("Not implemented for UMDF\n", FALSE); + return 0; +} + +VOID +MxDeviceObject::SetStackSize( + _In_ CCHAR Size + ) +{ + (static_cast(m_DeviceObject))->SetStackSize2((ULONG)Size); +} + +VOID +MxDeviceObject::SetFlags( + ULONG Flags + ) +{ + UNREFERENCED_PARAMETER(Flags); + + + + + + + + +} + diff --git a/sdk/lib/drivers/wdf/shared/primitives/um/mxdriverobjectum.cpp b/sdk/lib/drivers/wdf/shared/primitives/um/mxdriverobjectum.cpp new file mode 100644 index 00000000000..17546a6f81a --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/um/mxdriverobjectum.cpp @@ -0,0 +1,75 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxDeviceObjectUm.cpp + +Abstract: + + User Mode implementation of Device Object defined in MxDeviceObject.h + +--*/ + +#include "fxmin.hpp" +#include "fxldrum.h" + +PVOID +MxDriverObject::GetDriverExtensionAddDevice( + VOID + ) +{ + return m_DriverObject->AddDevice; +} + +VOID +MxDriverObject::SetDriverExtensionAddDevice( + _In_ MdDriverAddDevice Value + ) +{ + m_DriverObject->AddDevice = Value; +} + +MdDriverUnload +MxDriverObject::GetDriverUnload( + VOID + ) +{ + m_DriverObject->DriverUnload; + return NULL; +} + +VOID +MxDriverObject::SetDriverUnload( + _In_ MdDriverUnload Value + ) +{ + m_DriverObject->DriverUnload = Value; +} + +VOID +MxDriverObject::SetMajorFunction( + _In_ UCHAR i, + _In_ MdDriverDispatch Value + ) +{ + m_DriverObject->MajorFunction[i] = Value; +} + +VOID +MxDriverObject::SetDriverObjectFlag( + _In_ FxDriverObjectUmFlags Flag + ) +{ + m_DriverObject->Flags |= Flag; +} + +BOOLEAN +MxDriverObject::IsDriverObjectFlagSet( + _In_ FxDriverObjectUmFlags Flag + ) +{ + return (!!(m_DriverObject->Flags & Flag)); +} + diff --git a/sdk/lib/drivers/wdf/shared/primitives/um/mxfileobjectum.cpp b/sdk/lib/drivers/wdf/shared/primitives/um/mxfileobjectum.cpp new file mode 100644 index 00000000000..c97abc73416 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/um/mxfileobjectum.cpp @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxFileObjectUm.cpp + +Abstract: + + Implementation of MxFileObjectUm functions. + +Author: + +Revision History: + + + +--*/ + +#include "Mx.h" + +#include + +#include "fxmin.hpp" + +PUNICODE_STRING +MxFileObject::GetFileName( + _Inout_opt_ PUNICODE_STRING Filename + ) +{ + LPCWSTR name; + + ASSERTMSG("Filename parameter cannot be NULL\n", Filename != NULL); + + name = m_FileObject->GetName(); + RtlInitUnicodeString(Filename, name); + + return Filename; +} + diff --git a/sdk/lib/drivers/wdf/shared/primitives/um/mxgeneralum.cpp b/sdk/lib/drivers/wdf/shared/primitives/um/mxgeneralum.cpp new file mode 100644 index 00000000000..5887db90998 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/um/mxgeneralum.cpp @@ -0,0 +1,123 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxGeneralUm.cpp + +Abstract: + + Implementation of MxGeneralUm functions. + +Author: + + + +Revision History: + + + +--*/ + +#include "Mx.h" + +#include + +#include "fxmin.hpp" + +extern "C" IUMDFPlatform *g_IUMDFPlatform; + +VOID +Mx::MxDbgPrint( + __drv_formatString(printf) + __in PCSTR DebugMessage, + ... + ) +{ +#if DBG + +#define TEMP_BUFFER_SIZE 1024 + va_list list; + CHAR debugMessageBuffer[TEMP_BUFFER_SIZE]; + HRESULT hr; + + va_start(list, DebugMessage); + + if (DebugMessage) { + + // + // Using new safe string functions instead of _vsnprintf. + // This function takes care of NULL terminating if the message + // is longer than the buffer. + // + hr = StringCbVPrintfA( debugMessageBuffer, + sizeof(debugMessageBuffer), + DebugMessage, + list ); + if(!SUCCEEDED(hr)) { + OutputDebugStringA("WDF DbgPrint: Unable to expand: "); + OutputDebugStringA(DebugMessage); + } + else { + OutputDebugStringA(debugMessageBuffer); + } + } + va_end(list); + +#else + UNREFERENCED_PARAMETER(DebugMessage); +#endif + return; +} + +VOID +Mx::MxBugCheckEx( + _In_ ULONG BugCheckCode, + _In_ ULONG_PTR BugCheckParameter1, + _In_ ULONG_PTR BugCheckParameter2, + _In_ ULONG_PTR BugCheckParameter3, + _In_ ULONG_PTR BugCheckParameter4 +) +{ + + UNREFERENCED_PARAMETER(BugCheckParameter1); + UNREFERENCED_PARAMETER(BugCheckParameter2); + UNREFERENCED_PARAMETER(BugCheckParameter3); + UNREFERENCED_PARAMETER(BugCheckParameter4); + + FX_VERIFY(DRIVER(BadAction, BugCheckCode), TRAPMSG("UMDF verification " + "faults should not call this code path")); +} + +VOID +Mx::MxGlobalInit( + VOID + ) +{ + // + // Currently just a placeholder. If there is any global initialization + // needed for the user-mode primitives, it can be done here. + // +} + +VOID +Mx::MxDetachDevice( + _Inout_ MdDeviceObject Device + ) +{ + + + + + + HRESULT hrDetachDev = + Device->GetDeviceStackInterface()->DetachDevice(Device); + + + + + + UNREFERENCED_PARAMETER(hrDetachDev); +} + diff --git a/sdk/lib/drivers/wdf/shared/primitives/um/mxworkitemum.cpp b/sdk/lib/drivers/wdf/shared/primitives/um/mxworkitemum.cpp new file mode 100644 index 00000000000..ecba0363e56 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/primitives/um/mxworkitemum.cpp @@ -0,0 +1,66 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + MxWorkItemUm.cpp + +Abstract: + + Work item callback thunk implementation for user mode + + We need this thunk to wire the um callback to a mode agnostic work item + callback. + +Author: + + + +Revision History: + + + +--*/ + +#include "Mx.h" + +VOID +CALLBACK +MxWorkItem::_WorkerThunk ( + _Inout_ PTP_CALLBACK_INSTANCE Instance, + _Inout_opt_ PVOID Parameter, + _Inout_ PTP_WAIT Wait, + _In_ TP_WAIT_RESULT WaitResult + ) +{ + MdWorkItem workItem = (MdWorkItem) Parameter; + + UNREFERENCED_PARAMETER(Instance); + UNREFERENCED_PARAMETER(Wait); + UNREFERENCED_PARAMETER(WaitResult); + + (*workItem->Callback)( + workItem->DeviceObject, + workItem->Context + ); + + return; +} + +VOID +MxWorkItem::WaitForCallbacksToComplete( + VOID + ) +{ + Mx::MxAssert(NULL != m_WorkItem->WaitBlock); + + // + // Wait for outstanding callbacks to complete. + // + WaitForThreadpoolWaitCallbacks(m_WorkItem->WaitBlock, + FALSE // donot cancel pending waits + ); + +} + diff --git a/sdk/lib/drivers/wdf/shared/support/fxcollection.cpp b/sdk/lib/drivers/wdf/shared/support/fxcollection.cpp new file mode 100644 index 00000000000..fffcda75334 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxcollection.cpp @@ -0,0 +1,285 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCollection.cpp + +Abstract: + + This module implements a simple collection class to operate on + objects derived from FxObject. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +FxCollectionInternal::FxCollectionInternal( + VOID + ) +{ + m_Count = 0; + InitializeListHead(&m_ListHead); +} + +FxCollectionInternal::~FxCollectionInternal( + VOID + ) +{ + Clear(); +} + +VOID +FxCollectionInternal::Clear( + VOID + ) +{ + while (!IsListEmpty(&m_ListHead)) { + Remove(0); + } +} + +ULONG +FxCollectionInternal::Count( + VOID + ) +{ + return m_Count; +} + +BOOLEAN +FxCollectionInternal::Add( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxObject *Item + ) +{ + FxCollectionEntry *pNode; + + pNode = AllocateEntry(FxDriverGlobals); + + if (pNode != NULL) { + InsertTailList(&m_ListHead, &pNode->m_ListEntry); + + AddEntry(pNode, Item); + } + + return pNode != NULL; +} + +_Must_inspect_result_ +FxCollectionEntry* +FxCollectionInternal::FindEntry( + __in ULONG Index + ) +{ + PLIST_ENTRY ple; + ULONG i; + + if (Index >= m_Count) { + return NULL; + } + + for (i = 0, ple = m_ListHead.Flink; + ple != &m_ListHead; + ple = ple->Flink, i++) { + if (i != Index) { + continue; + } + + return CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry); + } + + return NULL; +} + +_Must_inspect_result_ +FxCollectionEntry* +FxCollectionInternal::FindEntryByObject( + __in FxObject* Object + ) +{ + PLIST_ENTRY ple; + + for (ple = m_ListHead.Flink; ple != &m_ListHead; ple = ple->Flink) { + FxCollectionEntry* pNode; + + pNode = CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry); + if (pNode->m_Object == Object) { + return pNode; + } + } + + return NULL; +} + +NTSTATUS +FxCollectionInternal::Remove( + __in ULONG Index + ) +{ + FxCollectionEntry *pNode; + + pNode = FindEntry(Index); + + if (pNode != NULL) { + return RemoveEntry(pNode); + } + else { + return STATUS_NOT_FOUND; + } +} + +_Must_inspect_result_ +NTSTATUS +FxCollectionInternal::RemoveItem( + __in FxObject* Item + ) +{ + FxCollectionEntry* pNode; + + pNode = FindEntryByObject(Item); + + if (pNode != NULL) { + return RemoveEntry(pNode); + } + + return STATUS_NOT_FOUND; +} + +VOID +FxCollectionInternal::CleanupEntry( + __in FxCollectionEntry* Entry + ) +{ + RemoveEntryList(&Entry->m_ListEntry); + delete Entry; + + m_Count--; +} + +NTSTATUS +FxCollectionInternal::RemoveEntry( + __in FxCollectionEntry* Entry + ) +{ + CleanupEntryObject(Entry->m_Object); + CleanupEntry(Entry); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +FxObject* +FxCollectionInternal::GetItem( + __in ULONG Index + ) + +{ + FxCollectionEntry* pNode; + + pNode = FindEntry(Index); + if (pNode != NULL) { + return pNode->m_Object; + } + else { + return NULL; + } +} + +_Must_inspect_result_ +FxObject* +FxCollectionInternal::GetFirstItem( + VOID + ) +{ + if (IsListEmpty(&m_ListHead)) { + return NULL; + } + else { + return CONTAINING_RECORD(m_ListHead.Flink, + FxCollectionEntry, + m_ListEntry)->m_Object; + } +} + +_Must_inspect_result_ +FxObject* +FxCollectionInternal::GetLastItem( + VOID + ) +{ + if (IsListEmpty(&m_ListHead)) { + return NULL; + } + else { + return CONTAINING_RECORD(m_ListHead.Blink, + FxCollectionEntry, + m_ListEntry)->m_Object; + } +} + +FxCollection::FxCollection( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxNonPagedObject(FX_TYPE_COLLECTION, sizeof(FxCollection), FxDriverGlobals) +{ +} + +FxCollection::FxCollection( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFTYPE Type, + __in USHORT Size + ) : FxNonPagedObject(Type, Size, FxDriverGlobals) +{ +} + +FxCollection::~FxCollection( + VOID + ) +{ + Clear(); +} + +VOID +FxCollection::StealCollection( + __in FxCollection* Collection + ) +{ + PLIST_ENTRY ple; + + m_Count = Collection->m_Count; + Collection->m_Count = 0; + + while (!IsListEmpty(&Collection->m_ListHead)) { + FxCollectionEntry* pEntry; + + ple = RemoveHeadList(&Collection->m_ListHead); + pEntry = CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry); + + // + // When we are tracking reference tags, the tag associated with the + // reference matters. When we added the object to Collection, we used + // that pointer as the tag. We must remove that tag and readd the + // reference using the this value as a tag. + // + // Obviously, order is important here. Add the reference first so that + // we know the relese will make the object go away. + // + pEntry->m_Object->ADDREF(this); + pEntry->m_Object->RELEASE(Collection); + + InsertTailList(&m_ListHead, ple); + } +} + diff --git a/sdk/lib/drivers/wdf/shared/support/fxcollectionapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxcollectionapi.cpp new file mode 100644 index 00000000000..01b0c45b347 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxcollectionapi.cpp @@ -0,0 +1,384 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxCollectionApi.cpp + +Abstract: + + This module implements the "C" interface to the collection object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxCollectionApi.tmh" +} + +// +// Extern the entire file +// +extern "C" { +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfCollectionCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + __out + WDFCOLLECTION *Collection + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxCollection *pCollection; + WDFCOLLECTION hCol; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle( + pFxDriverGlobals, CollectionAttributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + CollectionAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, Collection); + + *Collection = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, CollectionAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + pCollection = new (pFxDriverGlobals, CollectionAttributes) + FxCollection(pFxDriverGlobals); + + if (pCollection != NULL) { + status = pCollection->Commit(CollectionAttributes, (WDFOBJECT*)&hCol); + + if (NT_SUCCESS(status)) { + *Collection = hCol; + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Could not create collection object: %!STATUS!", + status); + + pCollection->DeleteFromFailedCreate(); + } + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Could not create collection object: " + "STATUS_INSUFFICIENT_RESOURCES" ); + status = STATUS_INSUFFICIENT_RESOURCES; + } + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfCollectionGetCount)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOLLECTION Collection + ) +{ + DDI_ENTRY(); + + FxCollection *pCollection; + KIRQL irql; + ULONG count; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Collection, + FX_TYPE_COLLECTION, + (PVOID *)&pCollection); + + pCollection->Lock(&irql); + count = pCollection->Count(); + pCollection->Unlock(irql); + + return count; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfCollectionAdd)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOLLECTION Collection, + __in + WDFOBJECT Object + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCollection *pCollection; + FxObject *pObject; + NTSTATUS status; + KIRQL irql; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Collection, + FX_TYPE_COLLECTION, + (PVOID*) &pCollection, + &pFxDriverGlobals); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Object, + FX_TYPE_OBJECT, + (PVOID*) &pObject); + + pCollection->Lock(&irql); + status = pCollection->Add(pObject) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; + pCollection->Unlock(irql); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfCollectionRemoveItem)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOLLECTION Collection, + __in + ULONG Index + ) +{ + 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); + + pCollection->Lock(&irql); + + pEntry = pCollection->FindEntry(Index); + + if (pEntry != NULL) { + pObject = pEntry->m_Object; + 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, + "Index %d is not valid in WDFCOLLECTION %p (count is %d), %!STATUS!", + Index, Collection, pCollection->Count(), status); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +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); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFOBJECT +WDFEXPORT(WdfCollectionGetItem)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOLLECTION Collection, + __in + ULONG Index + ) +{ + DDI_ENTRY(); + + FxCollection *pCollection; + FxObject *pObject; + WDFOBJECT hObject; + KIRQL irql; + + hObject = NULL; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Collection, + FX_TYPE_COLLECTION, + (PVOID*) &pCollection); + + pCollection->Lock(&irql); + pObject = pCollection->GetItem(Index); + pCollection->Unlock(irql); + + if (pObject == NULL) { + return NULL; + } + + return pObject->GetObjectHandle(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFOBJECT +WDFEXPORT(WdfCollectionGetFirstItem)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOLLECTION Collection + ) +{ + DDI_ENTRY(); + + FxCollection *pCollection; + FxObject* pObject; + KIRQL irql; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Collection, + FX_TYPE_COLLECTION, + (PVOID*) &pCollection); + + pCollection->Lock(&irql); + pObject = pCollection->GetFirstItem(); + pCollection->Unlock(irql); + + if (pObject != NULL) { + return pObject->GetObjectHandle(); + } + else { + return NULL; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFOBJECT +WDFEXPORT(WdfCollectionGetLastItem)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCOLLECTION Collection + ) +{ + DDI_ENTRY(); + + FxCollection *pCollection; + FxObject* pObject; + KIRQL irql; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Collection, + FX_TYPE_COLLECTION, + (PVOID*) &pCollection); + + pCollection->Lock(&irql); + pObject = pCollection->GetLastItem(); + pCollection->Unlock(irql); + + if (pObject != NULL) { + return pObject->GetObjectHandle(); + } + else { + return NULL; + } +} + +} // extern "C" of entire file diff --git a/sdk/lib/drivers/wdf/shared/support/fxdeviceinterface.cpp b/sdk/lib/drivers/wdf/shared/support/fxdeviceinterface.cpp new file mode 100644 index 00000000000..666772df448 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxdeviceinterface.cpp @@ -0,0 +1,155 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInterface.cpp + +Abstract: + + This module implements the device interface object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxDeviceInterface.tmh" +} + +FxDeviceInterface::FxDeviceInterface( + ) +/*++ + +Routine Description: + Constructor for the object. Initializes all fields + +Arguments: + None + +Return Value: + None + + --*/ +{ + RtlZeroMemory(&m_InterfaceClassGUID, sizeof(m_InterfaceClassGUID)); + + RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName)); + RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString)); + + m_Entry.Next = NULL; + + m_State = FALSE; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + m_Device = NULL; +#endif + +} + +FxDeviceInterface::~FxDeviceInterface() +/*++ + +Routine Description: + Destructor for FxDeviceInterface. Cleans up any allocations previously + allocated. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // the device interface should be off now + ASSERT(m_State == FALSE); + + // should no longer be in any list + ASSERT(m_Entry.Next == NULL); + + if (m_ReferenceString.Buffer != NULL) { + FxPoolFree(m_ReferenceString.Buffer); + RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString)); + } + + if (m_SymbolicLinkName.Buffer != NULL) { + RtlFreeUnicodeString(&m_SymbolicLinkName); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Initialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CONST GUID* InterfaceGUID, + __in_opt PCUNICODE_STRING ReferenceString + ) +/*++ + +Routine Description: + Initializes the object with the interface GUID and optional reference string + +Arguments: + InterfaceGUID - GUID describing the interface + + ReferenceString - string used to differentiate between 2 interfaces on the + same PDO + +Return Value: + STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES + + --*/ +{ + RtlCopyMemory(&m_InterfaceClassGUID, InterfaceGUID, sizeof(GUID)); + + if (ReferenceString != NULL) { + return FxDuplicateUnicodeString(FxDriverGlobals, + ReferenceString, + &m_ReferenceString); + } + else { + return STATUS_SUCCESS; + } +} + + +VOID +FxDeviceInterface::SetState( + __in BOOLEAN State + ) +/*++ + +Routine Description: + Sets the state of the device interface + +Arguments: + State - the state to set + + +Return Value: + None. + + --*/ +{ + m_State = State; + + // + // Only set the state if the interface has been registered + // + if (m_SymbolicLinkName.Buffer != NULL) { + Mx::MxSetDeviceInterfaceState(&m_SymbolicLinkName, m_State); + } +} + diff --git a/sdk/lib/drivers/wdf/shared/support/fxdeviceinterfaceapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxdeviceinterfaceapi.cpp new file mode 100644 index 00000000000..6af050dade2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxdeviceinterfaceapi.cpp @@ -0,0 +1,400 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInterfaceAPI.cpp + +Abstract: + + This module implements the device interface object external APIs + +Author: + + + + +Environment: + + kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxDeviceInterfaceAPI.tmh" +} + +// +// extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceCreateDeviceInterface)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + CONST GUID *InterfaceClassGUID, + __in_opt + PCUNICODE_STRING ReferenceString + ) +/*++ + +Routine Description: + Creates a device interface associated with the passed in device object + +Arguments: + Device - Handle which represents the device exposing the interface + + InterfaceGUID - GUID describing the interface being exposed + + ReferenceString - OPTIONAL string which allows the driver writer to + distinguish between different exposed interfaces + +Return Value: + STATUS_SUCCESS or appropriate NTSTATUS code + + --*/ +{ + DDI_ENTRY(); + + SINGLE_LIST_ENTRY **ppPrev, *pCur; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDeviceInterface *pDeviceInterface; + FxDevice *pDevice; + FxPkgPnp* pPkgPnp; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (ReferenceString != NULL) { + status = FxValidateUnicodeString(pFxDriverGlobals, ReferenceString); + if (!NT_SUCCESS(status)) { + return status; + } + } + + if (pDevice->IsLegacy()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p is not a PNP device, device interface creation not " + "allowed %!STATUS!", Device, status); + + return status; + } + + pDeviceInterface = new(pFxDriverGlobals, PagedPool) FxDeviceInterface(); + + if (pDeviceInterface == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p DeviceInterface object creation failed, %!STATUS!", + Device, status); + + return status; + } + + status = pDeviceInterface->Initialize(pFxDriverGlobals, + InterfaceClassGUID, + ReferenceString); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p, DeviceInterface object initialization failed, %!STATUS!", + Device, status ); + + goto Done; + } + + pPkgPnp = pDevice->m_PkgPnp; + + pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals); + + status = pDeviceInterface->Register(pDevice); + + if (NT_SUCCESS(status)) { + // + // Insert into the end of the list + // + ppPrev = &pPkgPnp->m_DeviceInterfaceHead.Next; + pCur = pPkgPnp->m_DeviceInterfaceHead.Next; + while (pCur != NULL) { + ppPrev = &pCur->Next; + pCur = pCur->Next; + } + + *ppPrev = &pDeviceInterface->m_Entry; + } + + pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals); + +Done: + if (!NT_SUCCESS(status)) { + delete pDeviceInterface; + pDeviceInterface = NULL; + } + + return status; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + CONST GUID *InterfaceClassGUID, + __in_opt + PCUNICODE_STRING RefString, + __in + BOOLEAN State + ) +{ + DDI_ENTRY(); + + PSINGLE_LIST_ENTRY ple; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxDevice* pDevice; + FxPkgPnp* pPkgPnp; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + if (RefString != NULL) { + status = FxValidateUnicodeString(pFxDriverGlobals, RefString); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + } + + if (pDevice->IsLegacy()) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p is not a PNP device, device interfaces not allowed", + Device); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pPkgPnp = pDevice->m_PkgPnp; + + pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals); + + // + // Iterate over the interfaces and see if we have a match + // + for (ple = pPkgPnp->m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) { + FxDeviceInterface *pDI; + + pDI = FxDeviceInterface::_FromEntry(ple); + + if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) { + if (RefString != NULL) { + if ((RefString->Length == pDI->m_ReferenceString.Length) + && + (RtlCompareMemory(RefString->Buffer, + pDI->m_ReferenceString.Buffer, + RefString->Length) == RefString->Length)) { + // + // They match, carry on + // + DO_NOTHING(); + } + else { + // + // The ref strings do not match, continue on in the search + // of the collection. + // + continue; + } + } + else if (pDI->m_ReferenceString.Length > 0) { + // + // Caller didn't specify a ref string but this interface has + // one, continue on in the search through the collection. + // + continue; + } + + // + // Set the state and break out of the loop because we found our + // interface. + // + pDI->SetState(State); + break; + } + } + + pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + CONST GUID* InterfaceClassGUID, + __in_opt + PCUNICODE_STRING RefString, + __in + WDFSTRING String + ) +/*++ + +Routine Description: + Returns the symbolic link value of the registered device interface. + +Arguments: + + +Return Value: + + + --*/ + +{ + DDI_ENTRY(); + + PSINGLE_LIST_ENTRY ple; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDevice* pDevice; + FxPkgPnp* pPkgPnp; + FxString* pString; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE, + (PVOID*) &pDevice, + &pFxDriverGlobals ); + + FxPointerNotNull(pFxDriverGlobals, InterfaceClassGUID); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (RefString != NULL) { + status = FxValidateUnicodeString(pFxDriverGlobals, RefString); + if (!NT_SUCCESS(status)) { + return status; + } + } + + if (pDevice->IsLegacy()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFDEVICE %p is not a PNP device, device interface creation not " + "allowed %!STATUS!", Device, status); + + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + String, + FX_TYPE_STRING, + (PVOID*) &pString); + + pPkgPnp = pDevice->m_PkgPnp; + + status = STATUS_OBJECT_NAME_NOT_FOUND; + + pPkgPnp->m_DeviceInterfaceLock.AcquireLock(pFxDriverGlobals); + + // + // Iterate over the interfaces and see if we have a match + // + for (ple = pPkgPnp->m_DeviceInterfaceHead.Next; + ple != NULL; + ple = ple->Next) { + FxDeviceInterface *pDI; + + pDI = FxDeviceInterface::_FromEntry(ple); + + if (FxIsEqualGuid(&pDI->m_InterfaceClassGUID, InterfaceClassGUID)) { + if (RefString != NULL) { + if ((RefString->Length == pDI->m_ReferenceString.Length) + && + (RtlCompareMemory(RefString->Buffer, + pDI->m_ReferenceString.Buffer, + RefString->Length) == RefString->Length)) { + // + // They match, carry on + // + DO_NOTHING(); + } + else { + // + // The ref strings do not match, continue on in the search + // of the collection. + // + continue; + } + } + else if (pDI->m_ReferenceString.Length > 0) { + // + // Caller didn't specify a ref string but this interface has + // one, continue on in the search through the collection. + // + continue; + } + + status = pDI->GetSymbolicLinkName(pString); + + break; + } + } + + pPkgPnp->m_DeviceInterfaceLock.ReleaseLock(pFxDriverGlobals); + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/support/fxdevicetext.cpp b/sdk/lib/drivers/wdf/shared/support/fxdevicetext.cpp new file mode 100644 index 00000000000..86902a567e7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxdevicetext.cpp @@ -0,0 +1,52 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceText.cpp + +Abstract: + + This module implements the device text object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +FxDeviceText::FxDeviceText( + VOID + ) : + m_Description(NULL), + m_LocationInformation(NULL), + m_LocaleId(0) +{ + m_Entry.Next = NULL; +} + +FxDeviceText::~FxDeviceText() +{ + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + ASSERT(m_Entry.Next == NULL); + + if (m_Description != NULL) { + FxPoolFree(m_Description); + m_Description = NULL; + } + + if (m_LocationInformation != NULL) { + FxPoolFree(m_LocationInformation); + m_LocationInformation = NULL; + } +} diff --git a/sdk/lib/drivers/wdf/shared/support/fxregistryapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxregistryapi.cpp new file mode 100644 index 00000000000..8c6efb3ad1b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxregistryapi.cpp @@ -0,0 +1,1530 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRegistryAPI.cpp + +Abstract: + + This module implements registry access in the framework + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxRegistryAPI.tmh" +} + +extern "C" { +// +// Not in a public header that we can reach, but is documented +// +NTSYSAPI +NTSTATUS +NTAPI +ZwDeleteValueKey( + __in IN HANDLE Key, + __in IN PUNICODE_STRING ValueName + ); +} + + +// +// Extern "C" the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryOpenKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + WDFKEY ParentKey, + __in + PCUNICODE_STRING KeyName, + __in + ACCESS_MASK DesiredAccess, + __in_opt + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + __out + WDFKEY* Key + ) +{ + DDI_ENTRY(); + + FxRegKey* pKey; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + WDFKEY keyHandle; + HANDLE parentHandle; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + keyHandle = NULL; + + if (ParentKey != NULL) { + FxRegKey* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + ParentKey, + FX_TYPE_REG_KEY, + (PVOID*) &pParent, + &pFxDriverGlobals); + + parentHandle = pParent->GetHandle(); + } + else { + parentHandle = NULL; + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + KeyAttributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + KeyAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + } + + FxPointerNotNull(pFxDriverGlobals, KeyName); + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, KeyName); + if (!NT_SUCCESS(status)) { + return status; + } + + pKey = new (pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals); + if (pKey == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Could not allocate memory for a WDFKEY, %!STATUS!", status); + + return status; + } + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + + if (NT_SUCCESS(status)) { + status = pKey->Open(parentHandle, KeyName, DesiredAccess); + + if (NT_SUCCESS(status)) { + *Key = keyHandle; + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "new WDFKEY object open failed, %!STATUS!", status); + } + } + + if (!NT_SUCCESS(status)) { + pKey->DeleteFromFailedCreate(); + pKey = NULL; + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryCreateKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + WDFKEY ParentKey, + __in + PCUNICODE_STRING KeyName, + __in + ACCESS_MASK DesiredAccess, + __in + ULONG CreateOptions, + __out_opt + PULONG CreateDisposition, + __in_opt + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + __out + WDFKEY* Key + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + WDFKEY keyHandle; + HANDLE parentHandle; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + if (ParentKey != NULL) { + FxRegKey* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + ParentKey, + FX_TYPE_REG_KEY, + (PVOID*) &pParent, + &pFxDriverGlobals); + + parentHandle = pParent->GetHandle(); + } + else { + parentHandle = NULL; + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + KeyAttributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + KeyAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + } + + FxPointerNotNull(pFxDriverGlobals, KeyName); + FxPointerNotNull(pFxDriverGlobals, Key); + + *Key = NULL; + keyHandle = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, KeyAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, KeyName); + if (!NT_SUCCESS(status)) { + return status; + } + + pKey = new (pFxDriverGlobals, KeyAttributes) FxRegKey(pFxDriverGlobals); + + if (pKey == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Could not allocate memory for WDFKEY, %!STATUS!", status); + + return status; + } + + status = pKey->Commit(KeyAttributes, (WDFOBJECT*)&keyHandle); + + if (NT_SUCCESS(status)) { + status = pKey->Create(parentHandle, + KeyName, + DesiredAccess, + CreateOptions, + CreateDisposition); + + if (NT_SUCCESS(status)) { + *Key = keyHandle; + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Registry key creation failed, %!STATUS!", status); + } + } + + if (!NT_SUCCESS(status)) { + pKey->DeleteFromFailedCreate(); + pKey = NULL; + } + + return status; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfRegistryClose)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pKey->Close(); + + pKey->DeleteObject(); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +HANDLE +WDFEXPORT(WdfRegistryWdmGetHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key + ) +{ + DDI_ENTRY(); + + FxRegKey* pKey; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey); + + return pKey->GetHandle(); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryRemoveKey)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = Mx::MxDeleteKey(pKey->GetHandle()); + + if (NT_SUCCESS(status)) { + // + // pKey->GetHandle() is now useless, delete the Fx object + // + pKey->DeleteObject(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryRemoveValue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + FxPointerNotNull(pFxDriverGlobals, ValueName); + + status = ZwDeleteValueKey(pKey->GetHandle(), (PUNICODE_STRING) ValueName); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryQueryValue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + ULONG ValueLength, + __out_bcount_opt( ValueLength) + PVOID Value, + __out_opt + PULONG ValueLengthQueried, + __out_opt + PULONG ValueType + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxRegKey::_QueryValue(pFxDriverGlobals, + pKey->GetHandle(), + ValueName, + ValueLength, + Value, + ValueLengthQueried, + ValueType); + if (!NT_SUCCESS(status)) { + UCHAR traceLevel = TRACE_LEVEL_ERROR; + + // + // Label message as Verbose if this is the known pattern of + // passing a 0-length NULL buffer to query the required buffer size. + // + if (status == STATUS_BUFFER_OVERFLOW && Value == NULL && ValueLength == 0) { + traceLevel = TRACE_LEVEL_VERBOSE; + } + + DoTraceLevelMessage(pFxDriverGlobals, traceLevel, TRACINGERROR, + "WDFKEY %p QueryValue failed, %!STATUS!", + Key, status); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryQueryMemory)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + __drv_strictTypeMatch( 1) + POOL_TYPE PoolType, + __in_opt + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + __out + WDFMEMORY* Memory, + __out_opt + PULONG ValueType + ) +{ + DDI_ENTRY(); + + FxRegKey* pKey; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + ULONG dataLength; + PVOID dataBuffer; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, Memory); + + *Memory = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag); + + status = FxValidateObjectAttributes(pFxDriverGlobals, MemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Query the buffer length required. + // + status = pKey->QueryValue(ValueName, 0, NULL, &dataLength, NULL); + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) { + return status; + } + + dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength); + if (dataBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, %!STATUS!", + Key, status); + + return status; + } + + status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, ValueType); + if (NT_SUCCESS(status)) { + FxMemoryObject* pObject; + + status = FxMemoryObject::_Create(pFxDriverGlobals, + MemoryAttributes, + PoolType, + pFxDriverGlobals->Tag, + dataLength, + &pObject); + + if (NT_SUCCESS(status)) { + status = pObject->Commit(MemoryAttributes, (WDFOBJECT*) Memory); + + if (NT_SUCCESS(status)) { + RtlCopyMemory(pObject->GetBuffer(), + dataBuffer, + dataLength); + } + else { + pObject->DeleteFromFailedCreate(); + } + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p WDFMEMORY object create failed, %!STATUS!", + Key, status); + } + } + else { + DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p QueryPartial failed, %!STATUS!", + Key, status); + } + + FxPoolFree(dataBuffer); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryQueryMultiString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in_opt + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + __in + WDFCOLLECTION Collection + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDeviceBase* pDeviceBase; + FxCollection* pCollection; + FxRegKey* pKey; + NTSTATUS status; + ULONG dataLength, type; + PVOID dataBuffer; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + pDeviceBase = NULL; + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, Collection); + + status = FxValidateObjectAttributes(pFxDriverGlobals, StringsAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + Collection, + FX_TYPE_COLLECTION, + (PVOID*) &pCollection); + + pDeviceBase = FxDeviceBase::_SearchForDevice(pFxDriverGlobals, + StringsAttributes); + + status = pKey->QueryValue(ValueName, 0, NULL, &dataLength, &type); + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p QueryPartial failed: %!STATUS!", Key, status); + + return status; + } + + if (type != REG_MULTI_SZ) { + return STATUS_OBJECT_TYPE_MISMATCH; + } + + dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength); + if (dataBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, %!STATUS!", + Key, status); + + return status; + } + + status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, &type); + if (NT_SUCCESS(status)) { + // + // Verify that the data from the registry is a valid multi-sz string. + // + status = FxRegKey::_VerifyMultiSzString(pFxDriverGlobals, + ValueName, + (PWCHAR) dataBuffer, + dataLength); + } + + if (NT_SUCCESS(status)) { + ULONG initialCount; + PWCHAR pCur; + + initialCount = pCollection->Count(); + pCur = (PWCHAR) dataBuffer; + + while (*pCur != UNICODE_NULL) { + FxString* pString; + + pString = new (pFxDriverGlobals, StringsAttributes) + FxString(pFxDriverGlobals); + + if (pString != NULL) { + if (pDeviceBase != NULL) { + pString->SetDeviceBase(pDeviceBase); + } + + status = pString->Assign(pCur); + + if (NT_SUCCESS(status)) { + WDFOBJECT dummy; + + status = pString->Commit(StringsAttributes, &dummy); + } + + if (NT_SUCCESS(status)) { + if (pCollection->Add(pString) == FALSE) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p, WDFCOLLECTION %p, collection add failed " + "%!STATUS!", Key, Collection, status); + } + } + + if (!NT_SUCCESS(status)) { + // + // Delete the string we just created + // + pString->DeleteFromFailedCreate(); + } + else { + // + // NT_SUCCES(status) + // + // Either the caller is responsible for freeing the + // WDFSTRING or it has been parented to another object. + // + DO_NOTHING(); + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p: WDFSTRING creation failed: %!STATUS!", + Key, status); + break; + } + + // + // Increment to the next string in the multi sz (length of string + + // 1 for the NULL) + // + pCur += wcslen(pCur) + 1; + } + + if (!NT_SUCCESS(status)) { + // + // Clear out all the items we added to the collection + // + while (pCollection->Count() > initialCount) { + pCollection->Remove(initialCount); + } + } + } + + FxPoolFree(dataBuffer); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryQueryUnicodeString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __out_opt + PUSHORT ValueByteLength, + __inout_opt + PUNICODE_STRING Value + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + ULONG dataLength, type; + PVOID dataBuffer; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Value != NULL) { + status = FxValidateUnicodeString(pFxDriverGlobals, Value); + if (!NT_SUCCESS(status)) { + return status; + } + } + + if (Value == NULL) { + // + // Caller wants to know just the length + // + dataLength = 0; + dataBuffer = NULL; + } + else { + dataLength = Value->MaximumLength; + dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength); + + if (dataBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, " + "%!STATUS!", Key, status); + + return status; + } + } + + status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, &type); + if (NT_SUCCESS(status) && + FxRegKey::_IsValidSzType(type) == FALSE) { + status = STATUS_OBJECT_TYPE_MISMATCH; + } + + // + // Set ValueByteLength before doing the copy + // + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { + // + // pPartial->DataLength is in bytes, convert to number of + // WCHARs + // + if (ValueByteLength != NULL) { + *ValueByteLength = (USHORT)dataLength ; + } + } + + if (NT_SUCCESS(status) && Value != NULL) { + + + + + ASSERT(ValueByteLength == NULL || + *ValueByteLength >= dataLength); + + // + // pPartial->DataLength cannot be greater than Value->MaximumLength + // based on the call to _ComputePartialSize above. So it is safe to + // copy the pPartial data buffer to the Value buffer. + // + __analysis_assume(dataLength <= Value->MaximumLength); + RtlCopyMemory(Value->Buffer, dataBuffer, dataLength); + + //terminating null shouldn't be included in the Length + Value->Length = (USHORT)dataLength; + + if (Value->Buffer[Value->Length/sizeof(WCHAR)-1] == UNICODE_NULL) { + Value->Length -= sizeof(WCHAR); + } + } + + if (dataBuffer != NULL) { + FxPoolFree(dataBuffer); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryQueryString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + WDFSTRING String + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxString* pString; + FxRegKey* pKey; + NTSTATUS status; + ULONG dataLength, type; + PVOID dataBuffer; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, String); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + String, + FX_TYPE_STRING, + (PVOID*) &pString); + + status = pKey->QueryValue(ValueName, 0, NULL, &dataLength, &type); + if (NT_SUCCESS(status) && + FxRegKey::_IsValidSzType(type) == FALSE) { + status = STATUS_OBJECT_TYPE_MISMATCH; + } + + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_OVERFLOW) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p, QueryPartial failed, %!STATUS!", + Key, status); + return status; + } + + dataBuffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, dataLength); + if (dataBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p KEY_VALUE_PARTIAL_INFORMATION allocation failed, " + "%!STATUS!", Key, status); + + return status; + } + + status = pKey->QueryValue(ValueName, dataLength, dataBuffer, &dataLength, &type); + if (NT_SUCCESS(status) && + FxRegKey::_IsValidSzType(type) == FALSE) { + status = STATUS_OBJECT_TYPE_MISMATCH; + } + + if (NT_SUCCESS(status)) { + if (dataLength <= USHORT_MAX) { + UNICODE_STRING tmp; + + if (dataLength == 0x0) { + // + // Empty string + // + tmp.Buffer = L""; + tmp.Length = 0; + tmp.MaximumLength = 0; + } + else { + + // + // The string we read may not be NULL terminated, so put it into a + // UNICODE_STRING. If the final character is NULL, shorten the + // length of the string so that it does not include for the NULL. + // + // If there are embedded NULLs in the string previous to the final + // character, we leave them in place. + // + tmp.Buffer = (PWCHAR) dataBuffer; + tmp.Length = (USHORT) dataLength; + tmp.MaximumLength = tmp.Length; + + if (tmp.Buffer[(tmp.Length/sizeof(WCHAR))-1] == UNICODE_NULL) { + // + // Do not include the UNICODE_NULL in the length + // + tmp.Length -= sizeof(WCHAR); + } + } + + status = pString->Assign(&tmp); + } + else { + status = STATUS_INVALID_BUFFER_SIZE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p QueryPartial failed, Length %d > max %d, %!STATUS!", + Key, dataLength, USHORT_MAX, status); + } + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p QueryPartial failed, Length %d, %!STATUS!", + Key, dataLength, status); + } + + FxPoolFree(dataBuffer); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryQueryULong)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __out + PULONG Value + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, Value); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxRegKey::_QueryULong(pKey->GetHandle(), ValueName, Value); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p, QueryULong, %!STATUS!", Key, status); + } + + return status; +} + + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryAssignValue)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + ULONG ValueType, + __in + ULONG ValueLength, + __in_ecount( ValueLength) + PVOID Value + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pKey->SetValue(ValueName, ValueType, Value, ValueLength); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p SetValue, %!STATUS!", Key, status); + } + + return status; +} + + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryAssignMemory)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + ULONG ValueType, + __in + WDFMEMORY Memory, + __in_opt + PWDFMEMORY_OFFSET MemoryOffsets + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxMemory* pMemory; + FxRegKey* pKey; + PVOID pBuffer; + ULONG length; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, Memory); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + Memory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + pBuffer = pMemory->GetBuffer(); + length = (ULONG) pMemory->GetBufferSize(); + + if (MemoryOffsets != NULL) { + status = pMemory->ValidateMemoryOffsets(MemoryOffsets); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p, WDFMEMORY %p Offsets overflowed, %!STATUS!", + Key, Memory, status); + + return status; + } + + if (MemoryOffsets->BufferLength > 0) { + status = RtlSizeTToULong(MemoryOffsets->BufferLength, &length); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p, WDFMEMORY %p BufferLength in Offsets truncated, " + "%!STATUS!", Key, Memory, status); + + return status; + } + } + + pBuffer = WDF_PTR_ADD_OFFSET(pBuffer, MemoryOffsets->BufferOffset); + } + + status = pKey->SetValue(ValueName, ValueType, pBuffer, length); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY handle %p SetValue, %!STATUS!", Key, status); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryAssignULong)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + ULONG Value + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pKey->SetValue(ValueName, REG_DWORD, &Value, sizeof(Value)); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p SetValue, %!STATUS!", + Key, status); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryAssignUnicodeString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + PCUNICODE_STRING Value + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRegKey* pKey; + NTSTATUS status; + PWCHAR tempValueBuf; + ULONG length; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, Value); + + tempValueBuf = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, Value); + if (!NT_SUCCESS(status)) { + return status; + } + + length = Value->Length + sizeof(UNICODE_NULL); + + // + // Buffer must be NULL terminated and Length of the buffer must also include the NULL + // Allocate a temporary buffer and NULL terminate it. + // + tempValueBuf = (PWCHAR) FxPoolAllocate(pFxDriverGlobals, PagedPool, length); + + if (tempValueBuf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p allocate temporary buffer failed, " + "%!STATUS!", Key, status); + + return status; + } + + // + // Copy over the string from the callers buffer and make sure it is + // NULL terminated. + // + RtlCopyMemory(tempValueBuf, Value->Buffer, Value->Length); + tempValueBuf[Value->Length/sizeof(WCHAR)] = UNICODE_NULL; + + status = pKey->SetValue(ValueName, REG_SZ, tempValueBuf, length); + + FxPoolFree(tempValueBuf); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p set value failed, %!STATUS!", + Key, status); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryAssignString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + WDFSTRING String + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxString* pString; + FxRegKey* pKey; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, String); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + String, + FX_TYPE_STRING, + (PVOID*) &pString); + + status = pKey->SetValue(ValueName, + REG_SZ, + pString->Buffer(), + pString->ByteLength(TRUE)); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY handle %p SetValue, %!STATUS!", + Key, status); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfRegistryAssignMultiString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFKEY Key, + __in + PCUNICODE_STRING ValueName, + __in + WDFCOLLECTION StringsCollection + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCollection* pCollection; + FxRegKey* pKey; + PWCHAR pValue; + NTSTATUS status; + ULONG length; + BOOLEAN valid; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Key, + FX_TYPE_REG_KEY, + (PVOID*) &pKey, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ValueName); + FxPointerNotNull(pFxDriverGlobals, StringsCollection); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateUnicodeString(pFxDriverGlobals, ValueName); + if (!NT_SUCCESS(status)) { + return status; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + StringsCollection, + FX_TYPE_COLLECTION, + (PVOID *) &pCollection); + + valid = FALSE; + + status = RtlSizeTToULong( + FxCalculateTotalStringSize(pCollection, TRUE, &valid), + &length); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFCOLLECTION %p, collection too large to fit into " + "a ULONG, %!STATUS!", StringsCollection, status); + return status; + } + + if (valid == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p, WDFCOLLECTION %p contains " + "non string objects, %!STATUS!", + Key, StringsCollection, status); + return status; + } + + pValue = (PWCHAR) FxPoolAllocate(pFxDriverGlobals, PagedPool, length); + + if (pValue == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p allocate for query buffer failed, " + "%!STATUS!", Key, status); + + return status; + } + + FxCopyMultiSz(pValue, pCollection); + + status = pKey->SetValue(ValueName, REG_MULTI_SZ, pValue, length); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFKEY %p SetValue, %!STATUS!", + Key, status); + } + + FxPoolFree(pValue); + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/support/fxregkey.cpp b/sdk/lib/drivers/wdf/shared/support/fxregkey.cpp new file mode 100644 index 00000000000..6141abd3e23 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxregkey.cpp @@ -0,0 +1,66 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "FxSupportPch.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxRegKey.tmh" +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxRegKey::_VerifyMultiSzString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegValueName, + __in_bcount(DataLength) PWCHAR DataString, + __in ULONG DataLength + ) +/*++ + +Routine Description: + This static function checks the input buffer to verify that it contains + a multi-sz string with a double-NULL termination at the end of the buffer. + +Arguments: + DataString - buffer containing multi-sz strings. If there are no strings + in the buffer, the buffer should at least contain two UNICODE_NULL + characters. + + DataLength - the size in bytes of the input buffer. + +Return Value: + STATUS_OBJECT_TYPE_MISMATCH - if the the data buffer is off odd-length, + or it doesnt end with two UNICODE_NULL characters. + + STATUS_SUCCESS - if the buffer contains valid multi-sz strings. + + --*/ +{ + ULONG numChars; + + if ((DataLength % 2) != 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Reg value name %wZ, DataLength %d, Data buffer length is invalid, " + "STATUS_OBJECT_TYPE_MISMATCH", + RegValueName, DataLength); + return STATUS_OBJECT_TYPE_MISMATCH; + } + + numChars = DataLength / sizeof(WCHAR); + if (numChars < 2 || + DataString[numChars-1] != UNICODE_NULL || + DataString[numChars-2] != UNICODE_NULL) { + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Read value name %wZ, DataLength %d, Data buffer from registry does not " + "have double NULL terminal chars, STATUS_OBJECT_TYPE_MISMATCH", + RegValueName, DataLength); + return STATUS_OBJECT_TYPE_MISMATCH; + } + + return STATUS_SUCCESS; +} diff --git a/sdk/lib/drivers/wdf/shared/support/fxrequestbuffer.cpp b/sdk/lib/drivers/wdf/shared/support/fxrequestbuffer.cpp new file mode 100644 index 00000000000..41b4f228965 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxrequestbuffer.cpp @@ -0,0 +1,340 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRequestBuffer.cpp + +Abstract: + + This module implements a memory union object + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxRequestBuffer.tmh" +} + +FxRequestBuffer::FxRequestBuffer( + VOID + ) +{ + DataType = FxRequestBufferUnspecified; + RtlZeroMemory(&u, sizeof(u)); +} + +NTSTATUS +FxRequestBuffer::ValidateMemoryDescriptor( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_MEMORY_DESCRIPTOR Descriptor, + __in ULONG Flags + ) +{ + IFxMemory* pMemory; + NTSTATUS status; + + if (Descriptor == NULL) { + if (Flags & MemoryDescriptorNullAllowed) { + return STATUS_SUCCESS; + } + else { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "A NULL Descriptor is not allowed"); + + return STATUS_INVALID_PARAMETER; + } + } + + // + // For each type, check to see if the buffer is non NULL and err out if the + // calller considers this an error. If the buffer is NULL, but a length + // was specified, this is considered an error. + // + switch (Descriptor->Type) { + case WdfMemoryDescriptorTypeBuffer: + if (Descriptor->u.BufferType.Buffer == NULL) { + if ((Flags & MemoryDescriptorNoBufferAllowed) == 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "A NULL Buffer is not allowed"); + + return STATUS_INVALID_PARAMETER; + } + else if (Descriptor->u.BufferType.Length != 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Buffer is NULL, but a length (0x%x) is specified", + Descriptor->u.BufferType.Length); + + return STATUS_INVALID_PARAMETER; + } + } + + SetBuffer(Descriptor->u.BufferType.Buffer, + Descriptor->u.BufferType.Length); + + status = STATUS_SUCCESS; + break; + + case WdfMemoryDescriptorTypeMdl: + if (Descriptor->u.MdlType.Mdl == NULL) { + if ((Flags & MemoryDescriptorNoBufferAllowed) == 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "A NULL MDL is not allowed"); + + return STATUS_INVALID_PARAMETER; + } + else if (Descriptor->u.MdlType.BufferLength != 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "MDL is NULL, but a length (0x%x) is specified", + Descriptor->u.MdlType.BufferLength); + + return STATUS_INVALID_PARAMETER; + } + } + + SetMdl(Descriptor->u.MdlType.Mdl, Descriptor->u.MdlType.BufferLength); + status = STATUS_SUCCESS; + break; + + case WdfMemoryDescriptorTypeHandle: + pMemory = NULL; + if (Descriptor->u.HandleType.Memory == NULL) { + if (Flags & MemoryDescriptorNoBufferAllowed) { + status = STATUS_SUCCESS; + } + else { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "A NULL WDFMEMORY handle is not allowed"); + + status = STATUS_INVALID_PARAMETER; + } + } + else { + FxObjectHandleGetPtr(FxDriverGlobals, + Descriptor->u.HandleType.Memory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + status = pMemory->ValidateMemoryOffsets( + Descriptor->u.HandleType.Offsets); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Memory offset values are not valid %!STATUS!", status); + } + } + + if (NT_SUCCESS(status) && pMemory != NULL) { + SetMemory(pMemory, Descriptor->u.HandleType.Offsets); + } + break; + + default: + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + +ULONG +FxRequestBuffer::GetBufferLength( + VOID + ) +{ + switch (DataType) { + case FxRequestBufferMemory: + // + // If the BufferLength and BufferOffset is zero, then the transfer length is same + // as the length of the request. + // + if (u.Memory.Offsets == NULL || + (u.Memory.Offsets->BufferOffset == 0 && u.Memory.Offsets->BufferLength == 0)) { + return (ULONG) u.Memory.Memory->GetBufferSize(); + } + else { + // + // If the BufferLength value is zero then the transfer length is request length + // minus the offset value. + // + if (u.Memory.Offsets->BufferLength == 0) { + return ((ULONG) u.RefMdl.Memory->GetBufferSize() - (ULONG) u.RefMdl.Offsets->BufferOffset); + } + else { + return (ULONG) u.Memory.Offsets->BufferLength; + } + } + break; + + case FxRequestBufferMdl: + return u.Mdl.Length; + + case FxRequestBufferReferencedMdl: + // + // If the BufferLength and BufferOffset is zero, then the transfer length is same + // as the length of the request. + // + if (u.RefMdl.Offsets == NULL || + (u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) { + return (ULONG) u.RefMdl.Memory->GetBufferSize(); + } + else { + // + // If the BufferLength value is zero then the transfer length is request length + // minus the offset value. + // + if (u.RefMdl.Offsets->BufferLength == 0) { + return ((ULONG) u.RefMdl.Memory->GetBufferSize() - (ULONG) u.RefMdl.Offsets->BufferOffset); + } + else { + return (ULONG) u.RefMdl.Offsets->BufferLength; + } + } + + case FxRequestBufferBuffer: + return u.Buffer.Length; + + default: + return 0; + } +} + +_Must_inspect_result_ +NTSTATUS +FxRequestBuffer::GetBuffer( + __deref_out PVOID* Buffer + ) +{ + switch (DataType) { + case FxRequestBufferUnspecified: + *Buffer = NULL; + return STATUS_SUCCESS; + + case FxRequestBufferMemory: + if (u.Memory.Offsets != NULL) { + *Buffer = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(), + u.Memory.Offsets->BufferOffset); + } + else { + *Buffer = u.Memory.Memory->GetBuffer(); + } + return STATUS_SUCCESS; + + case FxRequestBufferBuffer: + *Buffer = u.Buffer.Buffer; + return STATUS_SUCCESS; + + case FxRequestBufferMdl: + *Buffer = Mx::MxGetSystemAddressForMdlSafe(u.Mdl.Mdl, NormalPagePriority); + if (*Buffer != NULL) { + return STATUS_SUCCESS; + } + else { + return STATUS_INSUFFICIENT_RESOURCES; + } + + case FxRequestBufferReferencedMdl: + *Buffer = Mx::MxGetSystemAddressForMdlSafe(u.RefMdl.Mdl, NormalPagePriority); + if (*Buffer != NULL) { + if (u.RefMdl.Offsets != NULL) { + *Buffer = WDF_PTR_ADD_OFFSET(*Buffer, + u.RefMdl.Offsets->BufferOffset); + } + return STATUS_SUCCESS; + } + else { + return STATUS_INSUFFICIENT_RESOURCES; + } + + default: + return STATUS_INVALID_PARAMETER; + } +} + + +VOID +FxRequestBuffer::AssignValues( + __deref_out_opt PVOID* PPBuffer, + __deref_out_opt PMDL* PPMdl, + __out PULONG BufferLength + ) +{ + PVOID pBuffer; + PMDL pMdl; + size_t bufferSize; + + // + // Make sure we have valid double pointers, make life simpler below + // + if (PPBuffer == NULL) { + PPBuffer = &pBuffer; + } + if (PPMdl == NULL) { + PPMdl = &pMdl; + } + + switch (DataType) { + case FxRequestBufferMemory: + pBuffer = u.Memory.Memory->GetBuffer(); + bufferSize = u.Memory.Memory->GetBufferSize(); + + if (u.Memory.Offsets != NULL) { + if (u.Memory.Offsets->BufferLength > 0) { + bufferSize = u.Memory.Offsets->BufferLength; + } + if (u.Memory.Offsets->BufferOffset > 0) { + pBuffer = WDF_PTR_ADD_OFFSET(pBuffer, u.Memory.Offsets->BufferOffset); + } + } + + *PPBuffer = pBuffer; + *BufferLength = (ULONG) bufferSize; + break; + + case FxRequestBufferMdl: + *PPMdl = u.Mdl.Mdl; + *PPBuffer = NULL; + *BufferLength = u.Mdl.Length; + break; + + case FxRequestBufferBuffer: + *PPMdl = NULL; + *PPBuffer = u.Buffer.Buffer; + *BufferLength = u.Buffer.Length; + break; + + case FxRequestBufferReferencedMdl: + *PPMdl = u.RefMdl.Mdl; + *PPBuffer = NULL; + if (u.RefMdl.Offsets != NULL && u.RefMdl.Offsets->BufferLength > 0) { + *BufferLength = (ULONG) u.RefMdl.Offsets->BufferLength; + } + else { + *BufferLength = (ULONG) u.RefMdl.Memory->GetBufferSize(); + } + break; + + default: + *PPMdl = NULL; + *PPBuffer = NULL; + *BufferLength = 0; + break; + } +} diff --git a/sdk/lib/drivers/wdf/shared/support/fxresourceapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxresourceapi.cpp new file mode 100644 index 00000000000..9b1071a9417 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxresourceapi.cpp @@ -0,0 +1,1314 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxResourceAPI.cpp + +Abstract: + + This module implements the resource class. + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxResourceAPI.tmh" +} + +// +// Extern "C" the entire file +// +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceRequirementsListSetSlotNumber)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + ULONG SlotNumber + ) +/*++ + +Routine Description: + Sets the slot number for a given resource requirements list + +Arguments: + RequirementsList - list to be modified + + SlotNumber - slot value to assign + +Return Value: + None + + --*/ +{ + FxIoResReqList* pIoResReqList; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pIoResReqList); + + if (pIoResReqList->m_SlotNumber != SlotNumber) { + pIoResReqList->MarkChanged(); + } + pIoResReqList->m_SlotNumber = SlotNumber; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceRequirementsListSetInterfaceType)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + __drv_strictTypeMatch(__drv_typeCond) + INTERFACE_TYPE InterfaceType + ) +/*++ + +Routine Description: + Sets the InterfaceType for a given resource requirements list + +Arguments: + RequirementsList - list to be modified + + InterfaceType - interface type to assign + +Return Value: + None + + --*/ +{ + FxIoResReqList* pIoResReqList; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pIoResReqList); + + if (pIoResReqList->m_InterfaceType != InterfaceType) { + pIoResReqList->MarkChanged(); + } + + pIoResReqList->m_InterfaceType = InterfaceType; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +FxIoResourceRequirementsListInsertIoResList( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + WDFIORESLIST IoResList, + ULONG Index + ) +/*++ + +Routine Description: + Inserts a resource list into a requirements list at a particular index. + +Arguments: + RequirementsList - list to be modified + + IoResList - resource list to add + + Index - zero based index to insert at + +Return Value: + NTSTATUS + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoResReqList* pIoResReqList; + FxIoResList* pIoResList; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pIoResReqList, + &pFxDriverGlobals); + + FxObjectHandleGetPtr(pFxDriverGlobals, + IoResList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pIoResList); + + if (pIoResList->m_OwningList != pIoResReqList) { + return STATUS_INVALID_DEVICE_REQUEST; + } + + status = pIoResReqList->AddAt(Index, pIoResList); + + if (NT_SUCCESS(status)) { + // + // Mirror the access flags as well. + // + pIoResList->m_AccessFlags = pIoResReqList->m_AccessFlags; + pIoResList->m_OwningList = pIoResReqList; + } + + return status; +} + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoResourceRequirementsListInsertIoResList)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + WDFIORESLIST IoResList, + __in + ULONG Index + ) +/*++ + +Routine Description: + Inserts a resource list into a requirements list at a particular index. + +Arguments: + RequirementsList - list to be modified + + IoResList - resource list to add + + Index - zero based index to insert at + +Return Value: + NTSTATUS + + --*/ +{ + return FxIoResourceRequirementsListInsertIoResList(DriverGlobals, + RequirementsList, + IoResList, + Index); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoResourceRequirementsListAppendIoResList)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + WDFIORESLIST IoResList + ) +/*++ + +Routine Description: + Appends a resource list to a resource requirements list + +Arguments: + RequirementsList - list to be modified + + IoResList - resource list to append + +Return Value: + NTSTATUS + + --*/ + +{ + return FxIoResourceRequirementsListInsertIoResList(DriverGlobals, + RequirementsList, + IoResList, + WDF_INSERT_AT_END); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfIoResourceRequirementsListGetCount)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList + ) +/*++ + +Routine Description: + Returns the number of resource lists in the requirements list + + +Arguments: + RequirementsList - requirements list whose count will be returned + +Return Value: + number of elements in the list + + --*/ + +{ + FxIoResReqList* pList; + ULONG count; + KIRQL irql; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pList); + + pList->Lock(&irql); + count = pList->Count(); + pList->Unlock(irql); + + return count; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFIORESLIST +WDFEXPORT(WdfIoResourceRequirementsListGetIoResList)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + ULONG Index + ) +/*++ + +Routine Description: + Retrieves a resource list from the requirements list at a given index. + +Arguments: + RequirementsList - list to retrieve the resource list from + + Index - zero based index from which to retrieve the list + +Return Value: + resource list handle or NULL + + --*/ +{ + FxIoResReqList* pIoResReqList; + FxObject* pObject; + KIRQL irql; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pIoResReqList); + + pIoResReqList->Lock(&irql); + pObject = pIoResReqList->GetItem(Index); + pIoResReqList->Unlock(irql); + + if (pObject == NULL) { + return NULL; + } + else { + return (WDFIORESLIST) pObject->GetObjectHandle(); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceRequirementsListRemove)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + ULONG Index + ) +/*++ + +Routine Description: + Removes a resource list from the requirements list at a given index + +Arguments: + RequirementsList - list of resource requirements which will be modified + + Index - zero based index which indictes location in the list to find the + resource list + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoResReqList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + if (pList->RemoveAndDelete(Index) == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFIORESLIST %p, could not remove list at index %d (not found), " + "list item count is %d", RequirementsList, Index, pList->Count()); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceRequirementsListRemoveByIoResList)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in + WDFIORESLIST IoResList + ) +/*++ + +Routine Description: + Removes a resource list from the requirements list based on the resource list's + handle + +Arguments: + RequirementsList - resource requirements list being modified + + IoResList - resource list to be removed + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCollectionEntry* cur, *end; + FxIoResReqList* pList; + FxIoResList* pResList; + KIRQL irql; + BOOLEAN listFound; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + if (pList->IsRemoveAllowed() == FALSE) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFIORESREQLIST %p: Removes not allowed", + RequirementsList); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + IoResList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pResList); + + pList->Lock(&irql); + + cur = pList->Start(); + end = pList->End(); + listFound = FALSE; + + while (cur != end) { + if (cur->m_Object == pResList) { + pList->MarkChanged(); + + pList->RemoveEntry(cur); + listFound = TRUE; + break; + } + + cur = cur->Next(); + } + + pList->Unlock(irql); + + if (listFound) { + pResList->DeleteObject(); + pResList = NULL; + } +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoResourceListCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESREQLIST RequirementsList, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFIORESLIST* ResourceList + ) +/*++ + +Routine Description: + Creates a resource list. + +Arguments: + RequirementsList - the resource requirements list that the resource list will + be associated with + + Attributes - generic object attributes for the new resource list + + ResourceList - pointer which will receive the new object handle + +Return Value: + NTSTATUS + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoResReqList* pIoResReqList; + FxIoResList* pIoResList; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + RequirementsList, + FX_TYPE_IO_RES_REQ_LIST, + (PVOID*) &pIoResReqList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ResourceList); + *ResourceList = NULL; + + status = FxValidateObjectAttributes(pFxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + + if (!NT_SUCCESS(status)) { + return status; + } + + pIoResList = new (pFxDriverGlobals, Attributes) FxIoResList( + pFxDriverGlobals, pIoResReqList); + + if (pIoResList == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pIoResList->Commit(Attributes, + (WDFOBJECT*) ResourceList, + pIoResReqList); + + if (!NT_SUCCESS(status)) { + pIoResList->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +FxIoResourceListInsertDescriptor( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + PIO_RESOURCE_DESCRIPTOR Descriptor, + ULONG Index + ) +/*++ + +Routine Description: + Inserts a descriptor into a resource list at a particular index. + +Arguments: + ResourceList - list to be modified + + Descriptor - descriptor to insert + + Index - zero based index to insert at + +Return Value: + NTSTATUS + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoResList* pList; + FxResourceIo* pObject; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + ResourceList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Descriptor); + + if (pList->m_OwningList->IsAddAllowed() == FALSE) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Removes not allowed on WDFIORESLIST %p", + ResourceList); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return STATUS_ACCESS_DENIED; + } + + pObject = new(pFxDriverGlobals) + FxResourceIo(pFxDriverGlobals, Descriptor); + + if (pObject == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pObject->AssignParentObject(pList); + if (!NT_SUCCESS(status)) { + pObject->DeleteObject(); + return status; + } + + status = pList->AddAt(Index, pObject); + + // + // Mark both this list and its owning list as changed so when it comes + // time to evaluate the entire requirements list for changes, we do not + // have to iterate over all the resource lists. + // + if (NT_SUCCESS(status)) { + pList->m_OwningList->MarkChanged(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoResourceListInsertDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + PIO_RESOURCE_DESCRIPTOR Descriptor, + __in + ULONG Index + ) +/*++ + +Routine Description: + Inserts a descriptor into a resource list at a particular index. + +Arguments: + ResourceList - list to be modified + + Descriptor - descriptor to insert + + Index - zero based index to insert at + +Return Value: + NTSTATUS + + --*/ +{ + return FxIoResourceListInsertDescriptor(DriverGlobals, + ResourceList, + Descriptor, + Index); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoResourceListAppendDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + PIO_RESOURCE_DESCRIPTOR Descriptor + ) +/*++ + +Routine Description: + Appends a descriptor to a resource list + +Arguments: + ResourceList - list to be modified + + Descriptor - item to be appended + +Return Value: + NTSTATUS + + --*/ +{ + return FxIoResourceListInsertDescriptor(DriverGlobals, + ResourceList, + Descriptor, + WDF_INSERT_AT_END); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceListUpdateDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + PIO_RESOURCE_DESCRIPTOR Descriptor, + __in + ULONG Index + ) +/*++ + +Routine Description: + Updates resource requirement in place in the list. + +Arguments: + ResourceList - list to be modified + + Descriptor - Pointer to descriptor whic contains the updated value + + Index - zero based location in the list to update + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoResList* pList; + FxResourceIo* pObject; + KIRQL irql; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + ResourceList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Descriptor); + + pList->Lock(&irql); + pObject = (FxResourceIo*) pList->GetItem(Index); + pList->Unlock(irql); + + if (pObject != NULL) { + // + // We don't check for add or remove access because we don't know what + // the update is actually doing (ie widening a range, shortening it, etc). + // For this operation we have to trust the driver that it is doing the + // right thing at the right time. + // + RtlCopyMemory(&pObject->m_Descriptor, + Descriptor, + sizeof(pObject->m_Descriptor)); + + // + // Mark both this list and its owning list as changed so when it comes + // time to evaluate the entire requirements list for changes, we do not + // have to iterate over all the resource lists. + // + pList->MarkChanged(); + pList->m_OwningList->MarkChanged(); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFIORESREQLIST %p, cannot update item at index %d, item not found," + " list item count is %d", ResourceList, Index, pList->Count()); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfIoResourceListGetCount)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList + ) +/*++ + +Routine Description: + Returns the number of descriptors in the resource list + +Arguments: + ResourceList - resource list whose count will be returned + +Return Value: + number of elements in the list + + --*/ +{ + FxIoResList* pList; + ULONG count; + KIRQL irql; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + ResourceList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pList); + + pList->Lock(&irql); + count = pList->Count(); + pList->Unlock(irql); + + return count; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +PIO_RESOURCE_DESCRIPTOR +WDFEXPORT(WdfIoResourceListGetDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + ULONG Index + ) +/*++ + +Routine Description: + Retrieves an io resource desciptor for a given index in the resource list + +Arguments: + ResourceList - list being looked up + + Index - zero based index into the list to find the value of + +Return Value: + pointer to an io resource descriptor upon success, NULL upon error + + --*/ + +{ + FxIoResList* pList; + FxResourceIo* pObject; + KIRQL irql; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + ResourceList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pList); + + pList->Lock(&irql); + pObject = (FxResourceIo*) pList->GetItem(Index); + pList->Unlock(irql); + + if (pObject == NULL) { + return NULL; + } + else { + // + // Copy the current descriptor to the clone and return it + // + RtlCopyMemory(&pObject->m_DescriptorClone, + &pObject->m_Descriptor, + sizeof(pObject->m_Descriptor)); + + return &pObject->m_DescriptorClone; + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceListRemove)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + ULONG Index + ) +/*++ + +Routine Description: + Removes a descriptor in an io resource list + +Arguments: + ResourceList - resource list to modify + + Index - zero based index into the list in which to remove the descriptor + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoResList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + ResourceList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + if (pList->RemoveAndDelete(Index)) { + // + // Mark this list's owning list as changed so when it comes + // time to evaluate the entire requirements list for changes, we do not + // have to iterate over all the resource lists. + // + // RemoveAndDelete marked pList as changed already + // + pList->m_OwningList->MarkChanged(); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFIORESLIST %p, could not remove item at index %d (not found), " + "list item count is %d", ResourceList, Index, pList->Count()); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfIoResourceListRemoveByDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIORESLIST ResourceList, + __in + PIO_RESOURCE_DESCRIPTOR Descriptor + ) +/*++ + +Routine Description: + Removes a descriptor by value in a given io resource list. Equality is + determined by RtlCompareMemory. + +Arguments: + ResourceList - the io resource list to modify + + Descriptor - pointer to a descriptor to remove. + +Return Value: + None + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCollectionEntry* cur, *end; + FxIoResList* pList; + FxResourceIo* pObject; + KIRQL irql; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + ResourceList, + FX_TYPE_IO_RES_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Descriptor); + + if (pList->IsRemoveAllowed() == FALSE) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Removes not allowed on WDFIORESLIST %p", + ResourceList); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pList->Lock(&irql); + + cur = pList->Start(); + end = pList->End(); + pObject = NULL; + + while (cur != end) { + pObject = (FxResourceIo*) cur->m_Object; + + if (RtlCompareMemory(&pObject->m_Descriptor, + Descriptor, + sizeof(*Descriptor)) == sizeof(*Descriptor)) { + // + // Mark both this list and its owning list as changed so when it + // comes time to evaluate the entire requirements list for + // changes, we do not have to iterate over all the resource lists. + // + pList->MarkChanged(); + pList->m_OwningList->MarkChanged(); + + pList->RemoveEntry(cur); + break; + } + + // + // Set to NULL so that we do not delete it if this is the last item in + // the list. + // + pObject = NULL; + + cur = cur->Next(); + } + + pList->Unlock(irql); + + if (pObject != NULL) { + pObject->DeleteObject(); + } +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +FxCmResourceListInsertDescriptor( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List, + __in + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + __in + ULONG Index + ) +/*++ + +Routine Description: + Inserts a descriptor into a cm resource list at a particular index. + +Arguments: + ResourceList - list to be modified + + Descriptor - descriptor to insert + + Index - zero based index to insert at + +Return Value: + NTSTATUS + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCmResList* pList; + FxResourceCm* pObject; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Descriptor); + + FxObjectHandleGetPtr(pFxDriverGlobals, + List, + FX_TYPE_CM_RES_LIST, + (PVOID*) &pList); + + pObject = new(pFxDriverGlobals) FxResourceCm(pFxDriverGlobals, Descriptor); + + if (pObject == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pObject->AssignParentObject(pList); + if (!NT_SUCCESS(status)) { + pObject->DeleteObject(); + return status; + } + + return pList->AddAt(Index, pObject); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfCmResourceListInsertDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List, + __in + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + __in + ULONG Index + ) +/*++ + +Routine Description: + Inserts a descriptor into a cm resource list at a particular index. + +Arguments: + ResourceList - list to be modified + + Descriptor - descriptor to insert + + Index - zero based index to insert at + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + return FxCmResourceListInsertDescriptor(DriverGlobals, + List, + Descriptor, + Index); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfCmResourceListAppendDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List, + __in + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ) +/*++ + +Routine Description: + Appends a descriptor to a cm resource list + +Arguments: + ResourceList - list to be modified + + Descriptor - item to be appended + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + return FxCmResourceListInsertDescriptor(DriverGlobals, + List, + Descriptor, + WDF_INSERT_AT_END); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +ULONG +WDFEXPORT(WdfCmResourceListGetCount)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List + ) +/*++ + +Routine Description: + Returns the number of cm descriptors in the resource list + +Arguments: + ResourceList - resource list whose count will be returned + +Return Value: + number of elements in the list + + --*/ +{ + FxCmResList* pList; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + List, + FX_TYPE_CM_RES_LIST, + (PVOID*) &pList); + + return pList->GetCount(); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +PCM_PARTIAL_RESOURCE_DESCRIPTOR +WDFEXPORT(WdfCmResourceListGetDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List, + __in + ULONG Index + ) +/*++ + +Routine Description: + Retrieves a cm resource desciptor for a given index in the resource list + +Arguments: + ResourceList - list being looked up + + Index - zero based index into the list to find the value of + +Return Value: + pointer to a cm resource descriptor upon success, NULL upon error + + --*/ +{ + DDI_ENTRY(); + + FxCmResList* pList; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + List, + FX_TYPE_CM_RES_LIST, + (PVOID*) &pList); + + return pList->GetDescriptor(Index); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfCmResourceListRemove)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List, + __in + ULONG Index + ) +/*++ + +Routine Description: + Removes a descriptor in an cm resource list + +Arguments: + ResourceList - resource list to modify + + Index - zero based index into the list in which to remove the descriptor + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCmResList* pList; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + List, + FX_TYPE_CM_RES_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + if (pList->RemoveAndDelete(Index) == FALSE) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "WDFCMRESLIST %p, could not remove list at index %d (not found), " + "list item count is %d", List, Index, pList->Count()); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfCmResourceListRemoveByDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFCMRESLIST List, + __in + PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor + ) +/*++ + +Routine Description: + Removes a descriptor by value in a given cm resource list. Equality is + determined by RtlCompareMemory. + +Arguments: + ResourceList - the io resource list to modify + + Descriptor - pointer to a descriptor to remove. + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxCollectionEntry* cur; + FxCollectionEntry* end; + FxCmResList* pList; + FxResourceCm* pObject; + KIRQL irql; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + List, + FX_TYPE_CM_RES_LIST, + (PVOID*) &pList, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Descriptor); + + if (pList->IsRemoveAllowed() == FALSE) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Removes not allowed on WDFCMRESLIST %p", List); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pList->Lock(&irql); + + cur = pList->Start(); + end = pList->End(); + pObject = NULL; + + while (cur != end) { + pObject = (FxResourceCm*) cur->m_Object; + + if (RtlCompareMemory(&pObject->m_Descriptor, + Descriptor, + sizeof(*Descriptor)) == sizeof(*Descriptor)) { + pList->MarkChanged(); + + pList->RemoveEntry(cur); + break; + } + + // + // Set to NULL so that we do not delete it if this is the last item in + // the list. + // + pObject = NULL; + + cur = cur->Next(); + } + + pList->Unlock(irql); + + if (pObject != NULL) { + pObject->DeleteObject(); + pObject = NULL; + } +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/support/fxresourcecollection.cpp b/sdk/lib/drivers/wdf/shared/support/fxresourcecollection.cpp new file mode 100644 index 00000000000..58f481c2d60 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxresourcecollection.cpp @@ -0,0 +1,739 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxResourceCollection.cpp + +Abstract: + + This module implements a base object for derived collection classes and + the derived collection classes. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxResourceCollection.tmh" +#endif +} + +BOOLEAN +FxResourceCollection::RemoveAndDelete( + __in ULONG Index + ) +/*++ + +Routine Description: + Removes an entry from the collection and then deletes it if found. The + caller must have removal permissions to perform this action. + +Arguments: + Index - zero based index into the collection at which to perform the removal + +Return Value: + TRUE if the item was found and deleted, FALSE otherwise + + --*/ +{ + FxObject* pObject; + FxCollectionEntry* pEntry; + KIRQL irql; + + if (IsRemoveAllowed() == FALSE) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Removes not allowed on handle %p, remove at index %d" + "failed", GetObjectHandle(), Index); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + return FALSE; + } + + pObject = NULL; + + Lock(&irql); + + pEntry = FindEntry(Index); + if (pEntry != NULL) { + + // + // Mark the list as changed so when we go to create a WDM resource list we + // know if a new list is needed. + // + MarkChanged(); + + pObject = pEntry->m_Object; + + // + // Remove the entry + // + RemoveEntry(pEntry); + } + Unlock(irql); + + if (pObject != NULL) { + // + // Delete the object since we created it + // + pObject->DeleteObject(); + pObject = NULL; + + return TRUE; + } + else { + return FALSE; + } +} + +_Must_inspect_result_ +NTSTATUS +FxResourceCollection::AddAt( + __in ULONG Index, + __in FxObject* Object + ) +/*++ + +Routine Description: + Adds an object into the collection at the specified index. + +Arguments: + Index - zero baesd index in which to insert into the list. WDF_INSERT_AT_END + is a special value which indicates that the insertion is an append. + + Object - object to add + +Return Value: + NTSTATUS + + --*/ +{ + FxCollectionEntry *pNew; + PLIST_ENTRY ple; + NTSTATUS status; + KIRQL irql; + + if (IsAddAllowed() == FALSE) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Adds not allowed on handle %p, add at index %d" + "failed", GetObjectHandle(), Index); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + return STATUS_ACCESS_DENIED; + } + + Lock(&irql); + + ple = NULL; + status = STATUS_SUCCESS; + + pNew = AllocateEntry(GetDriverGlobals()); + + if (pNew != NULL) { + // + // Inserting at the current count (i.e. one past the end) is the same + // as append. + // + if (Index == WDF_INSERT_AT_END || Index == Count()) { + ple = &m_ListHead; + } + else { + FxCollectionEntry* cur, *end; + ULONG i; + + for (cur = Start(), end = End(), i = 0; + cur != end; + cur = cur->Next(), i++) { + if (i == Index) { + ple = &cur->m_ListEntry; + break; + } + } + + if (ple == NULL) { + delete pNew; + status = STATUS_ARRAY_BOUNDS_EXCEEDED; + } + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status)) { + PLIST_ENTRY blink; + + // ple now points to the list entry which we will insert our node + // *before* + + blink = ple->Blink; + + // Link the previous with the new entry + blink->Flink = &pNew->m_ListEntry; + pNew->m_ListEntry.Blink = blink; + + // Link the current with the new entry + pNew->m_ListEntry.Flink = ple; + ple->Blink = &pNew->m_ListEntry; + + AddEntry(pNew, Object); + + // + // Mark the list as changed so when we go to create a WDM resource list + // we know if a new list is needed. + // + MarkChanged(); + } + + Unlock(irql); + + if (!NT_SUCCESS(status)) { + Object->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoResList::BuildFromWdmList( + __deref_in PIO_RESOURCE_LIST* WdmResourceList + ) +/*++ + +Routine Description: + Builds up the collection with FxResourceIo objects based on the passed in + WDM io resource list + +Arguments: + WdmResourceList - list which specifies the io resource objects to create + +Return Value: + NTSTATUS + + --*/ +{ + PIO_RESOURCE_DESCRIPTOR pWdmDescriptor; + ULONG i, count; + NTSTATUS status; + + pWdmDescriptor = &(*WdmResourceList)->Descriptors[0]; + count = (*WdmResourceList)->Count; + status = STATUS_SUCCESS; + + for (i = 0; i < count; i++) { + // + // Now create a new resource object for each resource + // in our list. + // + FxResourceIo *pResource; + + pResource = new(GetDriverGlobals()) + FxResourceIo(GetDriverGlobals(), pWdmDescriptor); + + if (pResource == NULL) { + // + // We failed, clean up, and exit. Since we are only + // keeping references on the master collection, if + // we free this, everything else will go away too. + // + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status)) { + status = pResource->AssignParentObject(this); + + // + // See notes in previous AssignParentObject as to why + // we are asserting. + // + ASSERT(NT_SUCCESS(status)); + UNREFERENCED_PARAMETER(status); + + status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; + } + + if (!NT_SUCCESS(status)) { + break; + } + + pWdmDescriptor++; + } + + if (NT_SUCCESS(status)) { + status = m_OwningList->Add(this) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status)) { + *WdmResourceList = (PIO_RESOURCE_LIST) pWdmDescriptor; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxCmResList::BuildFromWdmList( + __in PCM_RESOURCE_LIST WdmResourceList, + __in UCHAR AccessFlags + ) +/*++ + +Routine Description: + Builds up the collection with FxResourceCm objects based on the passed in + WDM io resource list. + +Arguments: + WdmResourceList - list which specifies the io resource objects to create + + AccessFlags - permissions to be associated with the list + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + + // + // Predispose to success + // + status = STATUS_SUCCESS; + + Clear(); + + m_AccessFlags = AccessFlags; + + if (WdmResourceList != NULL) { + PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; + ULONG count, i; + + // + // We only expect to see one full resource descriptor. + // + ASSERT(WdmResourceList->Count == 1); + + count = WdmResourceList->List[0].PartialResourceList.Count; + pDescriptor = WdmResourceList->List[0].PartialResourceList.PartialDescriptors; + + for(i = 0; i < count; i++, pDescriptor++) { + FxResourceCm *pResource; + + pResource = new(GetDriverGlobals()) + FxResourceCm(GetDriverGlobals(), pDescriptor); + + if (pResource == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (NT_SUCCESS(status)) { + status = pResource->AssignParentObject(this); + + // + // Since we control our own lifetime here, the assign should + // always work. + // + ASSERT(NT_SUCCESS(status)); + + status = Add(pResource) ? STATUS_SUCCESS : STATUS_INSUFFICIENT_RESOURCES; + } + + if (!NT_SUCCESS(status)) { + Clear(); + break; + } + } + } + + return status; +} + +_Must_inspect_result_ +PCM_RESOURCE_LIST +FxCmResList::CreateWdmList( + __in __drv_strictTypeMatch(__drv_typeExpr) POOL_TYPE PoolType + ) +/*++ + +Routine Description: + Allocates and initializes a WDM CM resource list based off of the current + contents of this collection. + +Arguments: + PoolType - the pool type from which to allocate the resource list + +Return Value: + a new resource list upon success, NULL upon failure + + --*/ +{ + PCM_RESOURCE_LIST pWdmResourceList; + ULONG size; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pWdmResourceList = NULL; + pFxDriverGlobals = GetDriverGlobals(); + + if (Count()) { + // + // NOTE: This function assumes all resources are on the same bus + // and therefore there is only one FULL_RESOURCE_DESCRIPTOR. + // + size = sizeof(CM_RESOURCE_LIST) + + (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * (Count() - 1)); + + pWdmResourceList = (PCM_RESOURCE_LIST) + MxMemory::MxAllocatePoolWithTag(PoolType, size, pFxDriverGlobals->Tag); + + if (pWdmResourceList != NULL) { + PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; + FxCollectionEntry *cur, *end; + + RtlZeroMemory(pWdmResourceList, size); + + pWdmResourceList->Count = 1; // We only return one full descriptor + + pWdmResourceList->List[0].PartialResourceList.Version = 1; + pWdmResourceList->List[0].PartialResourceList.Revision = 1; + pWdmResourceList->List[0].PartialResourceList.Count = Count(); + + pDescriptor = + pWdmResourceList->List[0].PartialResourceList.PartialDescriptors; + + end = End(); + for (cur = Start(); cur != end; cur = cur->Next()) { + FxResourceCm *pResource; + + pResource = (FxResourceCm*) cur->m_Object; + + RtlCopyMemory(pDescriptor, + &pResource->m_Descriptor, + sizeof(pResource->m_Descriptor)); + pDescriptor++; + } + } + } + + return pWdmResourceList; +} + +ULONG +FxCmResList::GetCount( + VOID + ) +{ + ULONG count; + KIRQL irql; + + Lock(&irql); + count = Count(); + Unlock(irql); + + return count; +} + +PCM_PARTIAL_RESOURCE_DESCRIPTOR +FxCmResList::GetDescriptor( + __in ULONG Index + ) +{ + FxResourceCm* pObject; + KIRQL irql; + + Lock(&irql); + pObject = (FxResourceCm*) GetItem(Index); + Unlock(irql); + + if (pObject == NULL) { + return NULL; + } + else { + // + // Copy the current descriptor to the clone and return it + // + RtlCopyMemory(&pObject->m_DescriptorClone, + &pObject->m_Descriptor, + sizeof(pObject->m_Descriptor)); + + return &pObject->m_DescriptorClone; + } +} + +_Must_inspect_result_ +FxIoResReqList* +FxIoResReqList::_CreateFromWdmList( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PIO_RESOURCE_REQUIREMENTS_LIST WdmRequirementsList, + __in UCHAR AccessFlags + ) +/*++ + +Routine Description: + Allocates and populates an FxIoResReqList based on the WDM resource + requirements list. + +Arguments: + WdmRequirementsList - a list of IO_RESOURCE_LISTs which will indicate how + to fill in the returned collection object + + AccessFlags - permissions to associate with the newly created object + +Return Value: + a new object upon success, NULL upon failure + + --*/ + +{ + FxIoResReqList* pIoResReqList; + ULONG i; + + pIoResReqList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxIoResReqList(FxDriverGlobals, AccessFlags); + + if (pIoResReqList != NULL) { + PIO_RESOURCE_LIST pWdmResourceList; + NTSTATUS status; + + if (WdmRequirementsList == NULL) { + return pIoResReqList; + } + + status = STATUS_SUCCESS; + pWdmResourceList = &WdmRequirementsList->List[0]; + + pIoResReqList->m_InterfaceType = WdmRequirementsList->InterfaceType; + pIoResReqList->m_SlotNumber = WdmRequirementsList->SlotNumber; + + for (i = 0; i < WdmRequirementsList->AlternativeLists; i++) { + FxIoResList *pResList; + + pResList = new(FxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxIoResList(FxDriverGlobals, pIoResReqList); + + if (pResList != NULL) { + status = pResList->AssignParentObject(pIoResReqList); + + // + // Since we control our own lifetime, assigning the parent should + // never fail. + // + ASSERT(NT_SUCCESS(status)); + + status = pResList->BuildFromWdmList(&pWdmResourceList); + } + else { + // + // We failed to allocate a child collection. Clean up + // and break out of the loop. + // + status = STATUS_INSUFFICIENT_RESOURCES; + } + + if (!NT_SUCCESS(status)) { + break; + } + } + + if (!NT_SUCCESS(status)) { + // + // Cleanup and return a NULL object + // + pIoResReqList->DeleteObject(); + pIoResReqList = NULL; + } + } + + return pIoResReqList; +} + +_Must_inspect_result_ +PIO_RESOURCE_REQUIREMENTS_LIST +FxIoResReqList::CreateWdmList( + VOID + ) +/*++ + +Routine Description: + Creates a WDM io resource requirements list based off of the current + contents of the collection + +Arguments: + None + +Return Value: + new WDM io resource requirements list allocated out of paged pool upon success, + NULL upon failure or an empty list + + --*/ +{ + PIO_RESOURCE_REQUIREMENTS_LIST pRequirementsList; + FxCollectionEntry *cur, *end; + NTSTATUS status; + ULONG totalDescriptors; + ULONG size; + ULONG count; + ULONG tmp; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + totalDescriptors = 0; + pRequirementsList = NULL; + + count = Count(); + pFxDriverGlobals = GetDriverGlobals(); + + if (count > 0) { + // + // The collection object should contain a set of child collections + // with each of the various requirement lists. Use the number of + // these collections to determine the size of our requirements + // list. + // + end = End(); + for (cur = Start(); cur != end; cur = cur->Next()) { + status = RtlULongAdd(totalDescriptors, + ((FxIoResList *) cur->m_Object)->Count(), + &totalDescriptors); + + if (!NT_SUCCESS(status)) { + goto Overflow; + } + } + + // + // We now have enough information to determine how much memory we + // need to allocate for our requirements list. + // + // size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + + // (sizeof(IO_RESOURCE_LIST) * (count - 1)) + + // (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) - + // (sizeof(IO_RESOURCE_DESCRIPTOR) * count); + // + // sizeof(IO_RESOURCE_DESCRIPTOR) * count is subtracted off because + // each IO_RESOURCE_LIST has an embedded IO_RESOURCE_DESCRIPTOR in it + // and we don't want to overallocated. + // + + // + // To handle overflow each mathematical operation is split out into an + // overflow safe call. + // + size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST); + + // sizeof(IO_RESOURCE_LIST) * (count - 1) + status = RtlULongMult(sizeof(IO_RESOURCE_LIST), count - 1, &tmp); + if (!NT_SUCCESS(status)) { + goto Overflow; + } + + status = RtlULongAdd(size, tmp, &size); + if (!NT_SUCCESS(status)) { + goto Overflow; + } + + // (sizeof(IO_RESOURCE_DESCRIPTOR) * totalDescriptors) + status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), + totalDescriptors, + &tmp); + if (!NT_SUCCESS(status)) { + goto Overflow; + } + + status = RtlULongAdd(size, tmp, &size); + if (!NT_SUCCESS(status)) { + goto Overflow; + } + + // - sizeof(IO_RESOURCE_DESCRIPTOR) * Count() (note the subtraction!) + status = RtlULongMult(sizeof(IO_RESOURCE_DESCRIPTOR), count, &tmp); + if (!NT_SUCCESS(status)) { + goto Overflow; + } + + // Sub, not Add! + status = RtlULongSub(size, tmp, &size); + if (!NT_SUCCESS(status)) { + goto Overflow; + } + + pRequirementsList = (PIO_RESOURCE_REQUIREMENTS_LIST) + MxMemory::MxAllocatePoolWithTag(PagedPool, size, pFxDriverGlobals->Tag); + + if (pRequirementsList != NULL) { + PIO_RESOURCE_LIST pList; + FxResourceIo *pResource; + + pList = pRequirementsList->List; + + // + // Start by zero initializing our structure + // + RtlZeroMemory(pRequirementsList, size); + + // + // InterfaceType and BusNumber are unused for WDM, but InterfaceType + // is used by the arbiters. + // + pRequirementsList->InterfaceType = m_InterfaceType; + + pRequirementsList->SlotNumber = m_SlotNumber; + + // + // Now populate the requirements list with the resources from + // our collections. + // + pRequirementsList->ListSize = size; + pRequirementsList->AlternativeLists = Count(); + + end = End(); + for (cur = Start(); cur != end; cur = cur->Next()) { + FxIoResList* pIoResList; + PIO_RESOURCE_DESCRIPTOR pDescriptor; + FxCollectionEntry *pIoResCur, *pIoResEnd; + + pIoResList = (FxIoResList*) cur->m_Object; + + pList->Version = 1; + pList->Revision = 1; + pList->Count = pIoResList->Count(); + + pDescriptor = pList->Descriptors; + + pIoResEnd = pIoResList->End(); + for (pIoResCur = pIoResList->Start(); + pIoResCur != pIoResEnd; + pIoResCur = pIoResCur->Next()) { + + pResource = (FxResourceIo *) pIoResCur->m_Object; + RtlCopyMemory(pDescriptor, + &pResource->m_Descriptor, + sizeof(pResource->m_Descriptor)); + pDescriptor++; + } + + pList = (PIO_RESOURCE_LIST) pDescriptor; + } + } + } + + return pRequirementsList; + +Overflow: + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Integer overflow occured when computing size of " + "IO_RESOURCE_REQUIREMENTS_LIST"); + + return NULL; +} diff --git a/sdk/lib/drivers/wdf/shared/support/fxspinlock.cpp b/sdk/lib/drivers/wdf/shared/support/fxspinlock.cpp new file mode 100644 index 00000000000..7adb740ffa1 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxspinlock.cpp @@ -0,0 +1,142 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSpinLock.cpp + +Abstract: + + This module implements FxSpinLock + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" +#include "FxSpinLock.hpp" + +extern "C" { +#include "FxSpinLock.tmh" +} + +FxSpinLock::FxSpinLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ExtraSize + ) : + FxObject(FX_TYPE_SPIN_LOCK, COMPUTE_OBJECT_SIZE(sizeof(FxSpinLock), ExtraSize), FxDriverGlobals) +{ + FX_SPIN_LOCK_HISTORY* pHistory; + + m_Irql = 0; + m_InterruptLock = FALSE; + + pHistory = GetHistory(); + + if (pHistory != NULL) { + RtlZeroMemory(pHistory, sizeof(FX_SPIN_LOCK_HISTORY)); + + pHistory->CurrentHistory = &pHistory->History[0]; + } +} + + +__drv_raisesIRQL(DISPATCH_LEVEL) +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +FxSpinLock::AcquireLock( + __in PVOID CallersAddress + ) +{ + PFX_SPIN_LOCK_HISTORY pHistory; + KIRQL irql; + + m_SpinLock.Acquire(&irql); + + m_Irql = irql; + + pHistory = GetHistory(); + + if (pHistory != NULL) { + PFX_SPIN_LOCK_HISTORY_ENTRY pCur; + + // + // This assert should never fire here, but this helps track ownership + // in the case of a release without an acquire. + // + ASSERT(pHistory->OwningThread == NULL); + pHistory->OwningThread = Mx::MxGetCurrentThread(); + + pCur = pHistory->CurrentHistory; + + Mx::MxQueryTickCount(&pCur->AcquiredAtTime); + pCur->CallersAddress = CallersAddress; + } +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +FxSpinLock::ReleaseLock( + VOID + ) +{ + PFX_SPIN_LOCK_HISTORY pHistory; + + pHistory = GetHistory(); + + if (pHistory != NULL) { + LARGE_INTEGER now; + PFX_SPIN_LOCK_HISTORY_ENTRY pCur; + + if (pHistory->OwningThread != Mx::MxGetCurrentThread()) { + if (pHistory->OwningThread == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFSPINLOCK %p being released by thread 0x%p, but was " + "never acquired!", GetObjectHandle(), Mx::MxGetCurrentThread()); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFSPINLOCK 0x%p not owned by thread 0x%p, owned by thread 0x%p", + GetObjectHandle(), Mx::MxGetCurrentThread(), + pHistory->OwningThread); + } + + FxVerifierBugCheck(GetDriverGlobals(), + WDF_INVALID_LOCK_OPERATION, + (ULONG_PTR) GetObjectHandle(), + 0x1); + // + // Will not get here + // + return; + } + + ASSERT(pHistory->OwningThread != NULL); + + Mx::MxQueryTickCount(&now); + + pCur = pHistory->CurrentHistory; + pCur->LockedDuraction = now.QuadPart - pCur->AcquiredAtTime.QuadPart; + + pHistory->CurrentHistory++; + if (pHistory->CurrentHistory >= + pHistory->History + FX_SPIN_LOCK_NUM_HISTORY_ENTRIES) { + pHistory->CurrentHistory = pHistory->History; + } + + pHistory->OwningThread = NULL; + } + + m_SpinLock.Release(m_Irql); +} diff --git a/sdk/lib/drivers/wdf/shared/support/fxspinlockapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxspinlockapi.cpp new file mode 100644 index 00000000000..a9c576580ec --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxspinlockapi.cpp @@ -0,0 +1,181 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxSpinLockAPI.cpp + +Abstract: + + This module implements external APIS to access FxSpinLock + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" +#include "FxSpinLock.hpp" + +extern "C" { +#include "FxSpinLockAPI.tmh" +} + +// +// Extern the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfSpinLockCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + __out + WDFSPINLOCK* SpinLock + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxSpinLock* pLock; + WDFSPINLOCK lock; + USHORT extra; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle( + pFxDriverGlobals, SpinLockAttributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + SpinLockAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, SpinLock); + + status = FxValidateObjectAttributes(pFxDriverGlobals, SpinLockAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pFxDriverGlobals->FxVerifierLock) { + extra = sizeof(FX_SPIN_LOCK_HISTORY); + } + else { + extra = 0; + } + + *SpinLock = NULL; + + pLock = new(pFxDriverGlobals, SpinLockAttributes, extra) + FxSpinLock(pFxDriverGlobals, extra); + + if (pLock == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pLock->Commit(SpinLockAttributes, (WDFOBJECT*)&lock); + + if (NT_SUCCESS(status)) { + *SpinLock = lock; + } + else { + pLock->DeleteFromFailedCreate(); + } + + return status; +} + +__drv_raisesIRQL(DISPATCH_LEVEL) +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfSpinLockAcquire)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + __drv_savesIRQL + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFSPINLOCK SpinLock + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxSpinLock* pLock; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + SpinLock, + FX_TYPE_SPIN_LOCK, + (PVOID*) &pLock, + &pFxDriverGlobals); + + if (pLock->IsInterruptLock()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFSPINLOCK %p is associated with an interrupt, " + "cannot be used for normal sync operations", + SpinLock); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pLock->AcquireLock( + pFxDriverGlobals->FxVerifierLock ? _ReturnAddress() : NULL); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +__drv_minIRQL(DISPATCH_LEVEL) +VOID +WDFEXPORT(WdfSpinLockRelease)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + __drv_restoresIRQL + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFSPINLOCK SpinLock + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxSpinLock* pLock; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + SpinLock, + FX_TYPE_SPIN_LOCK, + (PVOID*) &pLock, + &pFxDriverGlobals); + + if (pLock->IsInterruptLock()) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "WDFSPINLOCK %p is associated with an interrupt, " + "cannot be used for normal sync operations", + SpinLock); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pLock->ReleaseLock(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/support/fxstring.cpp b/sdk/lib/drivers/wdf/shared/support/fxstring.cpp new file mode 100644 index 00000000000..a4f0c763852 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxstring.cpp @@ -0,0 +1,67 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxString.cpp + +Abstract: + + This module implements a simple string class to operate on + unicode strings. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +FxString::FxString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxObject(FX_TYPE_STRING, sizeof(FxString), FxDriverGlobals) +{ + RtlInitUnicodeString(&m_UnicodeString, NULL); + MarkPassiveDispose(ObjectDoNotLock); +} + +FxString::~FxString() +{ + if (m_UnicodeString.Buffer) { + FxPoolFree(m_UnicodeString.Buffer); + } +} + +_Must_inspect_result_ +NTSTATUS +FxString::Assign( + __in const UNICODE_STRING* UnicodeString + ) +{ + return FxDuplicateUnicodeString(GetDriverGlobals(), + UnicodeString, + &m_UnicodeString); +} + +_Must_inspect_result_ +NTSTATUS +FxString::Assign( + __in PCWSTR SourceString + ) + +{ + UNICODE_STRING string; + + RtlInitUnicodeString(&string, SourceString); + + return Assign(&string); +} diff --git a/sdk/lib/drivers/wdf/shared/support/fxstringapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxstringapi.cpp new file mode 100644 index 00000000000..34f3f18b45b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxstringapi.cpp @@ -0,0 +1,152 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxStringApi.cpp + +Abstract: + + This module implements the "C" interface to the collection object. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxStringAPI.tmh" +} + +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfStringCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PCUNICODE_STRING UnicodeString, + __in_opt + PWDF_OBJECT_ATTRIBUTES StringAttributes, + __out + WDFSTRING* String + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxString* pString; + NTSTATUS status; + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, + StringAttributes))) { + FxObject* pParent; + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + StringAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + } + + FxPointerNotNull(pFxDriverGlobals, String); + + *String = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, StringAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + if (UnicodeString != NULL) { + status = FxValidateUnicodeString(pFxDriverGlobals, UnicodeString); + if (!NT_SUCCESS(status)) { + return status; + } + } + + pString = new (pFxDriverGlobals, StringAttributes) FxString(pFxDriverGlobals); + + if (pString != NULL) { + if (UnicodeString != NULL) { + status = pString->Assign(UnicodeString); + } + + if (NT_SUCCESS(status)) { + status = pString->Commit(StringAttributes, (WDFOBJECT*)String); + } + + if (!NT_SUCCESS(status)) { + pString->DeleteFromFailedCreate(); + pString = NULL; + } + } + else { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Could not allocate WDFSTRING handle, %!STATUS!", status); + } + + return status; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfStringGetUnicodeString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFSTRING String, + __out + PUNICODE_STRING UnicodeString + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxString* pString; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + String, + FX_TYPE_STRING, + (PVOID*) &pString, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, UnicodeString); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + RtlCopyMemory(UnicodeString, + pString->GetUnicodeString(), + sizeof(UNICODE_STRING)); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/support/fxsupportpch.hpp b/sdk/lib/drivers/wdf/shared/support/fxsupportpch.hpp new file mode 100644 index 00000000000..2c9fbfa7cfe --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxsupportpch.hpp @@ -0,0 +1,25 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxsupportpch.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in fx\support + +--*/ + +#ifndef __FX_SUPPORT_PCH_HPP__ +#define __FX_SUPPORT_PCH_HPP__ + +#if FX_CORE_MODE == FX_CORE_USER_MODE +#include "um\FxSupportPchUM.hpp" +#elif FX_CORE_MODE == FX_CORE_KERNEL_MODE +#include "km\FxSupportPchKM.hpp" +#endif + +#endif // __FX_SUPPORT_PCH_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/support/fxtelemetry.cpp b/sdk/lib/drivers/wdf/shared/support/fxtelemetry.cpp new file mode 100644 index 00000000000..09ff414d9e6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxtelemetry.cpp @@ -0,0 +1,149 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetry.cpp + +Abstract: + + This module implements a telemetry methods. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +Notes: + +--*/ + + + +#include "fxsupportpch.hpp" + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#include "fxldr.h" +#include +#else +#include "DriverFrameworks-UserMode-UmEvents.h" +#include "FxldrUm.h" +#endif + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxTelemetry.tmh" +#endif +} + +#if defined(__cplusplus) +extern "C" { +#endif + + + + + +VOID +GetNameFromPath( + _In_ PCUNICODE_STRING Path, + _Out_ PUNICODE_STRING Name + ) +/*++ + +Routine Description: + + Given a potential full path name, return just the filename portion, OR, + Given a potential full registry path name, return just the subkey portion. + + Pointer to the filename protion in the full path name string, OR, + Pointer to the subkey portion in the full registry path name. + +Arguments: + + Path - Pointer to the full path name string. + + Name - Pointer to receive the name + +Return Value: + None + +--*/ +{ + BOOLEAN foundSlash; + + ASSERT(Path != NULL); + + // + // Ideally a check of Path->Length == 0 would be sufficient except that + // PreFAST thinks that Length can be odd, so it thinks Length == 1 is possible. + // Comparing Length < sizeof(WCHAR) satisfies PreFAST and keeps the logic + // at runtime correct. + // + if (Path->Length < sizeof(WCHAR)) { + RtlZeroMemory(Name, sizeof(UNICODE_STRING)); + return; + } + + // + // Initialize Name to point to the last WCHAR of the buffer and we will work + // our way backwards to the beginning of the string or a \ + // + + Name->Buffer = WDF_PTR_ADD_OFFSET_TYPE(Path->Buffer, + Path->Length - sizeof(WCHAR), + PWCH); + Name->Length = sizeof(WCHAR); + foundSlash = FALSE; + + while (Name->Buffer >= Path->Buffer) { + if (*Name->Buffer == L'\\') { + // + // Skip the \ in the buffer moving forward a character and adjusting + // the length + // + foundSlash = TRUE; + Name->Buffer++; + Name->Length -= sizeof(WCHAR); + break; + } + + // + // Move backwards in the string + // + Name->Buffer--; + Name->Length += sizeof(WCHAR); + } + + if (foundSlash && Name->Length == 0) { + // + // Handle the case where a slash was found and it is the only character + // + Name->Buffer = NULL; + } + else if (foundSlash == FALSE) { + // + // Handle the case where no slash was found. In this case, Name->Buffer + // points to one WCHAR before the beginning of the string. + // + Name->Length -= sizeof(WCHAR); + Name->Buffer++; + } + + // + // Need to set MaximumLength to the same value as Length so that the struct + // format is valid. + // + Name->MaximumLength = Name->Length; +} + +#if defined(__cplusplus) +} +#endif + diff --git a/sdk/lib/drivers/wdf/shared/support/fxtransactionedlist.cpp b/sdk/lib/drivers/wdf/shared/support/fxtransactionedlist.cpp new file mode 100644 index 00000000000..e970f1a0c15 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxtransactionedlist.cpp @@ -0,0 +1,552 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + FxTransactionedList.cpp + +Abstract: + + This module implements a simple transactioned list which allows the caller + to lock the list and then iterate over it without worrying about deletes + and adds. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +FxTransactionedList::FxTransactionedList() +{ + m_ListLockedRecursionCount = 0; + m_DeleteOnRemove = FALSE; + m_Deleting = FALSE; + m_Retries = 0; + m_DeletingDoneEvent = NULL; + + InitializeListHead(&m_ListHead); + InitializeListHead(&m_TransactionHead); +} + +FxTransactionedList::~FxTransactionedList() +{ + FxTransactionedEntry* pEntry; + PLIST_ENTRY ple; + + // + // If m_DeleteOnRemove is FALSE, there is no need to iterate over any of the + // lists to free anything. + // + if (m_DeleteOnRemove == FALSE) { + ASSERT(IsListEmpty(&m_ListHead)); + ASSERT(IsListEmpty(&m_TransactionHead)); + return; + } + + ASSERT(m_ListLockedRecursionCount == 0); + + while (!IsListEmpty(&m_ListHead)) { + ple = RemoveHeadList(&m_ListHead); + InitializeListHead(ple); + + pEntry = FxTransactionedEntry::_FromEntry(ple); + + switch (pEntry->m_Transaction) { + case FxTransactionActionNothing: + // + // Nothing to do, no pending transaction + // + break; + + case FxTransactionActionAdd: + // + // Should not have an add transaction and be on the main list at the + // same time! + // + ASSERT(FALSE); + break; + + case FxTransactionActionRemove: + // + // Make sure it is not on the transaction list + // + RemoveEntryList(&pEntry->m_TransactionLink); + InitializeListHead(&pEntry->m_TransactionLink); + + // + // When inserted as a remove transaction, we add this reference in + // RemoveLocked + // + pEntry->GetTransactionedObject()->RELEASE(pEntry); + break; + + } + + pEntry->GetTransactionedObject()->DeleteObject(); + } + + while (!IsListEmpty(&m_TransactionHead)) { + ple = RemoveHeadList(&m_TransactionHead); + InitializeListHead(ple); + + pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink); + + // + // We yanked out all of the removes in the previous loop + // + ASSERT(pEntry->m_Transaction == FxTransactionActionAdd); + + // + // Delete the object since this list owns it. + // + pEntry->GetTransactionedObject()->DeleteObject(); + } +} + +VOID +FxTransactionedList::LockForEnum( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + KIRQL irql; + + AcquireLock(FxDriverGlobals, &irql); + m_ListLockedRecursionCount++; + ReleaseLock(FxDriverGlobals, irql); +} + +VOID +FxTransactionedList::UnlockFromEnum( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +{ + LIST_ENTRY releaseHead; + KIRQL irql; + MxEvent* event; + + InitializeListHead(&releaseHead); + event = NULL; + AcquireLock(FxDriverGlobals, &irql); + m_ListLockedRecursionCount--; + ProcessTransactionList(&releaseHead); + + if (m_ListLockedRecursionCount == 0 && m_Deleting) { + event = m_DeletingDoneEvent; + m_DeletingDoneEvent = NULL; + } + ReleaseLock(FxDriverGlobals, irql); + + ProcessObjectsToRelease(&releaseHead); + + if (event != NULL) { + event->Set(); + } +} + +VOID +FxTransactionedList::ProcessTransactionList( + __in PLIST_ENTRY ReleaseHead + ) +{ + LIST_ENTRY *ple; + FxTransactionedEntry* pEntry; + + // + // If there are other iterators, do not process transactions until they are + // done. + // + if (m_ListLockedRecursionCount != 0) { + return; + } + + while (!IsListEmpty(&m_TransactionHead)) { + ple = RemoveHeadList(&m_TransactionHead); + InitializeListHead(ple); + + pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink); + + ASSERT(pEntry->m_Transaction != FxTransactionActionNothing); + + if (pEntry->m_Transaction == FxTransactionActionAdd) { + // + // Add to the main list + // + InsertTailList(&m_ListHead, &pEntry->m_ListLink); + + // + // Virtual notification of addition + // + EntryAdded(pEntry); + } + else if (pEntry->m_Transaction == FxTransactionActionRemove) { + // + // Remove it from the main list and move it to a free list + // + RemoveEntryList(&pEntry->m_ListLink); + InsertTailList(ReleaseHead, &pEntry->m_TransactionLink); + + // + // Virtual notification of removal + // + EntryRemoved(pEntry); + } + + pEntry->m_Transaction = FxTransactionActionNothing; + } +} + +VOID +FxTransactionedList::ProcessObjectsToRelease( + __in PLIST_ENTRY ReleaseHead + ) +{ + LIST_ENTRY *ple; + FxTransactionedEntry* pEntry; + + while (!IsListEmpty(ReleaseHead)) { + ple = RemoveHeadList(ReleaseHead); + InitializeListHead(ple); + + pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink); + + // + // We always release our reference we took when we post the change + // to the list + // + pEntry->GetTransactionedObject()->RELEASE(pEntry); + + // + // 2ndary release if the list is set to do this + // + if (m_DeleteOnRemove) { + pEntry->GetTransactionedObject()->DeleteObject(); + } + } +} + +BOOLEAN +FxTransactionedList::Deleting( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt MxEvent* DeleteDoneEvent + ) +{ + KIRQL irql; + BOOLEAN result; + + result = TRUE; + + AcquireLock(FxDriverGlobals, &irql); + m_Deleting = TRUE; + + if (m_ListLockedRecursionCount != 0) { + m_DeletingDoneEvent = DeleteDoneEvent; + result = FALSE; + } + + ReleaseLock(FxDriverGlobals, irql); + + return result; +} + +_Must_inspect_result_ +NTSTATUS +FxTransactionedList::Add( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxTransactionedEntry* Entry + ) +{ + NTSTATUS status; + KIRQL irql; + + AcquireLock(FxDriverGlobals, &irql); + + if (m_Deleting) { + status = STATUS_INVALID_DEVICE_STATE; + } + else { + status = ProcessAdd(Entry); + } + + if (NT_SUCCESS(status)) { + if (m_ListLockedRecursionCount == 0) { + // + // We can insert the entry now, do so + // + InsertTailList(&m_ListHead, &Entry->m_ListLink); + + EntryAdded(Entry); + } + else { + // + // List is locked, queue a transaction + // + Entry->m_Transaction = FxTransactionActionAdd; + InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink); + } + } + + ReleaseLock(FxDriverGlobals, irql); + + return status; +} + +VOID +FxTransactionedList::SearchForAndRemove( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PVOID EntryData + ) +{ + KIRQL irql; + FxTransactionedEntry* pEntry; + PLIST_ENTRY ple; + BOOLEAN removed; + + removed = FALSE; + + AcquireLock(FxDriverGlobals, &irql); + + for (ple = m_TransactionHead.Flink; + ple != &m_TransactionHead; + ple = ple->Flink) { + + pEntry = CONTAINING_RECORD(ple, FxTransactionedEntry, m_TransactionLink); + + if (Compare(pEntry, EntryData)) { + if (pEntry->GetTransactionAction() == FxTransactionActionAdd) { + RemoveEntryList(&pEntry->m_TransactionLink); + InitializeListHead(&pEntry->m_TransactionLink); + + removed = TRUE; + } + else { + // + // Already being removed, just return + // + ASSERT(pEntry->GetTransactionAction() == + FxTransactionActionRemove); + } + + goto Done; + } + } + + // + // Walk the committed list + // + pEntry = NULL; + + while ((pEntry = GetNextEntryLocked(pEntry)) != NULL) { + if (Compare(pEntry, EntryData)) { + removed = RemoveLocked(pEntry); + break; + } + } + +Done: + ReleaseLock(FxDriverGlobals, irql); + + if (removed && m_DeleteOnRemove) { + pEntry->GetTransactionedObject()->DeleteObject(); + } +} + +VOID +FxTransactionedList::Remove( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxTransactionedEntry* Entry + ) +{ + BOOLEAN removed; + KIRQL irql; + + AcquireLock(FxDriverGlobals, &irql); + removed = RemoveLocked(Entry); + ReleaseLock(FxDriverGlobals,irql); + + if (removed && m_DeleteOnRemove) { + Entry->GetTransactionedObject()->DeleteObject(); + } +} + +BOOLEAN +FxTransactionedList::RemoveLocked( + __in FxTransactionedEntry* Entry + ) +{ + BOOLEAN removed; + + removed = FALSE; + + if (Entry->m_Transaction == FxTransactionActionAdd) { + // + // Not yet added to the list proper, remove it from the transaction list + // + removed = TRUE; + RemoveEntryList(&Entry->m_TransactionLink); + InitializeListHead(&Entry->m_TransactionLink); + + Entry->m_Transaction = FxTransactionActionNothing; + } + else { + ASSERT(!IsListEmpty(&Entry->m_ListLink)); + + if (m_ListLockedRecursionCount == 0) { + // + // List is not locked, remove it now + // + RemoveEntryList(&Entry->m_ListLink); + InitializeListHead(&Entry->m_ListLink); + + // + // Virtual notification + // + EntryRemoved(Entry); + + removed = TRUE; + } + else { + // + // List is locked for enumeration, queue a transaction + // + Entry->m_Transaction = FxTransactionActionRemove; + InsertTailList(&m_TransactionHead, &Entry->m_TransactionLink); + Entry->GetTransactionedObject()->ADDREF(Entry); + } + } + + return removed; +} + +_Must_inspect_result_ +FxTransactionedEntry* +FxTransactionedList::GetNextEntry( + __in_opt FxTransactionedEntry* Entry + ) +/*++ + +Routine Description: + Gets the next entry. Assumes the caller has called LockedForEnum + +Arguments: + Entry the current entry in the iteratation, NULL for the first + +Return Value: + next entry in the iteration, NULL if there are no more entries + + --*/ +{ + // + // The caller should have locked the list for enumeration + // + ASSERT(m_ListLockedRecursionCount > 0 || m_Deleting); + + return GetNextEntryLocked(Entry); +} + +_Must_inspect_result_ +FxTransactionedEntry* +FxTransactionedList::GetNextEntryLocked( + __in_opt FxTransactionedEntry* Entry + ) +/*++ + +Routine Description: + Returns the next entry. Assumes that the caller has the list locked through + a call to AcquireLock() or through LockForEnum() + +Arguments: + Entry the current entry in the iteratation, NULL for the first + +Return Value: + next entry in the iteration, NULL if there are no more entries + + --*/ +{ + PLIST_ENTRY ple; + + if (Entry == NULL) { + ple = m_ListHead.Flink; + } + else { + ple = Entry->m_ListLink.Flink; + } + + // + // Find the next entry which does not have a pending transaction on it + // + for ( ; ple != &m_ListHead; ple = ple->Flink) { + FxTransactionedEntry* pNext; + + pNext = FxTransactionedEntry::_FromEntry(ple); + if (pNext->m_Transaction == FxTransactionActionNothing) { + return pNext; + } + } + + // + // Reached the end of the list + // + return NULL; +} + +FxSpinLockTransactionedList::FxSpinLockTransactionedList() : + FxTransactionedList() +{ +} + +__drv_raisesIRQL(DISPATCH_LEVEL) +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +FxSpinLockTransactionedList::AcquireLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __out PKIRQL Irql + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + m_ListLock.Acquire(Irql); +} + +__drv_requiresIRQL(DISPATCH_LEVEL) +VOID +FxSpinLockTransactionedList::ReleaseLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in __drv_restoresIRQL KIRQL Irql + ) +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + m_ListLock.Release(Irql); +} + +_Acquires_lock_(_Global_critical_region_) +VOID +FxWaitLockTransactionedList::AcquireLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __out PKIRQL Irql + ) +{ + UNREFERENCED_PARAMETER(Irql); + m_StateChangeListLock.AcquireLock(FxDriverGlobals); +} + +_Releases_lock_(_Global_critical_region_) +VOID +FxWaitLockTransactionedList::ReleaseLock( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in KIRQL Irql + ) +{ + UNREFERENCED_PARAMETER(Irql); + m_StateChangeListLock.ReleaseLock(FxDriverGlobals); +} + + diff --git a/sdk/lib/drivers/wdf/shared/support/fxwaitlock.cpp b/sdk/lib/drivers/wdf/shared/support/fxwaitlock.cpp new file mode 100644 index 00000000000..12e01fde79e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxwaitlock.cpp @@ -0,0 +1,74 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWaitLock.cpp + +Abstract: + + This module implements the FxWaitLock's factory method. + +Author: + + +Revision History: + + +--*/ + +#include "FxSupportPch.hpp" + +#if defined(EVENT_TRACING) +// Tracing support +extern "C" { +#include "FxWaitLock.tmh" +} +#endif + +__checkReturn +NTSTATUS +FxWaitLock::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in_opt PWDF_OBJECT_ATTRIBUTES Attributes, + __in_opt FxObject* ParentObject, + __in BOOLEAN AssignDriverAsDefaultParent, + __out WDFWAITLOCK* LockHandle + ) +{ + FxWaitLock* lock; + NTSTATUS status; + + *LockHandle = NULL; + + lock = new (FxDriverGlobals, Attributes) FxWaitLock(FxDriverGlobals); + if (lock == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Memory allocation failed: %!STATUS!", status); + return status; + } + + status = lock->Initialize(); + if (!NT_SUCCESS(status)) { + lock->DeleteFromFailedCreate(); + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "faield to initialize wait lock: %!STATUS!", status); + return status; + } + + status = lock->Commit(Attributes, + (WDFOBJECT*)LockHandle, + ParentObject, + AssignDriverAsDefaultParent); + + if (!NT_SUCCESS(status)) { + lock->DeleteFromFailedCreate(); + } + + return status; +} + + + diff --git a/sdk/lib/drivers/wdf/shared/support/fxwaitlockapi.cpp b/sdk/lib/drivers/wdf/shared/support/fxwaitlockapi.cpp new file mode 100644 index 00000000000..c02e923c119 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/fxwaitlockapi.cpp @@ -0,0 +1,184 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxWaitLockAPI.cpp + +Abstract: + + This module implements the external APIs for FxWaitLock + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +// extern the entire file +extern "C" { + + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfWaitLockCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in_opt + PWDF_OBJECT_ATTRIBUTES LockAttributes, + __out + WDFWAITLOCK* Lock + ) +/*++ + +Routine Description: + Creates a lock object which can be acquired at PASSIVE_LEVEL and will return + to the caller at PASSIVE_LEVEL once acquired. + +Arguments: + LockAttributes - generic attributes to be associated with the created lock + + Lock - pointer to receive the newly created lock + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS fxDriverGlobals; + NTSTATUS status; + FxObject* parent; + + fxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + parent = NULL; + + // + // Get the parent's globals if it is present + // + if (NT_SUCCESS(FxValidateObjectAttributesForParentHandle(fxDriverGlobals, + LockAttributes))) { + FxObjectHandleGetPtrAndGlobals(fxDriverGlobals, + LockAttributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&parent, + &fxDriverGlobals); + } + + FxPointerNotNull(fxDriverGlobals, Lock); + + status = FxValidateObjectAttributes(fxDriverGlobals, LockAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + return FxWaitLock::_Create(fxDriverGlobals, + LockAttributes, + parent, + TRUE, + Lock); +} + +__drv_when(Timeout != 0, _Must_inspect_result_) +__drv_when(Timeout == 0, __drv_maxIRQL(PASSIVE_LEVEL)) +__drv_when(Timeout != 0 && *Timeout == 0, __drv_maxIRQL(DISPATCH_LEVEL)) +__drv_when(Timeout != 0 && *Timeout != 0, __drv_maxIRQL(PASSIVE_LEVEL)) +NTSTATUS +WDFAPI +WDFEXPORT(WdfWaitLockAcquire)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWAITLOCK Lock, + __in_opt + PLONGLONG Timeout + ) +/*++ + +Routine Description: + Attempts to acquire the lock object. If a non NULL timeout is provided, the + attempt to acquire the lock may fail if it cannot be acquired in the + specified time. + +Arguments: + Lock - the lock to acquire + + Timeout - optional timeout in acquiring the lock. If calling at an IRQL >= + DISPATCH_LEVEL, then this parameter is not NULL (and should more + then likely be zero) + +Return Value: + STATUS_TIMEOUT if a timeout was provided and the lock could not be acquired + in the specified time, otherwise STATUS_SUCCESS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxWaitLock* pLock; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Lock, + FX_TYPE_WAIT_LOCK, + (PVOID*) &pLock, + &pFxDriverGlobals); + + if (Timeout == NULL || *Timeout != 0) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + } + + return pLock->AcquireLock(pFxDriverGlobals, Timeout); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfWaitLockRelease)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFWAITLOCK Lock + ) +/*++ + +Routine Description: + Releases a previously acquired wait lock + +Arguments: + Lock - the lock to release + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxWaitLock* pLock; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Lock, + FX_TYPE_WAIT_LOCK, + (PVOID*) &pLock, + &pFxDriverGlobals); + + pLock->ReleaseLock(pFxDriverGlobals); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxdeviceinterfacekm.cpp b/sdk/lib/drivers/wdf/shared/support/km/fxdeviceinterfacekm.cpp new file mode 100644 index 00000000000..0fb95e621b2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/km/fxdeviceinterfacekm.cpp @@ -0,0 +1,236 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInterfaceKM.cpp + +Abstract: + + This module implements the device interface object. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxDeviceInterfaceKM.tmh" +} + +FxDeviceInterface::FxDeviceInterface( + ) +/*++ + +Routine Description: + Constructor for the object. Initializes all fields + +Arguments: + None + +Return Value: + None + + --*/ +{ + RtlZeroMemory(&m_InterfaceClassGUID, sizeof(m_InterfaceClassGUID)); + + RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName)); + RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString)); + + m_Entry.Next = NULL; + + m_State = FALSE; +} + +FxDeviceInterface::~FxDeviceInterface() +/*++ + +Routine Description: + Destructor for FxDeviceInterface. Cleans up any allocations previously + allocated. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // the device interface should be off now + ASSERT(m_State == FALSE); + + // should no longer be in any list + ASSERT(m_Entry.Next == NULL); + + if (m_ReferenceString.Buffer != NULL) { + FxPoolFree(m_ReferenceString.Buffer); + RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString)); + } + + if (m_SymbolicLinkName.Buffer != NULL) { + RtlFreeUnicodeString(&m_SymbolicLinkName); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Initialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CONST GUID* InterfaceGUID, + __in_opt PCUNICODE_STRING ReferenceString + ) +/*++ + +Routine Description: + Initializes the object with the interface GUID and optional reference string + +Arguments: + InterfaceGUID - GUID describing the interface + + ReferenceString - string used to differentiate between 2 interfaces on the + same PDO + +Return Value: + STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES + + --*/ +{ + RtlCopyMemory(&m_InterfaceClassGUID, InterfaceGUID, sizeof(GUID)); + + if (ReferenceString != NULL) { + return FxDuplicateUnicodeString(FxDriverGlobals, + ReferenceString, + &m_ReferenceString); + } + else { + return STATUS_SUCCESS; + } +} + + +VOID +FxDeviceInterface::SetState( + __in BOOLEAN State + ) +/*++ + +Routine Description: + Sets the state of the device interface + +Arguments: + State - the state to set + + +Return Value: + None. + + --*/ +{ + m_State = State; + + // + // Only set the state if the interface has been registered + // + if (m_SymbolicLinkName.Buffer != NULL) { + Mx::MxSetDeviceInterfaceState(&m_SymbolicLinkName, m_State); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Register( + __in PDEVICE_OBJECT Pdo + ) +/*++ + +Routine Description: + Registers the device interface for a given PDO + +Arguments: + Pdo - PDO for the device stack + + +Return Value: + returned by IoRegisterDeviceInterface + + --*/ +{ + PUNICODE_STRING pString; + + if (m_ReferenceString.Length > 0) { + pString = &m_ReferenceString; + } + else { + pString = NULL; + } + + return Mx::MxRegisterDeviceInterface( + Pdo, &m_InterfaceClassGUID, pString, &m_SymbolicLinkName); +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Register( + _In_ FxDevice* Device + ) +{ + NTSTATUS status; + MdDeviceObject pdo; + + pdo = Device->GetSafePhysicalDevice(); + + if (pdo != NULL) { + status = Register(pdo); + } + else { + // + // Leave the device interface unregistered. When we are in hardware + // available, we will register there once we know for sure we have a + // real live PDO that the system has acknowledged. + // + DO_NOTHING(); + + status = STATUS_SUCCESS; + } + + return status; +} + +NTSTATUS +FxDeviceInterface::GetSymbolicLinkName( + _In_ FxString* LinkString + ) +{ + NTSTATUS status; + + if (m_SymbolicLinkName.Buffer == NULL) { + // + // The device interface has not yet been registered b/c it + // belongs to a PDO and the PDO has not been recognized by + // pnp yet. + // + status = STATUS_INVALID_DEVICE_STATE; + UNREFERENCED_PARAMETER(LinkString); + } + else { + // + // Attempt a copy + // + status = LinkString->Assign(&m_SymbolicLinkName); + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp b/sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp new file mode 100644 index 00000000000..a6c5e3fa23d --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/km/fxregkeykm.cpp @@ -0,0 +1,296 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRegKey.cpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxRegKeyKM.tmh" +} + +#define AT_PASSIVE() ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL) + +FxRegKey::FxRegKey( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals), + m_Key(NULL), + m_Globals(FxDriverGlobals) +{ +} + +__drv_maxIRQL(PASSIVE_LEVEL) +FxRegKey::~FxRegKey() +{ + if (m_Key != NULL) { + ZwClose(m_Key); + m_Key = NULL; + } +} + +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_Close( + __in HANDLE Key + ) +{ + return ZwClose(Key); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_Create( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __out HANDLE* NewKey, + __in ACCESS_MASK DesiredAccess, + __in ULONG CreateOptions, + __out_opt PULONG CreateDisposition + ) +{ + OBJECT_ATTRIBUTES oa; + + AT_PASSIVE(); + + // + // Force OBJ_KERNEL_HANDLE because we are never passing the handle back + // up to a process and we don't want to create a handle in an arbitrary + // process from which that process can close the handle out from underneath + // us. + // + InitializeObjectAttributes( + &oa, + (PUNICODE_STRING) KeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ParentKey, + NULL); + + return ZwCreateKey(NewKey, + DesiredAccess, + &oa, + 0, + 0, + CreateOptions, + CreateDisposition); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_OpenKey( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __out HANDLE* Key, + __in ACCESS_MASK DesiredAccess + ) +{ + OBJECT_ATTRIBUTES oa; + + AT_PASSIVE(); + + // + // Force OBJ_KERNEL_HANDLE because we are never passing the handle back + // up to a process and we don't want to create a handle in an arbitrary + // process from which that process can close the handle out from underneath + // us. + // + InitializeObjectAttributes( + &oa, + (PUNICODE_STRING)KeyName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + ParentKey, + NULL); + + return ZwOpenKey(Key, DesiredAccess, &oa); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_SetValue( + _In_ HANDLE Key, + __in PCUNICODE_STRING ValueName, + __in ULONG ValueType, + __in_bcount(ValueLength) PVOID Value, + __in ULONG ValueLength + ) +{ + AT_PASSIVE(); + + return ZwSetValueKey(Key, + (PUNICODE_STRING)ValueName, + 0, + ValueType, + Value, + ValueLength); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_QueryValue( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __in ULONG ValueLength, + __out_bcount_opt(ValueLength) PVOID Value, + __out_opt PULONG ValueLengthQueried, + __out_opt PULONG ValueType + ) +{ + KEY_VALUE_PARTIAL_INFORMATION *pPartial, partial; + NTSTATUS status; + ULONG length; + + if (Value == NULL) { + // + // Caller wants just the length + // + pPartial = &partial; + length = _ComputePartialSize(0); + RtlZeroMemory(&partial, length); + } + else { + length = _ComputePartialSize(ValueLength); + pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) + MxMemory::MxAllocatePoolWithTag(PagedPool, length, FxDriverGlobals->Tag); + + if (pPartial == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + } + + // + // We always pass a buffer of at least sizeof(KEY_VALUE_PARTIAL_INFORMATION) + // to ZwQueryValueKey. This means that ZwQueryValueKey will write at least + // some information to the buffer it receives, even if the user-supplied data + // buffer is NULL or too small. + // + // According to ZwQueryValueKey's contract, this means that it will never return + // STATUS_BUFFER_TOO_SMALL (returned when no data is written). Therefore, if the + // user passes a NULL or insufficient buffer and the value exists in the registry, + // ZwQueryValueKey will return STATUS_BUFFER_OVERFLOW. + // + status = ZwQueryValueKey(Key, + (PUNICODE_STRING)ValueName, + KeyValuePartialInformation, + pPartial, + length, + &length); + + if (NT_SUCCESS(status) && Value != NULL && (ValueLength >= pPartial->DataLength)) { + RtlCopyMemory(Value, &pPartial->Data[0], pPartial->DataLength); + } + + if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) { + if (ValueLengthQueried != NULL) { + *ValueLengthQueried = pPartial->DataLength; + } + if (ValueType != NULL) { + *ValueType = pPartial->Type; + } + } + + if (pPartial != &partial) { + MxMemory::MxFreePool(pPartial); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_QueryULong( + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __out PULONG Value + ) +{ + NTSTATUS status; + ULONG length; + + PKEY_VALUE_PARTIAL_INFORMATION pPartial; + UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(ULONG))]; + + length = sizeof(buffer); + pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0]; + + status = ZwQueryValueKey(Key, + (PUNICODE_STRING)ValueName, + KeyValuePartialInformation, + pPartial, + length, + &length); + + if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && + pPartial->Type != REG_DWORD) { + status = STATUS_OBJECT_TYPE_MISMATCH; + } + + if (NT_SUCCESS(status)) { + ASSERT(sizeof(ULONG) == pPartial->DataLength); + + RtlCopyMemory(Value, &pPartial->Data[0], sizeof(ULONG)); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +FxRegKey::_QueryQuadWord( + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __out PLARGE_INTEGER Value + ) +{ + NTSTATUS status; + ULONG length; + + PKEY_VALUE_PARTIAL_INFORMATION pPartial; + UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)+(sizeof(LARGE_INTEGER))]; + + length = sizeof(buffer); + pPartial = (PKEY_VALUE_PARTIAL_INFORMATION) &buffer[0]; + + status = ZwQueryValueKey(Key, + (PUNICODE_STRING)ValueName, + KeyValuePartialInformation, + pPartial, + length, + &length); + + if ((NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) && + pPartial->Type != REG_QWORD) { + status = STATUS_OBJECT_TYPE_MISMATCH; + } + + if (NT_SUCCESS(status)) { + ASSERT(sizeof(LARGE_INTEGER) == pPartial->DataLength); + + RtlCopyMemory(Value, &pPartial->Data[0], sizeof(LARGE_INTEGER)); + } + + return status; +} + + diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxrequestbufferkm.cpp b/sdk/lib/drivers/wdf/shared/support/km/fxrequestbufferkm.cpp new file mode 100644 index 00000000000..d2f82410dcc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/km/fxrequestbufferkm.cpp @@ -0,0 +1,277 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRequestBufferKm.cpp + +Abstract: + + This module implements a memory union object + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxRequestBufferKm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxRequestBuffer::GetOrAllocateMdl( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __deref_out_opt PMDL* Mdl, + __inout PMDL* MdlToFree, + __inout PBOOLEAN UnlockWhenFreed, + __in LOCK_OPERATION Operation, + __in BOOLEAN ReuseMdl, + __inout_opt size_t* SizeOfMdl + ) +/*++ + +Routine Description: + + This function attempts to reuse the passed-in MDL (if any) or allocates + a new MDL if reuse flag isn't passed-in or if the existing MDL isn't + big enough. + +Arguments: + +Return Value: + FxDriverGlobals - Driver globals + + Mdl - on return it contains the MDL allocated/reused + + MdlToFree - pointer to any MDL + * to be reused, if the size is <= current size, or + * freed and set to newly allocated MDL + + UnlockWhenFreed - whether to unlock pages when freeing MDL + (if FALSE, MDL may represent just MDL buffer but the pages + might have already been unlocked) + + Operation - Operation to pass to MmLockPages + + ReuseMdl - whether to reuse *MdlToFree + Please note that this can be FALSE even when MDL is supplied + + SizeOfMdl - on input contains size of *MdlToFree, + on return contains size of *Mdl + +Remarks: + + *MdlToFree is modified only when this function frees the passed in MDL + Otherwise it leaves it untouched. Caller is responsible for storing + properly initialized value and/or freeing what's stored in the value. + + --*/ +{ + PVOID pBuf; + NTSTATUS status; + ULONG length; + BOOLEAN oldUnlockValue; + + pBuf = NULL; + + oldUnlockValue = *UnlockWhenFreed; + + // + // Format functions that use this helper call + // FxRequestBase::ValidateTarget which calls ContextReleaseAndRestore + // which unlocks any locked pages. + // + // Hence pages must already be unlocked now. Let's assert that. + // + // This condition needs to be true since we unconditionally set + // *UnlockWhenFreed to FALSE just below. + // + ASSERT (oldUnlockValue == FALSE); + + *UnlockWhenFreed = FALSE; + + // + // Even if ReuseMdl is not true, SizeOfMdl may be supplied to store + // the size of allocated MDL to be used later + // + ASSERT(ReuseMdl ? (SizeOfMdl != NULL && *MdlToFree != NULL) : TRUE); + + switch (DataType) { + case FxRequestBufferUnspecified: + *Mdl = NULL; + // + // We should not set *MdlToFree to NULL as *MdlToFree might have a valid + // MDL which we should not overwrite with NULL without freeing it + // + return STATUS_SUCCESS; + + case FxRequestBufferMemory: + if (u.Memory.Offsets != NULL) { + pBuf = WDF_PTR_ADD_OFFSET(u.Memory.Memory->GetBuffer(), + u.Memory.Offsets->BufferOffset); + } + else { + pBuf = u.Memory.Memory->GetBuffer(); + } + // || || + // \/ \/ fall through + + case FxRequestBufferBuffer: + if (pBuf == NULL) { + pBuf = u.Buffer.Buffer; + } + + length = GetBufferLength(); + status = GetOrAllocateMdlWorker(FxDriverGlobals, + Mdl, + &ReuseMdl, + length, + pBuf, + SizeOfMdl, + oldUnlockValue, + MdlToFree + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status); + return status; + } + + // + // If we are reusing the MDL we need to initialize it with current + // buffer. + // + if (ReuseMdl == TRUE) { + Mx::MxInitializeMdl(*Mdl, pBuf, length); + } + + status = FxProbeAndLockWithAccess(*Mdl, KernelMode, Operation); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Couldn't lock pages for MDL 0x%p %!STATUS!", *Mdl, status); + + // + // Free MDL only if it was not reused. + // + if (ReuseMdl == FALSE) { + FxMdlFree(FxDriverGlobals, *Mdl); + } + + *Mdl = NULL; + return status; + } + + *UnlockWhenFreed = TRUE; + *MdlToFree = *Mdl; + + return STATUS_SUCCESS; + + case FxRequestBufferMdl: + *Mdl = u.Mdl.Mdl; + // + // We should not set *MdlToFree to NULL as *MdlToFree might have a valid + // MDL which we should not overwrite with NULL without freeing it + // + return STATUS_SUCCESS; + + case FxRequestBufferReferencedMdl: + if (u.RefMdl.Offsets == NULL || + (u.RefMdl.Offsets->BufferOffset == 0 && u.RefMdl.Offsets->BufferLength == 0)) { + *Mdl = u.RefMdl.Mdl; + // + // We should not set *MdlToFree to NULL as *MdlToFree might have a valid + // MDL which we should not overwrite with NULL without freeing it + // + } + else { + // + // Do not use MmGetSystemAddressForMdlSafe because StartVa could be + // in UM while MappedVa (obviously) is in KM. Since + // IoBuildPartial Mdl basically uses + // pBuf - MmGetMdlVirtualAddress(SrcMdl) to compute offset, if one + // VA is in UM (e.g. MmGetMdlVirtualAddress(SrcMdl)), you get the + // (drastically) wrong offset. + // + pBuf = Mx::MxGetMdlVirtualAddress(u.RefMdl.Mdl); + ASSERT(pBuf != NULL); + + pBuf = WDF_PTR_ADD_OFFSET(pBuf, u.RefMdl.Offsets->BufferOffset); + + // + // GetBufferLength will compute the correct length with the given offsets + // + length = GetBufferLength(); + status = GetOrAllocateMdlWorker(FxDriverGlobals, + Mdl, + &ReuseMdl, + length, + pBuf, + SizeOfMdl, + oldUnlockValue, + MdlToFree + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGAPIERROR, + "Couldn't allocate memory for MDL of length 0x%x %!STATUS!", length, status); + return status; + } + + Mx::MxBuildPartialMdl( + u.RefMdl.Mdl, + *Mdl, + pBuf, + length + ); + + *MdlToFree = *Mdl; + } + + return STATUS_SUCCESS; + + default: + *Mdl = NULL; + // + // We should not set *MdlToFree to NULL as *MdlToFree might have a valid + // MDL which we should not overwrite with NULL without freeing it + // + return STATUS_INVALID_PARAMETER; + } +} + +VOID +FxRequestBuffer::SetMemory( + __in IFxMemory* Memory, + __in PWDFMEMORY_OFFSET Offsets + ) +{ + PMDL pMdl; + + pMdl = Memory->GetMdl(); + if (pMdl != NULL) { + DataType = FxRequestBufferReferencedMdl; + u.RefMdl.Memory = Memory; + u.RefMdl.Offsets = Offsets; + u.RefMdl.Mdl = pMdl; + } + else { + DataType = FxRequestBufferMemory; + u.Memory.Memory = Memory; + u.Memory.Offsets = Offsets; + } +} + diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxresourcecollectionkm.cpp b/sdk/lib/drivers/wdf/shared/support/km/fxresourcecollectionkm.cpp new file mode 100644 index 00000000000..f74a1519150 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/km/fxresourcecollectionkm.cpp @@ -0,0 +1,39 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxResourceCollection.cpp + +Abstract: + + This module implements a base object for derived collection classes and + the derived collection classes. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +#if defined(EVENT_TRACING) +// Tracing support +extern "C" { +#include "FxResourceCollectionKm.tmh" +} +#endif + +FxCmResList::~FxCmResList() +{ +} + + diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxsupportpchkm.hpp b/sdk/lib/drivers/wdf/shared/support/km/fxsupportpchkm.hpp new file mode 100644 index 00000000000..67b2a6097c9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/km/fxsupportpchkm.hpp @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxsupportpchkm.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in fx\support + +Author: + +Environment: + Kernel mode only + +Revision History: + +--*/ + +#ifndef __FX_SUPPORT_PCH_KM_HPP__ +#define __FX_SUPPORT_PCH_KM_HPP__ + +extern "C" { +#include +} + +#include + +#include "FxCollection.hpp" +#include "StringUtil.hpp" +#include "FxString.hpp" +#include "FxDeviceText.hpp" +#include "FxWaitLock.hpp" + +#include +#include + +#endif // __FX_SUPPORT_PCH_KM_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/support/km/fxtelemetrykm.cpp b/sdk/lib/drivers/wdf/shared/support/km/fxtelemetrykm.cpp new file mode 100644 index 00000000000..c8d68a438e4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/km/fxtelemetrykm.cpp @@ -0,0 +1,732 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetryKm.cpp + +Abstract: + + This module implements a telemetry methods. + +Author: + + + +Environment: + + Kernel mode only + +Revision History: + +Notes: + +--*/ + +#include "fxsupportpch.hpp" +#include "fxldr.h" +#include +#include +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxTelemetryKm.tmh" +#endif +} + +/* ec044b58-3d13-3d13-936f-7b67dfb3e */ +TRACELOGGING_DEFINE_PROVIDER(g_TelemetryProvider, + KMDF_FX_TRACE_LOGGING_PROVIDER_NAME, + (0xec044b58, 0x3d13, 0x4880, 0x93, 0x6f, 0x7b, 0x67, 0xdf, 0xb3, 0xe0, 0x56), + TraceLoggingOptionMicrosoftTelemetry()); + +VOID +AllocAndInitializeTelemetryContext( + _In_ PFX_TELEMETRY_CONTEXT* TelemetryContext + ) +{ + PFX_TELEMETRY_CONTEXT context = NULL; + NTSTATUS status; + + context = (PFX_TELEMETRY_CONTEXT)MxMemory::MxAllocatePoolWithTag( + NonPagedPool, + sizeof(FX_TELEMETRY_CONTEXT), + FX_TAG); + if (NULL == context) { + goto exit; + } + + status = ExUuidCreate(&(context->DriverSessionGUID)); + if (!NT_SUCCESS(status)) { + MxMemory::MxFreePool(context); + context = NULL; + goto exit; + } + + context->DoOnceFlagsBitmap = 0; + +exit: + *TelemetryContext = context; +} + +VOID +RegisterTelemetryProvider( + VOID + ) +{ + TraceLoggingRegister(g_TelemetryProvider); +} + +VOID +UnregisterTelemetryProvider( + VOID + ) +{ + TraceLoggingUnregister(g_TelemetryProvider); +} + +VOID +LogDeviceStartTelemetryEvent( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ FxDevice* Fdo + ) +{ + // + // See if telemetry registered and all the criteria to log is met. + if (IsLoggingEnabledAndNeeded(DriverGlobals) == FALSE) { + return; + } + + // + // Log driver info stream + // + LogDriverInfoStream(DriverGlobals, Fdo); +} + +BOOLEAN +IsLoggingEnabledAndNeeded( + _In_ PFX_DRIVER_GLOBALS DriverGlobals + ) +{ + LARGE_INTEGER lastLoggedTime; + LARGE_INTEGER currentTime; + LONGLONG delta; + + // If provider is not enabled exit. + if (FALSE == FX_TELEMETRY_ENABLED(g_TelemetryProvider, DriverGlobals)) { + return FALSE; + } + + ASSERT(DriverGlobals->TelemetryContext); + + // + // If we already fired an event during PnP start we are done. This avoids + // repeatedly firing events during PnP rebalance. + // + if (InterlockedBitTestAndSet( + &DriverGlobals->TelemetryContext->DoOnceFlagsBitmap, + DeviceStartEventBit) != 0) { + return FALSE; + } + + // + // log only if it has been MIN_HOURS_BEFORE_NEXT_LOG time since last log. + // We don't log every time driver loads to avoid sending too much data + // too many times in case of a buggy driver going through load/unload cycle + // or when a device is plugged in two many times. + // + lastLoggedTime.QuadPart = 0; + RegistryReadLastLoggedTime(DriverGlobals, &lastLoggedTime); + + if (lastLoggedTime.QuadPart == 0) { + // + // driver is loading for first time ater install so need to log + // event + // + return TRUE; + } + + Mx::MxQuerySystemTime(¤tTime); + + delta = (currentTime.QuadPart - lastLoggedTime.QuadPart); + + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "lastlogged %I64x, current %I64x, delta %I64x", + lastLoggedTime.QuadPart, currentTime.QuadPart, delta); + + // + // KeQuerySystemTime returns time in 100-ns. We convert MIN_HOURS_BEFORE_NEXT_LOG + // to 100-nano sec unit and then compare. + // + if (delta < WDF_ABS_TIMEOUT_IN_SEC(MIN_HOURS_BEFORE_NEXT_LOG * 60 * 60)) { + return FALSE; + } + + return TRUE; +} + +VOID +LogDriverInfoStream( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_opt_ FxDevice* Fdo + ) +{ + FxTelemetryDriverInfo driverInfo = {0}; + FxAutoString hardwareIDs, setupClass, busEnum, manufacturer; + + // + // Log driver and device info + // + GetDriverInfo(DriverGlobals, Fdo, &driverInfo); + + if (Fdo != NULL) { + // + // Get Setup class + // + FxGetDevicePropertyString(Fdo, + DevicePropertyClassName, + &setupClass.m_UnicodeString); + // + // Get Bus enumerator + // + FxGetDevicePropertyString(Fdo, + DevicePropertyEnumeratorName, + &busEnum.m_UnicodeString); + // + // Get hardware id multi-string + // + FxGetDevicePropertyString(Fdo, + DevicePropertyHardwareID, + &hardwareIDs.m_UnicodeString); + + GetFirstHardwareId(&hardwareIDs.m_UnicodeString); + + // + // Get manufacturer + // + FxGetDevicePropertyString(Fdo, + DevicePropertyManufacturer, + &manufacturer.m_UnicodeString); + } + + KMDF_CENSUS_EVT_WRITE_DEVICE_START(g_TelemetryProvider, + DriverGlobals, + driverInfo, + setupClass, + busEnum, + hardwareIDs, + manufacturer); + + // + // write current time to registry + // + RegistryWriteCurrentTime(DriverGlobals); +} + +VOID +GetFirstHardwareId( + _Inout_ PUNICODE_STRING HardwareIds + ) +/*++ + + Routine Description: + + This routine returns the first hardware ID present in the multi-string. + If the first string is longer than max allowed by Telemetry, a null value is + returned instead of retruning a partial ID. + + Arguments: + + HardwareIds - a multi-string terminated by two unicode_nulls. + +--*/ + +{ + PWCHAR curr; + USHORT lengthCch; + + ASSERT(HardwareIds != NULL); + + curr = (PWCHAR) HardwareIds->Buffer; + lengthCch = (HardwareIds->Length)/sizeof(WCHAR); + + // + // if the caller supplied NULL buffer, then nothing to do. + // + if (curr == NULL) { + RtlInitUnicodeString(HardwareIds, NULL); + return; + } + + // + // if the first element is NULL then update the length + // + if (*curr == UNICODE_NULL) { + HardwareIds->Length = 0; + HardwareIds->MaximumLength = HardwareIds->Length + sizeof(UNICODE_NULL); + return; + } + + for (int i = 0; i < lengthCch; i++, curr++) { + + if (*curr == UNICODE_NULL) { + // + // We found the first string. Update size. We only want to keep the + // first string. + // + HardwareIds->Length = (USHORT)(i * sizeof(WCHAR)); + HardwareIds->MaximumLength = HardwareIds->Length + sizeof(UNICODE_NULL); + return; + } + } +} + +VOID +GetDriverInfo( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ FxDevice* Fdo, + _Out_ FxTelemetryDriverInfo* DriverInfo + ) +{ + FxPkgPnp* pnpPkg; + USHORT devInfo = 0; + + DriverInfo->bitmap.IsVerifierOn = Globals->FxVerifierOn; + DriverInfo->bitmap.IsEnhancedVerifierOn = FLAG_TO_BOOL(Globals->FxEnhancedVerifierOptions, FxEnhancedVerifierFunctionTableHookMask); + + if (Fdo == NULL) { + // + // this is for non-pnp or noDispatchOverride. + // + DriverInfo->bitmap.IsNonPnpDriver = FLAG_TO_BOOL(Globals->Public.DriverFlags, WdfDriverInitNonPnpDriver); + DriverInfo->bitmap.IsNoDispatchOverride = FLAG_TO_BOOL(Globals->Public.DriverFlags, WdfDriverInitNoDispatchOverride); + } + else { + pnpPkg = Fdo->m_PkgPnp; + devInfo = Fdo->GetDeviceTelemetryInfoFlags(); + + DriverInfo->bitmap.IsFilter = Fdo->GetFdoPkg()->IsFilter(); + DriverInfo->bitmap.IsUsingRemoveLockOption = Fdo->IsRemoveLockEnabledForIo(); + DriverInfo->bitmap.IsUsingNonDefaultHardwareReleaseOrder = pnpPkg->IsDefaultReleaseHardwareOrder(); + DriverInfo->bitmap.IsPowerPolicyOwner = pnpPkg->IsPowerPolicyOwner(); + DriverInfo->bitmap.IsS0IdleWakeFromS0Enabled = pnpPkg->IsS0IdleWakeFromS0Enabled(); + DriverInfo->bitmap.IsS0IdleUsbSSEnabled = pnpPkg->IsS0IdleUsbSSEnabled(); + DriverInfo->bitmap.IsS0IdleSystemManaged = pnpPkg->IsS0IdleSystemManaged(); + DriverInfo->bitmap.IsSxWakeEnabled = pnpPkg->IsSxWakeEnabled(); + DriverInfo->bitmap.IsUsingLevelTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedLevelTriggeredInterrupt); + DriverInfo->bitmap.IsUsingEdgeTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedEdgeTriggeredInterrupt); + DriverInfo->bitmap.IsUsingMsiXOrSingleMsi22Interrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsiXOrSingleMsi22Interrupt); + DriverInfo->bitmap.IsUsingMsi22MultiMessageInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsi22MultiMessageInterrupt); + DriverInfo->bitmap.IsUsingMultipleInterrupt = pnpPkg->HasMultipleInterrupts(); + DriverInfo->bitmap.IsUsingPassiveLevelInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoPassiveLevelInterrupt); + DriverInfo->bitmap.IsUsingBusMasterDma = IsDeviceInfoFlagSet(devInfo, DeviceInfoDmaBusMaster); + DriverInfo->bitmap.IsUsingSystemDma = IsDeviceInfoFlagSet(devInfo, DeviceInfoDmaSystem); + DriverInfo->bitmap.IsUsingSystemDmaDuplex = IsDeviceInfoFlagSet(devInfo, DeviceInfoDmaSystemDuplex); + DriverInfo->bitmap.IsUsingStaticBusEnumration = IsDeviceInfoFlagSet(devInfo, DeviceInfoHasStaticChildren); + DriverInfo->bitmap.IsUsingDynamicBusEnumeration = IsDeviceInfoFlagSet(devInfo, DeviceInfoHasDynamicChildren); + } +} + +VOID +RegistryReadLastLoggedTime( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _Out_ PLARGE_INTEGER LastLoggedTime + ) +{ + FxAutoRegKey hKey, hWdf; + DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf"); + DECLARE_CONST_UNICODE_STRING(valueName, WDF_LAST_TELEMETRY_LOG_TIME_VALUE); + LARGE_INTEGER value; + NTSTATUS status; + + ASSERT(LastLoggedTime != NULL); + LastLoggedTime->QuadPart = 0; + + status = FxRegKey::_OpenKey(NULL, + DriverGlobals->Driver->GetRegistryPathUnicodeString(), + &hWdf.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to open driver's service key, status %!STATUS!", status); + return; + } + + status = FxRegKey::_OpenKey(hWdf.m_Key, + ¶metersPath, + &hKey.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to open driver's service parameters key, status %!STATUS!", + status); + return; + } + + value.QuadPart = 0; + status = FxRegKey::_QueryQuadWord( + hKey.m_Key, &valueName, &value); + + // + // Set value only on success. + // + if (NT_SUCCESS(status)) { + LastLoggedTime->QuadPart = value.QuadPart; + } +} + +VOID +RegistryWriteCurrentTime( + _In_ PFX_DRIVER_GLOBALS DriverGlobals + ) +{ + FxAutoRegKey hDriver, hParameters, hWdf; + DECLARE_CONST_UNICODE_STRING(parametersPart, L"Parameters"); + DECLARE_CONST_UNICODE_STRING(wdfPart, L"Wdf"); + LARGE_INTEGER currentTime; + + // + // Not defined with the macro because ZwSetValue doesn't use + // PCUNICODE_STRING + // + UNICODE_STRING wdfTimeOfLastTelemetryLog; + NTSTATUS status; + + RtlInitUnicodeString(&wdfTimeOfLastTelemetryLog, WDF_LAST_TELEMETRY_LOG_TIME_VALUE); + + status = FxRegKey::_OpenKey(NULL, + DriverGlobals->Driver->GetRegistryPathUnicodeString(), + &hDriver.m_Key, + KEY_WRITE | KEY_READ + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to open driver's service key, status %!STATUS!", status); + return; + } + // + // Key creation, unlike user mode, must happen one level at a time, since + // create will also open take both steps instead of trying open first + // + status = FxRegKey::_Create(hDriver.m_Key, + ¶metersPart, + &hParameters.m_Key, + KEY_WRITE | KEY_READ + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to write Parameters key, status %!STATUS!", status); + return; + } + + status = FxRegKey::_Create(hParameters.m_Key, + &wdfPart, + &hWdf.m_Key, + KEY_WRITE | KEY_READ + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to write Parameters key, status %!STATUS!", status); + return; + } + + // + // Using ZwSetValueKey here to avoid having to change the implementation + // in FxRegKey of SetValue to a static / thiscall pair + // + currentTime.QuadPart = 0; + Mx::MxQuerySystemTime(¤tTime); + + status = Mx::MxSetValueKey(hWdf.m_Key, + &wdfTimeOfLastTelemetryLog, + 0, + REG_QWORD, + ¤tTime.QuadPart, + sizeof(currentTime) + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Failed to record current time for Telemetry log, status %!STATUS!", + status); + } +} + +VOID +FxGetDevicePropertyString( + _In_ FxDevice* Fdo, + _In_ DEVICE_REGISTRY_PROPERTY DeviceProperty, + _Out_ PUNICODE_STRING PropertyString + ) +{ + MdDeviceObject pdo; + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals = Fdo->GetDriverGlobals(); + ULONG length = 0; + PVOID buffer = NULL; + + ASSERT(PropertyString != NULL); + RtlZeroMemory(PropertyString, sizeof(UNICODE_STRING)); + + pdo = Fdo->GetSafePhysicalDevice(); + if (pdo == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not get PDO from FDO WDFDEVICE 0x%p, %!STATUS!", + Fdo->GetHandle(), status); + return; + } + + status = FxDevice::_GetDeviceProperty(pdo, DeviceProperty, 0, NULL, &length); + if (status != STATUS_BUFFER_TOO_SMALL) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not retrieve property %d length %d, %!STATUS!", + DeviceProperty, length, status); + return; + } + + buffer = FxPoolAllocate(pFxDriverGlobals, PagedPool, length); + if (buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not allocate memory for property %d length %d, %!STATUS!", + DeviceProperty, length, status); + return; + } + + status = FxDevice::_GetDeviceProperty(pdo, DeviceProperty, length, buffer, &length); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, + "Could not query for full buffer, size %d, for " + "property %d, %!STATUS!", + length, DeviceProperty, status); + FxPoolFree(buffer); + return; + } + + PropertyString->Buffer = (PWCH)buffer; + PropertyString->Length = (USHORT) length - sizeof(UNICODE_NULL); + PropertyString->MaximumLength = (USHORT) length; + + // + // ensure it's null terminated + // + PropertyString->Buffer[PropertyString->Length/sizeof(WCHAR)] = UNICODE_NULL; +} + +_Must_inspect_result_ +NTSTATUS +GetImageName( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _Out_ PUNICODE_STRING ImageName + ) +/*++ + +Routine Description: + Retrieve the ImageName value from the named Service registry key. + + Caller is responsible for freeing the buffer allocated in ImageName::Buffer. + +Arguments: + DriverGlobals - pointer to FX_DRIVER_GLOBALS + + ImageeName - Pointer to a UNICODE_STRING which will receive the image name + upon a return value of NT_SUCCESS() + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status; + FxAutoRegKey hKey; + DECLARE_CONST_UNICODE_STRING(valueName, L"ImagePath"); + UNICODE_STRING imagePath = {0}; + UNICODE_STRING imageName = {0}; + PKEY_VALUE_PARTIAL_INFORMATION value = NULL; + USHORT size; + + ASSERT(ImageName != NULL); + RtlZeroMemory(ImageName, sizeof(UNICODE_STRING)); + + // + // Open driver's Service base key + // + status = FxRegKey::_OpenKey(NULL, + DriverGlobals->Driver->GetRegistryPathUnicodeString(), + &hKey.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to open driver's service key, status %!STATUS!", status); + return status; + } + + status = QueryAndAllocString(hKey.m_Key, + DriverGlobals, + &valueName, + &value); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Failed to get Image name from service key, status %!STATUS!", + status); + return status; + } + + BuildStringFromPartialInfo(value, &imagePath); + + // + // Now read the "ImagePath" and extract just the driver filename as a new + // unicode string. + // + GetNameFromPath(&imagePath, &imageName); + + if (imageName.Length == 0x0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: GetNameFromPath could not find a name, status 0x%x\n", + status); + goto cleanUp; + } + + // + // Check for interger overflow for length before we allocate memory + // size = path->Length + sizeof(UNICODE_NULL); + // len is used below to compute the string size including the NULL, so + // compute len to include the terminating NULL. + // + status = RtlUShortAdd(imageName.Length, sizeof(UNICODE_NULL), &size); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: size computation failed with Status 0x%x\n", status); + goto cleanUp; + } + + // + // allocate a buffer to hold Unicode string + null char. + // + ImageName->Buffer = (PWCH) FxPoolAllocate(DriverGlobals, PagedPool, size); + + if (ImageName->Buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(DriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: ExAllocatePoolWithTag failed with Status 0x%x\n", status); + goto cleanUp; + } + + RtlZeroMemory(ImageName->Buffer, size); + ImageName->Length = 0x0; + ImageName->MaximumLength = size; + + status = RtlUnicodeStringCopy(ImageName, &imageName); + + // + // The copy cannot fail since we setup the buffer to hold enough space for + // the contents of the ImagePath value. + // + ASSERT(NT_SUCCESS(status)); + +cleanUp: + + if (value != NULL) { + FxPoolFree(value); + } + + return status; +} + + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +QueryAndAllocString( + _In_ HANDLE Key, + _In_ PFX_DRIVER_GLOBALS Globals, + _In_ PCUNICODE_STRING ValueName, + _Out_ PKEY_VALUE_PARTIAL_INFORMATION* Info + ) +{ + PKEY_VALUE_PARTIAL_INFORMATION info; + NTSTATUS status; + ULONG length; + + status = STATUS_UNSUCCESSFUL; + info = NULL; + + ASSERT(Info != NULL); + *Info = NULL; + + status = Mx::MxQueryValueKey(Key, + (PUNICODE_STRING)ValueName, + KeyValuePartialInformation, + NULL, + 0, + &length); + + if (!NT_SUCCESS(status) && status != STATUS_BUFFER_TOO_SMALL) { + goto cleanup; + } + + // + // Pool can be paged b/c we are running at PASSIVE_LEVEL and we are going + // to free it at the end of this function. + // + status = RtlULongAdd(length, + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data), + &length); + + if (!NT_SUCCESS(status)) { + goto cleanup; + } + + info = (PKEY_VALUE_PARTIAL_INFORMATION) FxPoolAllocate(Globals, + PagedPool, + length); + + if (info == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto cleanup; + } + + RtlZeroMemory(info, length); + + // + // Query registry for the data under ValueName + // + status = Mx::MxQueryValueKey(Key, + (PUNICODE_STRING) ValueName, + KeyValuePartialInformation, + info, + length, + &length); + + + if (NT_SUCCESS(status)) { + if (info->Type != REG_SZ && info->Type != REG_EXPAND_SZ) { + status = STATUS_OBJECT_TYPE_MISMATCH; + goto cleanup; + } + + if (info->DataLength == 0 || + (info->DataLength % 2) != 0 || + (info->DataLength > + (length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)))) { + status = STATUS_INVALID_PARAMETER; + goto cleanup; + } + + *Info = info; + } + +cleanup: + + if (!NT_SUCCESS(status)) { + if (info != NULL) { + FxPoolFree(info); + } + } + + return status; +} diff --git a/sdk/lib/drivers/wdf/shared/support/stringutil.cpp b/sdk/lib/drivers/wdf/shared/support/stringutil.cpp new file mode 100644 index 00000000000..35ec4f21fad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/stringutil.cpp @@ -0,0 +1,308 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + StringUtil.cpp + +Abstract: + + This module implements string utlities in the framework + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "StringUtil.tmh" +} + +size_t +FxCalculateTotalStringSize( + __in FxCollectionInternal *StringCollection, + __in BOOLEAN Verify, + __out_opt PBOOLEAN ContainsOnlyStrings + ) +{ + size_t cbLength; + FxString *pString; + FxCollectionEntry* cur, *end; + + cbLength = 0; + + end = StringCollection->End(); + for (cur = StringCollection->Start(); + cur != end; + cur = cur->Next()) { + pString = (FxString *) cur->m_Object; + + if (Verify && pString->GetType() != FX_TYPE_STRING) { + *ContainsOnlyStrings = FALSE; + return 0; + } + + cbLength += pString->ByteLength(TRUE); + } + + if (ContainsOnlyStrings != NULL) { + *ContainsOnlyStrings = TRUE; + } + + if (StringCollection->Count() == 0) { + // + // If there are not entries, we still need 2 NULLs + // + cbLength = sizeof(UNICODE_NULL) * 2; + } + else { + // + // Extra NULL + // + cbLength += sizeof(UNICODE_NULL); + } + + // + // ASSERT that we are reporting an integral number of WCHARs in bytes + // + ASSERT((cbLength % sizeof(WCHAR)) == 0); + + return cbLength; +} + +size_t +FxCalculateTotalMultiSzStringSize( + __in __nullnullterminated PCWSTR MultiSz + ) +{ + PCWSTR pCur; + size_t cbSize, cbLength; + + cbSize = 0; + + pCur = MultiSz; + + while (*pCur != NULL) { + // + // Compute length of string including terminating NULL + // + cbLength = (wcslen(pCur) + 1) * sizeof(WCHAR); + + cbSize += cbLength; + pCur = (PWSTR) WDF_PTR_ADD_OFFSET(pCur, cbLength); + } + + if (cbSize == 0) { + // + // If there are no strings, we still need 2 NULLs + // + cbSize = sizeof(UNICODE_NULL); + } + + // + // Final NULL which makes this a multi sz + // + cbSize += sizeof(UNICODE_NULL); + + // + // ASSERT that we are reporting an integral number of WCHARs in bytes + // + ASSERT((cbSize % sizeof(WCHAR)) == 0); + + return cbSize; +} + +#pragma prefast(push) +// Caller is responsible for allocating the correct amount of memory. +#pragma prefast(disable:__WARNING_INCORRECT_ANNOTATION_STRING ) +PWSTR +FxCopyMultiSz( + __out LPWSTR Buffer, + __in FxCollectionInternal* StringCollection + ) +{ + LPWSTR pCur; + ULONG length; + FxCollectionEntry* cur, *end; + + pCur = Buffer; + end = StringCollection->End(); + + for (cur = StringCollection->Start(); cur != end; cur = cur->Next()) { + FxString* pSourceString; + + pSourceString = (FxString *) cur->m_Object; + + length = pSourceString->ByteLength(TRUE); + RtlCopyMemory(pCur, pSourceString->Buffer(), length); + + // + // Length is expressed in number of bytes, not number of + // characters. + // + // length includes the NULL. + // + pCur = WDF_PTR_ADD_OFFSET_TYPE(pCur, length, LPWSTR); + } + + // + // If there are no entries, we still need 2 NULLs. + // + if (StringCollection->Count() == 0) { + *pCur = UNICODE_NULL; + pCur++; + } + + // + // double NULL terminate the string + // + *pCur = UNICODE_NULL; + + // + // Return the start of the next location in the buffer + // + return pCur + 1; +} +#pragma prefast(pop) + +_Must_inspect_result_ +NTSTATUS +FxDuplicateUnicodeString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in const UNICODE_STRING* Source, + __out PUNICODE_STRING Destination + ) +/*++ + +Routine Description: + Makes a deep copy from Source to Destination. + + Destination is assumed to have been initialized by the caller, be owned by + an internal Fx object. Destination could already contain a previously + allocated buffer. If one exists and is large enough, it will be reused + for the copy. + + This function guarantees that the Buffer will be NULL terminated. While + this is not necessary because Length describes the length of the buffer, the + resulting buffer can be copied back to the client driver and we cannot trust + the client driver to treat the string as an unterminated buffer, typically + the client driver will just extract the buffer and treat it as NULL + terminated. To be defensive with this type of (mis)use, we always NULL + terminate the resuling Buffer. + +Arguments: + Source - source struct to copy from. This string can originate from the + client driver. + + Destination - destination struct to copy to. This struct is assumed to be + internal and is not given to the outside caller + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + USHORT srcCbLength, srcCbLengthAndNull, dstMaxCbLength; + + // + // NOTE: We assume the sources string will be smaller than 64k. + // + srcCbLength = Source->Length; + dstMaxCbLength = Destination->MaximumLength; + + status = RtlUShortAdd(srcCbLength, + sizeof(UNICODE_NULL), + &srcCbLengthAndNull); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Interger overflow occured when duplicating string %!STATUS!", + status); + return status; + } + + // + // First see if we already have enough memory to hold the string + a NULL + // + if (dstMaxCbLength < srcCbLengthAndNull) { + // + // Allocate enough memory for the source string and a NULL character + // + dstMaxCbLength = srcCbLengthAndNull; + + // + // We need to allocate memory. Free any old memory first. + // + if (Destination->Buffer != NULL) { + FxPoolFree(Destination->Buffer); + + RtlZeroMemory(Destination, sizeof(UNICODE_STRING)); + } + + Destination->Buffer = (PWSTR) FxPoolAllocate( + FxDriverGlobals, PagedPool, dstMaxCbLength); + + if (Destination->Buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGERROR, + "Failed to allocate memory when duplicating string %!STATUS!", + status); + return status; + } + + Destination->MaximumLength = dstMaxCbLength; + } + + // + // If we get here and we have a buffer, then we can just copy the + // string into the buffer. + // + RtlCopyMemory(Destination->Buffer, Source->Buffer, srcCbLength); + Destination->Length = srcCbLength; + + // + // Make sure the string is NULL terminated and there is room for the NULL + // + ASSERT(Destination->Length + sizeof(UNICODE_NULL) <= + Destination->MaximumLength); + Destination->Buffer[Destination->Length/sizeof(WCHAR)] = UNICODE_NULL; + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +PWCHAR +FxDuplicateUnicodeStringToString( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in const UNICODE_STRING* Source + ) +{ + PWSTR pDuplicate; + + pDuplicate = (PWSTR) FxPoolAllocate( + FxDriverGlobals, PagedPool, Source->Length + sizeof(UNICODE_NULL)); + + if (pDuplicate != NULL) { + RtlCopyMemory(pDuplicate, Source->Buffer, Source->Length); + + // + // Make sure the string is NULL terminated. We can safely do this + // because we allocated an extra WCHAR for the null terminator. + // + pDuplicate[Source->Length/sizeof(WCHAR)] = UNICODE_NULL; + } + + return pDuplicate; +} diff --git a/sdk/lib/drivers/wdf/shared/support/um/fxdeviceinterfaceum.cpp b/sdk/lib/drivers/wdf/shared/support/um/fxdeviceinterfaceum.cpp new file mode 100644 index 00000000000..553f169e6f8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/fxdeviceinterfaceum.cpp @@ -0,0 +1,289 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxDeviceInterfaceUM.cpp + +Abstract: + + This module implements the device interface object. + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxDeviceInterfaceUM.tmh" +} + +FxDeviceInterface::FxDeviceInterface( + ) +/*++ + +Routine Description: + Constructor for the object. Initializes all fields + +Arguments: + None + +Return Value: + None + + --*/ +{ + RtlZeroMemory(&m_InterfaceClassGUID, sizeof(m_InterfaceClassGUID)); + + RtlZeroMemory(&m_SymbolicLinkName, sizeof(m_SymbolicLinkName)); + RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString)); + + m_Entry.Next = NULL; + + m_State = FALSE; +} + +FxDeviceInterface::~FxDeviceInterface() +/*++ + +Routine Description: + Destructor for FxDeviceInterface. Cleans up any allocations previously + allocated. + +Arguments: + None + +Return Value: + None + + --*/ +{ + // the device interface should be off now + ASSERT(m_State == FALSE); + + // should no longer be in any list + ASSERT(m_Entry.Next == NULL); + + if (m_ReferenceString.Buffer != NULL) { + FxPoolFree(m_ReferenceString.Buffer); + RtlZeroMemory(&m_ReferenceString, sizeof(m_ReferenceString)); + } + + if (m_SymbolicLinkName.Buffer != NULL) { + MxMemory::MxFreePool(m_SymbolicLinkName.Buffer); + } +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Initialize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in CONST GUID* InterfaceGUID, + __in_opt PCUNICODE_STRING ReferenceString + ) +/*++ + +Routine Description: + Initializes the object with the interface GUID and optional reference string + +Arguments: + InterfaceGUID - GUID describing the interface + + ReferenceString - string used to differentiate between 2 interfaces on the + same PDO + +Return Value: + STATUS_SUCCESS or STATUS_INSUFFICIENT_RESOURCES + + --*/ +{ + RtlCopyMemory(&m_InterfaceClassGUID, InterfaceGUID, sizeof(GUID)); + + if (ReferenceString != NULL) { + return FxDuplicateUnicodeString(FxDriverGlobals, + ReferenceString, + &m_ReferenceString); + } + else { + return STATUS_SUCCESS; + } +} + + +VOID +FxDeviceInterface::SetState( + __in BOOLEAN State + ) +/*++ + +Routine Description: + Sets the state of the device interface + +Arguments: + State - the state to set + + +Return Value: + None. + + --*/ +{ + HRESULT hr; + NTSTATUS status; + IWudfDeviceStack *pDeviceStack; + + + + + // + // Get the IWudfDeviceStack interface + // + pDeviceStack = m_Device->GetDeviceStackInterface(); + + // + // Enable the interface + // + hr = pDeviceStack->SetDeviceInterfaceState(&this->m_InterfaceClassGUID, + this->m_ReferenceString.Buffer, + State); + + if (SUCCEEDED(hr)) { + m_State = State; + } + else { + status = FxDevice::NtStatusFromHr(pDeviceStack, hr); + DoTraceLevelMessage( + FxDevice::GetFxDevice(m_Device)->GetDriverGlobals(), + TRACE_LEVEL_WARNING, TRACINGPNP, + "Failed to %s device interface %!STATUS!", + (State ? "enable" : "disable"), status); + + + + + + } +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Register( + __in MdDeviceObject DeviceObject + ) +/*++ + +Routine Description: + Registers the device interface for a given PDO + +Arguments: + DeviceObject - FDO for the device stack in case of UM, and PDO for + in case of KM. + +Return Value: + returned by IWudfDeviceStack::CreateDeviceInterface + + --*/ +{ + HRESULT hr; + NTSTATUS status; + IWudfDeviceStack *pDeviceStack; + + m_Device = DeviceObject; + + // + // Get the IWudfDeviceStack interface + // + pDeviceStack = m_Device->GetDeviceStackInterface(); + + hr = pDeviceStack->CreateDeviceInterface(&m_InterfaceClassGUID, + m_ReferenceString.Buffer); + + if (SUCCEEDED(hr)) { + status = STATUS_SUCCESS; + } + else { + status = FxDevice::NtStatusFromHr(pDeviceStack, hr); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxDeviceInterface::Register( + _In_ FxDevice* Device + ) +{ + NTSTATUS status; + + // + // For UMDF, PDO is already known so no reason to defer registration. + // Also, note that Register takes fdo as parameter for UMDF. + // + status = Register(Device->GetDeviceObject()); + + return status; +} + +NTSTATUS +FxDeviceInterface::GetSymbolicLinkName( + _In_ FxString* LinkString + ) +{ + NTSTATUS status; + PCWSTR symLink = NULL; + + if (m_SymbolicLinkName.Buffer == NULL) { + IWudfDeviceStack *pDeviceStack; + IWudfDeviceStack2 *pDeviceStack2; + + // + // Get the IWudfDeviceStack interface + // + pDeviceStack = m_Device->GetDeviceStackInterface(); + HRESULT hrQI; + HRESULT hr; + + hrQI = pDeviceStack->QueryInterface(IID_IWudfDeviceStack2, + (PVOID*)&pDeviceStack2); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pDeviceStack2)); + pDeviceStack->Release(); + + // + // Get the symbolic link + // + hr = pDeviceStack2->GetInterfaceSymbolicLink(&m_InterfaceClassGUID, + m_ReferenceString.Buffer, + &symLink); + if (FAILED(hr)) { + status = FxDevice::GetFxDevice(m_Device)->NtStatusFromHr(hr); + } + else { + RtlInitUnicodeString(&m_SymbolicLinkName, symLink); + status = STATUS_SUCCESS; + } + } + else { + status = STATUS_SUCCESS; + } + + if (NT_SUCCESS(status)) { + // + // Attempt a copy + // + status = LinkString->Assign(&m_SymbolicLinkName); + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/support/um/fxregkeyum.cpp b/sdk/lib/drivers/wdf/shared/support/um/fxregkeyum.cpp new file mode 100644 index 00000000000..64b8f1c31a2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/fxregkeyum.cpp @@ -0,0 +1,302 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxRegKey.cpp + +Abstract: + +Author: + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +//#define UNICODE +//#define _UNICODE +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxRegKeyUM.tmh" +#endif +} + +FxRegKey::FxRegKey( + PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxPagedObject(FX_TYPE_REG_KEY, sizeof(FxRegKey), FxDriverGlobals), + m_Key(NULL), + m_Globals(FxDriverGlobals), + m_CanCloseHandle(TRUE) +{ +} + +__drv_maxIRQL(PASSIVE_LEVEL) +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::~FxRegKey() +{ + if (m_Key != NULL) { + if (m_CanCloseHandle == TRUE) { + RegCloseKey((HKEY)m_Key); + } + m_Key = NULL; + } +} + +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::_Close( + __in HANDLE Key + ) +{ + DWORD err = RegCloseKey((HKEY)Key); + + if (ERROR_SUCCESS == err) { + return STATUS_SUCCESS; + } + else { + return WinErrorToNtStatus(err); + } +} + +_Must_inspect_result_ +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::_Create( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __out HANDLE* NewKey, + __in ACCESS_MASK DesiredAccess, + __in ULONG CreateOptions, + __out_opt PULONG CreateDisposition + ) +{ + HKEY parentKey; + + if (NULL == ParentKey) + { + parentKey = HKEY_LOCAL_MACHINE; + } + else + { + parentKey = (HKEY) ParentKey; + } + + DWORD err = RegCreateKeyEx(parentKey, + KeyName->Buffer, + 0, + NULL, + CreateOptions, + DesiredAccess, + NULL, + (PHKEY)NewKey, + CreateDisposition); + + if (ERROR_SUCCESS == err) { + return STATUS_SUCCESS; + } + else { + return WinErrorToNtStatus(err); + } +} + +_Must_inspect_result_ +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::_OpenKey( + __in_opt HANDLE ParentKey, + __in PCUNICODE_STRING KeyName, + __out HANDLE* Key, + __in ACCESS_MASK DesiredAccess + ) +{ + HKEY parentKey; + + if (NULL == ParentKey) + { + parentKey = HKEY_LOCAL_MACHINE; + } + else + { + parentKey = (HKEY) ParentKey; + } + + DWORD err = RegOpenKeyEx(parentKey, + KeyName->Buffer, + 0, + DesiredAccess, + (PHKEY)Key); + + if (ERROR_SUCCESS == err) { + return STATUS_SUCCESS; + } + else { + return WinErrorToNtStatus(err); + } +} + +_Must_inspect_result_ +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::_SetValue( + _In_ HANDLE Key, + _In_ PCUNICODE_STRING ValueName, + _In_ ULONG ValueType, + _In_reads_bytes_(ValueLength) PVOID Value, + _In_ ULONG ValueLength + ) +{ + DWORD err; + + err = RegSetValueEx((HKEY)Key, + ValueName->Buffer, + 0, + ValueType, + (BYTE*)Value, + ValueLength); + if (ERROR_SUCCESS == err) { + return STATUS_SUCCESS; + } + else { + return WinErrorToNtStatus(err); + } +} + +_Must_inspect_result_ +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::_QueryValue( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __in ULONG ValueLength, + __out_bcount_opt(ValueLength) PVOID Value, + __out_opt PULONG ValueLengthQueried, + __out_opt PULONG ValueType + ) +{ + DWORD err; + NTSTATUS status; + ULONG length; + + UNREFERENCED_PARAMETER(FxDriverGlobals); + ASSERT(Key != HKEY_PERFORMANCE_DATA); + + length = ValueLength; + + err = RegQueryValueEx((HKEY)Key, + ValueName->Buffer, + NULL, + ValueType, + (LPBYTE)Value, + &length); + + if (ValueLengthQueried != NULL) { + *ValueLengthQueried = length; + } + + // + // Please see the comment in FxRegKeyKm.cpp FxRegKey::_QueryValue about + // the call to ZwQueryValueKey. + // + // If the user supplies a NULL data buffer, RegQueryValueEx will return + // ERROR_SUCCESS. However, in order to satisfy UMDF-KMDF DDI parity as well + // as internal mode-agnostic code, we must overwrite RegQueryValueEx's + // return value of ERROR_SUCCESS (STATUS_SUCCESS) with STATUS_BUFFER_OVERFLOW. + // + // Other return values are overwritten because WinErrorToNtStatus does not map + // all Win32 error codes that RegQueryValueEx returns to the same NTSTATUS + // values that ZwQueryValueKey would return in the KM implementation of + // FxRegKey::_QueryValue. + // + if (err == ERROR_SUCCESS) { + if (Value != NULL) { + status = STATUS_SUCCESS; + } + else { + status = STATUS_BUFFER_OVERFLOW; + } + } + else if (err == ERROR_MORE_DATA) { + status = STATUS_BUFFER_OVERFLOW; + } + else if (err == ERROR_FILE_NOT_FOUND) { + status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else { + status = WinErrorToNtStatus(err); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +FxRegKey::_QueryULong( + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __out PULONG Value + ) +{ + DWORD err; + NTSTATUS status; + ULONG length, type; + + ASSERT(Key != HKEY_PERFORMANCE_DATA); + + type = REG_DWORD; + length = sizeof(ULONG); + + err = RegQueryValueEx((HKEY)Key, + ValueName->Buffer, + NULL, + &type, + (LPBYTE)Value, + &length); + + if ((err == ERROR_SUCCESS || err == ERROR_MORE_DATA) && + type != REG_DWORD) { + + ASSERT(FALSE); + + status = STATUS_OBJECT_TYPE_MISMATCH; + } + else { + if (ERROR_SUCCESS == err) { + status = STATUS_SUCCESS; + } + else { + status = WinErrorToNtStatus(err); + } + } + + return status; +} + +_Must_inspect_result_ +#pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "Can't apply kernel mode annotations."); +NTSTATUS +FxRegKey::_QueryQuadWord( + __in HANDLE Key, + __in PCUNICODE_STRING ValueName, + __out PLARGE_INTEGER Value + ) +{ + UNREFERENCED_PARAMETER(Key); + UNREFERENCED_PARAMETER(ValueName); + UNREFERENCED_PARAMETER(Value); + + return STATUS_UNSUCCESSFUL; +} + + diff --git a/sdk/lib/drivers/wdf/shared/support/um/fxrequestbufferum.cpp b/sdk/lib/drivers/wdf/shared/support/um/fxrequestbufferum.cpp new file mode 100644 index 00000000000..ae3d54b63ad --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/fxrequestbufferum.cpp @@ -0,0 +1,103 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + FxRequestBufferUm.cpp + +Abstract: + + This module implements a memory union object + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" + +extern "C" { +#include "FxRequestBufferUm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxRequestBuffer::GetOrAllocateMdl( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __deref_out_opt PMDL* Mdl, + __inout PMDL* MdlToFree, + __inout PBOOLEAN UnlockWhenFreed, + __in LOCK_OPERATION Operation, + __in BOOLEAN ReuseMdl, + __inout_opt size_t* SizeOfMdl + ) +/*++ + +Routine Description: + + This function attempts to reuse the passed-in MDL (if any) or allocates + a new MDL if reuse flag isn't passed-in or if the existing MDL isn't + big enough. + +Arguments: + +Return Value: + FxDriverGlobals - Driver globals + + Mdl - on return it contains the MDL allocated/reused + + MdlToFree - pointer to any MDL + * to be reused, if the size is <= current size, or + * freed and set to newly allocated MDL + + UnlockWhenFreed - whether to unlock pages when freeing MDL + (if FALSE, MDL may represent just MDL buffer but the pages + might have already been unlocked) + + Operation - Operation to pass to MmLockPages + + ReuseMdl - whether to reuse *MdlToFree + Please note that this can be FALSE even when MDL is supplied + + SizeOfMdl - on input contains size of *MdlToFree, + on return contains size of *Mdl + +Remarks: + + *MdlToFree is modified only when this function frees the passed in MDL + Otherwise it leaves it untouched. Caller is responsible for storing + properly initialized value and/or freeing what's stored in the value. + + --*/ +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + UNREFERENCED_PARAMETER(Mdl); + UNREFERENCED_PARAMETER(MdlToFree); + UNREFERENCED_PARAMETER(UnlockWhenFreed); + UNREFERENCED_PARAMETER(Operation); + UNREFERENCED_PARAMETER(ReuseMdl); + UNREFERENCED_PARAMETER(SizeOfMdl); + + UfxVerifierTrapNotImpl(); + return STATUS_NOT_IMPLEMENTED; +} + +VOID +FxRequestBuffer::SetMemory( + __in IFxMemory* Memory, + __in PWDFMEMORY_OFFSET Offsets + ) +{ + DataType = FxRequestBufferMemory; + u.Memory.Memory = Memory; + u.Memory.Offsets = Offsets; +} + diff --git a/sdk/lib/drivers/wdf/shared/support/um/fxresourcecollectionum.cpp b/sdk/lib/drivers/wdf/shared/support/um/fxresourcecollectionum.cpp new file mode 100644 index 00000000000..b9e96f603b8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/fxresourcecollectionum.cpp @@ -0,0 +1,788 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxResourceCollection.cpp + +Abstract: + + This module implements a base object for derived collection classes and + the derived collection classes. + +Author: + + + +Environment: + + User mode only + +Revision History: + +--*/ + +#include "FxSupportPch.hpp" +#include + +#if defined(EVENT_TRACING) +// Tracing support +extern "C" { +#include "FxResourceCollectionUm.tmh" +} +#endif + +FxCmResList::~FxCmResList() +{ + DeleteRegisterResourceTable(); + DeletePortResourceTable(); +} + +NTSTATUS +FxCmResList::BuildRegisterResourceTable( + VOID + ) +{ + ULONG count; + ULONG i, index; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + ULONG numRegisterDesc; + BOOLEAN locked = FALSE; + NTSTATUS status; + + count = GetCount(); + numRegisterDesc = 0; + + // + // count number of register descriptors + // + for (i = 0; i < count; i++) { + desc = GetDescriptor(i); + if (desc == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Resource Descriptor not found %!STATUS!", status); + goto exit; + } + + if (desc->Type == CmResourceTypeMemory || + desc->Type == CmResourceTypeMemoryLarge) { + numRegisterDesc++; + } + } + + if (numRegisterDesc == 0) { + return STATUS_SUCCESS; + } + + // + // allocate table + // + LockResourceTable(); + locked = TRUE; + + status = FxRegisterResourceInfo::_CreateAndInit( + GetDriverGlobals(), + numRegisterDesc, + &m_RegisterResourceTable + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to allocate memory for resource table" + " %!STATUS!", status); + goto exit; + } + m_RegisterResourceTableSizeCe = numRegisterDesc; + + // + // Populate table + // + index = 0; + for (i = 0; i < count; i++) { + desc = GetDescriptor(i); + if (desc == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Resource Descriptor not found %!STATUS!", status); + goto exit; + } + + if (desc->Type == CmResourceTypeMemory || + desc->Type == CmResourceTypeMemoryLarge) { + SIZE_T len; + PHYSICAL_ADDRESS pa; + + // + // This will populate Length and StartPa + // + len = GetResourceLength(desc, &pa); + if (len) { + m_RegisterResourceTable[index].SetPhysicalAddress(pa, len); + } + + index++; + } + } + +exit: + + if (!NT_SUCCESS(status)) { + if (m_RegisterResourceTable != NULL) { + delete [] m_RegisterResourceTable; + m_RegisterResourceTable = NULL; + m_RegisterResourceTableSizeCe = 0; + } + } + + if (locked) { + UnlockResourceTable(); + } + + return status; +} + +NTSTATUS +FxCmResList::BuildPortResourceTable( + VOID + ) +{ + ULONG count; + ULONG i, index; + PCM_PARTIAL_RESOURCE_DESCRIPTOR desc; + ULONG numPortDesc; + BOOLEAN locked = FALSE; + NTSTATUS status; + + count = GetCount(); + numPortDesc = 0; + + // + // count number of register descriptors + // + for (i = 0; i < count; i++) { + desc = GetDescriptor(i); + if (desc == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Resource Descriptor not found %!STATUS!", status); + goto exit; + } + + if (desc->Type == CmResourceTypePort) { + numPortDesc++; + } + } + + if (numPortDesc == 0) { + return STATUS_SUCCESS; + } + + // + // allocate table + // + LockResourceTable(); + locked = TRUE; + + status = FxPortResourceInfo::_CreateAndInit( + GetDriverGlobals(), + numPortDesc, + &m_PortResourceTable + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Failed to allocate memory for resource table" + " %!STATUS!", status); + goto exit; + } + m_PortResourceTableSizeCe = numPortDesc; + + // + // Populate table + // + index = 0; + for (i = 0; i < count; i++) { + desc = GetDescriptor(i); + if (desc == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Resource Descriptor not found %!STATUS!", status); + goto exit; + } + + if (desc->Type == CmResourceTypePort) { + SIZE_T len; + PHYSICAL_ADDRESS pa; + + // + // This will populate Length, StartPa and EndPa + // + len = GetResourceLength(desc, &pa); + if (len) { + m_PortResourceTable[index].SetPhysicalAddress(pa, len); + } + + index++; + } + } + +exit: + + if (!NT_SUCCESS(status)) { + if (m_PortResourceTable != NULL) { + delete [] m_PortResourceTable; + m_PortResourceTable = NULL; + m_PortResourceTableSizeCe = 0; + } + } + + if (locked) { + UnlockResourceTable(); + } + + return status; +} + + +VOID +FxCmResList::UpdateRegisterResourceEntryLocked( + __in FxRegisterResourceInfo* Entry, + __in PVOID SystemMappedAddress, + __in SIZE_T NumberOfBytes, + __in PVOID UsermodeMappedAddress + ) +{ + Entry->SetMappedAddress(SystemMappedAddress, NumberOfBytes, UsermodeMappedAddress); +} + +VOID +FxCmResList::ClearRegisterResourceEntryLocked( + __in FxRegisterResourceInfo* Entry + ) +{ + Entry->ClearMappedAddress(); +} + +HRESULT +FxCmResList::ValidateRegisterPhysicalAddressRange ( + __in PHYSICAL_ADDRESS PhysicalAddress, + __in SIZE_T Size, + __out FxRegisterResourceInfo** TableEntry + ) +/*++ + +Routine Description: + + This routine checks whether the physical address range is part of the resources + assigned to the device by pnp manager. It also returns the table entry + corresponding to the physical address range from register resource table. + +Arguments: + + PhysicalAddress - Supplies physical address to validate + + Size - Supplies size of address range in bytes. + + TableEntry - Supplies a pointer to store the table entry that corresponds to + this physical address. + +Return Value: + + HRESULT + + S_OK if physical address is one assigned by pnp manager to this device. + E_INAVLIDARG otherwise. + +--*/ +{ + ULONG i; + HRESULT hr; + ULONGLONG driverStartPa, driverEndPa, systemStartPa, systemEndPa; + ULONGLONG tmp; + FxRegisterResourceInfo* entry = NULL; + + *TableEntry = NULL; + + // + // Physical address is of LONGLONG type (signed) we need to cast it to + // ULONGLONG for comparision because in a LONGLONG comprison, the + // result is different when highest bit is set vs when it is not set. + // + driverStartPa = PhysicalAddress.QuadPart; + + // + // driverEndPa = driverStartPa + Size - 1; + // + hr = ULongLongAdd(driverStartPa, Size, &tmp); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred" + "when computing register address range", SUCCEEDED(hr)), + GetDriverGlobals()->Public.DriverName); + + driverEndPa = tmp - 1; + + // + // We allow one physical address range mapping only. The base address and + // length can be flexible within the assigned range. + // + for (i = 0; i < m_RegisterResourceTableSizeCe; i++) { + entry = &m_RegisterResourceTable[i]; + + // + // No need to do int overflow safe additon here since start address and + // length are assigned by pnp manager. Note that we don't store endPa in + // resource table the way we do for SystemVa is because endPa is not + // needed in hot path so can be computed using length. + // + systemStartPa = entry->m_StartPa.QuadPart; + systemEndPa = systemStartPa + entry->m_Length - 1; + + if (driverStartPa >= systemStartPa && + driverEndPa <= systemEndPa) { + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Attempt to do multiple " + "mapping of same resource, or multiple mapping in same resource" + " range", + (entry->m_StartSystemVa == NULL)), GetDriverGlobals()->Public.DriverName); + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(entry->m_EndSystemVa), + GetDriverGlobals()->Public.DriverName); + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NULL(entry->m_StartUsermodeVa), + GetDriverGlobals()->Public.DriverName); + FX_VERIFY_WITH_NAME(INTERNAL, CHECK("Mapped length not zero", + (entry->m_MappedLength == 0)), GetDriverGlobals()->Public.DriverName); + + *TableEntry = entry; + + return S_OK; + } + } + + return E_INVALIDARG; +} + +HRESULT +FxCmResList::ValidateAndClearMapping( + __in PVOID Address, + __in SIZE_T Length + ) +/*++ + +Routine Description: + + This routine checks whether the mapped system base address and size is part + of the resources assigned to the device by pnp manager. If so it clears the + system and usermode address mapping from the table. + +Arguments: + + Address - Supplies system base address to validate + + Size - Supplies size of address range in bytes. + +Return Value: + + HRESULT + + S_OK if system address is one mapped to a register resource. + E_INAVLIDARG otherwise. + +--*/ +{ + HRESULT hr = E_INVALIDARG; + ULONG i; + FxRegisterResourceInfo* entry = NULL; + + LockResourceTable(); + + for (i = 0; i < m_RegisterResourceTableSizeCe; i++) { + entry = &m_RegisterResourceTable[i]; + + if (NULL != entry->m_StartSystemVa && + Address == entry->m_StartSystemVa && + Length == entry->m_MappedLength) { + // + // there is a valid mapping. clear it. + // + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(entry->m_EndSystemVa), + GetDriverGlobals()->Public.DriverName); + + ClearRegisterResourceEntryLocked(entry); + + hr = S_OK; + break; + } + } + + UnlockResourceTable(); + + return hr; +} + +HRESULT +FxCmResList::ValidateRegisterSystemBaseAddress ( + __in PVOID Address, + __out PVOID* UsermodeBaseAddress + ) +/*++ + +Routine Description: + + This routine checks whether the mapped system base address and size is part + of the resources assigned to the device by pnp manager. If so, it returns + corresponding user-mode mapped base address. It is applicable + only when registers are mapped to user-mode. + +Arguments: + + Address - Supplies system base address to validate + +Return Value: + + HRESULT + + S_OK if system address is one mapped to a register resource. + E_INAVLIDARG otherwise. + +--*/ +{ + ULONG i; + FxRegisterResourceInfo* entry = NULL; + + LockResourceTable(); + for (i = 0; i < m_RegisterResourceTableSizeCe; i++) { + entry = &m_RegisterResourceTable[i]; + + if (Address == entry->m_StartSystemVa) { + + FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(entry->m_StartUsermodeVa), + GetDriverGlobals()->Public.DriverName); + + *UsermodeBaseAddress = entry->m_StartUsermodeVa; + + UnlockResourceTable(); + return S_OK; + } + } + + UnlockResourceTable(); + return E_INVALIDARG; +} + +HRESULT +FxCmResList::ValidateRegisterSystemAddressRange ( + __in PVOID SystemAddress, + __in SIZE_T Length, + __out_opt PVOID* UsermodeAddress + ) +/*++ + +Routine Description: + + This routine checks whether given system mapped address and length is within + one of the assigned resource ranges. Optionally, tt computes the usermode + address corresponding to the system address. + +Arguments: + + Address - Supplies register address to validate + + Size - Supplies size of address range in bytes. + + UsermodeAddress - returns usermode address corresponding to system address + +Return Value: + + HRESULT + + S_OK if system address range is valid. + E_INAVLIDARG otherwise. + +--*/ +{ + HRESULT hr = E_INVALIDARG; + FxRegisterResourceInfo* entry = NULL; + SIZE_T offset = 0; + ULONG i; + PVOID start = NULL; + PVOID end = NULL; + ULONG_PTR tmp; + + // + // compute system address range to look for + // + start = SystemAddress; + + // + // Use interger overflow safe functions + // end = ((PUCHAR)SystemAddress) + Length - 1; + // + hr = ULongPtrAdd((ULONG_PTR) start, Length, &tmp); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred" + "when computing register address range", SUCCEEDED(hr)), + GetDriverGlobals()->Public.DriverName); + + end = (PVOID)(tmp - 1); + + // + // check if range is in the register resource table + // + hr = E_INVALIDARG; + for (i = 0; i < m_RegisterResourceTableSizeCe; i++) { + entry = &m_RegisterResourceTable[i]; + + if (start >= entry->m_StartSystemVa && + end <= entry->m_EndSystemVa) { + hr = S_OK; + break; + } + } + + // + // compute the corresponding usermode address + // + if (SUCCEEDED(hr) && UsermodeAddress != NULL) { + offset = ((PUCHAR)SystemAddress) - ((PUCHAR)entry->m_StartSystemVa); + *UsermodeAddress = ((PUCHAR)entry->m_StartUsermodeVa) + offset; + } + + return hr; +} + +SIZE_T +FxCmResList::GetResourceLength( + __in PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor, + __out_opt PHYSICAL_ADDRESS* Start + ) +/*++ + +Routine Description: + + This routine decodes the length from a CmPartialResourceDescriptor + describing a memory resource. + +Arguments: + + Descriptor - Supplies resource descriptor from which to decode length + + Start - Supplies optional buffer into which start address will be stored. + +Return Value: + + Decoded Length + +--*/ +{ + ULONGLONG length; + + length = 0; + + ASSERT((Descriptor->Type == CmResourceTypeMemory) || + (Descriptor->Type == CmResourceTypeMemoryLarge) || + (Descriptor->Type == CmResourceTypePort)); + + // + // If it is not large memory resource than length is in u.Memory.Length. + // For large memory resource, the length is given by different fields in + // CM_PARTIAL_RESOURCE_DESCRIPTOR structure. + // + if ((Descriptor->Type == CmResourceTypeMemory) || + (Descriptor->Type == CmResourceTypePort)) { + length = Descriptor->u.Memory.Length; + + } else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_40) { + length = (((ULONGLONG)Descriptor->u.Memory40.Length40) << 8); + + } else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_48) { + length = (((ULONGLONG)Descriptor->u.Memory48.Length48) << 16); + + } else if (Descriptor->Flags & CM_RESOURCE_MEMORY_LARGE_64) { + length = (((ULONGLONG)Descriptor->u.Memory64.Length64) << 32); + + } else { + // + // It should not be possible to get here. + // + ASSERT(FALSE); + } + + if (Start != NULL) { + *Start = Descriptor->u.Generic.Start; + } + + // + // large memory descriptor is only supported on 64-bit so the casting + // below is ok. + // + return (SIZE_T) length; +} + +HRESULT +FxCmResList::MapIoSpaceWorker( + __in PHYSICAL_ADDRESS PhysicalAddress, + __in SIZE_T NumberOfBytes, + __in MEMORY_CACHING_TYPE CacheType, + __deref_out VOID** PseudoBaseAddress + ) +{ + IWudfDeviceStack *deviceStack; + PVOID systemAddress; + PVOID usermodeAddress; + HRESULT hr; + FxRegisterResourceInfo* resEntry; + + // + // check if this physical resource is among the assigned resources. + // If it is, retrieve the table entry corresponding to to register res. + // + LockResourceTable(); + + hr = ValidateRegisterPhysicalAddressRange(PhysicalAddress, + NumberOfBytes, + &resEntry); + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), + CHECK("Invalid physical address or number of bytes provided", + (SUCCEEDED(hr))), GetDriverGlobals()->Public.DriverName); + + *PseudoBaseAddress = NULL; + + // + // Call host + // + deviceStack = GetDevice()->GetDeviceStack(); + systemAddress = NULL; + usermodeAddress = NULL; + + if(GetDevice()->AreRegistersMappedToUsermode()) { + hr = deviceStack->MapIoSpace(PhysicalAddress, + NumberOfBytes, + CacheType, + &systemAddress, + &usermodeAddress); + } + else { + hr = deviceStack->MapIoSpace(PhysicalAddress, + NumberOfBytes, + CacheType, + &systemAddress, + NULL); + } + + if (SUCCEEDED(hr)) { + // + // update the mapped resource list entry and add it to list + // + UpdateRegisterResourceEntryLocked(resEntry, + systemAddress, + NumberOfBytes, + usermodeAddress); + + // + // Convert system address to pseudo (opaque) base address + // + *PseudoBaseAddress = GetDevice()->GetPseudoAddressFromSystemAddress( + systemAddress + ); + } + + UnlockResourceTable(); + + return hr; +} + +VOID +FxCmResList::ValidateResourceUnmap( + VOID + ) +{ + ULONG i; + FxRegisterResourceInfo* entry = NULL; + + // + // make sure driver has unmapped its resources. No need to + // acquire the resource validation table lock as this is called in + // ReleaseHardware pnp callback and cannot race with another framework + // pnp callback that updates this table (PrepareHardware) so no invalid + // access. If a driver thread unmaps after ReleaseHardware return then also + // it will be a valid access of table entry. + // + + for (i = 0; i < m_RegisterResourceTableSizeCe; i++) { + entry = &m_RegisterResourceTable[i]; + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Driver did not unmap its " + "register resources", (entry->m_StartSystemVa == NULL)), GetDriverGlobals()->Public.DriverName); + } +} + +HRESULT +FxCmResList::ValidatePortAddressRange( + __in PVOID Address, + __in SIZE_T Length + ) +{ + ULONG i; + HRESULT hr; + ULONGLONG driverStartPa, driverEndPa, systemStartPa, systemEndPa; + ULONGLONG tmp; + FxPortResourceInfo* entry = NULL; + + driverStartPa = (ULONGLONG)Address; + + // + // driverEndPa = driverStartPa + Length - 1; + // + hr = ULongLongAdd(driverStartPa, Length, &tmp); + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK("Integer overflow occurred" + "when computing port address range", SUCCEEDED(hr)), + GetDriverGlobals()->Public.DriverName); + + driverEndPa = tmp - 1; + + for (i = 0; i < m_PortResourceTableSizeCe; i++) { + entry = &m_PortResourceTable[i]; + + systemStartPa = entry->m_StartPa.QuadPart; + systemEndPa = entry->m_EndPa.QuadPart; + + if (driverStartPa >= systemStartPa && + driverEndPa <= systemEndPa) { + return S_OK; + } + } + + return E_INVALIDARG; +} + +_Must_inspect_result_ +NTSTATUS +FxCmResList::CheckForConnectionResources( + VOID + ) +{ + NTSTATUS status; + ULONG i; + ULONG count; + PCM_PARTIAL_RESOURCE_DESCRIPTOR pDescriptor; + + status = STATUS_SUCCESS; + count = GetCount(); + + for (i = 0; i < count; i++) { + pDescriptor = GetDescriptor(i); + if (pDescriptor == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP, + "Resource Descriptor not found %!STATUS!", status); + goto exit; + } + + if (pDescriptor->Type == CmResourceTypeConnection) { + m_HasConnectionResources = TRUE; + break; + } + } + +exit: + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/support/um/fxsupportpchum.hpp b/sdk/lib/drivers/wdf/shared/support/um/fxsupportpchum.hpp new file mode 100644 index 00000000000..587a40eb172 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/fxsupportpchum.hpp @@ -0,0 +1,44 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: + + fxsupportpchum.h + +Abstract: + + This module contains header definitions and include files needed by all + modules in fx\support + +Author: + +Environment: + User mode only + +Revision History: + +--*/ + +#ifndef __FX_SUPPORT_PCH_UM_HPP__ +#define __FX_SUPPORT_PCH_UM_HPP__ + +extern "C" { +#include "mx.h" +} + +#include "fxmin.hpp" + +#include "FxPagedObject.hpp" +#include "FxRegKey.hpp" +#include "FxCollection.hpp" +#include "FxString.hpp" +#include "StringUtil.hpp" + +#include "FxDeviceText.hpp" + +#include +#include + + +#endif // __FX_SUPPORT_PCH_UM_HPP__ diff --git a/sdk/lib/drivers/wdf/shared/support/um/fxtelemetryum.cpp b/sdk/lib/drivers/wdf/shared/support/um/fxtelemetryum.cpp new file mode 100644 index 00000000000..bfe31170c5b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/fxtelemetryum.cpp @@ -0,0 +1,426 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxTelemetryUm.cpp + +Abstract: + + This module implements a telemetry methods. + +Author: + + + +Environment: + + User mode only + +Revision History: + +Notes: + +--*/ + +#include "fxsupportpch.hpp" +#include "DriverFrameworks-UserMode-UmEvents.h" +#include "FxldrUm.h" +#include +#include +#include +#include +#include + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxTelemetryUm.tmh" +#endif +} + +/* 8ad60765-a021-4494-8594-9346970cf50f */ +TRACELOGGING_DEFINE_PROVIDER(g_TelemetryProvider, + UMDF_FX_TRACE_LOGGING_PROVIDER_NAME, + (0x8ad60765, 0xa021, 0x4494, 0x85, 0x94, 0x93, 0x46, 0x97, 0x0c, 0xf5, 0x0f), + TraceLoggingOptionMicrosoftTelemetry()); + +VOID +AllocAndInitializeTelemetryContext( + _In_ PFX_TELEMETRY_CONTEXT* TelemetryContext + ) +{ + PFX_TELEMETRY_CONTEXT context = NULL; + RPC_STATUS status; + + context = (PFX_TELEMETRY_CONTEXT)MxMemory::MxAllocatePoolWithTag(NonPagedPool, + sizeof(FX_TELEMETRY_CONTEXT), + FX_TAG); + if (NULL == context) { + goto exit; + } + + status = UuidCreate(&(context->DriverSessionGUID)); + if ((status != RPC_S_OK) && (status != RPC_S_UUID_LOCAL_ONLY)) { + MxMemory::MxFreePool(context); + context = NULL; + goto exit; + } + + context->DoOnceFlagsBitmap = 0; +exit: + *TelemetryContext = context; +} + +VOID +RegisterTelemetryProvider( + VOID + ) +{ + EventRegisterMicrosoft_Windows_DriverFrameworks_UserMode(); + + TraceLoggingRegister(g_TelemetryProvider); +} + +VOID +UnregisterTelemetryProvider( + VOID + ) +{ + EventUnregisterMicrosoft_Windows_DriverFrameworks_UserMode(); + + TraceLoggingUnregister(g_TelemetryProvider); +} + +VOID +LogDeviceStartTelemetryEvent( + _In_ PFX_DRIVER_GLOBALS Globals, + _In_opt_ FxDevice* Fdo + ) +{ + // If provider is not enabled we're done. + if (FALSE == FX_TELEMETRY_ENABLED(g_TelemetryProvider, Globals)) { + return; + } + + // + // If we already fired an event during PnP start we are done. This avoids + // repeatedly firing events during PnP rebalance. + // + if (InterlockedBitTestAndSet( + &Globals->TelemetryContext->DoOnceFlagsBitmap, + DeviceStartEventBit) == 1) { + return; + } + + // + // log the DriverInfo stream. + // + LogDriverInfoStream(Globals, Fdo); +} + +VOID +LogDriverInfoStream( + _In_ PFX_DRIVER_GLOBALS DriverGlobals, + _In_ FxDevice* Fdo + ) +{ + LONG error = ERROR_SUCCESS; + PWCHAR str = NULL; + UFxTelemetryDriverInfo driverInfo = {0}; + LPCWSTR hardwareIds = NULL; + LPCWSTR setupClass = NULL; + LPCWSTR busEnum = NULL; + LPCWSTR manufacturer = NULL; + UMDF_DRIVER_REGSITRY_INFO devRegInfo = {0}; + PCWSTR groupId = NULL; + IWudfDeviceStack* devStack = NULL; + + if (Fdo == NULL) { + // + // Telemetry events are logged during DriverEntry as well to capture non-pnp + // and class extension (which are non-pnp drivers) driver info. Although + // current UMDF datapoint doesn't have a separate flag for non-pnp driver, + // we still want to log the driver name and its properies if available. + // + devStack = DriverGlobals->Driver->GetDriverObject()->WudfDevStack; + if (devStack != NULL) { + devStack->GetPdoProperties(&hardwareIds, + &setupClass, + &busEnum, + &manufacturer); + } + } + else { + devStack = Fdo->GetDeviceStack(); + devStack->GetPdoProperties(&hardwareIds, + &setupClass, + &busEnum, + &manufacturer); + + Fdo->RetrieveDeviceInfoRegistrySettings(&groupId, &devRegInfo); + } + + // + // Log Driver info + // + if (Fdo != NULL) { + GetDriverInfo(Fdo, &devRegInfo, &driverInfo); + } + + UMDF_CENSUS_EVT_WRITE_DEVICE_START(g_TelemetryProvider, + DriverGlobals, + driverInfo, + setupClass, + busEnum, + hardwareIds, + manufacturer); + + if (groupId != NULL) { + delete [] groupId; + groupId = NULL; + } +} + +VOID +GetDriverInfo( + _In_ FxDevice* Fdo, + _In_ PUMDF_DRIVER_REGSITRY_INFO RegInfo, + _Out_ UFxTelemetryDriverInfo* DriverInfo + ) +{ + FxPkgPnp* pnpPkg; + USHORT devInfo = 0; + WDF_DEVICE_IO_TYPE readWritePreference; + WDF_DEVICE_IO_TYPE ioControlPreference; + UMDF_DRIVER_REGSITRY_INFO devRegInfo = {0}; + PWSTR groupId = NULL; + + pnpPkg = (FxPkgPnp*)Fdo->GetFdoPkg(); + devInfo = Fdo->GetDeviceTelemetryInfoFlags(); + Fdo->GetDeviceStackIoType(&readWritePreference, &ioControlPreference); + + DriverInfo->bitmap.IsFilter = Fdo->IsFilter(); + DriverInfo->bitmap.IsPowerPolicyOwner = pnpPkg->IsPowerPolicyOwner(); + DriverInfo->bitmap.IsS0IdleWakeFromS0Enabled = pnpPkg->IsS0IdleWakeFromS0Enabled(); + DriverInfo->bitmap.IsS0IdleUsbSSEnabled = pnpPkg->IsS0IdleUsbSSEnabled(); + DriverInfo->bitmap.IsS0IdleSystemManaged = pnpPkg->IsS0IdleSystemManaged(); + DriverInfo->bitmap.IsSxWakeEnabled = pnpPkg->IsSxWakeEnabled(); + DriverInfo->bitmap.IsUsingLevelTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedLevelTriggeredInterrupt); + DriverInfo->bitmap.IsUsingEdgeTriggeredLineInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoLineBasedEdgeTriggeredInterrupt); + DriverInfo->bitmap.IsUsingMsiXOrSingleMsi22Interrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsiXOrSingleMsi22Interrupt); + DriverInfo->bitmap.IsUsingMsi22MultiMessageInterrupt = IsDeviceInfoFlagSet(devInfo, DeviceInfoMsi22MultiMessageInterrupt); + DriverInfo->bitmap.IsUsingMultipleInterrupt = pnpPkg->HasMultipleInterrupts(); + DriverInfo->bitmap.IsDirectHardwareAccessAllowed = Fdo->IsDirectHardwareAccessAllowed(); + DriverInfo->bitmap.IsUsingUserModemappingAccessMode = Fdo->AreRegistersMappedToUsermode(); + DriverInfo->bitmap.IsKernelModeClientAllowed = RegInfo->IsKernelModeClientAllowed; + DriverInfo->bitmap.IsNullFileObjectAllowed = RegInfo->IsNullFileObjectAllowed; + DriverInfo->bitmap.IsPoolingDisabled = RegInfo->IsHostProcessSharingDisabled; + DriverInfo->bitmap.IsMethodNeitherActionCopy = RegInfo->IsMethodNeitherActionCopy; + DriverInfo->bitmap.IsUsingDirectIoForReadWrite = (readWritePreference == WdfDeviceIoDirect); + DriverInfo->bitmap.IsUsingDirectIoForIoctl = (ioControlPreference == WdfDeviceIoDirect); + DriverInfo->bitmap.IsUsingDriverWppRecorder = Fdo->GetDriver()->IsDriverObjectFlagSet(DriverObjectUmFlagsLoggingEnabled); + + return; +} + +_Must_inspect_result_ +NTSTATUS +GetImageName( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _Out_ PUNICODE_STRING ImageName + ) +/*++ + +Routine Description: + Retrieve the ImageName value from the named Service registry key. + + Caller is responsible for freeing the buffer allocated in ImageName::Buffer. + +Arguments: + DriverGlobals - pointer to FX_DRIVER_GLOBALS + + ImageeName - Pointer to a UNICODE_STRING which will receive the image name + upon a return value of NT_SUCCESS() + +Return Value: + NTSTATUS + +--*/ +{ + NTSTATUS status; + FxAutoRegKey hKey; + DECLARE_CONST_UNICODE_STRING(valueName, L"ImagePath"); + UNICODE_STRING imagePath = {0}; + UNICODE_STRING imageName = {0}; + PKEY_VALUE_PARTIAL_INFORMATION value = NULL; + USHORT size; + ULONG length, type; + PVOID dataBuffer; + + type = REG_SZ; + length = 0; + + ASSERT(ImageName != NULL); + RtlZeroMemory(ImageName, sizeof(UNICODE_STRING)); + + // + // Open driver's Service base key + // + status = FxRegKey::_OpenKey(NULL, + FxDriverGlobals->Driver->GetRegistryPathUnicodeString(), + &hKey.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Unable to open driver's service key, %!STATUS!", status); + return status; + } + + // + // Find out how big a buffer we need to allocate if the value is present + // + status = FxRegKey::_QueryValue(FxDriverGlobals, + hKey.m_Key, + &valueName, + length, + NULL, + &length, + &type); + + // + // We expect the list to be bigger then a standard partial, so if it is + // not, just bail now. + // + if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL) { + return STATUS_UNSUCCESSFUL; + } + + // + // Pool can be paged b/c we are running at PASSIVE_LEVEL and we are going + // to free it at the end of this function. + // + dataBuffer = FxPoolAllocate(FxDriverGlobals, PagedPool, length); + if (dataBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Failed to allocate memory for image path string, %!STATUS!", + status); + return status; + } + + // + // Requery now that we have a big enough buffer + // + status = FxRegKey::_QueryValue(FxDriverGlobals, + hKey.m_Key, + &valueName, + length, + dataBuffer, + &length, + &type); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "Failed to get Image name from service key, %!STATUS!", + status); + goto cleanUp; + } + + // + // Verify that the data from the registry is a valid string. + // + if (type != REG_SZ && type != REG_EXPAND_SZ) { + return STATUS_OBJECT_TYPE_MISMATCH; + } + + if (length == 0 || length > USHORT_MAX) { + return STATUS_INVALID_PARAMETER; + } + + // + // string must be NULL-terminated + // + PWCHAR str = (PWCHAR) dataBuffer; + if (str[(length/sizeof(WCHAR)) - 1] != UNICODE_NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: string not terminated with NULL, %!status!\n", + status); + goto cleanUp; + } + + RtlInitUnicodeString(&imagePath, (PCWSTR) dataBuffer); + + // + // Now read the "ImagePath" and extract just the driver filename as a new + // unicode string. + // + GetNameFromPath(&imagePath, &imageName); + + if (imageName.Length == 0x0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: GetNameFromPath could not find a name, %!status!\n", + status); + goto cleanUp; + } + + // + // Check for interger overflow for length before we allocate memory + // size = path->Length + sizeof(UNICODE_NULL); + // len is used below to compute the string size including the NULL, so + // compute len to include the terminating NULL. + // + status = RtlUShortAdd(imageName.Length, sizeof(UNICODE_NULL), &size); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: size computation failed, %!status!\n", status); + goto cleanUp; + } + + // + // allocate a buffer to hold Unicode string + null char. + // + ImageName->Buffer = (PWCH) FxPoolAllocate(FxDriverGlobals, PagedPool, size); + + if (ImageName->Buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: ExAllocatePoolWithTag failed, %!status!\n", status); + goto cleanUp; + } + + RtlZeroMemory(ImageName->Buffer, size); + ImageName->Length = 0x0; + ImageName->MaximumLength = size; + + HRESULT hr = StringCbCopy(ImageName->Buffer, size, imageName.Buffer); + if (FAILED(hr)) { + status = STATUS_UNSUCCESSFUL; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDRIVER, + "ERROR: failed to copy string buffer, HRESULT 0x%x, %!status!\n", + hr, status); + goto cleanUp; + } + + // + // The copy cannot fail since we setup the buffer to hold enough space for + // the contents of the ImagePath value. + // + ASSERT(NT_SUCCESS(status)); + +cleanUp: + + if (!NT_SUCCESS(status)) { + if (ImageName->Buffer != NULL) { + FxPoolFree(ImageName->Buffer); + RtlInitUnicodeString(ImageName, NULL); + } + } + + if (dataBuffer != NULL) { + FxPoolFree(dataBuffer); + } + + return status; +} diff --git a/sdk/lib/drivers/wdf/shared/support/um/tracingum.cpp b/sdk/lib/drivers/wdf/shared/support/um/tracingum.cpp new file mode 100644 index 00000000000..cb40585c83b --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/support/um/tracingum.cpp @@ -0,0 +1,838 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + Tracing.cpp + +Abstract: + + This module implements tracing for the driver frameworks + +Author: + + + + +Revision History: + + + + +--*/ + +#include "FxSupportPch.hpp" +#include "fxldrum.h" + +extern "C" { +#if defined(EVENT_TRACING) +#include "TracingUM.tmh" +#endif +} + +#include +#include +#include "fxIFR.h" // shared struct between IFR and debug ext. +#include "fxIFRKm.h" // kernel mode only IFR definitions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +_Must_inspect_result_ +NTSTATUS +FxTraceInitialize( + VOID + ) + +/*++ + +Routine Description: + + This routine initializes the frameworks tracing. + + It must be called early on in the frameworks DriverEntry + initialization. + +Arguments: + + None + +Returns: + + NTSTATUS code + +--*/ +{ + // + // Initialize the tracing package. + // + WPP_INIT_TRACING(NULL, NULL); + + return STATUS_SUCCESS; +} + +VOID +TraceUninitialize( + VOID + ) +/*++ + +Routine Description: + This routine uninitializes the frameworks tracing. It must be called just + before DriverUnload + +Arguments: + None + +Returns: + None + +--*/ +{ + WPP_CLEANUP(NULL); +} + +_Must_inspect_result_ +NTSTATUS +FxWmiQueryTraceInformation( + __in TRACE_INFORMATION_CLASS /* TraceInformationClass */, + __out_bcount(TraceInformationLength) PVOID /* TraceInformation */, + __in ULONG /* TraceInformationLength */, + __out_opt PULONG /* RequiredLength */, + __in_opt PVOID /* Buffer */ + ) +{ + return STATUS_UNSUCCESSFUL; +} + +_Must_inspect_result_ +NTSTATUS +FxWmiTraceMessage( + __in TRACEHANDLE LoggerHandle, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + ... + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + va_list va; + va_start(va, MessageNumber); + // + // UMDF is supported only on XP and newer OS so no need to support w2k + // tracing (which requires using a different tracing api, see kmdf impl) + // +#pragma prefast(suppress:__WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean"); + status = TraceMessageVa(LoggerHandle, + MessageFlags, + MessageGuid, + MessageNumber, + va); + + va_end(va); + + return status; +} + + +//----------------------------------------------------------------------------- +// Subcomponents for the In-Flight Recorder follow. +//----------------------------------------------------------------------------- + +ULONG +FxIFRGetSize( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + Checks to see if the service has overriden the default number of pages that + are in the IFR. + +Arguments: + RegistryPath - path to the service + +Return Value: + The size of the IFR to create in bytes (not pages!) + + --*/ +{ + FxAutoRegKey service, parameters; + NTSTATUS status; + ULONG numPages; + + // + // This is the value used in case of any error while retrieving 'LogPages' + // from the registry. + // + numPages = FxIFRMinLogPages; + + // + // External representation of the IFR is the "log", so use tha term when + // overriding the size via the registry. + // + DECLARE_CONST_UNICODE_STRING(parametersPath, L"Parameters\\Wdf"); + DECLARE_CONST_UNICODE_STRING(valueName, L"LogPages"); + + // + // UMDF may not provide this registry path + // + if (NULL == RegistryPath) { + goto defaultValues; + } + + status = FxRegKey::_OpenKey(NULL, + (PCUNICODE_STRING)RegistryPath, + &service.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + goto defaultValues; + } + + status = FxRegKey::_OpenKey(service.m_Key, + (PCUNICODE_STRING)¶metersPath, + ¶meters.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + goto defaultValues; + } + + status = FxRegKey::_QueryULong(parameters.m_Key, &valueName, &numPages); + if (!NT_SUCCESS(status)) { + goto defaultValues; + } + + if (numPages == 0) { + numPages = FxIFRMinLogPages; + } + +defaultValues: + // + // This behavior is different from KMDF. KMDF would allocate Average page count (5) + // if Verifier is on otherwise 1 page if the request is large. + // Since for UMDF the memory is coming from WudfRd, which does not know about verifier + // we will give it max pages here. + // + if (numPages > FxIFRMaxLogPages) { + numPages = FxIFRMaxLogPages; + } + + return numPages * PAGE_SIZE; +} + +VOID +FxIFRStart( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PCUNICODE_STRING RegistryPath, + __in MdDriverObject DriverObject + ) +/*++ + +Routine Description: + + This routine initialize the In-Flight Recorder (IFR). + + The default log size is set by WDF_IFR_LOG_SIZE and currently + is 4096 (one x86 page). + This routine should be called very early in driver initialization + to allow the capture of all significant events. + +Arguments: + +Returns: + +--*/ +{ + PWDF_IFR_HEADER pHeader; + ULONG pageCount; + ULONG sizeCb; + HRESULT hr; + IWudfDeviceStack2 *pDeviceStack2; + PDRIVER_OBJECT_UM umDriverObject; + PWCHAR serviceName; + size_t bufferLengthCch; + ULONG allocatedBufferLengthCb; + LONG i; + + // + // Return early if IFR is disabled. + // + if (FxLibraryGlobals.IfrDisabled) { + ASSERT(FxDriverGlobals->WdfLogHeader == NULL); + return; + } + + WDFCASSERT(FxIFRRecordSignature == WDF_IFR_RECORD_SIGNATURE); + + if (FxDriverGlobals == NULL || FxDriverGlobals->WdfLogHeader != NULL) { + return; + } + + // + // It is safe to use StringCchLength here as WudfHost makes sure that this + // RegistryPath is null terminated + // + hr = StringCchLength(RegistryPath->Buffer, + RegistryPath->MaximumLength/sizeof(WCHAR), + &bufferLengthCch); + + if (FAILED(hr)) { + return; + } + + // + // Lets find the last '\' that will mark the begining of the service name + // + for (i = (ULONG)bufferLengthCch - 1; + i >= 0 && RegistryPath->Buffer[i] != '\\'; + i--); + + // + // We did not find the service name + // + if (i < 0) { + return; + } + + serviceName = &RegistryPath->Buffer[i+1]; + + sizeCb = FxIFRGetSize(FxDriverGlobals, RegistryPath); + pageCount = sizeCb / PAGE_SIZE; + + // + // Get the IWudfDeviceStack interface + // + umDriverObject = (PDRIVER_OBJECT_UM)DriverObject; + + pDeviceStack2 = (IWudfDeviceStack2 *)umDriverObject->WudfDevStack; + + if(pDeviceStack2 == NULL) { + return; + } + + allocatedBufferLengthCb = 0; + hr = pDeviceStack2->AllocateIfrMemory(serviceName, + pageCount, + FALSE, + TRUE, + (PVOID *)&pHeader, + &allocatedBufferLengthCb); + + if (pHeader == NULL || allocatedBufferLengthCb <= sizeof(WDF_IFR_HEADER)) { + return; + } + + // + // Initialize the header. + // Base will be where the IFR records are placed. + // WPP_ThisDir_CTLGUID_FrameworksTraceGuid + // + RtlCopyMemory(&pHeader->Guid, (PVOID) &WdfTraceGuid, sizeof(GUID)); + + pHeader->Base = (PUCHAR) &pHeader[1]; + pHeader->Size = allocatedBufferLengthCb - sizeof(WDF_IFR_HEADER); + + pHeader->Offset.u.s.Current = 0; + pHeader->Offset.u.s.Previous = 0; + pHeader->SequenceNumberPointer = &(DriverObject->IfrSequenceNumber); + + StringCchCopyA(pHeader->DriverName, WDF_IFR_HEADER_NAME_LEN, FxDriverGlobals->Public.DriverName); + + FxDriverGlobals->WdfLogHeader = pHeader; + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGDRIVER, + "FxIFR logging started" ); + + if (sizeCb > FxIFRMinLogSize) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGDRIVER, + "FxIFR has been started with a size override: size 0x%x bytes, " + "# Pages %d. An extended IFR size may not be written to a minidump!", + sizeCb, sizeCb/PAGE_SIZE); + } + + if (sizeCb != allocatedBufferLengthCb) { + ASSERTMSG("FxIFR requested buffer size could not be allocated",FALSE); + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGDRIVER, + "FxIFR requested an allocation of size 0x%x bytes, " + "Allocated memory was of size 0x%x bytes", + sizeCb, allocatedBufferLengthCb); + } +} + +VOID +FxIFRStop( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) +/*++ + +Routine Description: + + This routine stops the In-Flight Recorder (IFR). + + For UMDF FxIFRStop is no longer required as WudfRd manages the buffer's lifetime + The buffer is kept alive till WudfRd unloads to aid in debugging in cases of + WudfHost crash or in dumps with WudfHost paged out or not captured + +Arguments: + +Returns: + +--*/ +{ + UNREFERENCED_PARAMETER(FxDriverGlobals); + + // + // Uncomment the code below if you add any logic to this function. + // + // if (FxLibraryGlobals.IfrDisabled) { + // ASSERT(FxDriverGlobals->WdfLogHeader == NULL); + // return; + // } + // +} + +_Must_inspect_result_ +NTSTATUS +FxIFR( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in UCHAR MessageLevel, + __in ULONG MessageFlags, + __in LPGUID MessageGuid, + __in USHORT MessageNumber, + ... + ) +/*++ + +Routine Description: + + This routine is the main In-Flight Recorder (IFR) routine. + + It captures a WPP message to the IFR log. + The IFR is always running, e.g. not WPP logger is necessary + to start logging. + +Arguments: + + MessageLevel - The WPP message level for this event + MessageFlags - The WPP message flags for this event (see trace GUID) + MessageGuid - The tracewpp generated guid for module emitting this event. + MessageNumber - The tracewpp generated message number within + the emitting module. + ... - Variable arguments associates with the emitted message. + +Returns: + + NTSTATUS + +--*/ +{ + size_t size; + PWDF_IFR_RECORD record; + + UNREFERENCED_PARAMETER( MessageLevel ); + + // + // Return early if IFR is disabled. + // + if (FxLibraryGlobals.IfrDisabled) { + ASSERT(FxDriverGlobals->WdfLogHeader == NULL); + return STATUS_SUCCESS; + } + + if ( FxDriverGlobals->WdfLogHeader == NULL) { + return STATUS_UNSUCCESSFUL; + } + + + + + + + + + + + + + + + + + + + + + + + + + + UNREFERENCED_PARAMETER( MessageFlags ); + + + // + // Determine the number bytes to follow header + // + size = 0; // For Count of Bytes + + // + // Determine how much log space is needed for this + // trace record's data. + // + { + va_list ap; + size_t argLen; + + va_start(ap, MessageNumber); +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean"); + while ((va_arg(ap, PVOID)) != NULL) { + + argLen = va_arg(ap, size_t); + + if (argLen > 0) { + + if (argLen > FxIFRMaxMessageSize) { + goto drop_message; + } + size += (USHORT) argLen; + } + } + + va_end(ap); + + // + // NOTE: The final size must be 32-bit (ULONG) aligned. + // This is necessary for IA64 to prevent Alignment Faults. + // + size += (size % sizeof(ULONG)) ? sizeof(ULONG) - (size % sizeof(ULONG)) : 0; + + if (size > FxIFRMaxMessageSize) { + goto drop_message; + } + } + + size += sizeof(WDF_IFR_RECORD); + + // + // Allocate log space of the calculated size + // + { + PWDF_IFR_HEADER header; + WDF_IFR_OFFSET offsetRet; + WDF_IFR_OFFSET offsetCur; + WDF_IFR_OFFSET offsetNew; + USHORT usSize = (USHORT) size; // for a prefast artifact. + + header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader; + ASSERT(header->Size < FxIFRMaxLogSize); // size doesn't include header. + ASSERT(header->Size >= header->Offset.u.s.Current); + ASSERT(header->Size >= header->Offset.u.s.Previous); + + offsetRet.u.AsLONG = header->Offset.u.AsLONG; + offsetNew.u.AsLONG = offsetRet.u.s.Current; + + do { + offsetCur.u.AsLONG = offsetRet.u.AsLONG; + + if (&header->Base[header->Size] < &header->Base[offsetCur.u.s.Current+size]) { + + offsetNew.u.s.Current = 0; + offsetNew.u.s.Previous = offsetRet.u.s.Previous; + + offsetRet.u.AsLONG = + InterlockedCompareExchange( &header->Offset.u.AsLONG, + offsetNew.u.AsLONG, + offsetCur.u.AsLONG ); + + if (offsetCur.u.AsLONG != offsetRet.u.AsLONG) { + continue; + } else { + offsetNew.u.s.Current = offsetCur.u.s.Current + usSize; + offsetNew.u.s.Previous = offsetRet.u.s.Current; + } + } else { + + offsetNew.u.s.Current = offsetCur.u.s.Current + usSize; + offsetNew.u.s.Previous = offsetCur.u.s.Current; + } + + offsetRet.u.AsLONG = + InterlockedCompareExchange( &header->Offset.u.AsLONG, + offsetNew.u.AsLONG, + offsetCur.u.AsLONG ); + + } while (offsetCur.u.AsLONG != offsetRet.u.AsLONG); + + record = (PWDF_IFR_RECORD) &header->Base[offsetRet.u.s.Current]; + + // RtlZeroMemory( record, sizeof(WDF_IFR_RECORD) ); + + // + // Build record (fill all fields!) + // + record->Signature = FxIFRRecordSignature; + record->Length = (USHORT) size; + record->PrevOffset = (USHORT) offsetRet.u.s.Previous; + record->MessageNumber = MessageNumber; + record->Sequence = InterlockedIncrement(header->SequenceNumberPointer); + record->MessageGuid = *MessageGuid; + } + + // + // Move variable part of data into log. + // + { + va_list ap; + size_t argLen; + PVOID source; + PUCHAR argsData; + + argsData = (UCHAR*) &record[1]; + + va_start(ap, MessageNumber); +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Recommneded by EndClean"); + while ((source = va_arg(ap, PVOID)) != NULL) { + + argLen = va_arg(ap, size_t); + + if (argLen > 0) { + + RtlCopyMemory( argsData, source, argLen ); + argsData += argLen; + } + } + + va_end(ap); + } + + return STATUS_SUCCESS; + + { + // + // Increment sequence number to indicate dropped message + // +drop_message: + PWDF_IFR_HEADER header; + header = (PWDF_IFR_HEADER) FxDriverGlobals->WdfLogHeader; + InterlockedIncrement(header->SequenceNumberPointer); + return STATUS_UNSUCCESSFUL; + } +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/fxtargetsshared.hpp b/sdk/lib/drivers/wdf/shared/targets/fxtargetsshared.hpp new file mode 100644 index 00000000000..2f1ab4dbcdf --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/fxtargetsshared.hpp @@ -0,0 +1,187 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + corepriv.hpp + +Abstract: + + This is the main driver framework. + +Author: + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#pragma once + +#if ((FX_CORE_MODE)==(FX_CORE_USER_MODE)) +#define FX_IS_USER_MODE (TRUE) +#define FX_IS_KERNEL_MODE (FALSE) +#elif ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#define FX_IS_USER_MODE (FALSE) +#define FX_IS_KERNEL_MODE (TRUE) +#endif + +extern "C" { +#include "mx.h" +} + +#include "FxMin.hpp" + + + +#include "wdfmemory.h" +#include "wdfrequest.h" +#include "wdfdevice.h" +#include "wdfWmi.h" +#include "wdfChildList.h" +#include "wdfpdo.h" +#include "wdffdo.h" +#include "wdfiotarget.h" +#include "wdfcontrol.h" +#include "wdfcx.h" +#include "wdfio.h" +#include "wdfqueryinterface.h" + +#include "FxIrpQueue.hpp" +#include "FxCallback.hpp" +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +#include "FxIrpUm.hpp" +#else if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) +#include "FxIrpKm.hpp" +#endif +#include "FxTransactionedList.hpp" + +#include "FxCollection.hpp" +#include "FxDeviceInitShared.hpp" +#include "FxDeviceToMxInterface.hpp" +#include "FxRequestContext.hpp" +#include "FxRequestContextTypes.h" +#include "FxRequestBase.hpp" +#include "FxRequestBuffer.hpp" +#include "IfxMemory.hpp" +#include "FxIoTarget.hpp" +#include "FxIoTargetRemote.hpp" +#include "FxIoTargetSelf.hpp" + + + + + + + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V1_11 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + ACCESS_MASK DesiredAccess; + + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // + // A zero value means exclusive access to the target. + // + ULONG ShareAccess; + + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG FileAttributes; + + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + ULONG CreateDisposition; + + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + PVOID EaBuffer; + + ULONG EaBufferLength; + + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + +} WDF_IO_TARGET_OPEN_PARAMS_V1_11, *PWDF_IO_TARGET_OPEN_PARAMS_V1_11; diff --git a/sdk/lib/drivers/wdf/shared/targets/general/fxiotarget.cpp b/sdk/lib/drivers/wdf/shared/targets/general/fxiotarget.cpp new file mode 100644 index 00000000000..57867b55d25 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/fxiotarget.cpp @@ -0,0 +1,2716 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTarget.cpp + +Abstract: + + This module implements the IO Target APIs + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + + +#include "..\FxTargetsShared.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoTarget.tmh" +#endif +} + +const PVOID FxIoTarget::m_SentRequestTag = (PVOID) 'lcnC'; + +FxIoTarget::FxIoTarget( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize + ) : + FxNonPagedObject(FX_TYPE_IO_TARGET, ObjectSize, FxDriverGlobals) +{ + Construct(); +} + +FxIoTarget::FxIoTarget( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USHORT ObjectSize, + __in USHORT WdfType + ) : + FxNonPagedObject(WdfType, ObjectSize, FxDriverGlobals) +{ + Construct(); +} + +VOID +FxIoTarget::Construct( + VOID + ) +{ + InitializeListHead(&m_SentIoListHead); + InitializeListHead(&m_IgnoredIoListHead); + + m_InStack = TRUE; + + m_State = WdfIoTargetStarted; + + m_WaitingForSentIo = FALSE; + m_Removing = FALSE; + m_AddedToDeviceList = FALSE; + + m_Driver = NULL; + m_InStackDevice = NULL; + m_TargetDevice = NULL; + m_TargetPdo = NULL; + m_TargetFileObject = NULL; + m_TargetStackSize = 0; + m_TargetIoType = WdfDeviceIoUndefined; + m_IoCount = 1; + m_DisposeEvent = NULL; + m_TransactionedEntry.SetTransactionedObject(this); + + m_PendedQueue.Initialize(this, _RequestCancelled); + + // + // We want to guarantee that the cleanup callback is called at passive level + // so the driver writer can override the automatic behavior the target uses + // when shutting down with i/o in progress. + // + MarkPassiveDispose(ObjectDoNotLock); + MarkDisposeOverride(ObjectDoNotLock); +} + +FxIoTarget::~FxIoTarget() +{ + ASSERT(IsListEmpty(&m_SentIoListHead)); + ASSERT(IsListEmpty(&m_IgnoredIoListHead)); + ASSERT(m_IoCount == 0); +} + +VOID +FxIoTarget::PrintDisposeMessage( + VOID + ) +/*++ + +Routine Description: + To prevent WPP from reporting incorrect module or line number if the + caller is an inline function we use this function to print the message + to the IFR. + +Arguments: + None + +Return Value: + None + + --*/ + +{ + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p, setting Dispose event %p", + GetObjectHandle(), m_DisposeEvent->GetEvent()); +} + +VOID +FxIoTarget::WaitForDisposeEvent( + VOID + ) +{ +#if (FX_CORE_MODE==FX_CORE_USER_MODE) + FxCREvent * event = m_DisposeEventUm.GetSelfPointer(); +#else + FxCREvent eventOnStack; + eventOnStack.Initialize(); + FxCREvent * event = eventOnStack.GetSelfPointer(); +#endif + + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + m_DisposeEvent = event; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p, Waiting on Dispose event %p", + GetObjectHandle(),m_DisposeEvent->GetEvent()); + + if (InterlockedDecrement(&m_IoCount) > 0) { + event->EnterCRAndWaitAndLeave(); + } + + m_DisposeEvent = NULL; + ASSERT(m_IoCount == 0); +} + + +BOOLEAN +FxIoTarget::Dispose( + VOID + ) +/*++ + +Routine Description: + Dispose is overridden so that the driver can have a chance to override the + default remove behavior for the target. By default, remove will cancel + all sent I/O and then wait for it to complete. For instance, if the driver + wants to wait for all i/o to complete rather then be canceled, a cleanup + callback should be registered on the target and the wait should be performed + there. + +Arguments: + None + +Return Value: + FALSE, indicating to the FxObject state machine *NOT* to call + + --*/ + +{ + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + if (m_AddedToDeviceList) { + // + // Remove the target from the list of targets that the device keeps track + // of. + // + ASSERT(m_DeviceBase != NULL); + m_DeviceBase->RemoveIoTarget(this); + } + + // + // + // Call all of the cleanup callbacks first + // + CallCleanup(); + + // + // Now cancel all sent i/o and shut the target down + // + Remove(); + + // + // By returning FALSE, the object state machine will not attempt to call + // cleanup again. + // + return FALSE; +} + +VOID +FxIoTarget::SubmitPendedRequest( + __in FxRequestBase* Request + ) +{ + ULONG action; + FxIrp* irp = NULL; + + irp = Request->GetSubmitFxIrp(); + action = Submit(Request, NULL, 0); + if (action & SubmitSend) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Sending Pended WDFREQUEST %p, Irp %p", + Request->GetTraceObjectHandle(), + irp->GetIrp()); + + Send(irp->GetIrp()); + } + + // + // If the request was not sent or pended (queued), complete it. + // + if ((action & (SubmitSend | SubmitQueued)) == 0) { + ASSERT(0 == action); + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Completing Pended WDFREQUEST %p, Irp %p, %!STATUS!", + Request->GetTraceObjectHandle(), irp->GetIrp(), irp->GetStatus()); + + // + // Fail the request. + // + ASSERT(!NT_SUCCESS(irp->GetStatus())); + irp->SetInformation(0); + + // + // This function updates the outstanding 'io count' value and + // decrement the ref count on Request. + // + HandleFailedResubmit(Request); + } + else { + // + // Submit() updated the 'io count' counter for request that got sent or + // queued. Note that the input request was already tracked via this + // counter, thus decrement its value. + // + DecrementIoCount(); + + // + // SubmitLocked will add another ref if it needs it. Release the + // reference taken when the request was pended. + // + // Release the reference after submitting it in case the request was deleted. + // If it was deleted, the reference taken by the target is the only keep + // it alive. + // + Request->RELEASE(this); + } +} + +VOID +FxIoTarget::SubmitPendedRequests( + __in PLIST_ENTRY RequestListHead + ) +{ + PLIST_ENTRY ple; + + while (!IsListEmpty(RequestListHead)) { + ple = RemoveHeadList(RequestListHead); + SubmitPendedRequest(FxRequestBase::_FromListEntry(ple)); + } +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::Start( + VOID + ) +{ + LIST_ENTRY head; + NTSTATUS status; + + InitializeListHead(&head); + + status = GotoStartState(&head); + + SubmitPendedRequests(&head); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p started status %!STATUS!", + GetHandle(),status); + return status; +} + +#define START_TAG ((PVOID) ('trtS')) + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::GotoStartState( + __in PLIST_ENTRY RequestListHead, + __in BOOLEAN Lock + ) +{ + FxRequestBase* pRequest; + NTSTATUS status; + KIRQL irql; + + irql = PASSIVE_LEVEL; + pRequest = NULL; + + ADDREF(START_TAG); + + if (Lock) { + FxIoTarget::Lock(&irql); + } + +CheckState: + if (m_State == WdfIoTargetDeleted) { + status = STATUS_INVALID_DEVICE_STATE; + } + else if (m_WaitingForSentIo) { + + PFX_DRIVER_GLOBALS pFxDriverGlobals = GetDriverGlobals(); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "WDFIOTARGET %p is being started while it is being stopped or " + "purged by another thread. WdfIoTargetStart and " + "WdfIoTargetStop/WdfIoTargetPurge must be called synchronously. " + "After the driver calls one of these functions, it must not call " + "the other function before the first one returns.", + GetObjectHandle()); + + if ((pFxDriverGlobals->IsVerificationEnabled(1, 11, OkForDownLevel)) && + (irql > PASSIVE_LEVEL)) { + + // + // We cannont wait for a previous stop to complete if we are at + // dispatch level + // + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + + // + // Wait for the stop code to complete + // + ASSERT(m_State == WdfIoTargetStopped || m_State == WdfIoTargetPurged); + + ASSERT(Lock); + Unlock(irql); + + WaitForSentIoToComplete(); + + // + // Go back and check our state again since we dropped the lock. + // + FxIoTarget::Lock(&irql); + goto CheckState; + } + else { + status = STATUS_SUCCESS; + } + + // + // Restart all of the pended i/o. + // + if (NT_SUCCESS(status)) { + m_State = WdfIoTargetStarted; + + m_WaitingForSentIo = FALSE; + m_SentIoEvent.Clear(); + + // + // TRUE - requests will be resent to the target, so attempt to claim + // cancelation ownership + // + DrainPendedRequestsLocked(RequestListHead, TRUE); + } + + if (Lock) { + Unlock(irql); + } + + RELEASE(START_TAG); + + return status; +} + +VOID +FxIoTarget::DrainPendedRequestsLocked( + __in PLIST_ENTRY RequestListHead, + __in BOOLEAN RequestWillBeResent + ) +{ + PMdIoCsqIrpContext pContext; + MdIrp pIrp; + FxIrp* pFxIrp = NULL; + pContext = NULL; + + while ((pIrp = m_PendedQueue.GetNextRequest(&pContext)) != NULL) { + FxRequestBase* pRequest; + BOOLEAN enqueue; + + enqueue = FALSE; + + // + // Each FxRequestBase on the pending list has a reference taken against + // it already. We will release the reference after we call Submit. + // + // After this call we are done with the m_CsqContext field. + // + pRequest = FxRequestBase::_FromCsqContext(pContext); + + // + // m_ListEntry and m_CsqContext are a union. Now that we are done with + // m_CsqContext, initialize it to be a valid list entry. + // + InitializeListHead(&pRequest->m_ListEntry); + + // + // Undo the affects of the IoSetNextIrpStackLocation made when we + // enqueued the request. We want to do this no matter if we can claim + // cancellation ownership of the request or not. + // + pFxIrp = pRequest->GetSubmitFxIrp(); + pFxIrp->SkipCurrentIrpStackLocation(); + + // + // Request is not longer pended. + // + ASSERT(pRequest->GetTargetFlags() & FX_REQUEST_PENDED); + pRequest->ClearTargetFlags(FX_REQUEST_PENDED); + + if (RequestWillBeResent) { + // + // Make sure timer callback is not about to run. After the call + // below the timer was successfully canceled or the timer callback + // already run. + // + if (pRequest->CancelTimer()) { + // + // Try to claim cancellation (*) ownership of the request. + // CanComplete() decrements the irp completion ref count and + // whomever decrements to zero owns the request. Ownership in + // this case is resubmission as well as completion (as the name + // of the function implies). + // + // (*) - cancellation as defined by WDF and the myriad of + // functions which are calling FxRequestBase::Cancel(). + // By this point we have already removed the cancellation + // routine by calling m_PendedQueue.GetNextRequest() + // + if (pRequest->CanComplete()) { + + enqueue = TRUE; + } + } + + if (FALSE == enqueue) { + // + // Some other thread is responsible for canceling this request. + // We are assuming here that the other thread will complete it + // in that thread because we are no longer tracking this request + // in any of our lists. + // + pRequest->m_Irp.SetStatus(STATUS_CANCELLED); + + // + // Mark that the request has been completed so that if the other + // thread is the timer DPC, it will handle the case properly and + // complete the request. + // + ASSERT((pRequest->GetTargetFlags() & FX_REQUEST_COMPLETED) == 0); + pRequest->SetTargetFlags(FX_REQUEST_COMPLETED); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, WDFREQUEST %p is being canceled on another thread," + " allowing other thread to complete request, not resending", + GetObjectHandle(), pRequest->GetTraceObjectHandle()); + } + } + else { + // + // The caller is going to attempt to complete the requests. To make + // the caller's life easier and let it reuse RequestCompletionRoutine, + // to handle the completion semantics, keep the completion reference + // count != 0 and return the request back to the caller. + // + enqueue = TRUE; + } + + if (enqueue) { + ClearCompletedRequestVerifierFlags(pRequest); + InsertTailList(RequestListHead, &pRequest->m_ListEntry); + } + + pContext = NULL; + } +} + +VOID +FxIoTarget::CompletePendedRequest( + __in FxRequestBase* Request + ) +{ + // + // This will attempt to claim cancelation ownership and call the + // request's completion routine. + // + FailPendedRequest(Request, STATUS_WDF_DEVICE_REMOVED_NOT_SENT); +} + +VOID +FxIoTarget::CompletePendedRequestList( + __in PLIST_ENTRY RequestListHead + ) +{ + PLIST_ENTRY ple; + + while (!IsListEmpty(RequestListHead)) { + ple = RemoveHeadList(RequestListHead); + InitializeListHead(ple); + CompletePendedRequest(FxRequestBase::_FromListEntry(ple)); + } +} + +VOID +FxIoTarget::_CancelSentRequest( + __in FxRequestBase* Request + ) +{ + // + // Attempt to cancel the request + // + Request->Cancel(); + + // + // Release the reference taken by GetSentRequestsListLocked + // + Request->RELEASE(m_SentRequestTag); +} + +VOID +FxIoTarget::_CancelSentRequests( + __in PSINGLE_LIST_ENTRY RequestListHead + ) +/*++ + +Routine Description: + Cancels all FxRequestBases in RequestListHead + +Arguments: + RequestListHead - List head containing the requests + +Return Value: + None. + + --*/ +{ + PSINGLE_LIST_ENTRY ple; + + while (RequestListHead->Next != NULL) { + ple = PopEntryList(RequestListHead); + + // + // Set the Next pointer back to NULL so that if it is reinserted into a + // cancel list, it will not point to unknown pool. + // + ple->Next = NULL; + + _CancelSentRequest(FxRequestBase::_FromDrainEntry(ple)); + } +} + +VOID +FxIoTarget::GetSentRequestsListLocked( + __in PSINGLE_LIST_ENTRY RequestListHead, + __in PLIST_ENTRY SendList, + __out PBOOLEAN AddedToList + ) +{ + PLIST_ENTRY ple; + + *AddedToList = IsListEmpty(SendList) ? FALSE : TRUE; + + // + // Since we are inserting into the head of the single list head, if we walked + // over the list from first to last, we would reverse the entries. By walking + // the list backwards, we build the single list head in the order of SendList. + // + for (ple = SendList->Blink; ple != SendList; ple = ple->Blink) { + FxRequestBase* pRequest; + + pRequest = FxRequestBase::_FromListEntry(ple); + + // + // Add a reference since the request will be touched outside of the + // lock being held. + // + pRequest->ADDREF(m_SentRequestTag); + + // + // Add the request at the head of the list. + // + pRequest->m_DrainSingleEntry.Next = RequestListHead->Next; + RequestListHead->Next = &pRequest->m_DrainSingleEntry; + } +} + +VOID +FxIoTarget::GotoStopState( + __in WDF_IO_TARGET_SENT_IO_ACTION Action, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ) +/*++ + +Routine Description: + Accumulates all pending I/O for cancelling out of this function if + RequestListHead != NULL. + +Arguments: + + +Return Value: + + --*/ + +{ + KIRQL irql; + BOOLEAN getSentList, wait, added; + + getSentList = FALSE; + wait = FALSE; + irql = PASSIVE_LEVEL; + + if (LockSelf) { + Lock(&irql); + } + + // + // The following transitions are allowed: + // (1) Started -> Stopped + // (2) Purged -> Stopped + // (3) Stopped -> Stopped + // + // A Stopped -> Stopped transition + // is feasible if the previous stop left all pending i/o and the current + // stop wants to cancel all i/o. + // + if (m_State == WdfIoTargetStarted || m_State == WdfIoTargetPurged) { + m_State = WdfIoTargetStopped; + } + else if (m_State != WdfIoTargetStopped) { + // + // Stopping in any state other then stopped or started is not fatal, + // but should be logged. + // + + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p stopped, but it is currently in the " + "%!WDF_IO_TARGET_STATE! state, not started or stopped", + GetHandle(), m_State); + } + + switch (Action) { + case WdfIoTargetCancelSentIo: + getSentList = TRUE; + // || || Drop through || || + // \/ \/ \/ \/ + + case WdfIoTargetWaitForSentIoToComplete: + if (IsListEmpty(&m_SentIoListHead)) { + // + // By using m_WaitingForSentIo as value for wait, we can handle the + // case where GotoStopState is called when we are already in the + // stopping case (in which case we would have drained + // m_SendIoListHead already). + // + wait = m_WaitingForSentIo; + + if (m_WaitingForSentIo) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "WDFIOTARGET %p is already in the process of being stopped " + "or purged from another thread. Driver must wait for the " + "first WdfIoTargetStop or WdfIoTargetPurge to complete " + "before calling it again.", + GetObjectHandle()); + } + } + else { + wait = TRUE; + + if (getSentList) { + // + // Ignore the assignment to added since we have already computed + // if we need to wait or not. + // + GetSentRequestsListLocked(SentRequestListHead, + &m_SentIoListHead, + &added); + } + } + + break; + + case WdfIoTargetLeaveSentIoPending: + wait = FALSE; + break; + } + + m_WaitingForSentIo = wait; + *Wait = wait; + + if (wait) { + // + // If Stop(leave sent io pending) was previously called, m_SentIoEvent + // will be in the signalled state. We need to wait for sent i/o to be + // completed, so make sure it is not signalled while holding the lock + // + m_SentIoEvent.Clear(); + } + else { + // + // Even though *Wait is set to FALSE, the caller may wait anyways + // if it is aggregating targets to move into the stopped state and + // wait on them all. + // + m_SentIoEvent.Set(); + } + + if (LockSelf) { + Unlock(irql); + } +} + +VOID +FxIoTarget::Stop( + __in WDF_IO_TARGET_SENT_IO_ACTION Action + ) +{ + SINGLE_LIST_ENTRY head; + BOOLEAN wait; + + head.Next = NULL; + wait = FALSE; + + GotoStopState(Action, &head, &wait, TRUE); + + if (head.Next != NULL) { + _CancelSentRequests(&head); + } + + if (wait) { + KIRQL irql; + + // + // Under the lock, if wait is set, m_WaitingForSentIo is true, but once + // we drop the lock, all pended i/o could have already been canceled + // and m_WaitingForSentIo is FALSE at this point. + // + // ASSERT(m_WaitingForSentIo); + + WaitForSentIoToComplete(); + + // + // Mark that we are no longer stopping and waiting for i/o to complete. + // + Lock(&irql); + m_WaitingForSentIo = FALSE; + Unlock(irql); + } + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p stopped ",GetHandle()); +} + +VOID +FxIoTarget::GotoPurgeState( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ) +/*++ + +Routine Description: + Accumulates all pending and sent I/O. The I/O target is moved into + the 'purged' state. + +Arguments: + + +Return Value: + + --*/ + +{ + KIRQL irql; + BOOLEAN wait, added; + + wait = FALSE; + irql = PASSIVE_LEVEL; + + if (LockSelf) { + Lock(&irql); + } + + // + // The following transitions are allowed: + // (1) Started -> Purged + // (2) Stop -> Purged + // (3) Purged -> Purged + // + // A Purged -> Purged transition is feasible if the previous purge didn't + // wait for pending i/o to complete and the current purge wants to wait + // for them. + // + if (m_State == WdfIoTargetStarted || m_State == WdfIoTargetStopped) { + m_State = WdfIoTargetPurged; + } + else if (m_State != WdfIoTargetPurged) { + // + // Purging in any state other then purged or started is not fatal, + // but should be logged. + // + + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p purged, but it is currently in the " + "%!WDF_IO_TARGET_STATE! state, not started, stopped or purged", + GetHandle(), m_State); + } + + // + // FALSE - requests will not be resent to the target. As such, + // cancellation ownership will not be claimed b/c the request + // will subsequently be passed to FailPendedRequest. + // + DrainPendedRequestsLocked(PendedRequestListHead, FALSE); + + GetSentRequestsListLocked(SentRequestListHead, + &m_SentIoListHead, + &added); + + switch (Action) { + case WdfIoTargetPurgeIoAndWait: + if (added == FALSE) { + // + // By using m_WaitingForSentIo as value for wait, we can handle the + // case where GotoPurgeState is called when we are already in the + // purging case (in which case we would have drained + // m_SendIoListHead already). + // + wait = m_WaitingForSentIo; + + if (m_WaitingForSentIo) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p is already in the process of being purged " + "or stopped from another thread. Driver must wait for the " + "first WdfIoTargetPurge or WdfIoTargetStop to complete " + "before calling it again.", + GetObjectHandle()); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + else { + wait = TRUE; + } + break; + + case WdfIoTargetPurgeIo: + wait = FALSE; + break; + } + + m_WaitingForSentIo = wait; + *Wait = wait; + + if (wait) { + // + // If Stop/Purge(don't wait) was previously called, m_SentIoEvent + // will be in the signalled state. We need to wait for sent i/o to be + // completed, so make sure it is not signalled while holding the lock + // + m_SentIoEvent.Clear(); + } + else { + // + // Even though *Wait is set to FALSE, the caller may wait anyways + // if it is aggregating targets to move into the purged state and + // wait on them all. + // + m_SentIoEvent.Set(); + } + + if (LockSelf) { + Unlock(irql); + } +} + +VOID +FxIoTarget::Purge( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action + ) +{ + LIST_ENTRY pendedHead; + SINGLE_LIST_ENTRY sentHead; + BOOLEAN wait; + + InitializeListHead(&pendedHead); + sentHead.Next = NULL; + wait = FALSE; + + GotoPurgeState(Action, &pendedHead, &sentHead, &wait, TRUE); + + // + // Complete any requests we might have pulled off of our lists + // + CompletePendedRequestList(&pendedHead); + _CancelSentRequests(&sentHead); + + if (wait) { + KIRQL irql; + + // + // Under the lock, if wait is set, m_WaitingForSentIo is true, but once + // we drop the lock, all pended i/o could have already been canceled + // and m_WaitingForSentIo is FALSE at this point. + // + // ASSERT(m_WaitingForSentIo); + + WaitForSentIoToComplete(); + + // + // Mark that we are no longer purging and waiting for i/o to complete. + // + Lock(&irql); + m_WaitingForSentIo = FALSE; + Unlock(irql); + } + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p purged ",GetHandle()); +} + +VOID +FxIoTarget::GotoRemoveState( + __in WDF_IO_TARGET_STATE NewState, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __in BOOLEAN Lock, + __out PBOOLEAN Wait + ) +{ + KIRQL irql; + BOOLEAN sentAdded, ignoredAdded; + + irql = PASSIVE_LEVEL; + + if (Lock) { + this->Lock(&irql); + } + + if (m_WaitingForSentIo) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "WDFIOTARGET %p is being deleted while it is being stopped/purged " + "by another thread. Driver must wait for WdfIoTargetStop or " + "WdfIoTargetPurge to complete before deleting the object.", + GetObjectHandle()); + + ASSERT(Lock); + + Unlock(irql); + WaitForSentIoToComplete(); + this->Lock(&irql); + + ASSERT(m_WaitingForSentIo == FALSE); + } + + *Wait = FALSE; + m_State = NewState; + + // + // FALSE - requests will not be resent to the target. As such, + // cancellation ownership will not be claimed b/c the request + // will subsequently be passed to FailPendedRequest. + // + DrainPendedRequestsLocked(PendedRequestListHead, FALSE); + + // + // Now cancel all of the sent I/O since we are being removed for good. + // + if (NewState == WdfIoTargetDeleted || NewState == WdfIoTargetClosed || + NewState == WdfIoTargetClosedForQueryRemove) { + // + // If the caller is aggregating calls to GotoRemoveState among many + // targets (for instance, WDFUSBDEVICE will do this over its WDFUSBPIPEs + // on remove), we cannot use the state of SentRequestListHead after these + // two calls as a test to see if any requests are being canceled (and the + // diff between removing and removed). Instead, we rely on the added + // state returned by each call. + // + GetSentRequestsListLocked(SentRequestListHead, + &m_SentIoListHead, + &sentAdded); + GetSentRequestsListLocked(SentRequestListHead, + &m_IgnoredIoListHead, + &ignoredAdded); + + if (sentAdded || ignoredAdded) { + // + // We will have to wait for the i/o to come back. As such, we are + // in the transition state and must wait for it to complete. In this + // transitionary stage, I/O can still be sent if they are marked to + // ignore the target state. + // + m_Removing = TRUE; + *Wait = TRUE; + + // + // If Stop(leave sent io pending) or Purge(do-not-wait) was + // previously called, m_SentIoEvent will be in the signalled state. + // We need to wait for sent i/o to be completed, so make sure it + // is not signalled while hodling the lock + // + m_SentIoEvent.Clear(); + } + else { + ClearTargetPointers(); + + // + // Even though *Wait is set to FALSE, the caller may wait anyways + // if it is aggregating targets to move into the remove state and + // wait on all of them. + // + m_SentIoEvent.Set(); + } + } + + if (Lock) { + Unlock(irql); + } + + return; +} + +VOID +FxIoTarget::Remove( + VOID + ) +{ + SINGLE_LIST_ENTRY sentHead; + LIST_ENTRY pendedHead; + BOOLEAN wait; + + sentHead.Next = NULL; + InitializeListHead(&pendedHead); + + GotoRemoveState(WdfIoTargetDeleted, + &pendedHead, + &sentHead, + TRUE, + &wait); + + // + // Complete any requests we might have pulled off of our lists + // + CompletePendedRequestList(&pendedHead); + _CancelSentRequests(&sentHead); + + if (wait) { + ASSERT(m_State == WdfIoTargetDeleted); + + WaitForSentIoToComplete(); + } + + WaitForDisposeEvent(); + + return; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::QueryInterface( + __inout FxQueryInterfaceParams* Params + ) +{ + switch (Params->Type) { + case FX_TYPE_IO_TARGET: + *Params->Object = (FxIoTarget*) this; + break; + default: + return __super::QueryInterface(Params); + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::Init( + __in CfxDeviceBase* Device + ) +{ + NTSTATUS status; + + status = InitModeSpecific(Device); + if (!NT_SUCCESS(status)) { + return status; + } + + SetDeviceBase(Device); + MxDeviceObject deviceObject; + + m_InStackDevice = Device->GetDeviceObject(); + + // + // Note that AttachedDevice can be NULL for UMDF for + // example when there is only one device in the stack. + // + m_TargetDevice = GetTargetDeviceObject(Device); + m_TargetPdo = Device->GetPhysicalDevice(); + + m_Driver = Device->GetDriver(); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (m_InStackDevice == NULL || m_Driver == NULL || + m_TargetDevice == NULL || m_TargetPdo == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Init WDFIOTARGET %p, unexpected NULL, m_InStackDevice %p, " + "m_TargetDevice %p, m_TargetPdo %p, m_Driver %p", + GetObjectHandle(), m_InStackDevice, m_TargetDevice, m_TargetPdo, + m_Driver); + + return STATUS_UNSUCCESSFUL; + } +#else + if (m_InStackDevice == NULL || m_Driver == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Init WDFIOTARGET %p, unexpected NULL, m_InStackDevice %p, " + "m_Driver %p", + GetObjectHandle(), m_InStackDevice, m_Driver); + + return STATUS_UNSUCCESSFUL; + } +#endif + + // + // For UMDF the target device can be NULL if there is only one driver in the + // stack. In that case m_TargetStackSize retains its initial value (0). + // + if (m_TargetDevice != NULL) { + deviceObject.SetObject(m_TargetDevice); + + m_TargetStackSize = deviceObject.GetStackSize(); + + m_TargetIoType = GetTargetIoType(); + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FX_VF_METHOD(FxIoTarget, VerifySubmitLocked) ( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ FxRequestBase* Request + ) +{ + NTSTATUS status = STATUS_SUCCESS; + KIRQL irql; + SHORT flags; + FxIrp* irp; + + PAGED_CODE_LOCKED(); + + irp = Request->GetSubmitFxIrp(); + Request->Lock(&irql); + flags = Request->GetVerifierFlagsLocked(); + + if ((flags & FXREQUEST_FLAG_FORMATTED) == 0x0) { + status = STATUS_REQUEST_NOT_ACCEPTED; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p has not been formatted, cannot send, %!STATUS!", + Request->GetTraceObjectHandle(), status); + } + else if (flags & FXREQUEST_FLAG_SENT_TO_TARGET) { + // + // Technically this is the same check as m_IrpCompletionReferenceCount + // above, but we make this check in many more locations. + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p is already pending on a WDFIOTARGET", + Request->GetTraceObjectHandle()); + + FxVerifierBugCheck(FxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_REQUEST_ALREADY_SENT, + (ULONG_PTR) Request->GetHandle()); + } + else if (HasEnoughStackLocations(irp) == FALSE) { + status = STATUS_REQUEST_NOT_ACCEPTED; + + // + // For reasons why we subtract 1 from CurrentLocation, see comments + // in FxIoTarget::HasEnoughStackLocations. + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p, PIRP %p does not have enough stack locations %d" + " for this WDFIOTARGET %p (requires %d locations), %!STATUS!", + Request->GetTraceObjectHandle(), irp->GetIrp(), irp->GetCurrentIrpStackLocationIndex() - 1, + GetHandle(), m_TargetStackSize, status); + } + + Request->Unlock(irql); + return status; +} + +ULONG +FxIoTarget::SubmitLocked( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options, + __in ULONG Flags + ) +/*++ + +Routine Description: + Core processing logic for submitting a request. Will return the send flag + if the request can be submitted immediately. If the flag is not returned, + the pended flag may be set. If neither are set, status in the Request will + be set with the error. + + NTSTATUS status; + ULONG action; + + Lock(); + action |= SubmitLocked(...); + UnLock(); + + if (action & Send) { + // IoCallDriver .... + } + else if (action & Pended) { + // request was pended + } + + return ...; + +Arguments: + Request - The request that will be submitted to the target + + Options - send options associated with the request being sent + + Flags - Additional flags to control how the request is being sent + +Return Value: + A bit field whose flags are defined by SubmitActionFlags + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + ULONG action; + BOOLEAN startTimer, stateIgnored, verify; + BOOLEAN addedRef; + FxIrp* irp; + + pFxDriverGlobals = GetDriverGlobals(); + + action = 0; + startTimer = FALSE; + stateIgnored = FALSE; + addedRef = FALSE; + + // + // If the reference count is not zero, the irp has not completed and the + // driver is reusing it before it has returned to the driver. Not good! + // + ASSERT(Request->m_IrpCompletionReferenceCount == 0); + if (Request->m_IrpCompletionReferenceCount != 0) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p already sent to a target", + Request->GetTraceObjectHandle()); + + // + // Last ditch assert + // + ASSERT((Request->GetTargetFlags() & FX_REQUEST_PENDED) == 0); + + // no return + FxVerifierBugCheck(pFxDriverGlobals, + WDF_REQUEST_FATAL_ERROR, + WDF_REQUEST_FATAL_ERROR_REQUEST_ALREADY_SENT, + (ULONG_PTR) Request->GetHandle()); + } + + irp = Request->GetSubmitFxIrp(); + + if (pFxDriverGlobals->FxVerifierOn && + pFxDriverGlobals->FxVerifierIO) { + + verify = TRUE; + status = VerifySubmitLocked(pFxDriverGlobals, Request); + if (!NT_SUCCESS(status)){ + goto Done; + } + } + else { + verify = FALSE; + } + + // + // if WDF_REQUEST_SEND_OPTION_TIMEOUT is set, Options != NULL + // + if ((Flags & WDF_REQUEST_SEND_OPTION_TIMEOUT) && Options->Timeout != 0) { + // + // Create the timer under the lock + // + status = Request->CreateTimer(); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFREQUEST %p, could not create timer, %!STATUS!", + Request->GetTraceObjectHandle(), status); + + goto Done; + } + + startTimer = TRUE; + } + + if (Flags & WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE) { + // + // If we are in the deleted or closed state, we must be in the transitioning + // state to allow I/O at this time. For any other state, always allow + // the i/o to go through. + // + if ((m_State == WdfIoTargetDeleted || + m_State == WdfIoTargetClosed || + m_State == WdfIoTargetClosedForQueryRemove) && + m_Removing == FALSE) { + // + // The target is truly closed or removed, it is not in the + // transitionary state. We don't allow I/O anymore. + // + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p state %!WDF_IO_TARGET_STATE!, sending " + "WDFREQUEST %p cannot ignore current state, %!STATUS!", + GetObjectHandle(), m_State, Request->GetTraceObjectHandle(), + status); + + goto Done; + } + else { + action |= SubmitSend; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "ignoring WDFIOTARGET %p state, sending WDFREQUEST %p, state " + "%!WDF_IO_TARGET_STATE!", + GetObjectHandle(), Request->GetTraceObjectHandle(), m_State); + + Request->SetTargetFlags(FX_REQUEST_IGNORE_STATE); + + status = STATUS_SUCCESS; + stateIgnored = TRUE; + } + } + else { + switch (m_State) { + case WdfIoTargetStarted: + status = STATUS_SUCCESS; + action |= SubmitSend; + break; + + case WdfIoTargetStopped: + if (Flags & WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND) { + status = STATUS_INVALID_DEVICE_STATE; + goto Done; + } + else { + status = STATUS_WDF_QUEUED; + action |= SubmitQueued; + } + break; + + case WdfIoTargetClosedForQueryRemove: + case WdfIoTargetClosed: + case WdfIoTargetDeleted: + case WdfIoTargetPurged: + default: + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "failing WDFREQUEST %p, WDFIOTARGET %p not accepting requests, " + "state %!WDF_IO_TARGET_STATE!", Request->GetTraceObjectHandle(), + GetObjectHandle(), m_State); + + status = STATUS_INVALID_DEVICE_STATE; + goto Done; + } + } + + // + // Make sure the list entry is initialized so if we call RemoveEntryList + // later, we don't corrupt whatever Flink and Blink point to. + // + InitializeListHead(&Request->m_ListEntry); + + ASSERT(((action & SubmitSend) || (action & SubmitQueued)) && NT_SUCCESS(status)); + +Done: + if (NT_SUCCESS(status)) { + // + // Request should not be pended + // + ASSERT((Request->GetTargetFlags() & FX_REQUEST_PENDED) == 0); + + // + // Set m_Target before setting the reference count to one because as soon + // as it is set to 1, it can be decremented to zero and then it will + // assume that m_Target is valid. + // + Request->SetTarget(this); + + // + // Assume we are successful, we will adjust this value in case of error. + // + IncrementIoCount(); + + // + // All paths which are pulling the request off of the list must use this + // specific tag. This would include the cancel, timer, and completion + // routines. + // + // We don't add a reference in the error case because the caller + // will just complete the request back to the caller (for a queue + // presented request) or free it (for a driver created request). + // + // This released at the end of FxRequestBase::CompleteSubmitted + // + Request->ADDREF(this); + + // + // In case of error, we use this flag to know if the IoCount and + // RequestRef need to be rolled back. + // + addedRef = TRUE; + + // + // Set the reference count to one. This reference count guards prevents + // Request::Cancel from touching an invalid PIRP outside of any lock. + // + Request->m_IrpCompletionReferenceCount = 1; + + if (Request->m_Canceled) { + // + // CanComplete() decrements the count that was set above. If the + // count goes to zero, CanComplete() returns TRUE and + // FxRequestBase::Cancel will not touch the irp. If it returns + // FALSE, we indicate that the request was sent, in actuality we + // don't send the request b/c FxRequestBase::Cancel will call + // CompleteCanceledRequest, where the irp will complete. + // + if (Request->CanComplete()) { + // + // This thread owns the irp. Set the status to !NT_SUCCESS and + // clear any actions we indicate to the caller. + // + action = 0; + } + else { + // + // There is still an reference count on the completion count, + // let the other thread complete it. + // + + // + // Make the caller think that the request was queued. By doing + // this, it will not attempt to call IoCallDriver. SubmitSend + // will be cleared after jump to Done: and evaluate status. + // + action |= SubmitQueued; + } + + // + // Either way, we want to set STATUS_CANCELLED in the PIRP when we + // are done. + // + status = STATUS_CANCELLED; + + // + // Just jump to the end and avoid any more compares. + // + goto CheckError; + } + + if (action & SubmitSend) { + if (stateIgnored) { + InsertTailList(&m_IgnoredIoListHead, &Request->m_ListEntry); + } + else { + // + // Keep track of the request so that we can cancel it later if needed + // + InsertTailList(&m_SentIoListHead, &Request->m_ListEntry); + } + + // + // We know we are going to send the request, set the completion + // routine now. Since IoSetCompletionRoutineEx allocates memory + // which is only freed when the completion routine is called when + // the request is completing, we can only set the CR when we *KNOW* + // the request will be sent, ie SubmitSend is set and returned to + // the caller. + // + SetCompletionRoutine(Request); + + // + // NOTE: No need to reference the file object before we drop the lock + // because will not deref the file object while there is outstanding + // I/O. + // + } + else { + status = PendRequestLocked(Request); + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "Pending WDFREQUEST %p, WDFIOTARGET %p is paused, %!STATUS!", + Request->GetTraceObjectHandle(), GetObjectHandle(), status); + + if (!NT_SUCCESS(status)) { + // + // CanComplete() decrements the count that was set above. If the + // count goes to zero, CanComplete() returns TRUE and + // FxRequestBase::Cancel will not touch the irp. If it returns + // FALSE, we indicate that the request was sent, in actuality we + // don't send the request b/c FxRequestBase::Cancel will call + // CompleteCanceledRequest, where the irp will complete. + // + if (Request->CanComplete()) { + // + // This thread owns the irp. + // Clear any actions we indicate to the caller. + // + action = 0; + } + else { + // + // The cancel/timer routine (whoever has ownership of + // request) will complete the request. + // + ASSERT(action & SubmitQueued); + DO_NOTHING(); + } + } + } + + if (NT_SUCCESS(status)) { + // + // Delay starting the timer to the last possible moment where we know + // there will be no error and we don't have to deal with any cancel + // logic in the error case. + // + if (startTimer) { + ASSERT(action & (SubmitSend | SubmitQueued)); + + // + // Set the timer under the lock + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Starting timer on WDFREQUEST %p", + Request->GetTraceObjectHandle()); + + Request->StartTimer(Options->Timeout); + } + } + } + +CheckError: + // + // Not an else clause to the if (NT_SUCCESS(status)) above b/c status can + // be changed within the NT_SUCCESS(status) clause. + // + if (!NT_SUCCESS(status)) { + irp->SetStatus(status); + action &= ~SubmitSend; + } + else if (verify) { + Request->SetVerifierFlags(FXREQUEST_FLAG_SENT_TO_TARGET); + } + + // + // Keep the IoCount and Request->AddRef() only if the request is going + // to be sent, or it is queued, or another thread took ownership of its + // cancellation. + // + if (addedRef && (action & (SubmitSend | SubmitQueued)) == 0) { + Request->RELEASE(this); + DecrementIoCount(); + } + + return action; +} + +ULONG +FxIoTarget::Submit( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options, + __in_opt ULONG Flags + ) +{ + ULONG result; + KIRQL irql; + + Lock(&irql); + result = SubmitLocked(Request, Options, Flags); + Unlock(irql); + + return result; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::SubmitSync( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options, + __out_opt PULONG Action + ) +{ + FxTargetSubmitSyncParams params = {0}; + LONGLONG timeout; + ULONG action; + NTSTATUS status; + KIRQL irql; + BOOLEAN clearContext; + + status = STATUS_SUCCESS; + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, WDFREQUEST %p", + GetObjectHandle(), Request->GetTraceObjectHandle()); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + // + // FxCREvent events needs to be initiliazed in UMDF, and failure handled + // gracefully. For KMDF, it will result in double initialization which is + // not a problem. Note that for KMDF, FxCREvent->Initialize will never fail. + // + status = params.SynchEvent.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize sync event for " + "WDFIOTARGET %p, WDFREQUEST %p", + GetObjectHandle(), Request->GetTraceObjectHandle()); + if (Action != NULL) { + *Action = 0; + } + return status; + } +#endif + + clearContext = Request->ShouldClearContext(); + + if (Action != NULL) { + action = *Action; + } + else { + action = 0; + } + + if (Options != NULL && + (Options->Flags & WDF_REQUEST_SEND_OPTION_TIMEOUT) && + Options->Timeout != 0) { + // + // If this flag is set, SubmitLocked will start a timer, which we don't + // want because we will timeout the I/O using KeWaitForSingleObject. + // + // params.Constraints &= ~WDF_REQUEST_SEND_OPTION_TIMEOUT; + timeout = Options->Timeout; + action |= SubmitTimeout; + } + + // + // Must set the completion routine before calling Submit() so that in the + // pended or sent case, the completion routine is set in place during + // cancelation or delayed completion. + // + if (action & SubmitSyncCallCompletion) { + params.OrigTargetCompletionContext = Request->m_TargetCompletionContext; + params.OrigTargetCompletionRoutine = + Request->m_CompletionRoutine.m_Completion; + } + else { + params.OrigTargetCompletionContext = NULL; + params.OrigTargetCompletionRoutine = NULL; + } + + Request->SetCompletionRoutine(_SyncCompletionRoutine, ¶ms); + + // + // SubmitLocked will return whether the request should be sent *right now*. + // If SubmitSend is clear, SubmitQueued must be checked. If set, then + // the request was queued, otherwise, the request has failed and the + // status was already set in the irp. + // + // Clear the WDF_REQUEST_SEND_OPTION_TIMEOUT flag so that SumbitLocked doesn't + // try to allocate a timer + // + action |= Submit( + Request, + Options, + (Options != NULL) ? (Options->Flags & ~WDF_REQUEST_SEND_OPTION_TIMEOUT) : 0); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p, Action 0x%x", Request->GetTraceObjectHandle(), + action); + + // + // Add reference so that if we call Request->Cancel(), Request is still + // a valid object in between the wait timeout and the cancel call if + // request completes before Cancel is called. + // + Request->ADDREF(&status); + + if (action & SubmitSend) { + action |= SubmitSent; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Sending WDFREQUEST %p, Irp %p", Request->GetTraceObjectHandle(), + Request->GetSubmitIrp()); + + Send(Request->GetSubmitIrp()); + + // + // We always wait, even in the synchronous case. We do this because + // even though the WDM completion routine ran synchronously in this + // thread, the WDF processing of the completion could have been post- + // poned by another thread attempting to cancel the I/O. The postpone- + // ment would occur when the canceling thread has an oustanding reference + // on m_IrpCompletionReferenceCount, which would cause the call to + // CanComplete() in RequestCompletionRoutine() to return FALSE and not + // call _SyncCompletionRoutine in the context of the WDM completion + // routine, but in the context of the canceling thread. + // + action |= SubmitWait; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + else if (action & SubmitQueued) { + // + // To the caller, we say we sent the request (and all the cancel + // semantics of a sent request still work). + // + action |= (SubmitSent | SubmitWait); + } + else if (action & SubmitSyncCallCompletion) { + // + // The request was not sent nor queued, reset the completion routine + // since we overwrote it. + // + Request->m_TargetCompletionContext = params.OrigTargetCompletionContext; + Request->m_CompletionRoutine.m_Completion = + params.OrigTargetCompletionRoutine; + ASSERT(!NT_SUCCESS(Request->GetSubmitFxIrp()->GetStatus())); + } + + if (action & SubmitSent) { + if (action & SubmitWait) { + status = params.SynchEvent.EnterCRAndWaitAndLeave( + (action & SubmitTimeout) ? &timeout : NULL + ); + + if (status == STATUS_TIMEOUT) { + // + // By setting FX_REQUEST_CANCELLED_FROM_TIMER, we match the + // async timer behavior where we change the completion status + // from STATUS_CANCELLED to STATUS_IO_TIMEOUT. + // + Lock(&irql); + Request->SetTargetFlags(FX_REQUEST_CANCELLED_FROM_TIMER); + Unlock(irql); + + Request->Cancel(); + + params.SynchEvent.EnterCRAndWaitAndLeave(); + } + } + + status = params.Status; + } + else { + status = Request->GetSubmitFxIrp()->GetStatus(); + } + + Request->RELEASE(&status); + + if (Action != NULL) { + *Action = action; + } + + if (clearContext) { + Request->ContextReleaseAndRestore(); + } + + return status; +} + +VOID +FxIoTarget::FailPendedRequest( + __in FxRequestBase* Request, + __in NTSTATUS Status + ) +/*++ + +Routine Description: + Completes a request that has failed due to timer expiration or cancellation. + +Assumes: + Assumes that the caller has undone the effects of the + IoSetNextIrpStackLocation made when we enqueued the request. + +Arguments: + Request - request that failed + + Status - the status to set in the request + + TakeReference - add a reference before completing the request + +Return Value: + None. + + --*/ +{ + FxIrp* irp; + + irp = Request->GetSubmitFxIrp(); + + // + // Simulate failure in the IRP + // + irp->SetStatus(Status); + irp->SetInformation(0); + + // + // Manaully process the irp as if it has completed back from the target. + // + RequestCompletionRoutine(Request); +} + +BOOLEAN +FxIoTarget::RemoveCompletedRequestLocked( + __in FxRequestBase* Request + ) +/*++ + +Routine Description: + Removes a previously sent request from the bookkeeping structures + +Arguments: + Request - The request being completed + +Assumes: + This object's Lock is being held by the caller. + +Return Value: + TRUE if the m_SentIoEvent should be set after the caller has released the + object lock. + + --*/ +{ + ULONG oldFlags; + + // + // We will decrement the pending io count associated with this completed + // request in FxIoTarget::CompleteRequest + // + // DecrementPendingIoCount(); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, WDFREQUEST %p", GetObjectHandle(), + Request->GetTraceObjectHandle()); + + RemoveEntryList(&Request->m_ListEntry); + + // + // The request expects not to be on a list when it is destroyed. + // + InitializeListHead(&Request->m_ListEntry); + + // + // By the time we get here, there should never ever be a timer set for the + // request. + // + ASSERT((Request->GetTargetFlags() & FX_REQUEST_TIMER_SET) == 0); + + // + // Clear flags that may have been set previously. + // + oldFlags = Request->ClearTargetFlags(FX_REQUEST_COMPLETED | + FX_REQUEST_TIMER_SET | + FX_REQUEST_CANCELLED_FROM_TIMER | + FX_REQUEST_IGNORE_STATE); + + ClearCompletedRequestVerifierFlags(Request); + + // + // If we are removing, we must wait for *ALL* requests that were sent down + // the stack. + // + // If we are stopping, we only wait for i/o which do not ignore state + // + // NOTE: if we are completing a request which was inserted onto a list + // Cancel()'ed before SubmitLocked was called and the Cancel() + // thread already had a completion reference taken we are going to + // evaluate a state transition even though the request is not a part + // in that transition. I think this is OK b/c the transition would + // have already occurred if the request(s) holding up the transition + // have completed and will not occur here if they are still pending. + // + if (m_Removing) { + if (IsListEmpty(&m_SentIoListHead) && IsListEmpty(&m_IgnoredIoListHead)) { + // + // We are no longer transitioning, do not allow new I/O of any kind + // to come in. + // + m_Removing = FALSE; + + // + // Now that all i/o has ceased, clear out our pointers with relation + // to the target itself. + // + ClearTargetPointers(); + + return TRUE; + } + } + else if (m_WaitingForSentIo && + (oldFlags & FX_REQUEST_IGNORE_STATE) == 0 && + IsListEmpty(&m_SentIoListHead)) { + m_WaitingForSentIo = FALSE; + return TRUE; + } + + return FALSE; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::PendRequestLocked( + __in FxRequestBase* Request + ) +{ + NTSTATUS status; + FxIrp* irp; + + // + // Assumes this object's lock is being held + // + Request->SetTargetFlags(FX_REQUEST_PENDED); + + irp = Request->GetSubmitFxIrp(); + + // + // Make sure there is a valid current stack location in the irp. If we + // allocated the irp ourself, then the current stack location is not valid. + // Even if we didn't allocate the irp ourself, this will do no harm. In + // every spot where we remove the request, we undo this call with a call to + // IoSkipCurrentIrpStackLocation + // + irp->SetNextIrpStackLocation(); + + ASSERT(irp->IsCurrentIrpStackLocationValid()); + + status = m_PendedQueue.InsertTailRequest(irp->GetIrp(), &Request->m_CsqContext, NULL); + + if (!NT_SUCCESS(status)) { + // + // Undo the affects of the IoSetNextIrpStackLocation made when we + // enqueued the request. + // + irp->SkipCurrentIrpStackLocation(); + + // + // Request was not pended. + // + Request->ClearTargetFlags(FX_REQUEST_PENDED); + } + + return status; +} + +VOID +FxIoTarget::TimerCallback( + __in FxRequestBase* Request + ) +/*++ + +Routine Description: + Timer routine for when a request has timed out. This routine will attempt + to cancel the request if it hasn't yet completed or complete it if it has. + +Arguments: + Request - The request that has timed out + +Return Value: + None. + + --*/ + +{ + KIRQL irql; + BOOLEAN completeRequest, setStopEvent; + LONG completionRefCount; + + completeRequest = FALSE; + setStopEvent = FALSE; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, WDFREQUEST %p", GetObjectHandle(), + Request->GetTraceObjectHandle()); + + Lock(&irql); + + // + // Clear the flag so that when the completion routine runs, there is no attempt + // to cancel this timer. + // + Request->ClearTargetFlags(FX_REQUEST_TIMER_SET); + + if (Request->GetTargetFlags() & FX_REQUEST_COMPLETED) { + // + // Completion routine ran on a separate processor as the same time as + // the timer DPC. The completion routine will have deferred + // completion to the timer DPC or the caller of Request::Cancel(). + // + completeRequest = Request->CanComplete(); + } + else { + // + // Attempt to cancel the request later outside of the lock. By setting + // the cancelled from timer flag, the completion routine can morph the + // status to timeout if the request is returned as cancelled. + // + Request->SetTargetFlags(FX_REQUEST_CANCELLED_FROM_TIMER); + + // + // Make sure the completion routine does not complete the request + // while the timer callback is still running, in case the completion + // is invoked in the unlock/lock window below. + // + completionRefCount = FxInterlockedIncrementGTZero( + &Request->m_IrpCompletionReferenceCount); + ASSERT(completionRefCount != 0); + UNREFERENCED_PARAMETER(completionRefCount); + + Unlock(irql); + + Request->Cancel(); + + Lock(&irql); + + // + // CanComplete() returns true if completion ownership was claimed. + // + completeRequest = Request->CanComplete(); + } + + // + // If completion ownership was claimed, complete request. + // + if (completeRequest) { + ASSERT(Request->GetTargetFlags() & FX_REQUEST_COMPLETED); + + setStopEvent = RemoveCompletedRequestLocked(Request); + + if (Request->m_Irp.GetStatus() == STATUS_CANCELLED) { + // + // We cancelled the request in another thread and the timer + // fired at the same time. Treat this as if we did the cancel + // from timer directly. + // + // Morph the status code into a timeout status. + // + // Don't muck with the IoStatus.Information field. + // + Request->m_Irp.SetStatus(STATUS_IO_TIMEOUT); + } + } + + Unlock(irql); + + if (completeRequest) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p completed in timer callback", + Request->GetTraceObjectHandle()); + CompleteRequest(Request); + } + + if (setStopEvent) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p, setting stop event %p in timer callback", + GetObjectHandle(), m_SentIoEvent.GetEvent()); + + m_SentIoEvent.Set(); + } + + if (completeRequest) { + DecrementIoCount(); + } +} + +VOID +FxIoTarget::CompleteCanceledRequest( + __in FxRequestBase* Request + ) +{ + KIRQL irql; + BOOLEAN setStopEvent; + + Lock(&irql); + + // + // RemoveCompletedRequestLocked clears Request->m_TargetFlags, so we must + // do this check before that call. + // + if ((Request->GetTargetFlags() & FX_REQUEST_CANCELLED_FROM_TIMER) && + Request->m_Irp.GetStatus() == STATUS_CANCELLED) { + // + // We cancelled the request from the timer and it has completed with + // cancelled. Morph the status code into a timeout status. + // + // Don't muck with the IoStatus.Information field. + // + Request->m_Irp.SetStatus(STATUS_IO_TIMEOUT); + } + + setStopEvent = RemoveCompletedRequestLocked(Request); + Unlock(irql); + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p completed in from cancel", + Request->GetTraceObjectHandle()); + CompleteRequest(Request); + + if (setStopEvent) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, setting stop event %p", + GetObjectHandle(), m_SentIoEvent.GetEvent()); + + m_SentIoEvent.Set(); + } + + DecrementIoCount(); +} + +VOID +FxIoTarget::HandleFailedResubmit( + __in FxRequestBase* Request + ) +/*++ + +Routine Description: + This function handles the completion of the request when Submit() fails. + Request is tracked by the 'Io Count' counter, caller is responsible for + updating its value. + +Arguments: + Request - The request being completed. + +Return Value: + None. + + --*/ +{ + KIRQL irql; + BOOLEAN setStopEvent; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p", Request->GetTraceObjectHandle()); + + setStopEvent = FALSE; + + Lock(&irql); + + // + // Flag should be clear until we set it below + // + ASSERT((Request->GetTargetFlags() & FX_REQUEST_COMPLETED) == 0); + + // + // Mark that the request has been completed + // + Request->SetTargetFlags(FX_REQUEST_COMPLETED); + + // + // Timer should not have been started. + // + ASSERT((Request->GetTargetFlags() & FX_REQUEST_TIMER_SET) == 0); + + // + // RemoveCompletedRequestLocked clears Request->m_TargetFlags, so we must + // do this check before that call. + // + if ((Request->GetTargetFlags() & FX_REQUEST_CANCELLED_FROM_TIMER) && + Request->m_Irp.GetStatus() == STATUS_CANCELLED) { + // + // We cancelled the request from the timer and it has completed with + // cancelled. Morph the status code into a timeout status. + // + // Don't muck with the IoStatus.Information field. + // + Request->m_Irp.SetStatus(STATUS_IO_TIMEOUT); + } + + setStopEvent = RemoveCompletedRequestLocked(Request); + + Unlock(irql); + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p completed in completion routine", + Request->GetTraceObjectHandle()); + CompleteRequest(Request); + + if (setStopEvent) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, setting stop event %p", + GetObjectHandle(), m_SentIoEvent.GetEvent()); + m_SentIoEvent.Set(); + } + + DecrementIoCount(); +} + +VOID +FxIoTarget::RequestCompletionRoutine( + __in FxRequestBase* Request + ) +/*++ + +Routine Description: + The previously submitted request has been completed. This function will + handle coordination with the (optional) request timer and the potential + simultaneous call to FxRequest::Cancel as to which function + will actually complete the request. + +Arguments: + Request - The request being completed. + +Return Value: + None. + + --*/ +{ + KIRQL irql; + BOOLEAN completeRequest, setStopEvent; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p", Request->GetTraceObjectHandle()); + + + setStopEvent = FALSE; + completeRequest = FALSE; + + Lock(&irql); + + // + // Flag should be clear until we set it below + // + ASSERT((Request->GetTargetFlags() & FX_REQUEST_COMPLETED) == 0); + + // + // Mark that the request has been completed so that the potential timer + // DPC will handle the case properly + // + Request->SetTargetFlags(FX_REQUEST_COMPLETED); + + // + // CancelTimer() returns TRUE if the timer was successfully canceled (if + // queued) or if no timer was queued. + // + if (Request->CancelTimer()) { + // + // Sync with Request->Cancel() to make sure we can delete the request. + // + completeRequest = Request->CanComplete(); + } + + if (completeRequest) { + // + // RemoveCompletedRequestLocked clears Request->m_TargetFlags, so we must + // do this check before that call. + // + if ((Request->GetTargetFlags() & FX_REQUEST_CANCELLED_FROM_TIMER) && + Request->m_Irp.GetStatus() == STATUS_CANCELLED) { + // + // We cancelled the request from the timer and it has completed with + // cancelled. Morph the status code into a timeout status. + // + // Don't muck with the IoStatus.Information field. + // + Request->m_Irp.SetStatus(STATUS_IO_TIMEOUT); + } + + setStopEvent = RemoveCompletedRequestLocked(Request); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFREQUEST %p deferring completion due to outstanding completion " + "references", Request->GetTraceObjectHandle()); + } + + Unlock(irql); + + if (completeRequest) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFREQUEST %p completed in completion routine", + Request->GetTraceObjectHandle()); + CompleteRequest(Request); + } + + if (setStopEvent) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, setting stop event %p", + GetObjectHandle(), m_SentIoEvent.GetEvent()); + m_SentIoEvent.Set(); + } + + if (completeRequest) { + DecrementIoCount(); + } +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::_RequestCompletionRoutine( + MdDeviceObject DeviceObject, + MdIrp Irp, + PVOID Context + ) +/*++ + +Routine Description: + Generic I/O completion routine for all submitted requests. + +Arguments: + DeviceObject - Our device object. Most likely NULL since we created the + request and we are the top most driver with respect to it + Irp - Request itself. Ignored since the context also contains this value + Context - Our context, FxRequestBase*. + +Return Value: + STATUS_MORE_PROCESSING_REQUIRED since the lifetime of the Irp is controlled + by the lifetime of our context which may outlive this function call. + + --*/ +{ + FxIoTarget* pThis; + FxRequestBase* pRequest; + + FxIrp irp(Irp); + + UNREFERENCED_PARAMETER(DeviceObject); + + pRequest = (FxRequestBase*) Context; + pThis = pRequest->m_Target; + + // + // Only propagate the the pending returned bit in the IRP if this is an + // asynchronous request + // + if (pRequest->m_CompletionRoutine.m_Completion != + _SyncCompletionRoutine) { + irp.PropagatePendingReturned(); + } + + pThis->RequestCompletionRoutine(pRequest); + + return STATUS_MORE_PROCESSING_REQUIRED; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::FormatInternalIoctlOthersRequest( + __in FxRequestBase* Request, + __in ULONG Ioctl, + __in FxRequestBuffer* Buffers + ) +{ + FxInternalIoctlOthersContext *pContext; + PVOID* bufs[FX_REQUEST_NUM_OTHER_PARAMS]; + NTSTATUS status; + ULONG i; + FxIrp* irp; + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Request->HasContextType(FX_RCT_INTERNAL_IOCTL_OTHERS)) { + pContext = (FxInternalIoctlOthersContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxInternalIoctlOthersContext(); + + if (pContext == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate context for request"); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + // + // Save away any references to IFxMemory pointers that are passed. + // (StoreAndReferenceMemory can only store one buffer, so it doesn't help). + // + pContext->StoreAndReferenceOtherMemories(&Buffers[0], + &Buffers[1], + &Buffers[2]); + + + irp = Request->GetSubmitFxIrp(); + irp->ClearNextStackLocation(); + + irp->SetMajorFunction(IRP_MJ_INTERNAL_DEVICE_CONTROL); + irp->SetParameterIoctlCode(Ioctl); + + CopyFileObjectAndFlags(Request); + + i = 0; + bufs[i] = irp->GetNextStackParameterOthersArgument1Pointer(); + bufs[++i] = irp->GetNextStackParameterOthersArgument2Pointer(); + bufs[++i] = irp->GetNextStackParameterOthersArgument4Pointer(); + + for (i = 0; i < FX_REQUEST_NUM_OTHER_PARAMS; i++) { + status = Buffers[i].GetBuffer(bufs[i]); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve buffer %d, status %!STATUS!", i+1, status); + + Request->ContextReleaseAndRestore(); + + return status; + } + } + + if (NT_SUCCESS(status)) { + Request->VerifierSetFormatted(); + } + + return status; +} + +VOID +FxIoTarget::_RequestCancelled( + __in FxIrpQueue* Queue, + __in MdIrp Irp, + __in PMdIoCsqIrpContext CsqContext, + __in KIRQL CallerIrql + ) +{ + FxIoTarget* pThis; + FxRequestBase* pRequest; + KIRQL irql; + FxIrp pFxIrp; + + pThis = CONTAINING_RECORD(Queue, FxIoTarget, m_PendedQueue); + + pThis->Unlock(CallerIrql); + + // + // Grab the request out of the irp. After this call we are done with the + // m_CsqContext field. + // + pRequest = FxRequestBase::_FromCsqContext(CsqContext); + + DoTraceLevelMessage( + pRequest->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "Pended WDFREQUEST %p canceled", pRequest->GetTraceObjectHandle()); + + // + // m_ListEntry is union'ed with m_CsqContext. m_CsqContext was in use up + // until this function was called. From this point on, we are going to + // process the request as if it has been completed. The completed code path + // assumes m_ListEntry is on a list head. To have a valid m_ListEntry when + // we call RemoveEntryList, initialize it now. Since we have an outstanding + // irp completion reference count (which is decremented in the call to + // FailPendedRequest later), we can safely initialize this field without + // holding any locks. + // + InitializeListHead(&pRequest->m_ListEntry); + + // + // Undo the affects of the IoSetNextIrpStackLocation made when we + // enqueued the request. + // + pFxIrp.SetIrp(Irp); + pFxIrp.SkipCurrentIrpStackLocation(); + + // + // Request is no longer pended + // + pThis->Lock(&irql); + ASSERT(pRequest->GetTargetFlags() & FX_REQUEST_PENDED); + pRequest->ClearTargetFlags(FX_REQUEST_PENDED); + pThis->Unlock(irql); + + // + // Call the driver's completion routine + // + pThis->FailPendedRequest(pRequest, STATUS_CANCELLED); +} + +VOID +FxIoTarget::_SyncCompletionRoutine( + __in WDFREQUEST Request, + __in WDFIOTARGET Target, + __in PWDF_REQUEST_COMPLETION_PARAMS Params, + __in WDFCONTEXT Context + ) +{ + FxTargetSubmitSyncParams* pParams; + + pParams = (FxTargetSubmitSyncParams*) Context; + pParams->Status = Params->IoStatus.Status; + + if (pParams->OrigTargetCompletionRoutine != NULL) { + pParams->OrigTargetCompletionRoutine( + Request, + Target, + Params, + pParams->OrigTargetCompletionContext + ); + } + + pParams->SynchEvent.Set(); +} + + +VOID +FxIoTarget::CancelSentIo( + VOID + ) +/*++ + +Routine Description: + This will be used whenever we send a reset request. + For example if you are sending a reset request + to USB target, you must cancel outstanding I/O before sending a reset + or cycle port request for error recovery. +--*/ + +{ + SINGLE_LIST_ENTRY sentRequestListHead; + BOOLEAN sentAdded; + KIRQL irql; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + + pFxDriverGlobals = GetDriverGlobals(); + sentRequestListHead.Next = NULL; + Lock(&irql); + + GetSentRequestsListLocked(&sentRequestListHead, + &m_SentIoListHead, + &sentAdded); + + Unlock(irql); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "Cancelling pending I/O on WDFIOTARGET %p ", + GetHandle()); + + if (sentAdded) { + _CancelSentRequests(&sentRequestListHead); + } +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::SubmitSyncRequestIgnoreTargetState( + __in FxRequestBase* Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +/*++ + +Routine Description: + Use this for sending a request which ignores target state. +--*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_REQUEST_SEND_OPTIONS requestOptions; + + pFxDriverGlobals = GetDriverGlobals(); + if (RequestOptions != NULL) { + + // + // Do a copy so that the passed in paramters is + // not modified. + // + RtlCopyMemory(&requestOptions, + RequestOptions, + sizeof(WDF_REQUEST_SEND_OPTIONS)); + + if ((requestOptions.Flags & WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE) == 0) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Ignoring WDFIOTARGET %p state to send request", + GetHandle()); + requestOptions.Flags |= WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE; + } + } + else{ + WDF_REQUEST_SEND_OPTIONS_INIT(&requestOptions, + WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + } + + return SubmitSync(Request, &requestOptions); +} + +VOID +FxIoTarget::UpdateTargetIoType( + VOID + ) +{ + UCHAR ioType = GetTargetIoType(); + + // + // m_IoCount is initialized to 1 + // + if ((ioType != m_TargetIoType) && (m_IoCount > 1)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p has changed IoType with outstanding IO", + GetHandle()); + } + m_TargetIoType = (UCHAR) ioType; +} diff --git a/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetapi.cpp b/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetapi.cpp new file mode 100644 index 00000000000..625c16a1890 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetapi.cpp @@ -0,0 +1,2012 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetAPI.cpp + +Abstract: + + This module implements the IO Target APIs + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "..\FxTargetsShared.hpp" + +extern "C" { +#include "FxIoTargetAPI.tmh" +} + +// +// Extern the entire file +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetStart)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Changes the target's state to started. In the started state, the target + can send I/O. + +Arguments: + IoTarget - the target whose state will change + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + FxIoTarget* pTarget; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget); + + return pTarget->Start(); +} + +__drv_when(Action == 3, __drv_maxIRQL(DISPATCH_LEVEL)) +__drv_when(Action == 0 || Action == 1 || Action == 2, __drv_maxIRQL(PASSIVE_LEVEL)) +VOID +WDFEXPORT(WdfIoTargetStop)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + __drv_strictTypeMatch(__drv_typeConst) + WDF_IO_TARGET_SENT_IO_ACTION Action + ) +/*++ + +Routine Description: + This function puts the target into the stopped state. Depending on the value + of Action, this function may not return until sent I/O has been canceled and/or + completed. + +Arguments: + IoTarget - the target whose state is being changed + + Action - what to do with the I/O that is pending in the target already + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + if (Action == WdfIoTargetSentIoUndefined || + Action > WdfIoTargetLeaveSentIoPending) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Action %d undefined or out of range", Action); + return; + } + + if (Action == WdfIoTargetCancelSentIo || + Action == WdfIoTargetWaitForSentIoToComplete) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + } + + pTarget->Stop(Action); +} + +__drv_when(Action == 2, __drv_maxIRQL(DISPATCH_LEVEL)) +__drv_when(Action == 0 || Action == 1, __drv_maxIRQL(PASSIVE_LEVEL)) +VOID +WDFEXPORT(WdfIoTargetPurge)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + __drv_strictTypeMatch(__drv_typeConst) + WDF_IO_TARGET_PURGE_IO_ACTION Action + ) +/*++ + +Routine Description: + This function puts the target into the purged state. Depending on the value + of Action, this function may not return until pending and sent I/O has been + canceled and completed. + +Arguments: + IoTarget - the target whose state is being changed + + Action - purge action: wait or not for I/O to complete after doing the purge. + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + if (Action == WdfIoTargetPurgeIoUndefined || + Action > WdfIoTargetPurgeIo) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Action %d undefined or out of range", Action); + return; + } + + if (Action == WdfIoTargetPurgeIoAndWait) { + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + } + + pTarget->Purge(Action); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDF_IO_TARGET_STATE +WDFEXPORT(WdfIoTargetGetState)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Returns the current state of the target + +Arguments: + IoTarget - target whose state is being returned + +Return Value: + current target state + + --*/ +{ + DDI_ENTRY(); + + FxIoTarget* pTarget; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget); + + return pTarget->GetState(); +} + +_Must_inspect_result_ +NTSTATUS +FxIoTargetValidateOpenParams( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +/*++ + +Routine Description: + Validates the target open parameters structure. + +Arguments: + FxDriverGlobals - driver globals + + OpenParams - the structure to validate + +Return Value: + NTSTATUS + + --*/ + +{ + NTSTATUS status; + + // + // Check specific fields based on Type + // + switch (OpenParams->Type) { + case WdfIoTargetOpenUseExistingDevice: + if (OpenParams->TargetDeviceObject == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Expected non NULL TargetDeviceObject in OpenParams, %!STATUS!", + status); + return status; + } + + // + // This type is supported only in KMDF. + // + if (FxDriverGlobals->IsUserModeDriver) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "The open type WdfIoTargetOpenUseExistingDevice is not " + "supported in UMDF drivers. It is supported in KMDF " + "drivers only, %!STATUS!", + status); + return status; + } + + if (OpenParams->TargetFileObject == NULL && + (OpenParams->EvtIoTargetQueryRemove != NULL || + OpenParams->EvtIoTargetRemoveCanceled != NULL || + OpenParams->EvtIoTargetRemoveComplete != NULL)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "OpenParams %p TargetFileObject is NULL but a state callback " + "(query remove %p, remove canceled %p, remove complete %p)" + " was specified, %!STATUS!", + OpenParams, OpenParams->EvtIoTargetQueryRemove, + OpenParams->EvtIoTargetRemoveCanceled, + OpenParams->EvtIoTargetRemoveComplete, status); + + return status; + } + break; + + case WdfIoTargetOpenByName: + if (OpenParams->TargetDeviceName.Buffer == NULL || + OpenParams->TargetDeviceName.Length == 0 || + OpenParams->TargetDeviceName.MaximumLength == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Expected valid OpenParams TargetDeviceName string, %!STATUS!", + status); + return status; + } + break; + + case WdfIoTargetOpenLocalTargetByFile: + // + // This type is supported only in UMDF. + // + if (FxDriverGlobals->IsUserModeDriver == FALSE) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "The open type WdfIoTargetOpenLocalTargetByFile is not " + "supported in KMDF drivers. It is supported in UMDF " + "drivers only, %!STATUS!", + status); + return status; + } + + if ((OpenParams->EvtIoTargetQueryRemove != NULL || + OpenParams->EvtIoTargetRemoveCanceled != NULL || + OpenParams->EvtIoTargetRemoveComplete != NULL)) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "The open type is WdfIoTargetOpenLocalTargetByFile but a state" + " callback (query remove %p, remove canceled %p, remove" + " complete %p) was specified, %!STATUS!", + OpenParams->EvtIoTargetQueryRemove, + OpenParams->EvtIoTargetRemoveCanceled, + OpenParams->EvtIoTargetRemoveComplete, status); + + return status; + } + + if (OpenParams->FileName.Buffer != NULL || + OpenParams->FileName.Length != 0 || + OpenParams->FileName.MaximumLength != 0) { + status = FxValidateUnicodeString(FxDriverGlobals, + &OpenParams->FileName); + if (!NT_SUCCESS(status)) { + return status; + } + } + + + break; + + case WdfIoTargetOpenReopen: + break; + + default: + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "OpenParams Type (%d) incorrect, %!STATUS!", + OpenParams->Type, status); + + return status; + } + + return STATUS_SUCCESS; +} + + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in_opt + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + __out + WDFIOTARGET* IoTarget + ) +/*++ + +Routine Description: + Creates a WDFIOTARGET which can be opened upon success. + +Arguments: + Device - the device which will own the target. The target will be parented + by the owning device + + IoTargetAttributes - optional attributes to apply to the target + + IoTarget - pointer which will receive the created target handle + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pTarget; + FxDeviceBase* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PWDFOBJECT) &pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, IoTarget); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFDEVICE 0x%p", Device); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Since the target is auto parented to the Device, we don't allow the client + // to specify a parent. + // + status = FxValidateObjectAttributes(pFxDriverGlobals, IoTargetAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxIoTargetRemote::_Create( + pFxDriverGlobals, IoTargetAttributes, pDevice, &pTarget); + + if (NT_SUCCESS(status)) { + *IoTarget = pTarget->GetHandle(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetOpen)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +/*++ + +Routine Description: + Opens a target. The target must be in the closed state for an open to + succeed. Open is either wrapping an existing PDEVICE_OBJECT + PFILE_OBJECT + that the client provides or opening a PDEVICE_OBJECT by name. + +Arguments: + IoTarget - Target to be opened + + OpenParams - structure which describes how to open the target + +Return Value: + NTSTATUS + + --*/ +{ + // + // UMDF only, noop for KMDF. + // It's ok to be impersonated here, because it can be required in order for + // the CreateFile() call to succeed. + // + DDI_ENTRY_IMPERSONATION_OK(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pTarget; + NTSTATUS status; + ULONG expectedConfigSize; + WDF_IO_TARGET_OPEN_PARAMS openParams; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET_REMOTE, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + FxPointerNotNull(pFxDriverGlobals, OpenParams); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + expectedConfigSize = pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13) ? + sizeof(WDF_IO_TARGET_OPEN_PARAMS) : + sizeof(WDF_IO_TARGET_OPEN_PARAMS_V1_11); + + // + // Check Size + // + if (OpenParams->Size != sizeof(WDF_IO_TARGET_OPEN_PARAMS) && + OpenParams->Size != sizeof(WDF_IO_TARGET_OPEN_PARAMS_V1_11)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "OpenParams size (%d) incorrect, expected %d, %!STATUS!", + OpenParams->Size, expectedConfigSize, status); + return status; + } + + // + // Normalize WDF_IO_TARGET_OPEN_PARAMS structure. + // + if (OpenParams->Size < sizeof(WDF_IO_TARGET_OPEN_PARAMS)) { + RtlZeroMemory(&openParams, sizeof(WDF_IO_TARGET_OPEN_PARAMS)); + + // + // Copy over existing fields and readjust the struct size. + // + RtlCopyMemory(&openParams, OpenParams, OpenParams->Size); + openParams.Size = sizeof(openParams); + + // + // Use new open params structure from now on. + // + OpenParams = &openParams; + } + + status = FxIoTargetValidateOpenParams(pFxDriverGlobals, OpenParams); + if (!NT_SUCCESS(status)) { + // + // FxIoTargetValidateCreateParams traces the error + // + return status; + } + + status = pTarget->Open(OpenParams); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, %!STATUS!", IoTarget, status); + + return status; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfIoTargetCloseForQueryRemove)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Closes a target in response to a query remove notification callback. This + will pend all i/o sent after the call returns. + +Arguments: + IoTarget - Target to be closed + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pTarget; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET_REMOTE, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + pFxDriverGlobals = GetFxDriverGlobals(DriverGlobals); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + pTarget->Close(FxIoTargetRemoteCloseReasonQueryRemove); +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFEXPORT(WdfIoTargetClose)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Closes the target for good. The target can be in either a query removed or + opened state. + +Arguments: + IoTarget - target to close + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pTarget; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET_REMOTE, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + pTarget->Close(FxIoTargetRemoteCloseReasonPlainClose); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFDEVICE +WDFEXPORT(WdfIoTargetGetDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Returns the owning WDFDEVICE for the WDFIOTARGET, this is not necessarily + the PDEVICE_OBJECT of the target itself. + +Arguments: + IoTarget - the target being retrieved + +Return Value: + a valid WDFDEVICE handle , NULL if there are any problems + + --*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + WDFDEVICE device; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + device = pTarget->GetDeviceHandle(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, WDFDEVICE 0x%p", IoTarget, device); + + return device; +} + +static +_Must_inspect_result_ +NTSTATUS +FxIoTargetSendIo( + __in + PFX_DRIVER_GLOBALS FxDriverGlobals, + __in + WDFIOTARGET IoTarget, + __inout_opt + WDFREQUEST Request, + __in + UCHAR MajorCode, + __inout_opt + PWDF_MEMORY_DESCRIPTOR IoBuffer, + __in_opt + PLONGLONG DeviceOffset, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesReturned + ) +/*++ + +Routine Description: + This routine sends a read or write synchronously to the target. If Request + is not NULL, the PIRP it contains will be used to send the IO. + +Arguments: + IoTarget - target to where the IO is going to be sent + + Request - optional. If specified, the PIRP it contains will be used + to send the I/O + + MajorCode - read or write major code + + IoBuffer - Buffer which will be used in the I/O. The buffer can be a PMDL, + buffer, or WDFMEMORY + + DeviceOffset - offset into the target (and not the memory) in which the I/O + will start + + RequestOptions - optional. If specified, the timeout value is used to cancel + the sent i/o if the timeout is exceeded + + BytesReturned - upon success, the number of bytes transferred in the I/O + request + +Return Value: + NTSTATUS + + --*/ + +{ + FxIoTarget* pTarget; + FxRequestBuffer ioBuf; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &FxDriverGlobals); + + // + // Minimize the points of failure by using the stack instead of allocating + // out of pool. For UMDF, request initialization can fail so we still need + // to call initialize for FxSyncRequest. Initialization always succeeds for + // KM. + // + FxIoContext context; + FxSyncRequest request(FxDriverGlobals, &context, Request); + + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest for WDFIOTARGET " + "0x%p", IoTarget); + return status; + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, MJ code 0x%x", + IoTarget, Request, MajorCode); + + // + // Since we are synchronously waiting, we must be at passive level + // + status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid options, %!STATUS!", status); + return status; + } + + if (IoBuffer != NULL) { + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + status = ioBuf.ValidateMemoryDescriptor(FxDriverGlobals, IoBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid input buffer descriptor 0x%p, %!STATUS!", + IoBuffer, status); + return status; + } + } + + // + // Format the next stack location in the PIRP + // + status = pTarget->FormatIoRequest( + request.m_TrueRequest, MajorCode, &ioBuf, DeviceOffset, NULL); + + if (NT_SUCCESS(status)) { + // + // And send it + // + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted", + IoTarget, request.m_TrueRequest->GetTraceObjectHandle()); + + status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions); + + if (BytesReturned != NULL) { + *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation(); + + } + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "could not format MJ 0x%x request, %!STATUS!", + MajorCode, status); + } + + return status; +} + +static +_Must_inspect_result_ +NTSTATUS +FxIoTargetFormatIo( + __in + PFX_DRIVER_GLOBALS FxDriverGlobals, + __in + WDFIOTARGET IoTarget, + __inout + WDFREQUEST Request, + __in + UCHAR MajorCode, + __inout_opt + WDFMEMORY IoBuffer, + __in_opt + PWDFMEMORY_OFFSET IoBufferOffsets, + __in_opt + PLONGLONG DeviceOffset + ) +/*++ + +Routine Description: + Formats a Request for a read or write. The request can later be sent to the + target using WdfRequestSend. Upon success, this will take a reference on the + Iobuffer handle if it is not NULL. This reference will be released when + one of the following occurs: + 1) the request is completed through WdfRequestComplete + 2) the request is reused through WdfRequestReuse + 3) the request is reformatted through any target format DDI + +Arguments: + IoTarget - the request that the read or write will later be sent to + + Request - the request that will be formatted + + MajorCode - read or write major code + + IoBuffer - optional reference counted memory handle + + IoBufferOffset - optional offset into the IoBuffer. This can specify the + starting offset and/or length of the transfer + + DeviceOffset - offset into the target in which the i/o will start + +Return Value: + NTSTATUS + + --*/ +{ + FxIoTarget *pTarget; + FxRequest *pRequest; + IFxMemory* pIoMemory; + FxRequestBuffer ioBuf; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &FxDriverGlobals); + + DoTraceLevelMessage(FxDriverGlobals, + TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, MJ code 0x%x, WDFMEMORY 0x%p", + IoTarget, Request, MajorCode, IoBuffer); + + FxObjectHandleGetPtr(FxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + if (IoBuffer != NULL) { + FxObjectHandleGetPtr(FxDriverGlobals, + IoBuffer, + IFX_TYPE_MEMORY, + (PVOID*) &pIoMemory); + + status = pIoMemory->ValidateMemoryOffsets(IoBufferOffsets); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid memory offsets, %!STATUS!", + status); + return status; + } + + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + ioBuf.SetMemory(pIoMemory, IoBufferOffsets); + } + else { + pIoMemory = NULL; + } + + // + // Format the next stack locaiton in the PIRP + // + status = pTarget->FormatIoRequest( + pRequest, MajorCode, &ioBuf, DeviceOffset, NULL); + + if (NT_SUCCESS(status)) { + if (MajorCode == IRP_MJ_WRITE) { + pRequest->GetContext()->FormatWriteParams(pIoMemory, IoBufferOffsets); + } + else if (MajorCode == IRP_MJ_READ) { + pRequest->GetContext()->FormatReadParams(pIoMemory, IoBufferOffsets); + } + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, WDFREQUEST 0x%p, %!STATUS!", + IoTarget, Request, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetSendReadSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + __in_opt + PLONGLONG DeviceOffset, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesRead + ) +{ + DDI_ENTRY(); + + return FxIoTargetSendIo(GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + IRP_MJ_READ, + OutputBuffer, + DeviceOffset, + RequestOptions, + BytesRead); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForRead)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + WDFREQUEST Request, + __in_opt + WDFMEMORY OutputBuffer, + __in_opt + PWDFMEMORY_OFFSET OutputBufferOffsets, + __in_opt + PLONGLONG DeviceOffset + ) +{ + DDI_ENTRY(); + + return FxIoTargetFormatIo(GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + IRP_MJ_READ, + OutputBuffer, + OutputBufferOffsets, + DeviceOffset); +} + + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetSendWriteSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_MEMORY_DESCRIPTOR InputBuffer, + __in_opt + PLONGLONG DeviceOffset, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesWritten + ) +{ + DDI_ENTRY(); + + return FxIoTargetSendIo(GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + IRP_MJ_WRITE, + InputBuffer, + DeviceOffset, + RequestOptions, + BytesWritten); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForWrite)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + WDFREQUEST Request, + __in_opt + WDFMEMORY InputBuffer, + __in_opt + PWDFMEMORY_OFFSET InputBufferOffsets, + __in_opt + PLONGLONG DeviceOffset + ) +{ + DDI_ENTRY(); + + return FxIoTargetFormatIo(GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + IRP_MJ_WRITE, + InputBuffer, + InputBufferOffsets, + DeviceOffset); +} + +_Must_inspect_result_ +NTSTATUS +FxIoTargetSendIoctl( + __in + PFX_DRIVER_GLOBALS FxDriverGlobals, + __in + WDFIOTARGET IoTarget, + __in_opt + WDFREQUEST Request, + __in + ULONG Ioctl, + __in + BOOLEAN Internal, + __in_opt + PWDF_MEMORY_DESCRIPTOR InputBuffer, + __in_opt + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesReturned + ) +/*++ + +Routine Description: + Sends an external or internal IOCTL to the target. If the optional request + is specified, this function will use it's PIRP to send the request to the + target. Both buffers are optional. + +Arguments: + IoTarget - the target to which the IOCTL is being sent + + IOCTL - the device io control value + + Internal - if TRUE, an internal IOCTL, if FALSE, a normal IOCTL + + InputBuffer - optional. Can be one of the following: PMDL, PVOID, or WDFMEMORY + + OutputBuffer - optional. Can be one of the following: PMDL, PVOID, or WDFMEMORY + + RequestOptions - optional. Specifies a timeout to be used if the sent IO + does not return within the time specified. + + BytesReturned - number of bytes transfered + +Return Value: + NTSTATUS + + --*/ +{ + FxIoTarget* pTarget; + FxRequestBuffer inputBuf, outputBuf; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &FxDriverGlobals); + + // + // Minimize the points of failure by using the stack instead of allocating + // out of pool. For UMDF, request initialization can fail so we still need + // to call initialize for FxSyncRequest. Initialization always succeeds for + // KM. + // + FxIoContext context; + FxSyncRequest request(FxDriverGlobals, &context, Request); + + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest for WDFIOTARGET " + "0x%p", IoTarget); + return status; + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, " + "internal %d", IoTarget, Request, Ioctl, Internal); + + // + // Since we are synchronously waiting, we must be at passive + // + status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid options, %!STATUS!", status); + return status; + } + + if (InputBuffer != NULL) { + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + status = inputBuf.ValidateMemoryDescriptor(FxDriverGlobals, InputBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid input buffer descriptor 0x%p, %!STATUS!", + InputBuffer, status); + return status; + } + } + + if (OutputBuffer != NULL) { + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + status = outputBuf.ValidateMemoryDescriptor(FxDriverGlobals, OutputBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid output buffer descriptor 0x%p, %!STATUS!", + OutputBuffer, status); + return status; + } + } + + // + // Format the next stack location + // + status = pTarget->FormatIoctlRequest( + request.m_TrueRequest, Ioctl, Internal, &inputBuf, &outputBuf, NULL); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted", + IoTarget, + request.m_TrueRequest->GetTraceObjectHandle()); + + status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions); + + if (BytesReturned != NULL) { + *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation(); + } + } + else { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "could not format IOCTL 0x%x request, %!STATUS!", + Ioctl, status); + } + + return status; +} + +static +_Must_inspect_result_ +NTSTATUS +FxIoTargetFormatIoctl( + __in + PFX_DRIVER_GLOBALS FxDriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + WDFREQUEST Request, + __in + ULONG Ioctl, + __in + BOOLEAN Internal, + __in_opt + WDFMEMORY InputBuffer, + __in_opt + PWDFMEMORY_OFFSET InputBufferOffsets, + __in_opt + WDFMEMORY OutputBuffer, + __in_opt + PWDFMEMORY_OFFSET OutputBufferOffsets + ) +/*++ + +Routine Description: + Formats a request as an IOCTL to be sent to the specified target. Upon + success, this will take a reference on each of the WDFMEMORY handles that + are passed in. This reference will be released when one of the following + occurs: + 1) the request is completed through WdfRequestComplete + 2) the request is reused through WdfRequestReuse + 3) the request is reformatted through any target format DDI + +Arguments: + IoTarget - the target to which the IOCTL will be formatted for + + Request - the request which will be formatted + + IOCTL - the device IO control itself to be used + + Internal - if TRUE, an internal IOCTL, if FALSE, a normal IOCTL + + InputBuffer - optional. If specified, a reference counted memory handle to + be placed in the next stack location. + + InputBufferOffsets - optional. If specified, it can override the starting + offset of the buffer and the length of the buffer used + + OutputBuffer - optional. If specified, a reference counted memory handle to + be placed in the next stack location. + + OutputBufferOffsets - optional. If specified, it can override the starting + offset of the buffer and the length of the buffer used + +Return Value: + NTSTATUS + + --*/ +{ + FxIoTarget *pTarget; + FxRequest *pRequest; + IFxMemory *pInputMemory, *pOutputMemory; + FxRequestBuffer inputBuf, outputBuf; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &FxDriverGlobals); + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, internal %d, input " + "WDFMEMORY 0x%p, output WDFMEMORY 0x%p", + IoTarget, Request, Ioctl, Internal, InputBuffer, OutputBuffer); + + FxObjectHandleGetPtr(FxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + if (InputBuffer != NULL) { + FxObjectHandleGetPtr(FxDriverGlobals, + InputBuffer, + IFX_TYPE_MEMORY, + (PVOID*) &pInputMemory); + + status = pInputMemory->ValidateMemoryOffsets(InputBufferOffsets); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Invalid input memory offsets, %!STATUS!", + status); + return status; + } + + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + inputBuf.SetMemory(pInputMemory, InputBufferOffsets); + } + + if (OutputBuffer != NULL) { + FxObjectHandleGetPtr(FxDriverGlobals, + OutputBuffer, + IFX_TYPE_MEMORY, + (PVOID*) &pOutputMemory); + + status = pOutputMemory->ValidateMemoryOffsets(OutputBufferOffsets); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Invalid output memory offsets, %!STATUS!", + status); + return status; + } + + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + outputBuf.SetMemory(pOutputMemory, OutputBufferOffsets); + } + + // + // format the next stack location + // + status = pTarget->FormatIoctlRequest( + pRequest, Ioctl, Internal, &inputBuf, &outputBuf, NULL); + + if (NT_SUCCESS(status)) { + FxRequestContext* pContext; + + // + // Upon a successful format, a FxRequestContext will have been + // associated with the FxRequest + // + pContext = pRequest->GetContext(); + + pContext->m_CompletionParams.Parameters.Ioctl.IoControlCode = Ioctl; + + if (Internal) { + pContext->m_CompletionParams.Type = WdfRequestTypeDeviceControlInternal; + } + else { + pContext->m_CompletionParams.Type = WdfRequestTypeDeviceControl; + } + + pContext->m_CompletionParams.Parameters.Ioctl.Input.Buffer = InputBuffer; + if (InputBufferOffsets != NULL) { + pContext->m_CompletionParams.Parameters.Ioctl.Input.Offset = + InputBufferOffsets->BufferOffset; + } + + pContext->m_CompletionParams.Parameters.Ioctl.Output.Buffer = OutputBuffer; + if (OutputBufferOffsets != NULL) { + pContext->m_CompletionParams.Parameters.Ioctl.Output.Offset = + OutputBufferOffsets->BufferOffset; + } + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Exit WDFIOTARGET 0x%p, WDFREQUEST 0x%p, %!STATUS!", + IoTarget, Request, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in_opt + WDFREQUEST Request, + __in + ULONG Ioctl, + __in_opt + PWDF_MEMORY_DESCRIPTOR InputBuffer, + __in_opt + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesReturned + ) +{ + DDI_ENTRY(); + + return FxIoTargetSendIoctl( + GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + Ioctl, + FALSE, + InputBuffer, + OutputBuffer, + RequestOptions, + BytesReturned + ); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + WDFREQUEST Request, + __in + ULONG Ioctl, + __in_opt + WDFMEMORY InputBuffer, + __in_opt + PWDFMEMORY_OFFSET InputBufferOffsets, + __in_opt + WDFMEMORY OutputBuffer, + __in_opt + PWDFMEMORY_OFFSET OutputBufferOffsets + ) +{ + DDI_ENTRY(); + + return FxIoTargetFormatIoctl(GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + Ioctl, + FALSE, + InputBuffer, + InputBufferOffsets, + OutputBuffer, + OutputBufferOffsets); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetSendInternalIoctlSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in_opt + WDFREQUEST Request, + __in + ULONG Ioctl, + __in_opt + PWDF_MEMORY_DESCRIPTOR InputBuffer, + __in_opt + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesReturned + ) +{ + DDI_ENTRY(); + + return FxIoTargetSendIoctl( + GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + Ioctl, + TRUE, + InputBuffer, + OutputBuffer, + RequestOptions, + BytesReturned + ); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctl)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + WDFREQUEST Request, + __in + ULONG Ioctl, + __in_opt + WDFMEMORY InputBuffer, + __in_opt + PWDFMEMORY_OFFSET InputBufferOffsets, + __in_opt + WDFMEMORY OutputBuffer, + __in_opt + PWDFMEMORY_OFFSET OutputBufferOffsets + ) +{ + DDI_ENTRY(); + + return FxIoTargetFormatIoctl(GetFxDriverGlobals(DriverGlobals), + IoTarget, + Request, + Ioctl, + TRUE, + InputBuffer, + InputBufferOffsets, + OutputBuffer, + OutputBufferOffsets); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetSendInternalIoctlOthersSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in_opt + WDFREQUEST Request, + __in + ULONG Ioctl, + __in_opt + PWDF_MEMORY_DESCRIPTOR OtherArg1, + __in_opt + PWDF_MEMORY_DESCRIPTOR OtherArg2, + __in_opt + PWDF_MEMORY_DESCRIPTOR OtherArg4, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_opt + PULONG_PTR BytesReturned + ) +/*++ + +Routine Description: + Sends an internal IOCTL to the target synchronously. Since all 3 buffers can + be used, we cannot overload WdfIoTargetSendInternalIoctlSynchronously since + it can only take 2 buffers. + +Arguments: + IoTarget - the target to which the request will be sent + + Request - optional. If specified, the request's PIRP will be used to send + the i/o to the target. + + Ioctl - internal ioctl value to send + + OtherArg1 + OtherArg2 + OtherArg4 - arguments to use in the stack locations's Others field. There + is no OtherArg3 because 3 is where the IOCTL value is written. + All buffers are optional. + + RequestOptions - optional. If specified, the timeout indicated will be used + if the request exceeds the timeout. + + BytesReturned - the number of bytes returned by the target + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS]; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + // + // Minimize the points of failure by using the stack instead of allocating + // out of pool. For UMDF, request initialization can fail so we still need + // to call initialize for FxSyncRequest. Initialization always succeeds for + // KM. + // + FxInternalIoctlOthersContext context; + FxSyncRequest request(pFxDriverGlobals, &context, Request); + + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest for WDFIOTARGET " + "0x%p", IoTarget); + return status; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, Args %p %p %p", + IoTarget, Request, Ioctl, OtherArg1, OtherArg2, OtherArg4); + + // + // Since we are waiting synchronously, we must be at pasisve + // + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Invalid options, %!STATUS!", status); + return status; + } + + ULONG i; + + i = 0; + if (OtherArg1 != NULL) { + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg1); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid OtherArg1 buffer descriptor 0x%p, %!STATUS!", + OtherArg1, status); + return status; + } + } + + i++; + if (OtherArg2 != NULL) { + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg2); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid OtherArg2 buffer descriptor 0x%p, %!STATUS!", + OtherArg2, status); + return status; + } + } + + i++; + if (OtherArg4 != NULL) { + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + status = args[i].ValidateMemoryDescriptor(pFxDriverGlobals, OtherArg4); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "invalid OtherArg4 buffer descriptor 0x%p, %!STATUS!", + OtherArg4, status); + return status; + } + } + + // + // Format the next stack location + // + status = pTarget->FormatInternalIoctlOthersRequest(request.m_TrueRequest, + Ioctl, + args); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET 0x%p, WDFREQUEST 0x%p being submitted", + IoTarget, + request.m_TrueRequest->GetTraceObjectHandle()); + + status = pTarget->SubmitSync(request.m_TrueRequest, RequestOptions); + + if (BytesReturned != NULL) { + *BytesReturned = request.m_TrueRequest->GetSubmitFxIrp()->GetInformation(); + } + } + else { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not format IOCTL 0x%x request, %!STATUS!", + Ioctl, status); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForInternalIoctlOthers)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + WDFREQUEST Request, + __in + ULONG Ioctl, + __in_opt + WDFMEMORY OtherArg1, + __in_opt + PWDFMEMORY_OFFSET OtherArg1Offsets, + __in_opt + WDFMEMORY OtherArg2, + __in_opt + PWDFMEMORY_OFFSET OtherArg2Offsets, + __in_opt + WDFMEMORY OtherArg4, + __in_opt + PWDFMEMORY_OFFSET OtherArg4Offsets + ) +/*++ + +Routine Description: + Formats an internal IOCTL so that it can sent to the target. Since all 3 + buffers can be used, we cannot overload + WdfIoTargetFormatRequestForInternalIoctlOthers since it can only take 2 buffers. + + Upon success, this will take a reference on each of the WDFMEMORY handles that + are passed in. This reference will be released when one of the following + occurs: + 1) the request is completed through WdfRequestComplete + 2) the request is reused through WdfRequestReuse + 3) the request is reformatted through any target format DDI + +Arguments: + IoTarget - the target to which the request will be sent + + Request - the request to be formatted + + Ioctl - internal ioctl value to send + + OtherArg1 + OtherArg2 + OtherArg4 - arguments to use in the stack locations's Others field. There + is no OtherArg3 because 3 is where the IOCTL value is written. + All buffers are optional + + OterhArgXOffsets - offset into each buffer which can override the starting + offset of the buffer. Length does not matter since + there is no way of generically describing the length of + each of the 3 buffers in the PIRP + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget *pTarget; + FxRequest *pRequest; + IFxMemory *pMemory[FX_REQUEST_NUM_OTHER_PARAMS]; + FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS]; + WDFMEMORY memoryHandles[FX_REQUEST_NUM_OTHER_PARAMS]; + PWDFMEMORY_OFFSET offsets[FX_REQUEST_NUM_OTHER_PARAMS]; + NTSTATUS status; + ULONG i; + FxInternalIoctlParams InternalIoctlParams; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Enter: WDFIOTARGET 0x%p, WDFREQUEST 0x%p, IOCTL 0x%x, " + "WDFMEMORY 1 0x%p, 2 0x%p, 3 0x%p", + IoTarget, Request, Ioctl, OtherArg1, OtherArg2, + OtherArg4); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + i = 0; + InternalIoctlParams.Argument1 = memoryHandles[i] = OtherArg1; + offsets[i] = OtherArg1Offsets; + + InternalIoctlParams.Argument2 = memoryHandles[++i] = OtherArg2; + offsets[i] = OtherArg2Offsets; + + InternalIoctlParams.Argument4 = memoryHandles[++i] = OtherArg4; + offsets[i] = OtherArg4Offsets; + + for (i = 0; i < FX_REQUEST_NUM_OTHER_PARAMS; i++) { + if (memoryHandles[i] != NULL) { + + FxObjectHandleGetPtr(pFxDriverGlobals, + memoryHandles[i], + IFX_TYPE_MEMORY, + (PVOID*) &pMemory[i]); + + status = pMemory[i]->ValidateMemoryOffsets(offsets[i]); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Invalid OtherArg%d memory offsets, %!STATUS!", + i+1, status); + return status; + } + + // + // This transcribes the client union into a local structure which we + // can change w/out altering the client's buffer. + // + args[i].SetMemory(pMemory[i], offsets[i]); + } + } + + status = pTarget->FormatInternalIoctlOthersRequest(pRequest, Ioctl, args); + if (NT_SUCCESS(status)) { + pRequest->GetContext()->FormatOtherParams(&InternalIoctlParams); + } + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Exit: WDFIOTARGET %p, WDFREQUEST %p, IOCTL 0x%x, " + "Arg Handles %p %p %p, status %!STATUS!", + IoTarget, Request, Ioctl, OtherArg1, OtherArg2, + OtherArg4, status); + + return status; +} + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ) + +/*++ + +Routine Description: + + Assigns a default queue for the Self IO Target. + + By default the IO sent to the Self IO Target is dispatched ot the + client's default / top level queue. + + This routine assigns a default queue for the Intenral I/O target. + If a client calls this API, all the I/O directed to the Self IO target + is dispatched to the queue specified. + +Arguments: + + IoTarget - Handle to the Self Io Target. + + Queue - Handle to a queue that is being assigned as the default queue for + the Self io target. + +Returns: + + NTSTATUS + +--*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pGlobals; + NTSTATUS status; + FxIoTargetSelf* pTargetSelf; + FxDevice* pDevice; + FxIoQueue* pFxIoQueue; + + pDevice = NULL; + pFxIoQueue = NULL; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET_SELF, + (PVOID *) &pTargetSelf, + &pGlobals); + + pDevice = pTargetSelf->GetDevice(); + + // + // Validate the Queue handle + // + FxObjectHandleGetPtr(pGlobals, + Queue, + FX_TYPE_QUEUE, + (PVOID*)&pFxIoQueue); + + if (pDevice != pFxIoQueue->GetDevice()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Input WDFQUEUE 0x%p belongs to WDFDEVICE 0x%p, but " + "Self Io Target 0x%p corresponds to the WDFDEVICE 0x%p, %!STATUS!", + Queue, pFxIoQueue->GetDevice()->GetHandle(), IoTarget, + pDevice->GetHandle(), status); + + return status; + } + + if (pDevice->IsLegacy()) { + // + // This is a controldevice. Make sure the create is called after the device + // is initialized and ready to accept I/O. + // + MxDeviceObject deviceObject(pDevice->GetDeviceObject()); + if ((deviceObject.GetFlags() & DO_DEVICE_INITIALIZING) == 0x0) { + + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Queue cannot be configured for automatic dispatching" + " after WdfControlDeviceFinishInitializing" + "is called on the WDFDEVICE %p is called %!STATUS!", + pDevice->GetHandle(), + status); + return status; + } + } + else { + // + // This is either FDO or PDO. Make sure it's not started yet. + // + if (pDevice->GetDevicePnpState() != WdfDevStatePnpInit) { + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + pGlobals, TRACE_LEVEL_ERROR, TRACINGPNP, + "Queue cannot be configured for automatic dispatching" + "after the WDFDEVICE %p is started, %!STATUS!", + pDevice->GetHandle(), status); + return status; + } + } + + pTargetSelf->SetDispatchQueue(pFxIoQueue); + + return STATUS_SUCCESS; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +HANDLE +WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Returns the file handle that the target represents. For KMDF, the handle is a kernel + handle, so it is not tied to any process context. For UMDF it is a Win32 handle opened + in the host process context. Not all targets have a file handle associated with them, + so NULL is a valid return value that does not indicate error. + +Arguments: + IoTarget - target whose file handle is being returned + +Return Value: + A valid kernel/win32 handle or NULL + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pTarget; + PVOID handle; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET_REMOTE, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + handle = pTarget->GetTargetHandle(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, WDM file handle 0x%p", + IoTarget, handle); + + return handle; +} + + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetremote.cpp b/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetremote.cpp new file mode 100644 index 00000000000..5a125f852ed --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetremote.cpp @@ -0,0 +1,825 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetRemote.cpp + +Abstract: + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "..\FxTargetsShared.hpp" + +extern "C" { +#include "FxIoTargetRemote.tmh" +} + +#include +#include "wdmguid.h" + + +FxIoTargetRemote::FxIoTargetRemote( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxIoTarget(FxDriverGlobals, sizeof(FxIoTargetRemote)), + m_EvtQueryRemove(FxDriverGlobals), + m_EvtRemoveCanceled(FxDriverGlobals), + m_EvtRemoveComplete(FxDriverGlobals) +{ + + // + // No automatic state changes based on the pnp state changes of our own + // device stack. The one exception is remove where we need to shut + // everything down. + // + m_InStack = FALSE; + + m_ClearedPointers = NULL; + m_OpenState = FxIoTargetRemoteOpenStateClosed; + + m_TargetHandle = NULL; + + m_EvtQueryRemove.m_Method = NULL; + m_EvtRemoveCanceled.m_Method = NULL; + m_EvtRemoveComplete.m_Method = NULL; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_TargetNotifyHandle = NULL; +#else (FX_CORE_MODE == FX_CORE_USER_MODE) + m_TargetNotifyHandle = WUDF_TARGET_CONTEXT_INVALID; + + m_pIoDispatcher = NULL; + m_pRemoteDispatcher = NULL; + m_NotificationCallback = NULL; +#endif +} + +FxIoTargetRemote::~FxIoTargetRemote() +{ +} + +_Must_inspect_result_ +NTSTATUS +FxIoTargetRemote::_Create( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PWDF_OBJECT_ATTRIBUTES Attributes, + __in CfxDeviceBase* Device, + __out FxIoTargetRemote** Target + ) +{ + FxIoTargetRemote* pTarget; + FxObject* pParent; + WDFOBJECT hTarget; + NTSTATUS status; + + *Target = NULL; + + if (Attributes == NULL || Attributes->ParentObject == NULL) { + pParent = Device; + } + else { + CfxDeviceBase* pSearchDevice; + + FxObjectHandleGetPtr(FxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*) &pParent); + + pSearchDevice = FxDeviceBase::_SearchForDevice(pParent, NULL); + + if (pSearchDevice == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Attributes->ParentObject 0x%p must have WDFDEVICE as an " + "eventual ancestor, %!STATUS!", + Attributes->ParentObject, status); + + return status; + } + else if (pSearchDevice != Device) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Attributes->ParentObject 0x%p ancestor is WDFDEVICE %p, but " + "not the same WDFDEVICE 0x%p passed to WdfIoTargetCreate, " + "%!STATUS!", + Attributes->ParentObject, pSearchDevice->GetHandle(), + Device->GetHandle(), status); + + return status; + } + } + + pTarget = new (FxDriverGlobals, Attributes) + FxIoTargetRemote(FxDriverGlobals); + + if (pTarget == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for target, %!STATUS!", status); + return status; + } + + // + // initialize the new target + // + status = pTarget->InitRemote(Device); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Commit and apply the attributes + // + status = pTarget->Commit(Attributes, &hTarget, pParent); + + if (NT_SUCCESS(status)) { + *Target = pTarget; + } + else { + // + // This will properly clean up the target's state and free it + // + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Commit failed for target, %!STATUS!", status); + pTarget->DeleteFromFailedCreate(); + } + + return status; +} + +NTSTATUS +FxIoTargetRemote::InitRemote( + __in FxDeviceBase* Device + ) +{ + NTSTATUS status; + + // + // do the base class mode-specific initialization + // + status = __super::InitModeSpecific(Device); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Do mode-specific initilialization + // + status = InitRemoteModeSpecific(Device); + if (!NT_SUCCESS(status)) { + return status; + } + + m_Driver = Device->GetDriver(); + + SetDeviceBase(Device); + m_InStackDevice = Device->GetDeviceObject(); + + (void) Device->AddIoTarget(this); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTargetRemote::Open( + __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +{ + FxIoTargetRemoveOpenParams params, *pParams; + UNICODE_STRING name; + LIST_ENTRY pended; + WDF_IO_TARGET_OPEN_TYPE type; + NTSTATUS status; + BOOLEAN close, reopen; + PVOID pEa; + ULONG eaLength; + KIRQL irql; + + RtlZeroMemory(&name, sizeof(name)); + close = FALSE; + reopen = OpenParams->Type == WdfIoTargetOpenReopen ? TRUE : FALSE; + + pEa = NULL; + eaLength = 0; + + // + // We only support reopening using stored settings when we open by name + // + if (reopen && m_OpenParams.OpenType != WdfIoTargetOpenByName) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Reopen only supported if the open type is WdfIoTargetOpenByName WDFIOTARGET %p %!STATUS!", + GetObjectHandle(), status); + return status; + } + + // + // Must preallocate all settings now + // + if (reopen) { + // + // convert the type into the type used for the previous open + // + type = m_OpenParams.OpenType; + pParams = &m_OpenParams; + } + else { + type = OpenParams->Type; + pParams = ¶ms; + + if (OpenParams->Type == WdfIoTargetOpenByName) { + + status = FxDuplicateUnicodeString(GetDriverGlobals(), + &OpenParams->TargetDeviceName, + &name); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for target name for WDFIOTARGET %p", + GetObjectHandle()); + goto Done; + } + if (OpenParams->EaBuffer != NULL && OpenParams->EaBufferLength > 0) { + + pEa = FxPoolAllocate(GetDriverGlobals(), + PagedPool, + OpenParams->EaBufferLength); + + if (pEa == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for target name " + "for WDFIOTARGET %p", GetObjectHandle()); + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + else { + eaLength = OpenParams->EaBufferLength; + RtlCopyMemory(pEa, OpenParams->EaBuffer, eaLength); + } + } + } + } + + Lock(&irql); + + if (m_State == WdfIoTargetDeleted) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Opening WDFIOTARGET %p which is removed, state %d", + GetObjectHandle(), m_State); + status = STATUS_INVALID_DEVICE_STATE; + } + else if (m_OpenState != FxIoTargetRemoteOpenStateClosed) { + // + // We are either open or are opening + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Opening an already open WDFIOTARGET %p, open state %d", + GetObjectHandle(), m_OpenState); + status = STATUS_INVALID_DEVICE_STATE; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Opening WDFIOTARGET %p", GetObjectHandle()); + + // + // Clear the event so that if something is waiting on the state + // transition, they will block until we are done. + // + m_OpenedEvent.Clear(); + + m_OpenState = FxIoTargetRemoteOpenStateOpening; + status = STATUS_SUCCESS; + } + Unlock(irql); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + ASSERT(m_TargetFileObject == NULL); + ASSERT(m_TargetDevice == NULL); + ASSERT(m_TargetPdo == NULL); + ASSERT(m_TargetHandle == NULL); + + // + // m_TargetNotifyHandle can be a valid value if the caller has previously + // opened the target, received a query remove, then a cancel remove, and + // is now reopening the target. + // + UnregisterForPnpNotification(m_TargetNotifyHandle); + ResetTargetNotifyHandle(); + + // + // Only clear the open parameters if we are not attempting a reopen. + // + if (reopen == FALSE) { + m_OpenParams.Clear(); + } + + switch (type) { + case WdfIoTargetOpenUseExistingDevice: + KMDF_ONLY_CODE_PATH_ASSERT(); + + // + // OpenParams must be non NULL b/c we can't reopen a target with a + // previous device object. + // + ASSERT(OpenParams->Type == WdfIoTargetOpenUseExistingDevice); + + m_TargetDevice = (MdDeviceObject) OpenParams->TargetDeviceObject; + m_TargetFileObject = (MdFileObject) OpenParams->TargetFileObject; + m_TargetHandle = NULL; + + // + // By taking a manual reference here, we simplify the code in + // FxIoTargetRemote::Close where we can assume there is an outstanding + // reference on the PFILE_OBJECT at all times as long as we have a non + // NULL pointer. + // + if (m_TargetFileObject != NULL) { + Mx::MxReferenceObject(m_TargetFileObject); + } + + status = STATUS_SUCCESS; + + break; + + case WdfIoTargetOpenLocalTargetByFile: + UMDF_ONLY_CODE_PATH_ASSERT(); + + status = OpenLocalTargetByFile(OpenParams); + break; + + case WdfIoTargetOpenByName: + // + // Only capture the open parameters if we are not reopening. + // + if (reopen == FALSE) { + pParams->Set(OpenParams, &name, pEa, eaLength); + } + + status = OpenTargetHandle(OpenParams, pParams); + if (NT_SUCCESS(status)) { + if (reopen == FALSE) { + m_OpenParams.Set(OpenParams, &name, pEa, eaLength); + + // + // Setting pEa to NULL stops it from being freed later. + // Zeroing out name stops it from being freed later. + // + pEa = NULL; + RtlZeroMemory(&name, sizeof(name)); + } + } + else { + close = TRUE; + } + break; + } + + InitializeListHead(&pended); + + // + // Get Target file object for KMDF. Noop for UMDF. + // + if (NT_SUCCESS(status)) { + status = GetTargetDeviceRelations(&close); + } + + if (NT_SUCCESS(status) && CanRegisterForPnpNotification()) { + if (reopen == FALSE) { + // + // Set the values before the register so that if a notification + // comes in before the register returns, we have a function to call. + // + m_EvtQueryRemove.m_Method = OpenParams->EvtIoTargetQueryRemove; + m_EvtRemoveCanceled.m_Method = OpenParams->EvtIoTargetRemoveCanceled; + m_EvtRemoveComplete.m_Method = OpenParams->EvtIoTargetRemoveComplete; + } + + status = RegisterForPnpNotification(); + + // + // Even if we can't register, we still are successful in opening + // up the device and we will proceed from there. + // + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, could not register pnp notification, %!STATUS! not " + "treated as an error", GetObjectHandle(), status); + + m_EvtQueryRemove.m_Method = NULL; + m_EvtRemoveCanceled.m_Method = NULL; + m_EvtRemoveComplete.m_Method = NULL; + + status = STATUS_SUCCESS; + } + } + + // + // UMDF only. Bind handle to remote dispatcher. + // +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + if (NT_SUCCESS(status) && type != WdfIoTargetOpenLocalTargetByFile) { + status = BindToHandle(); + if (!NT_SUCCESS(status)) { + close = TRUE; + } + } +#endif + + Lock(&irql); + + if (NT_SUCCESS(status)) { + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_TargetStackSize = m_TargetDevice->StackSize; + m_TargetIoType = GetTargetIoType(); +#endif + + m_OpenState = FxIoTargetRemoteOpenStateOpen; + + // + // Set our state to started. This will also resend any pended requests + // due to a query remove. + // + status = GotoStartState(&pended, FALSE); + + // + // We could not successfully start, close back down + // + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p could not transition to started state, %!STATUS!", + GetObjectHandle(), status); + + close = TRUE; + } + } + else { + m_OpenState = FxIoTargetRemoteOpenStateClosed; + } + + // + // No matter what, indicate to any waiters that our state change has + // completed. + // + m_OpenedEvent.Set(); + + Unlock(irql); + +Done: + // + // Resubmit any reads that were pended until now. + // + if (NT_SUCCESS(status)) { + SubmitPendedRequests(&pended); + } + else if (close) { + Close(FxIoTargetRemoteCloseReasonPlainClose); + } + + if (name.Buffer != NULL) { + FxPoolFree(name.Buffer); + } + + if (pEa != NULL) { + FxPoolFree(pEa); + } + + return status; +} + + +VOID +FxIoTargetRemote::Close( + __in FxIoTargetRemoteCloseReason Reason + ) +{ + FxIoTargetClearedPointers pointers; + MdTargetNotifyHandle pNotifyHandle; + SINGLE_LIST_ENTRY sent; + LIST_ENTRY pended; + WDF_IO_TARGET_STATE removeState; + KIRQL irql; + BOOLEAN wait; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter: WDFIOTARGET %p, reason %d", GetObjectHandle(), Reason); + + RtlZeroMemory(&pointers, sizeof(pointers)); + pNotifyHandle = NULL; + + sent.Next = NULL; + InitializeListHead(&pended); + + wait = FALSE; + + // + // Pick a value that is not used anywhere in the function and make sure that + // we have changed it, before we go to the Remove state + // +#pragma prefast(suppress: __WARNING_UNUSED_SCALAR_ASSIGNMENT, "PFD is warning that the following assignement is unused. Suppress it to prevent changing any logic.") + removeState = WdfIoTargetStarted; + +CheckState: + Lock(&irql); + + // + // If we are in the process of opening the target, wait for that to finish. + // + if (m_OpenState == FxIoTargetRemoteOpenStateOpening) { + Unlock(irql); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Closing WDFIOTARGET %p which is opening, waiting on event %p", + GetObjectHandle(), m_OpenedEvent.GetEvent()); + + m_OpenedEvent.EnterCRAndWaitAndLeave(); + + // + // Jump back to the top and recheck + // + goto CheckState; + } + + if (Reason == FxIoTargetRemoteCloseReasonDelete) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Closing WDFIOTARGET %p, reason: delete", GetObjectHandle()); + + removeState = WdfIoTargetDeleted; + } + else if (m_OpenState == FxIoTargetRemoteOpenStateOpen) { + if (Reason == FxIoTargetRemoteCloseReasonQueryRemove) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Closing WDFIOTARGET %p, reason: query remove", + GetObjectHandle()); + // + // Not really being removed, but that is what the API name is... + // + removeState = WdfIoTargetClosedForQueryRemove; + } + else { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Closing WDFIOTARGET %p, reason: close", GetObjectHandle()); + + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { + removeState = WdfIoTargetClosed; + } + else { + removeState = WdfIoTargetClosedForQueryRemove; + } + } + + // + // Either way, we are no longer open for business + // + m_OpenState = FxIoTargetRemoteOpenStateClosed; + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Closing WDFIOTARGET %p which is not open", GetObjectHandle()); + + // + // We are not opened, so treat this as a cleanup + // + removeState = WdfIoTargetClosed; + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: fileobj %p, devobj %p, handle %p, notify handle %I64d", + GetObjectHandle(), m_TargetFileObject, + m_TargetDevice, m_TargetHandle, (UINT64)m_TargetNotifyHandle); + + if (Reason != FxIoTargetRemoteCloseReasonQueryRemove) { + // + // If we are closing for a query remove, we want to keep the handle + // around so that we can be notified of the final close or if the close + // was canceled. + // + pNotifyHandle = m_TargetNotifyHandle; + ResetTargetNotifyHandle(); + } + + ASSERT(removeState != WdfIoTargetStarted); + m_ClearedPointers = &pointers; + GotoRemoveState(removeState, &pended, &sent, FALSE, &wait); + + Unlock(irql); + + UnregisterForPnpNotification(pNotifyHandle); + + // + // Complete any requests we might have pulled off of our lists + // + CompletePendedRequestList(&pended); + _CancelSentRequests(&sent); + + // + // We were just removed, wait for any I/O to complete back if necessary. + // + if (wait) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p, waiting for stop to complete", GetObjectHandle()); + + WaitForSentIoToComplete(); + } + + switch (Reason) { + case FxIoTargetRemoteCloseReasonQueryRemove: + // + // m_OpenParams is needed for reopen on canceled query remove + // + DO_NOTHING(); + break; + + case FxIoTargetRemoteCloseReasonDelete: + m_OpenParams.Clear(); + break; + + default: + // + // If this object is not about to be deleted, we need to revert some + // of the state that just changed. + // + m_SentIoEvent.Clear(); + break; + } + + if (removeState == WdfIoTargetDeleted) { + WaitForDisposeEvent(); + } + + // + // Finally, close down our handle and pointers + // + if (pointers.TargetPdo != NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p derefing PDO %p on close", + GetObjectHandle(), pointers.TargetPdo); + + Mx::MxDereferenceObject(pointers.TargetPdo); + } + + if (pointers.TargetFileObject != NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p derefing FileObj %p on close", + GetObjectHandle(), pointers.TargetFileObject); + Mx::MxDereferenceObject(pointers.TargetFileObject); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + CloseWdfFileObject(pointers.TargetFileObject); +#endif + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + UnbindHandle(&pointers); +#endif + + if (pointers.TargetHandle != NULL) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p closing handle %p on close", + GetObjectHandle(), pointers.TargetHandle); + Mx::MxClose(pointers.TargetHandle); + } +} + +VOID +FxIoTargetRemote::ClearTargetPointers( + VOID + ) +{ + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p cleared pointers %p state %!WDF_IO_TARGET_STATE!," + " open state %d, pdo %p, fileobj %p, handle %p", + GetObjectHandle(), m_ClearedPointers, m_State, m_OpenState, m_TargetPdo, + m_TargetFileObject, m_TargetHandle); + + // + // Check to see if the caller who is changing state wants these pointer + // values before they being cleared out. + // + if (m_ClearedPointers != NULL) { + m_ClearedPointers->TargetPdo = m_TargetPdo; + m_ClearedPointers->TargetFileObject = m_TargetFileObject; + m_ClearedPointers->TargetHandle = m_TargetHandle; + m_ClearedPointers = NULL; + } + + // + // m_TargetHandle is only an FxIoTargetRemote field, clear it now + // + m_TargetHandle = NULL; + + // + // m_TargetPdo and m_TargetFileObject will be cleared in the following call. + // + // m_TargetNotifyHandle is not cleared in the following call and is left + // valid because we want to receive the notification about query remove being + // canceled or completing. When we receive either of those notifications, + // m_TargetNotifyHandle will be freed then. + // + __super::ClearTargetPointers(); +} + +VOID +FxIoTargetRemote::Remove( + VOID + ) +{ + // + // Close is the same as remove in this object + // + Close(FxIoTargetRemoteCloseReasonDelete); + + // + // Do mode-specific work + // + RemoveModeSpecific(); + + return ; +} + +VOID +FxIoTargetRemoveOpenParams::Clear( + VOID + ) +{ + if (EaBuffer != NULL) { + FxPoolFree(EaBuffer); + } + + if (TargetDeviceName.Buffer != NULL) { + FxPoolFree(TargetDeviceName.Buffer); + } + + RtlZeroMemory(this, sizeof(FxIoTargetRemoveOpenParams)); +} + +VOID +FxIoTargetRemoveOpenParams::Set( + __in PWDF_IO_TARGET_OPEN_PARAMS OpenParams, + __in PUNICODE_STRING Name, + __in PVOID Ea, + __in ULONG EaLength + ) +{ + OpenType = WdfIoTargetOpenByName; + + EaBuffer = Ea; + EaBufferLength = EaLength; + + RtlCopyMemory(&TargetDeviceName, Name, sizeof(UNICODE_STRING)); + + DesiredAccess = OpenParams->DesiredAccess; + FileAttributes = OpenParams->FileAttributes; + ShareAccess = OpenParams->ShareAccess; + CreateDisposition = OpenParams->CreateDisposition; + CreateOptions = OpenParams->CreateOptions; + + if (OpenParams->AllocationSize != NULL) { + AllocationSize.QuadPart = *(OpenParams->AllocationSize); + AllocationSizePointer = &AllocationSize; + } + else { + AllocationSizePointer = NULL; + } +} diff --git a/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetself.cpp b/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetself.cpp new file mode 100644 index 00000000000..a74b10c50a2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/fxiotargetself.cpp @@ -0,0 +1,176 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetSelf.cpp + +Abstract: + + This module implements the IO Target APIs + +Author: + + + + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + + +#include "..\FxTargetsShared.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoTargetSelf.tmh" +#endif +} + +FxIoTargetSelf::FxIoTargetSelf( + _In_ PFX_DRIVER_GLOBALS FxDriverGlobals, + _In_ USHORT ObjectSize + ) : + FxIoTarget(FxDriverGlobals, ObjectSize, FX_TYPE_IO_TARGET_SELF), + m_DispatchQueue(NULL) +{ +} + +FxIoTargetSelf::~FxIoTargetSelf() +{ +} + +FxIoQueue* +FxIoTargetSelf::GetDispatchQueue( + UCHAR MajorFunction + ) +/*++ +Routine Description: + Returns a pointer to the queue to which an IO sent to the Self + io target must be sent to + +Arguments: + + MajorFunction - IRP_MJ_READ, IRP_MJ_WRITE, or IRP_MJ_DEVICE_CONTROL + +Returns: + + FxIoQueue* + +--*/ +{ + if (m_DispatchQueue != NULL) { + return m_DispatchQueue; + } + + return m_Device->m_PkgIo->GetDispatchQueue(MajorFunction); +} + +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(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; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetapikm.cpp b/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetapikm.cpp new file mode 100644 index 00000000000..d25d41eeac4 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetapikm.cpp @@ -0,0 +1,433 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetAPIKm.cpp + +Abstract: + + This module implements the IO Target APIs + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "..\..\FxTargetsShared.hpp" + +extern "C" { +#include "FxIoTargetAPIKm.tmh" +} + +// +// Extern the entire file +// +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +PDEVICE_OBJECT +WDFEXPORT(WdfIoTargetWdmGetTargetDeviceObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Returns the PDEVICE_OBJECT. This is the device which PIRPs are sent to. + This is not necessarily the PDEVICE_OBJECT that WDFDEVICE is attached to. + +Arguments: + IoTarget - target whose WDM device object is being returned + +Return Value: + valid PDEVICE_OBJECT or NULL on failure + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + PDEVICE_OBJECT pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + pDevice = pTarget->GetTargetDevice(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, WDM DevObj 0x%p", IoTarget, pDevice); + + return pDevice; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +PDEVICE_OBJECT +WDFEXPORT(WdfIoTargetWdmGetTargetPhysicalDevice)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Returns the PDO for the target itself. This is not necessarily the same + PDO as the WDFDEVICE that owns the target. Not all targets have a PDO since + you can open a legacy non pnp PDEVICE_OBJECT which does not have one. + +Arguments: + IoTarget - target whose PDO is being returned + +Return Value: + A valid PDEVICE_OBJECT or NULL upon success + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + PDEVICE_OBJECT pPdo; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + pPdo = pTarget->GetTargetPDO(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, WDM PDO 0x%p", IoTarget, pPdo); + + return pPdo; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +PFILE_OBJECT +WDFEXPORT(WdfIoTargetWdmGetTargetFileObject)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget + ) +/*++ + +Routine Description: + Returns the PFILE_OBJECT associated with the target. Not all targets have + an underlying file object so NULL is a valid and successful return value. + +Arguments: + IoTarget - the target whose fileobject is being returned + +Return Value: + a valid PFILE_OBJECT or NULL upon success + + --*/ +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTarget* pTarget; + MdFileObject pFile; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "enter WDFIOTARGET 0x%p", IoTarget); + + pFile = pTarget->GetTargetFileObject(); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, WDM FileObj 0x%p", IoTarget, pFile); + + return pFile; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +_Must_inspect_result_ +NTSTATUS +WDFEXPORT(WdfIoTargetQueryForInterface)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + LPCGUID InterfaceType, + __out + PINTERFACE Interface, + __in + USHORT Size, + __in + USHORT Version, + __in_opt + PVOID InterfaceSpecificData + ) +/*++ + +Routine Description: + Sends a query interface pnp request to the top of the target's stack. + +Arguments: + IoTarget - the target which is being queried + + InterfaceType - interface type specifier + + Interface - Interface block which will be filled in by the component which + responds to the query interface + + Size - size in bytes of Interface + + Version - version of InterfaceType being requested + + InterfaceSpecificData - Additional data associated with Interface + +Return Value: + NTSTATUS + + --*/ +{ + FxIoTarget* pTarget; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PDEVICE_OBJECT pTopOfStack; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, InterfaceType); + FxPointerNotNull(pFxDriverGlobals, Interface); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + pTopOfStack = IoGetAttachedDeviceReference(pTarget->GetTargetDevice()); + ASSERT(pTopOfStack != NULL); + + status = FxQueryInterface::_QueryForInterface(pTopOfStack, + InterfaceType, + Interface, + Size, + Version, + InterfaceSpecificData); + + ObDereferenceObject(pTopOfStack); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfIoTargetQueryTargetProperty)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + DEVICE_REGISTRY_PROPERTY DeviceProperty, + __in + ULONG BufferLength, + __drv_when(BufferLength != 0, __out_bcount_part_opt(BufferLength, *ResultLength)) + __drv_when(BufferLength == 0, __out_opt) + PVOID PropertyBuffer, + __deref_out_range(<=,BufferLength) + PULONG ResultLength + ) +/*++ + +Routine Description: + Retrieves the requested device property for the given target + +Arguments: + IoTarget - the target whose PDO whose will be queried + + DeviceProperty - the property being queried + + BufferLength - length of PropertyBuffer in bytes + + PropertyBuffer - Buffer which will receive the property being queried + + ResultLength - if STATUS_BUFFER_TOO_SMALL is returned, then this will contain + the required length + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pGlobals; + NTSTATUS status; + FxIoTarget* pTarget; + MdDeviceObject pPdo; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pGlobals); + + FxPointerNotNull(pGlobals, ResultLength); + if (BufferLength > 0) { + FxPointerNotNull(pGlobals, PropertyBuffer); + } + + status = FxVerifierCheckIrqlLevel(pGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + pPdo = pTarget->GetTargetPDO(); + + if (pPdo == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET 0x%p has no PDO (not opened yet?), %!STATUS!", + IoTarget, status); + + return status; + } + + status = FxDevice::_GetDeviceProperty(pPdo, + DeviceProperty, + BufferLength, + PropertyBuffer, + ResultLength); + + DoTraceLevelMessage(pGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, Property %d, %!STATUS!", + IoTarget, DeviceProperty, status); + + + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetAllocAndQueryTargetProperty)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFIOTARGET IoTarget, + __in + DEVICE_REGISTRY_PROPERTY DeviceProperty, + __in + __drv_strictTypeMatch(1) + POOL_TYPE PoolType, + __in_opt + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + __out + WDFMEMORY* PropertyMemory + ) +/*++ + +Routine Description: + Allocates and retrieves the requested device property for the given target + +Arguments: + IoTarget - the target whose PDO whose will be queried + + DeviceProperty - the property being queried + + PoolType - what type of pool to allocate + + PropertyMemoryAttributes - attributes to associate with PropertyMemory + + PropertyMemory - handle which will receive the property buffer + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + FxIoTarget* pTarget; + MdDeviceObject pPdo; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + IoTarget, + FX_TYPE_IO_TARGET, + (PVOID*) &pTarget, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PropertyMemory); + + *PropertyMemory = NULL; + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + FxVerifierCheckNxPoolType(pFxDriverGlobals, PoolType, pFxDriverGlobals->Tag); + + status = FxValidateObjectAttributes(pFxDriverGlobals, PropertyMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + pPdo = pTarget->GetTargetPDO(); + + if (pPdo == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p has no PDO (not opened yet?), %!STATUS!", + IoTarget, status); + + return status; + } + + // + // Worker function which does the 2 passes. First pass to query the size, + // the second pass w/the correctly sized buffer. + // + status = FxDevice::_AllocAndQueryProperty(pFxDriverGlobals, + NULL, + NULL, + pPdo, + DeviceProperty, + PoolType, + PropertyMemoryAttributes, + PropertyMemory); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "exit WDFIOTARGET 0x%p, Property %d, %!STATUS!", + IoTarget, DeviceProperty, status); + + return status; +} + +} diff --git a/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetkm.cpp b/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetkm.cpp new file mode 100644 index 00000000000..ca2d075c9a2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetkm.cpp @@ -0,0 +1,524 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetKm.cpp + +Abstract: + + This module implements the IO Target APIs + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + + +#include "..\..\FxTargetsShared.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoTargetKm.tmh" +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::FormatIoRequest( + __inout FxRequestBase* Request, + __in UCHAR MajorCode, + __in FxRequestBuffer* IoBuffer, + __in_opt PLONGLONG DeviceOffset, + _In_opt_ FxFileObject* FileObject + ) +{ + FxIoContext* pContext; + PVOID pBuffer; + NTSTATUS status; + ULONG ioLength; + BOOLEAN freeSysBuf; + BOOLEAN setBufferAndLength; + FxIrp* irp; + + UNREFERENCED_PARAMETER(FileObject); + + ASSERT(MajorCode == IRP_MJ_WRITE || MajorCode == IRP_MJ_READ); + + freeSysBuf = FALSE; + pBuffer = NULL; + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Request->HasContextType(FX_RCT_IO)) { + pContext = (FxIoContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxIoContext(); + if (pContext == NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "could not allocate context for request"); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Since we can error out and return, remember the allocation before + // we do anything so we can free it later. + // + Request->SetContext(pContext); + } + + // + // Save away any references to IFxMemory pointers that are passed + // + pContext->StoreAndReferenceMemory(IoBuffer); + + irp = Request->GetSubmitFxIrp(); + irp->ClearNextStackLocation(); + + CopyFileObjectAndFlags(Request); + + // + // Note that by convention "Set" methods of FxIrp apply to next stack + // location unless specified otherwise in the name. + // + irp->SetMajorFunction(MajorCode); + pContext->m_MajorFunction = MajorCode; + + // + // Anytime we return here and we allocated the context above, the context + // will be freed when the FxRequest is freed or reformatted. + // + + ioLength = IoBuffer->GetBufferLength(); + + pContext->CaptureState(irp); + + switch (m_TargetIoType) { + case WdfDeviceIoBuffered: + irp->SetUserBuffer(NULL); + + if (ioLength != 0) { + + + if ((pContext->m_BufferToFreeLength >= ioLength) && + (pContext->m_BufferToFree != NULL)) { + irp->SetSystemBuffer(pContext->m_BufferToFree); + setBufferAndLength = FALSE; + } + else { + irp->SetSystemBuffer(FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + ioLength)); + if (irp->GetSystemBuffer() == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate common buffer"); + + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + setBufferAndLength = TRUE; + freeSysBuf = TRUE; + } + + status = IoBuffer->GetBuffer(&pBuffer); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve io buffer, %!STATUS!", status); + break; + } + + // + // If its a write, copy into the double buffer now, otherwise, + // no copy into the buffer is needed for a read. + // + if (MajorCode == IRP_MJ_WRITE) { + if (pBuffer != NULL) { + RtlCopyMemory(irp->GetSystemBuffer(), + pBuffer, + ioLength); + } + } + else { + irp->SetUserBuffer(pBuffer); + } + + // + // On reads, copy back to the double buffer after the read has + // completed. + // + if (setBufferAndLength) { + pContext->SetBufferAndLength(irp->GetSystemBuffer(), + ioLength, + (MajorCode == IRP_MJ_READ) ? TRUE : FALSE); + + freeSysBuf = FALSE; // FxIoContext will free the buffer. + } + else { + pContext->m_CopyBackToBuffer = MajorCode == IRP_MJ_READ ? + TRUE : FALSE; + } + } + else { + // + // This field was captured and will be restored by the context + // later. + // + irp->SetSystemBuffer(NULL); + } + break; + case WdfDeviceIoDirect: + { + BOOLEAN reuseMdl; + + reuseMdl = FALSE; + + if (pContext->m_MdlToFree != NULL) { + reuseMdl = TRUE; + } + + status = IoBuffer->GetOrAllocateMdl( + GetDriverGlobals(), + irp->GetMdlAddressPointer(), + &pContext->m_MdlToFree, + &pContext->m_UnlockPages, + (MajorCode == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess, + reuseMdl, + &pContext->m_MdlToFreeSize + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve io buffer as a PMDL, %!STATUS!", + status); + break; + } + break; + } + case WdfDeviceIoNeither: + // + // Neither MDL nor buffered + // + status = IoBuffer->GetBuffer(&pBuffer); + + if (NT_SUCCESS(status)) { + irp->SetUserBuffer(pBuffer); + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve io buffer as a PVOID, %!STATUS!", + status); + } + break; + + case WdfDeviceIoUndefined: + default: + status = STATUS_INVALID_DEVICE_STATE; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Trying to format closed WDFIOTARGET %p, %!STATUS!", + GetHandle(), status); + break; + } + + // + // We are assuming the read and write parts of the Parameters union + // are at the same offset. If this is FALSE, WDFCASSERT will not allow + // this file to compile, so keep these WDFCASSERTs here as long as the + // assumption is being made. + // + WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.ByteOffset) + == + FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.ByteOffset)); + + WDFCASSERT(FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Write.Length) + == + FIELD_OFFSET(IO_STACK_LOCATION, Parameters.Read.Length)); + + if (NT_SUCCESS(status)) { + + irp->SetNextParameterWriteLength(ioLength); + if (DeviceOffset != NULL) { + irp->SetNextParameterWriteByteOffsetQuadPart(*DeviceOffset); + } + else { + irp->SetNextParameterWriteByteOffsetQuadPart(0); + } + + Request->VerifierSetFormatted(); + } + else { + if (freeSysBuf) { + FxPoolFree(irp->GetSystemBuffer()); + irp->SetSystemBuffer(NULL); + } + + Request->ContextReleaseAndRestore(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::FormatIoctlRequest( + __in FxRequestBase* Request, + __in ULONG Ioctl, + __in BOOLEAN Internal, + __in FxRequestBuffer* InputBuffer, + __in FxRequestBuffer* OutputBuffer, + _In_opt_ FxFileObject* FileObject + ) +{ + FxIoContext* pContext; + NTSTATUS status; + PVOID pBuffer; + ULONG inLength, outLength; + BOOLEAN freeSysBuf; + BOOLEAN setBufferAndLength; + FxIrp* irp; + + UNREFERENCED_PARAMETER(FileObject); + + irp = Request->GetSubmitFxIrp(); + freeSysBuf = FALSE; + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Request->HasContextType(FX_RCT_IO)) { + pContext = (FxIoContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxIoContext(); + if (pContext == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate context for request"); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + pContext->CaptureState(irp); + + irp->ClearNextStackLocation(); + + // + // Save away any references to IFxMemory pointers that are passed + // + pContext->StoreAndReferenceMemory(InputBuffer); + pContext->StoreAndReferenceOtherMemory(OutputBuffer); + + UCHAR majorFunction; + if (Internal) { + majorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; + } + else { + majorFunction = IRP_MJ_DEVICE_CONTROL; + } + + irp->SetMajorFunction(majorFunction); + + pContext->m_MajorFunction = majorFunction; + + CopyFileObjectAndFlags(Request); + + inLength = InputBuffer->GetBufferLength(); + outLength = OutputBuffer->GetBufferLength(); + + irp->SetParameterIoctlCode(Ioctl); + irp->SetParameterIoctlInputBufferLength(inLength); + irp->SetParameterIoctlOutputBufferLength(outLength); + + + // + // Anytime we return here and we allocated the context above, the context + // will be freed when the FxRequest is freed or reformatted. + // + switch (METHOD_FROM_CTL_CODE(Ioctl)) { + case METHOD_BUFFERED: + + if (inLength != 0 || outLength != 0) { + ULONG allocationLength; + + allocationLength = (inLength > outLength ? inLength : outLength); + + if ((pContext->m_BufferToFreeLength >= allocationLength) && + (pContext->m_BufferToFree != NULL)) { + irp->SetSystemBuffer(pContext->m_BufferToFree); + setBufferAndLength = FALSE; + } + else { + irp->SetSystemBuffer(FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + allocationLength)); + if (irp->GetSystemBuffer() == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate common buffer"); + status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + setBufferAndLength = TRUE; + freeSysBuf = TRUE; + } + + status = InputBuffer->GetBuffer(&pBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve input buffer, %!STATUS!", + status); + break; + } + + if (pBuffer != NULL) { + RtlCopyMemory(irp->GetSystemBuffer(), + pBuffer, + inLength); + } + + status = OutputBuffer->GetBuffer(&pBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve output buffer, %!STATUS!", + status); + break; + } + + irp->SetUserBuffer(pBuffer); + if (setBufferAndLength) { + pContext->SetBufferAndLength(irp->GetSystemBuffer(), + allocationLength, + outLength > 0 ? TRUE : FALSE); + freeSysBuf = FALSE; // FxIoContext will free the buffer. + } else { + pContext->m_CopyBackToBuffer = outLength > 0 ? TRUE : FALSE; + } + + } + else { + // + // These fields were captured and will be restored by the context + // later. + // + irp->SetUserBuffer(NULL); + irp->SetSystemBuffer(NULL); + } + + break; + + case METHOD_DIRECT_TO_HARDWARE: // METHOD_IN_DIRECT + case METHOD_DIRECT_FROM_HARDWARE: // METHOD_OUT_DIRECT + { + BOOLEAN reuseMdl; + + reuseMdl = FALSE; + + status = InputBuffer->GetBuffer(&pBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve input buffer as a PVOID, %!STATUS!", + status); + break; + } + + irp->SetSystemBuffer(pBuffer); + + // + // NOTE: There is no need to compare the operation type since that + // applies only to the Pages locked in memory and not the MDL data + // structure itself per se. + // Also, note that if the size of the Outbuf need not be equal to the + // size of the MdlToFree as long as the number of page entries match. + // + if (pContext->m_MdlToFree != NULL) { + reuseMdl = TRUE; + } + + status = OutputBuffer->GetOrAllocateMdl( + GetDriverGlobals(), + irp->GetMdlAddressPointer(), + &pContext->m_MdlToFree, + &pContext->m_UnlockPages, + (METHOD_FROM_CTL_CODE(Ioctl) == METHOD_DIRECT_TO_HARDWARE) ? IoReadAccess : IoWriteAccess, + reuseMdl, + &pContext->m_MdlToFreeSize + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve output buffer as a PMDL, %!STATUS!", + status); + break; + } + break; + } + + case METHOD_NEITHER: + status = OutputBuffer->GetBuffer(&pBuffer); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve output buffer as a PVOID, %!STATUS!", + status); + break; + } + + irp->SetUserBuffer(pBuffer); + + status = InputBuffer->GetBuffer(&pBuffer); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve input buffer as a PVOID, %!STATUS!", + status); + + break; + } + + irp->SetParameterIoctlType3InputBuffer(pBuffer); + break; + } + + if (NT_SUCCESS(status)) { + Request->VerifierSetFormatted(); + } + else { + if (freeSysBuf) { + FxPoolFree(irp->GetSystemBuffer()); + irp->SetSystemBuffer(NULL); + } + + Request->ContextReleaseAndRestore(); + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetremotekm.cpp b/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetremotekm.cpp new file mode 100644 index 00000000000..ce88c1a1004 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/km/fxiotargetremotekm.cpp @@ -0,0 +1,366 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetRemoteKm.cpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "..\..\FxTargetsShared.hpp" + +extern "C" { +#include "FxIoTargetRemoteKm.tmh" +} + +#include +#include "wdmguid.h" + +_Must_inspect_result_ +NTSTATUS +FxIoTargetRemote::_PlugPlayNotification( + __in PVOID NotificationStructure, + __inout_opt PVOID Context + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + PTARGET_DEVICE_REMOVAL_NOTIFICATION pNotification; + FxIoTargetRemote* pThis; + NTSTATUS status; + + ASSERT(Mx::MxGetCurrentIrql() < DISPATCH_LEVEL); + pNotification = (PTARGET_DEVICE_REMOVAL_NOTIFICATION) NotificationStructure; + pThis = (FxIoTargetRemote*) Context; + + // + // In one of these callbacks, the driver may decide to delete the target. + // If that is the case, we need to be able to return and deref the object until + // we are done. + // + pThis->ADDREF(_PlugPlayNotification); + + pFxDriverGlobals = pThis->GetDriverGlobals(); + + status = STATUS_SUCCESS; + + if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_QUERY_REMOVE)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: query remove notification", pThis->GetObjectHandle()); + + // + // Device is gracefully being removed. PnP is asking us to close down + // the target. If there is a driver callback, there is *no* default + // behavior. This is because we don't know what the callback is going + // to do. For instance, the driver could reopen the target to a + // different device in a multi-path scenario. + // + if (pThis->m_EvtQueryRemove.m_Method != NULL) { + status = pThis->m_EvtQueryRemove.Invoke(pThis->GetHandle()); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: query remove, default action (close for QR)", + pThis->GetObjectHandle()); + + // + // No callback, close it down conditionally. + // + pThis->Close(FxIoTargetRemoteCloseReasonQueryRemove); + } + } + else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_COMPLETE)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove complete notification", pThis->GetObjectHandle()); + + // + // The device was surprise removed, close it for good if the driver has + // no override. + // + if (pThis->m_EvtRemoveComplete.m_Method != NULL) { + pThis->m_EvtRemoveComplete.Invoke(pThis->GetHandle()); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove complete, default action (close)", + pThis->GetObjectHandle()); + + // + // The device is now gone for good. Close down the target for good. + // + pThis->Close(FxIoTargetRemoteCloseReasonPlainClose); + } + } + else if (FxIsEqualGuid(&pNotification->Event, &GUID_TARGET_DEVICE_REMOVE_CANCELLED)) { + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove canceled notification", pThis->GetObjectHandle()); + + if (pThis->m_EvtRemoveCanceled.m_Method != NULL) { + pThis->m_EvtRemoveCanceled.Invoke(pThis->GetHandle()); + } + else { + WDF_IO_TARGET_OPEN_PARAMS params; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove canceled, default action (reopen)", + pThis->GetObjectHandle()); + + WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(¶ms); + + // + // Attempt to reopen the target with stored settings + // + status = pThis->Open(¶ms); + } + } + + pThis->RELEASE(_PlugPlayNotification); + + return status; +} + +NTSTATUS +FxIoTargetRemote::RegisterForPnpNotification( + ) +{ + NTSTATUS status; + + // + // Register for PNP notifications on the handle we just opened. + // This will notify us of pnp state changes on the handle. + // + status = IoRegisterPlugPlayNotification( + EventCategoryTargetDeviceChange, + 0, + m_TargetFileObject, + m_Driver->GetDriverObject(), + _PlugPlayNotification, + this, + &m_TargetNotifyHandle); + + return status; +} + +VOID +FxIoTargetRemote::UnregisterForPnpNotification( + _In_ MdTargetNotifyHandle Handle + ) +{ + if (Handle != NULL) { + + + + + + + + + + + + + + + + + + + + + + + + if (FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx != NULL) { + FxLibraryGlobals.IoUnregisterPlugPlayNotificationEx(Handle); + } + else { + IoUnregisterPlugPlayNotification(Handle); + } + } +} + +NTSTATUS +FxIoTargetRemote::OpenTargetHandle( + _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams, + _Inout_ FxIoTargetRemoveOpenParams* pParams + ) +{ + OBJECT_ATTRIBUTES oa; + IO_STATUS_BLOCK ioStatus; + NTSTATUS status; + + InitializeObjectAttributes(&oa, + &pParams->TargetDeviceName, + OBJ_KERNEL_HANDLE, + NULL, + NULL); + + status = ZwCreateFile(&m_TargetHandle, + pParams->DesiredAccess, + &oa, + &ioStatus, + pParams->AllocationSizePointer, + pParams->FileAttributes, + pParams->ShareAccess, + pParams->CreateDisposition, + pParams->CreateOptions, + pParams->EaBuffer, + pParams->EaBufferLength); + + OpenParams->FileInformation = (ULONG)ioStatus.Information; + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x", + GetObjectHandle(), status, (ULONG) ioStatus.Information); + + // + // The open operation was successful. Dereference the file handle and + // obtain a pointer to the device object for the handle. + // + status = ObReferenceObjectByHandle( + m_TargetHandle, + pParams->DesiredAccess, + *IoFileObjectType, + KernelMode, + (PVOID*) &m_TargetFileObject, + NULL); + + if (NT_SUCCESS(status)) { + m_TargetDevice = IoGetRelatedDeviceObject(m_TargetFileObject); + + if (m_TargetDevice == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p, could not convert filobj %p to devobj", + GetObjectHandle(), m_TargetFileObject); + + status = STATUS_NO_SUCH_DEVICE; + } + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p, could not convert handle %p to fileobject, " + "status %!STATUS!", + GetObjectHandle(), m_TargetHandle, status); + } + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "ZwCreateFile for WDFIOTARGET %p returned status %!STATUS!, info 0x%x", + GetObjectHandle(), status, (ULONG) ioStatus.Information); + } + + return status; +} + +NTSTATUS +FxIoTargetRemote::GetTargetDeviceRelations( + _Inout_ BOOLEAN* Close + ) +{ + PDEVICE_OBJECT pTopOfStack; + FxAutoIrp irp(NULL); + PIRP pIrp; + NTSTATUS status; + + pTopOfStack = IoGetAttachedDeviceReference(m_TargetDevice); + + pIrp = IoAllocateIrp(pTopOfStack->StackSize, FALSE); + + if (pIrp != NULL) { + PIO_STACK_LOCATION stack; + + irp.SetIrp(pIrp); + + stack = irp.GetNextIrpStackLocation(); + stack->MajorFunction = IRP_MJ_PNP; + stack->MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS; + stack->Parameters.QueryDeviceRelations.Type = TargetDeviceRelation; + + // + // Initialize the status to error in case the bus driver decides not + // to set it correctly. + // + irp.SetStatus(STATUS_NOT_SUPPORTED); + + status = irp.SendIrpSynchronously(pTopOfStack); + + if (NT_SUCCESS(status)) { + PDEVICE_RELATIONS pRelations; + + pRelations = (PDEVICE_RELATIONS) irp.GetInformation(); + + ASSERT(pRelations != NULL); + + // + // m_TargetPdo was referenced by the bus driver, it will be + // dereferenced when the target is closed. + // + m_TargetPdo = pRelations->Objects[0]; + + // + // We, as the caller, are responsible for freeing the relations + // that the bus driver allocated. + // + ExFreePool(pRelations); + } + else { + // + // Could not retrieve the PDO pointer, error handled later + // + DO_NOTHING(); + } + } + else { + // + // Could not even allocate an irp, failure. + // + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Unable to allocate memory for IRP WDFIOTARGET %p, %!STATUS!", + GetObjectHandle(), status); + } + + // + // Only fail the open if we cannot allocate an irp or if the lower + // driver could not allocate a relations. + // + if (status == STATUS_INSUFFICIENT_RESOURCES) { + *Close = TRUE; + } + else { + status = STATUS_SUCCESS; + } + + // + // Remove the reference taken by IoGetAttachedDeviceReference + // + ObDereferenceObject(pTopOfStack); + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/general/um/fxiotargetremoteum.cpp b/sdk/lib/drivers/wdf/shared/targets/general/um/fxiotargetremoteum.cpp new file mode 100644 index 00000000000..7cb68a6bcb7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/um/fxiotargetremoteum.cpp @@ -0,0 +1,658 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetRemoteUm.cpp + +Abstract: + +Author: + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "..\..\FxTargetsShared.hpp" + +extern "C" { +#include "FxIoTargetRemoteUm.tmh" +} + +#include +#include "wdmguid.h" + +NTSTATUS +FxIoTargetRemote::InitRemoteModeSpecific( + __in FxDeviceBase* Device + ) +{ + NTSTATUS status; + HRESULT hr; + IWudfDeviceStack* devStack; + + devStack = Device->GetDeviceObject()->GetDeviceStackInterface(); + + // + // Event initialization can fail in UM so initialize it now instead of in + // constructor. + // + status = m_OpenedEvent.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize m_OpenedEvent, %!STATUS!", status); + return status; + } + + // + // Create remote dispatcher. + // This calls directly into the Host to create. + // For most IoTargets the dispatcher is hidden from the Fx, but + // for the RemoteTarget, we need to directly dispatch I/O to + // a win32 handle, regardless of what dispatch method the device + // is set to use in it's INF. + // + hr = devStack->CreateRemoteDispatcher(&m_pIoDispatcher, + &m_pRemoteDispatcher); + + if (FAILED(hr)) { + status = FxDevice::NtStatusFromHr(devStack, hr); + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to Create RemoteDispatcher, %!STATUS!", status); + return status; + } + + return status; +} + +VOID +FxIoTargetRemote::RemoveModeSpecific( + VOID + ) + +{ + // + // Delete callback object + // + if (m_NotificationCallback != NULL) { + delete m_NotificationCallback; + m_NotificationCallback = NULL; + } + + SAFE_RELEASE(m_pIoDispatcher); + SAFE_RELEASE(m_pRemoteDispatcher); +} + +NTSTATUS +FxIoTargetRemote::OpenTargetHandle( + _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams, + _Inout_ FxIoTargetRemoveOpenParams* pParams + ) +{ + NTSTATUS status; + HRESULT hr = S_OK; + HANDLE hTarget; + ULONG flagsAndAttributes; + + FX_VERIFY_WITH_NAME(INTERNAL, + VERIFY(INVALID_HANDLE_VALUE == m_pRemoteDispatcher->GetHandle()), + GetDriverGlobals()->Public.DriverName); + + // + // UMDF 1.11 allowed following fields to be set by caller. + // DWORD dwDesiredAccess + // typedef struct _UMDF_IO_TARGET_OPEN_PARAMS + // { + // DWORD dwShareMode; // + // DWORD dwCreationDisposition; + // DWORD dwFlagsAndAttributes; + // } UMDF_IO_TARGET_OPEN_PARAMS; + // + // + // We always use overlapped I/O + // + flagsAndAttributes = pParams->FileAttributes | FILE_FLAG_OVERLAPPED; + + hTarget = CreateFile(pParams->TargetDeviceName.Buffer, + pParams->DesiredAccess, // dwDesiredAccess + pParams->ShareAccess, // dwShareMode + NULL, // lpSecurityAttributes + pParams->CreateDisposition, // dwCreationDisposition + flagsAndAttributes, // dwFlagsAndAttributes + NULL); + + if (INVALID_HANDLE_VALUE == hTarget) { + hr = HRESULT_FROM_WIN32(GetLastError()); + status = m_Device->NtStatusFromHr(hr); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "CreateFile for WDFIOTARGET %p returned status %!STATUS!", + GetObjectHandle(), status); + + FX_VERIFY_WITH_NAME(INTERNAL, VERIFY(FAILED(hr)), GetDriverGlobals()->Public.DriverName); + } + else { + m_TargetHandle = hTarget; + status = STATUS_SUCCESS; + } + + return status; +} + +HANDLE +FxIoTargetRemote::GetTargetHandle( + VOID + ) +{ + HRESULT hrQi; + IWudfFile2* pFile; + HANDLE handle = m_TargetHandle; + + if (m_OpenParams.OpenType == WdfIoTargetOpenLocalTargetByFile) { + if (m_TargetFileObject == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p has no target file object, could not get handle", + GetObjectHandle()); + } + else { + ASSERT(m_TargetHandle == NULL); + + hrQi = m_TargetFileObject->QueryInterface(IID_IWudfFile2, (PVOID*)&pFile); + FX_VERIFY(INTERNAL, CHECK_QI(hrQi, pFile)); + pFile->Release(); + + handle = pFile->GetWeakRefHandle(); + } + } + + // + // Normalize the invalid handle value returned by CreateFile in host + // to what's expected by the WdfIoTargetWdmGetTargetFileHandle caller. + // + if (handle == INVALID_HANDLE_VALUE) { + handle = NULL; + } + + return handle; +} + +NTSTATUS +FxIoTargetRemote::BindToHandle( + VOID + ) +{ + NTSTATUS status; + HRESULT hr; + + // + // Tell the RemoteDispatcher to bind to the new handle. + // + hr = m_pRemoteDispatcher->BindToHandle(m_TargetHandle); + if (FAILED(hr)) { + status = m_Device->NtStatusFromHr(hr); + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p could not bind remote dispatcher to new handle, " + "%!STATUS!", GetObjectHandle(), status); + return status; + } + + status = STATUS_SUCCESS; + return status; +} + +void +FxIoTargetRemote::UnbindHandle( + _In_ FxIoTargetClearedPointers* TargetPointers + ) +{ + if (NULL != m_pRemoteDispatcher) { + // + // Close the handle we gave to the RemoteDispatcher + // + // NOTE: IWudfRemoteDispatcher::CloseHandle can be safely called even if + // we've not previously given it a handle. In this case, it does + // nothing. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFIOTARGET %p Unbinding RemoteDispatcher %p to handle %p on close", + GetObjectHandle(), m_pRemoteDispatcher, TargetPointers->TargetHandle); + + m_pRemoteDispatcher->CloseHandle(); + + // + // Host closes the handle in CloseHandle call above so set the handle + // in TargetPointers to NULL. + // + TargetPointers->TargetHandle = NULL; + } +} + +NTSTATUS +FxIoTargetRemote::GetTargetDeviceRelations( + _Inout_ BOOLEAN* Close + ) +{ + UNREFERENCED_PARAMETER(Close); + + // + // Not needed for UMDF + // + DO_NOTHING(); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxIoTargetRemote::RegisterForPnpNotification( + VOID + ) +{ + NTSTATUS status = STATUS_SUCCESS; + HRESULT hr; + FxIoTargetRemoteNotificationCallback* callback; + + UNREFERENCED_PARAMETER(hr); + + // + // Allocate callback object + // + if (m_NotificationCallback == NULL) { + callback = new (GetDriverGlobals()) + FxIoTargetRemoteNotificationCallback(GetDriverGlobals(), this); + + if (callback == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p could not allocate resources for " + "notification registration, %!STATUS!", + GetObjectHandle(), status); + return status; + } + + m_NotificationCallback = callback; + } + + // + // Register for Target Device Change notifications + // These notifications will arrive asynchronously. + // + IWudfDeviceStack * pDevStack = m_Device->GetDeviceStack(); + + hr = pDevStack->RegisterTargetDeviceNotification( + static_cast (m_NotificationCallback), + m_TargetHandle, + &m_TargetNotifyHandle); + + if (FAILED(hr)) { + if (m_NotificationCallback != NULL) { + delete m_NotificationCallback; + m_NotificationCallback = NULL; + } + + status = m_Device->NtStatusFromHr(hr); + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFIOTARGET %p failed to register for Pnp notification, %!STATUS!", + GetObjectHandle(), status); + return status; + } + + status = STATUS_SUCCESS; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p registered for Pnp notification, %!STATUS!", + GetObjectHandle(), status); + + return status; +} + +VOID +FxIoTargetRemote::UnregisterForPnpNotification( + _In_ MdTargetNotifyHandle NotifyHandle + ) +{ + // + // check if we previously registered + // + if (NotifyHandle == WUDF_TARGET_CONTEXT_INVALID) { + return; + } + + // + // Unregister. + // + IWudfDeviceStack * pDevStack = m_Device->GetDeviceStack(); + pDevStack->UnregisterTargetDeviceNotification(NotifyHandle); + +} + +NTSTATUS +FxIoTargetRemote::OpenLocalTargetByFile( + _In_ PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ) +{ + NTSTATUS status; + + // + // OpenParams must be non NULL b/c we can't reopen a target with a + // previous device object. + // + ASSERT(OpenParams->Type == WdfIoTargetOpenLocalTargetByFile); + m_OpenParams.OpenType = OpenParams->Type; + + // + // Create a file object. This is UM-specific feature, where host opens + // the reflector control device (optionally supplying the reference string + // provided by caller). If there are lower device drivers in the um stack, + // host sends them IRP_MJ_CREATE as well. The lower drivers in kernel see + // IRP_MJ_CREATE as well as a result of opening the reflector control + // object. + // Note that m_TargetDevice is already set to next lower device during init. + // + status = CreateWdfFileObject(&OpenParams->FileName, + &m_TargetFileObject); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to create WDF File Object, %!STATUS!", status); + return status; + } + + // + // Target handle is not used in this type of open. + // + m_TargetHandle = NULL; + + // + // By taking a manual reference here, we simplify the code in + // FxIoTargetRemote::Close where we can assume there is an outstanding + // reference on the WDM file object at all times as long as we have a non + // NULL pointer. + // + if (m_TargetFileObject != NULL) { + Mx::MxReferenceObject(m_TargetFileObject); + } + + return status; +} + +NTSTATUS +FxIoTargetRemote::CreateWdfFileObject( + _In_opt_ PUNICODE_STRING FileName, + _Out_ MdFileObject* FileObject + ) +{ + HRESULT hr = S_OK; + NTSTATUS status; + MdFileObject wdmFileObject = NULL; + + FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK_NOT_NULL(FileObject), + GetDriverGlobals()->Public.DriverName); + + *FileObject = NULL; + + hr = m_Device->GetDeviceStack()->CreateWdfFile( + m_Device->GetDeviceObject(), + m_Device->GetAttachedDevice(), + FileName->Buffer, + &wdmFileObject + ); + if (SUCCEEDED(hr)) { + *FileObject = wdmFileObject; + status = STATUS_SUCCESS; + } + else { + status = m_Device->NtStatusFromHr(hr); + } + + return status; +} + +VOID +FxIoTargetRemote::CloseWdfFileObject( + _In_ MdFileObject FileObject + ) +{ + m_Device->GetDeviceStack()->CloseFile(FileObject); + SAFE_RELEASE(FileObject); +} + +BOOL +__stdcall +FxIoTargetRemoteNotificationCallback::OnQueryRemove( + _In_ WUDF_TARGET_CONTEXT RegistrationID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pThis; + NTSTATUS status; + BOOLEAN bStatus; + + pThis = m_RemoteTarget; + + // + // In one of these callbacks, the driver may decide to delete the target. + // If that is the case, we need to be able to return and deref the object until + // we are done. + // + pThis->ADDREF(m_RemoteTarget); + + pFxDriverGlobals = pThis->GetDriverGlobals(); + + status = STATUS_SUCCESS; + bStatus = TRUE; + + if (GetRegistrationId() != RegistrationID) { + // + // By design, we can get notification callbacks even after we have + // unregistered for notifications. This can happen if there were + // callbacks already in flight before we unregistered. In this case, we + // simply succeed on query-remove. Since we have already unregistered, + // there is no reason for us to fail query-remove. + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "QueryRemove callback was for an old registration, ignoring."); + + bStatus = TRUE; + goto exit; + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: query remove notification", + m_RemoteTarget->GetObjectHandle()); + + // + // Device is gracefully being removed. PnP is asking us to close down + // the target. If there is a driver callback, there is *no* default + // behavior. This is because we don't know what the callback is going + // to do. For instance, the driver could reopen the target to a + // different device in a multi-path scenario. + // + if (pThis->m_EvtQueryRemove.m_Method != NULL) { + status = pThis->m_EvtQueryRemove.Invoke( + pThis->GetHandle()); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: query remove, default action (close for QR)", + pThis->GetObjectHandle()); + + // + // No callback, close it down conditionally. + // + pThis->Close(FxIoTargetRemoteCloseReasonQueryRemove); + } + + if (!NT_SUCCESS(status)) { + bStatus = FALSE; + } + +exit: + + pThis->RELEASE(m_RemoteTarget); + + return bStatus; +} + +VOID +__stdcall +FxIoTargetRemoteNotificationCallback::OnRemoveComplete( + _In_ WUDF_TARGET_CONTEXT RegistrationID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pThis; + + pThis = m_RemoteTarget; + + // + // In one of these callbacks, the driver may decide to delete the target. + // If that is the case, we need to be able to return and deref the object until + // we are done. + // + pThis->ADDREF(m_RemoteTarget); + + pFxDriverGlobals = pThis->GetDriverGlobals(); + + if (GetRegistrationId() != RegistrationID) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "RemoveComplete callback was for an old registration, ignoring."); + + goto exit; + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove complete notification", pThis->GetObjectHandle()); + + // + // The device was surprise removed, close it for good if the driver has + // no override. + // + if (pThis->m_EvtRemoveComplete.m_Method != NULL) { + pThis->m_EvtRemoveComplete.Invoke(pThis->GetHandle()); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove complete, default action (close)", + pThis->GetObjectHandle()); + + // + // The device is now gone for good. Close down the target for good. + // + pThis->Close(FxIoTargetRemoteCloseReasonPlainClose); + } + +exit: + + pThis->RELEASE(m_RemoteTarget); +} + +VOID +__stdcall +FxIoTargetRemoteNotificationCallback::OnRemoveCanceled( + _In_ WUDF_TARGET_CONTEXT RegistrationID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxIoTargetRemote* pThis; + NTSTATUS status; + + pThis = m_RemoteTarget; + + // + // In one of these callbacks, the driver may decide to delete the target. + // If that is the case, we need to be able to return and deref the object until + // we are done. + // + pThis->ADDREF(m_RemoteTarget); + + pFxDriverGlobals = pThis->GetDriverGlobals(); + status = STATUS_SUCCESS; + + if (GetRegistrationId() != RegistrationID) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "RemoveCanceled callback was for an old registration, ignoring."); + + goto exit; + } + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove canceled notification", pThis->GetObjectHandle()); + + if (pThis->m_EvtRemoveCanceled.m_Method != NULL) { + pThis->m_EvtRemoveCanceled.Invoke(pThis->GetHandle()); + } + else { + WDF_IO_TARGET_OPEN_PARAMS params; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFIOTARGET %p: remove canceled, default action (reopen)", + pThis->GetObjectHandle()); + + WDF_IO_TARGET_OPEN_PARAMS_INIT_REOPEN(¶ms); + + // + // Attempt to reopen the target with stored settings + // + status = pThis->Open(¶ms); + + + + + + + + UNREFERENCED_PARAMETER(status); + } + +exit: + + pThis->RELEASE(m_RemoteTarget); +} + +VOID +__stdcall +FxIoTargetRemoteNotificationCallback::OnCustomEvent( + _In_ WUDF_TARGET_CONTEXT RegistrationID, + _In_ REFGUID Event, + _In_reads_bytes_(DataSize) BYTE * Data, + _In_ DWORD DataSize, + _In_ DWORD NameBufferOffset + ) +{ + UNREFERENCED_PARAMETER(RegistrationID); + UNREFERENCED_PARAMETER(Event); + UNREFERENCED_PARAMETER(Data); + UNREFERENCED_PARAMETER(DataSize); + UNREFERENCED_PARAMETER(NameBufferOffset); + + // + // UMDF 2.0 doesn't yet support custom event. Ignore the event. + // + DO_NOTHING(); + + return; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/general/um/fxiotargetum.cpp b/sdk/lib/drivers/wdf/shared/targets/general/um/fxiotargetum.cpp new file mode 100644 index 00000000000..5754eff58a6 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/general/um/fxiotargetum.cpp @@ -0,0 +1,315 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxIoTargetUm.cpp + +Abstract: + + This module implements the IO Target APIs + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + + +#include "..\..\FxTargetsShared.hpp" + +extern "C" { +#if defined(EVENT_TRACING) +#include "FxIoTargetUm.tmh" +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::InitModeSpecific( + __in CfxDeviceBase* Device + ) +{ + NTSTATUS status; + + // + // FxCREvent can fail in UMDF so it is initialized outside of constuctor + // for UMDF. It always succeeds for KMDF so it gets initialized in + // event's constructor. + // + + status = m_SentIoEvent.Initialize(SynchronizationEvent, FALSE); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGIOTARGET, + "Could not initialize m_SentIoEvent event for " + "WFIOTARGET %p, %!STATUS!", + GetObjectHandle(), status); + return status; + } + + status = m_DisposeEventUm.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGIOTARGET, + "Could not initialize m_DisposeEventUm event for " + "WFIOTARGET %p, %!STATUS!", + GetObjectHandle(), status); + return status; + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::FormatIoRequest( + __inout FxRequestBase* Request, + __in UCHAR MajorCode, + __in FxRequestBuffer* IoBuffer, + __in_opt PLONGLONG DeviceOffset, + __in_opt FxFileObject* FileObject + ) +{ + FxIoContext* pContext; + NTSTATUS status; + ULONG ioLength; + FxIrp* irp; + PVOID buffer; + + UNREFERENCED_PARAMETER(FileObject); + + ASSERT(MajorCode == IRP_MJ_WRITE || MajorCode == IRP_MJ_READ); + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Request->HasContextType(FX_RCT_IO)) { + pContext = (FxIoContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxIoContext(); + if (pContext == NULL) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "could not allocate context for request"); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Since we can error out and return, remember the allocation before + // we do anything so we can free it later. + // + Request->SetContext(pContext); + } + + // + // Save away any references to IFxMemory pointers that are passed + // + pContext->StoreAndReferenceMemory(IoBuffer); + + // + // Setup irp stack + // + irp = Request->GetSubmitFxIrp(); + irp->ClearNextStackLocation(); + + // + // copy File object and flags + // + CopyFileObjectAndFlags(Request); + + irp->SetMajorFunction(MajorCode); + pContext->m_MajorFunction = MajorCode; + + ioLength = IoBuffer->GetBufferLength(); + + status = IoBuffer->GetBuffer(&buffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve i/o buffer, %!STATUS!", + status); + goto exit; + } + + // + // Since we don't support buffer transformations (buffered->Direct->Neither) + // we are analogous to "Neither" method in KMDF + // in which case we just set the Irp buffer to the buffer that is passed in + // + if (IRP_MJ_READ == MajorCode) { + pContext->SwapIrpBuffer(Request, + 0, + NULL, + ioLength, + buffer); + + irp->GetIoIrp()->SetReadParametersForNextStackLocation( + ioLength, + DeviceOffset, + 0 + ); + } + else if (IRP_MJ_WRITE == MajorCode) { + pContext->SwapIrpBuffer(Request, + ioLength, + buffer, + 0, + NULL); + irp->GetIoIrp()->SetWriteParametersForNextStackLocation( + ioLength, + DeviceOffset, + 0 + ); + } + /* + else if (WdfRequestQueryInformation == RequestType) + { + pContext->SwapIrpBuffer(pRequest, + 0, + NULL, + ioLength, + buffer); + } + else if (WdfRequestSetInformation == RequestType) + { + pContext->SwapIrpBuffer(pRequest, + ioLength, + buffer, + 0, + NULL); + } + */ + else { + pContext->SwapIrpBuffer(Request, 0, NULL, 0, NULL); + } + +exit: + + if (NT_SUCCESS(status)) { + Request->VerifierSetFormatted(); + } + else { + Request->ContextReleaseAndRestore(); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxIoTarget::FormatIoctlRequest( + __in FxRequestBase* Request, + __in ULONG Ioctl, + __in BOOLEAN Internal, + __in FxRequestBuffer* InputBuffer, + __in FxRequestBuffer* OutputBuffer, + __in_opt FxFileObject* FileObject + ) +{ + FxIoContext* pContext; + NTSTATUS status; + ULONG inLength, outLength; + FxIrp* irp; + PVOID inputBuffer; + PVOID outputBuffer; + + UNREFERENCED_PARAMETER(FileObject); + + irp = Request->GetSubmitFxIrp(); + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Request->HasContextType(FX_RCT_IO)) { + pContext = (FxIoContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxIoContext(); + if (pContext == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate context for request"); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + inLength = InputBuffer->GetBufferLength(); + outLength = OutputBuffer->GetBufferLength(); + + // + // Capture irp buffers in context and set driver-provided buffers in the irp + // + status = InputBuffer->GetBuffer(&inputBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve input buffer, %!STATUS!", + status); + goto exit; + } + + status = OutputBuffer->GetBuffer(&outputBuffer); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve output buffer, %!STATUS!", + status); + goto exit; + } + + // + // Save away any references to IFxMemory pointers that are passed + // + pContext->StoreAndReferenceMemory(InputBuffer); + pContext->StoreAndReferenceOtherMemory(OutputBuffer); + pContext->m_MajorFunction = IRP_MJ_DEVICE_CONTROL; + + // + // Format next stack location + // + irp->ClearNextStackLocation(); + irp->SetMajorFunction(IRP_MJ_DEVICE_CONTROL); + + // + // copy File object and flags + // + CopyFileObjectAndFlags(Request); + + irp->GetIoIrp()->SetDeviceIoControlParametersForNextStackLocation( + Ioctl, + inLength, + outLength + ); + + pContext->SwapIrpBuffer(Request, + InputBuffer->GetBufferLength(), + inputBuffer, + OutputBuffer->GetBufferLength(), + outputBuffer); +exit: + + if (NT_SUCCESS(status)) { + Request->VerifierSetFormatted(); + } + else { + Request->ContextReleaseAndRestore(); + } + + return status;; +} + + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbdevice.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbdevice.cpp new file mode 100644 index 00000000000..01c1cc9ace0 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbdevice.cpp @@ -0,0 +1,2475 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbDevice.cpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +extern "C" { +#include +} + +#include "fxusbpch.hpp" + + +extern "C" { +#include "FxUsbDevice.tmh" +} + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) +#define UCHAR_MAX (0xff) +#endif + +FxUsbDeviceControlContext::FxUsbDeviceControlContext( + __in FX_URB_TYPE FxUrbType + ) : + FxUsbRequestContext(FX_RCT_USB_CONTROL_REQUEST) +{ + m_PartialMdl = NULL; + m_UnlockPages = FALSE; + m_USBDHandle = NULL; + + if (FxUrbType == FxUrbTypeLegacy) { + m_Urb = &m_UrbLegacy; + } + else { + m_Urb = NULL; + } +} + +FxUsbDeviceControlContext::~FxUsbDeviceControlContext( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)) { + USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); + } + m_Urb = NULL; + m_USBDHandle = NULL; +} + +__checkReturn +NTSTATUS +FxUsbDeviceControlContext::AllocateUrb( + __in USBD_HANDLE USBDHandle + ) +{ + NTSTATUS status; + + ASSERT(USBDHandle != NULL); + ASSERT(m_Urb == NULL); + + status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + m_USBDHandle = USBDHandle; + +Done: + return status; +} + +VOID +FxUsbDeviceControlContext::Dispose( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)){ + USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); + m_Urb = NULL; + m_USBDHandle = NULL; + } +} + +VOID +FxUsbDeviceControlContext::CopyParameters( + __in FxRequestBase* Request + ) +{ +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_CompletionParams.IoStatus.Information = m_Urb->TransferBufferLength; + m_UsbParameters.Parameters.DeviceControlTransfer.Length = m_Urb->TransferBufferLength; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + m_CompletionParams.IoStatus.Information = m_UmUrb.UmUrbControlTransfer.TransferBufferLength; + m_UsbParameters.Parameters.DeviceControlTransfer.Length = m_UmUrb.UmUrbControlTransfer.TransferBufferLength; +#endif + __super::CopyParameters(Request); +} + +VOID +FxUsbDeviceControlContext::ReleaseAndRestore( + __in FxRequestBase* Request + ) +{ + // + // Check now because Init will NULL out the field + // + if (m_PartialMdl != NULL) { + if (m_UnlockPages) { + Mx::MxUnlockPages(m_PartialMdl); + m_UnlockPages = FALSE; + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + FxMdlFree(Request->GetDriverGlobals(), m_PartialMdl); +#endif + m_PartialMdl = NULL; + } + + __super::ReleaseAndRestore(Request); +} + +USBD_STATUS +FxUsbDeviceControlContext::GetUsbdStatus( + VOID + ) +{ + return m_Urb->Hdr.Status; +} + +FxUsbDeviceStringContext::FxUsbDeviceStringContext( + __in FX_URB_TYPE FxUrbType + ) : + FxUsbRequestContext(FX_RCT_USB_STRING_REQUEST) +{ + m_USBDHandle = NULL; + m_StringDescriptor = NULL; + m_StringDescriptorLength = 0; + RtlZeroMemory(&m_UrbLegacy, sizeof(m_UrbLegacy)); + + if (FxUrbType == FxUrbTypeLegacy) { + m_Urb = &m_UrbLegacy; + m_Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + m_Urb->Hdr.Length = sizeof(*m_Urb); + m_Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE; + } + else { + m_Urb = NULL; + } +} + +FxUsbDeviceStringContext::~FxUsbDeviceStringContext( + VOID + ) +{ + if (m_StringDescriptor != NULL) { + FxPoolFree(m_StringDescriptor); + m_StringDescriptor = NULL; + } + + if (m_Urb && (m_Urb != &m_UrbLegacy)){ + USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); + } + m_Urb = NULL; + m_USBDHandle = NULL; +} + +__checkReturn +NTSTATUS +FxUsbDeviceStringContext::AllocateUrb( + __in USBD_HANDLE USBDHandle + ) +{ + NTSTATUS status; + + ASSERT(USBDHandle != NULL); + ASSERT(m_Urb == NULL); + + status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + m_USBDHandle = USBDHandle; + + m_Urb->Hdr.Function = URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE; + m_Urb->Hdr.Length = sizeof(*m_Urb); + m_Urb->DescriptorType = USB_STRING_DESCRIPTOR_TYPE; + +Done: + return status; +} + +VOID +FxUsbDeviceStringContext::Dispose( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)){ + USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); + m_Urb = NULL; + m_USBDHandle = NULL; + } + +} + +VOID +FxUsbDeviceStringContext::CopyParameters( + __in FxRequestBase* Request + ) +{ + // + // Make sure we got an even number of bytes and that we got a header + // + if ((m_StringDescriptor->bLength & 0x1) || + m_StringDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) { + m_CompletionParams.IoStatus.Status = STATUS_DEVICE_DATA_ERROR; + } + else if (NT_SUCCESS(Request->GetSubmitFxIrp()->GetStatus())) { + // + // No matter what, indicate the required size to the caller + // + m_UsbParameters.Parameters.DeviceString.RequiredSize = + m_StringDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR); + + if (m_UsbParameters.Parameters.DeviceString.RequiredSize > + m_RequestMemory->GetBufferSize()) { + // + // Too much string to fit into the buffer supplied by the client. + // Morph the status into a warning. Copy as much as we can. + // + m_CompletionParams.IoStatus.Status = STATUS_BUFFER_OVERFLOW; + RtlCopyMemory(m_RequestMemory->GetBuffer(), + &m_StringDescriptor->bString[0], + m_RequestMemory->GetBufferSize()); + } + else { + // + // Everything fits, copy it over + // + m_CompletionParams.IoStatus.Information = + m_UsbParameters.Parameters.DeviceString.RequiredSize; + + RtlCopyMemory(m_RequestMemory->GetBuffer(), + &m_StringDescriptor->bString[0], + m_UsbParameters.Parameters.DeviceString.RequiredSize); + } + } + + __super::CopyParameters(Request); +} + +VOID +FxUsbDeviceStringContext::SetUrbInfo( + __in UCHAR StringIndex, + __in USHORT LangID + ) +{ + SetUsbType(WdfUsbRequestTypeDeviceString); + + ASSERT(m_StringDescriptor != NULL && m_StringDescriptorLength != 0); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + m_Urb->TransferBuffer = m_StringDescriptor; + m_Urb->TransferBufferLength = m_StringDescriptorLength; + + m_Urb->Index = StringIndex; + m_Urb->LanguageId = LangID; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + m_UmUrb.UmUrbDescriptorRequest.Buffer = m_StringDescriptor; + m_UmUrb.UmUrbDescriptorRequest.BufferLength = m_StringDescriptorLength; + + m_UmUrb.UmUrbDescriptorRequest.Index = StringIndex; + m_UmUrb.UmUrbDescriptorRequest.LanguageID = LangID; +#endif +} + +USBD_STATUS +FxUsbDeviceStringContext::GetUsbdStatus( + VOID + ) +{ + return m_Urb->Hdr.Status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDeviceStringContext::AllocateDescriptor( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in size_t BufferSize + ) +{ + PUSB_STRING_DESCRIPTOR pDescriptor; + size_t length; + NTSTATUS status; + + if (BufferSize <= m_StringDescriptorLength) { + return STATUS_SUCCESS; + } + + length = sizeof(USB_STRING_DESCRIPTOR) - sizeof(pDescriptor->bString[0]) + + BufferSize; + + pDescriptor = (PUSB_STRING_DESCRIPTOR) FxPoolAllocate( + FxDriverGlobals, + NonPagedPool, + length); + + if (pDescriptor == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (m_StringDescriptor != NULL) { + FxPoolFree(m_StringDescriptor); + } + + RtlZeroMemory(pDescriptor, length); + + m_StringDescriptor = pDescriptor; + + status = RtlSizeTToULong(length, &m_StringDescriptorLength); + + return status; +} + +FxUsbUrb::FxUsbUrb( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in USBD_HANDLE USBDHandle, + __in_bcount(BufferSize) PVOID Buffer, + __in size_t BufferSize + ) : + FxMemoryBufferPreallocated(FxDriverGlobals, sizeof(*this), Buffer, BufferSize), + m_USBDHandle(USBDHandle) +{ + MarkDisposeOverride(); +} + +FxUsbUrb::~FxUsbUrb() +{ +} + +BOOLEAN +FxUsbUrb::Dispose( + VOID + ) +{ + ASSERT(m_USBDHandle != NULL); + ASSERT(m_pBuffer != NULL); + USBD_UrbFree(m_USBDHandle, (PURB)m_pBuffer); + m_pBuffer = NULL; + m_USBDHandle = NULL; + + return __super::Dispose(); +} + +FxUsbDevice::FxUsbDevice( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ) : + FxIoTarget(FxDriverGlobals, sizeof(FxUsbDevice), FX_TYPE_IO_TARGET_USB_DEVICE) +{ + RtlZeroMemory(&m_DeviceDescriptor, sizeof(m_DeviceDescriptor)); + RtlZeroMemory(&m_UsbdVersionInformation, sizeof(m_UsbdVersionInformation)); + + m_OnUSBD = FALSE; + m_Interfaces = NULL;; + m_NumInterfaces = 0; + + m_Traits = 0; + m_HcdPortCapabilities = 0; + m_ControlPipe = NULL; + m_QueryBusTime = NULL; + m_BusInterfaceContext = NULL; + m_BusInterfaceDereference = NULL; + m_ConfigHandle = NULL; + m_ConfigDescriptor = NULL; + + m_MismatchedInterfacesInConfigDescriptor = FALSE; + + m_USBDHandle = NULL; + m_UrbType = FxUrbTypeLegacy; + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + m_pHostTargetFile = NULL; + m_WinUsbHandle = NULL; +#endif + + MarkDisposeOverride(ObjectDoNotLock); +} + +BOOLEAN +FxUsbDevice::Dispose( + VOID + ) +{ +#if ((FX_CORE_MODE)==(FX_CORE_KERNEL_MODE)) + KeFlushQueuedDpcs(); +#endif + + if (m_USBDHandle) { + USBD_CloseHandle(m_USBDHandle); + m_USBDHandle = NULL; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + IWudfDevice* device = NULL; + IWudfDeviceStack* devstack = NULL; + + device = m_DeviceBase->GetDeviceObject(); + devstack = device->GetDeviceStackInterface(); + + if (m_pHostTargetFile) { + devstack->CloseFile(m_pHostTargetFile); + SAFE_RELEASE(m_pHostTargetFile); + } +#endif + + return __super::Dispose(); +} + +FxUsbDevice::~FxUsbDevice() +{ + UCHAR i; + + if (m_BusInterfaceDereference != NULL) { + m_BusInterfaceDereference(m_BusInterfaceContext); + m_BusInterfaceDereference = NULL; + } + + if (m_ConfigDescriptor != NULL) { + FxPoolFree(m_ConfigDescriptor); + m_ConfigDescriptor = NULL; + } + + for (i = 0; i < m_NumInterfaces; i++) { + ASSERT(m_Interfaces[i] == NULL); + } + + if (m_Interfaces != NULL){ + FxPoolFree(m_Interfaces); + m_Interfaces = NULL; + } + + m_NumInterfaces = 0; +} + +VOID +FxUsbDevice::RemoveDeletedInterface( + __in FxUsbInterface* Interface + ) +{ + UCHAR i; + + if (m_Interfaces == NULL) { + return; + } + + for (i = 0; i < m_NumInterfaces; i++) { + if (m_Interfaces[i] == Interface) { + m_Interfaces[i] = NULL; + return; + } + } +} + +VOID +FxUsbDevice::GetInformation( + __out PWDF_USB_DEVICE_INFORMATION Information + ) +{ + Information->Traits = m_Traits; + Information->HcdPortCapabilities = m_HcdPortCapabilities; + + RtlCopyMemory(&Information->UsbdVersionInformation, + &m_UsbdVersionInformation, + sizeof(m_UsbdVersionInformation)); +} + +ULONG +FxUsbDevice::GetDefaultMaxTransferSize( + VOID + ) +/*++ + +Routine Description: + Determines the default max transfer size based on the usb host controller + and OS we are running on. What it boils down to is that on XP and later + the usb core ignores the default max transfer size, but it does use the + value on Windows 2000. To make life fun, there is only one definition of + USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE whose value changes depending on header + versioning. Since we are versioned for the latest OS, we do not pick up the + Win2k value by using the #define, rather we have to use the value that we + *would* have picked up if we were header versioned for Win2k. + + NOTE: we could be on win2k with a usbport serviced stack. in this case, + usbport doesn't care about max transfer sizes + +Arguments: + None + +Return Value: + usb core and OS appropriate default max transfer size. + + --*/ +{ + // + // On a usbport serviced stack (which can be running on Win2k) or on a + // usbd stack on XP and later. In any case, always use the current max + // transfer size definition. + // + return USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::Start( + VOID + ) +{ + NTSTATUS status; + + status = FxIoTarget::Start(); + + if (NT_SUCCESS(status)) { + FxRequestBase* pRequest; + LIST_ENTRY head, *ple; + ULONG i, iInterface; + FxUsbInterface *pUsbInterface; + KIRQL irql; + + InitializeListHead(&head); + + Lock(&irql); + + // + // Iterate over all of the interfaces. For each pipe on each interface, + // grab all pended i/o for later submission. + // + for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++){ + + pUsbInterface = m_Interfaces[iInterface]; + + for (i = 0; i < pUsbInterface->m_NumberOfConfiguredPipes; i++) { + pUsbInterface->m_ConfiguredPipes[i]->GotoStartState(&head); + } + } + Unlock(irql); + + // + // Since we are going to reference the FxUsbPipe's outside of the + // lock and the interface can go away in the meantime, add a reference + // (multiple times perhaps) to each FxUsbPipe to make sure it sticks + // around. + // + for (ple = head.Flink; ple != &head; ple = ple->Flink) { + pRequest = FxRequestBase::_FromListEntry(ple); + pRequest->GetTarget()->ADDREF(this); + } + + // + // Drain the list of pended requests. + // + while (!IsListEmpty(&head)) { + FxIoTarget* pTarget; + + ple = RemoveHeadList(&head); + + pRequest = FxRequestBase::_FromListEntry(ple); + + pTarget = pRequest->GetTarget(); + + pTarget->SubmitPendedRequest(pRequest); + + // + // Release the reference taken above when accumulating pended i/o. + // + pTarget->RELEASE(this); + } + } + + return status; +} + +#define STOP_TAG (PVOID) 'pots' + +VOID +FxUsbDevice::Stop( + __in WDF_IO_TARGET_SENT_IO_ACTION Action + ) +{ + FxUsbInterface *pUsbInterface; + SINGLE_LIST_ENTRY head; + ULONG iPipe, iInterface; + KIRQL irql; + + head.Next = NULL; + + // + // Stop all of our own I/O first + // + FxIoTarget::Stop(Action); + + // + // if we are just canceling i/o, then we just acquire the spin lock b/c + // we can be called at dispatch level for this action code. + // + if (Action != WdfIoTargetLeaveSentIoPending) { + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + AcquireInterfaceIterationLock(); + } + + // + // Since we don't have to synchronize on the I/O already sent, just set + // each pipe's state to stop. + // + Lock(&irql); + + for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { + pUsbInterface = m_Interfaces[iInterface]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + BOOLEAN wait; + + wait = FALSE; + + pUsbInterface->m_ConfiguredPipes[iPipe]->GotoStopState( + Action, + &head, + &wait, + TRUE + ); + } + } + } + } + Unlock(irql); + + // + // If we are leaving sent IO pending, the io target will set the IO + // completion event during stop even if there is still outstanding IO. + // + + if (head.Next != NULL) { + _CancelSentRequests(&head); + } + + for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { + pUsbInterface = m_Interfaces[iInterface]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + // + // Iterate over the pipes and clean each one up + // + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + // + // Same reason as above + // + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + pUsbInterface->m_ConfiguredPipes[iPipe]-> + WaitForSentIoToComplete(); + } + } + } + } + + if (Action != WdfIoTargetLeaveSentIoPending) { + ReleaseInterfaceIterationLock(); + } +} + +VOID +FxUsbDevice::Purge( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action + ) +{ + FxUsbInterface *pUsbInterface; + SINGLE_LIST_ENTRY sentHead; + ULONG iPipe, iInterface; + KIRQL irql; + + sentHead.Next = NULL; + + // + // Purge all of our own I/O first + // + FxIoTarget::Purge(Action); + + // + // if we are just canceling i/o, then we just acquire the spin lock b/c + // we can be called at dispatch level for this action code. + // + if (Action != WdfIoTargetPurgeIo) { + ASSERT(Mx::MxGetCurrentIrql() == PASSIVE_LEVEL); + + AcquireInterfaceIterationLock(); + } + + // + // Since we don't have to synchronize on the I/O already sent, just set + // each pipe's state to purged. + // + Lock(&irql); + + for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { + pUsbInterface = m_Interfaces[iInterface]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + BOOLEAN wait; + LIST_ENTRY pendedHead; + + wait = FALSE; + InitializeListHead(&pendedHead); + + pUsbInterface->m_ConfiguredPipes[iPipe]->GotoPurgeState( + Action, + &pendedHead, + &sentHead, + &wait, + TRUE + ); + + // + // Complete any requests pulled off from this pipe. + // + pUsbInterface->m_ConfiguredPipes[iPipe]-> + CompletePendedRequestList(&pendedHead); + } + } + } + } + Unlock(irql); + + // + // Cancel all sent requests. + // + _CancelSentRequests(&sentHead); + + for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { + pUsbInterface = m_Interfaces[iInterface]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + // + // Iterate over the pipes and clean each one up + // + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + // + // Same reason as above + // + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + pUsbInterface->m_ConfiguredPipes[iPipe]-> + WaitForSentIoToComplete(); + } + } + } + } + + if (Action != WdfIoTargetPurgeIo) { + ReleaseInterfaceIterationLock(); + } +} + +VOID +FxUsbDevice::_CleanupPipesRequests( + __in PLIST_ENTRY PendHead, + __in PSINGLE_LIST_ENTRY SentHead + ) +{ + while (!IsListEmpty(PendHead)) { + PLIST_ENTRY ple; + FxRequestBase* pRequest; + + ple = RemoveHeadList(PendHead); + + InitializeListHead(ple); + + pRequest = FxRequestBase::_FromListEntry(ple); + pRequest->GetTarget()->CompletePendedRequest(pRequest); + } + + _CancelSentRequests(SentHead); +} + +VOID +FxUsbDevice::PipesGotoRemoveState( + __in BOOLEAN ForceRemovePipes + ) +{ + SINGLE_LIST_ENTRY sentHead; + LIST_ENTRY pendHead, interfaceHead; + FxUsbInterface* pUsbInterface; + ULONG iPipe, intfIndex; + KIRQL irql; + + sentHead.Next = NULL; + InitializeListHead(&pendHead); + InitializeListHead(&interfaceHead); + + AcquireInterfaceIterationLock(); + + Lock(&irql); + for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++ ) { + pUsbInterface = m_Interfaces[intfIndex]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + BOOLEAN wait; + + wait = FALSE; + + // + // Pipe can be NULL if the interface is half initialized + // + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + pUsbInterface->m_ConfiguredPipes[iPipe]->GotoRemoveState( + WdfIoTargetDeleted, + &pendHead, + &sentHead, + TRUE, + &wait); + + } + } + } + } + Unlock(irql); + + // + // We cleanup requests no matter what the new state is because we complete all + // pended requests in the surprise removed case. + // + _CleanupPipesRequests(&pendHead, &sentHead); + + // + // Only destroy child pipe objects when the parent is going away or the + // caller indicates that this is the desired action. + // + if (m_State == WdfIoTargetDeleted || ForceRemovePipes) { + for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++) { + pUsbInterface = m_Interfaces[intfIndex]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + // + // Iterate over the pipes and clean each one up + // + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + // + // Same reason as above + // + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + pUsbInterface->m_ConfiguredPipes[iPipe]-> + WaitForSentIoToComplete(); + } + } + } + + pUsbInterface->CleanUpAndDelete(FALSE); + } + } + + ReleaseInterfaceIterationLock(); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::CreateInterfaces( + VOID + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + UCHAR descCountBitMap[UCHAR_MAX / sizeof(UCHAR)]; + PUSB_INTERFACE_DESCRIPTOR pInterfaceDescriptor; + UCHAR iInterface, numFound; + NTSTATUS status; + ULONG size; + ULONG totalLength; + + pFxDriverGlobals = GetDriverGlobals(); + status = STATUS_SUCCESS; + totalLength = m_ConfigDescriptor->wTotalLength; + + // + // Make sure each PCOMMON_DESCRIPTOR_HEADER within the entire config descriptor is well formed. + // If successful, we can walk the config descriptor using common headers without any more top + // level error checking. Task specific checking of the specialized header types must still occur. + // + status = FxUsbValidateConfigDescriptorHeaders( + pFxDriverGlobals, + m_ConfigDescriptor, + m_ConfigDescriptor->wTotalLength + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Validation of the config descriptor failed due to a bad common descriptor header, %!STATUS!", + status); + return status; + } + + // + // Validate all interface descriptors in config descriptor are at least + // sizeof(USB_INTERFACE_DESCRIPTOR). + // + + + + + + status = FxUsbValidateDescriptorType( + pFxDriverGlobals, + m_ConfigDescriptor, + m_ConfigDescriptor, + WDF_PTR_ADD_OFFSET(m_ConfigDescriptor, m_ConfigDescriptor->wTotalLength), + USB_INTERFACE_DESCRIPTOR_TYPE, + sizeof(USB_INTERFACE_DESCRIPTOR), + FxUsbValidateDescriptorOpAtLeast, + 0 + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Validation of interface descriptors in config descriptor failed, %!STATUS!", + status); + + return status; + } + + if (m_ConfigDescriptor->bNumInterfaces == 0) { + // + // Use an array of one in the zero case + // + size = sizeof(FxUsbInterface*); + } + else { + size = sizeof(FxUsbInterface*) * m_ConfigDescriptor->bNumInterfaces; + } + + // + // Allocate an array large enough to hold pointers to interfaces + // + m_Interfaces = (FxUsbInterface**) + FxPoolAllocate(pFxDriverGlobals, NonPagedPool, size); + + if (m_Interfaces == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for %d interfaces, %!STATUS!", + m_ConfigDescriptor->bNumInterfaces, status); + + goto Done; + } + + RtlZeroMemory(m_Interfaces, size); + m_NumInterfaces = m_ConfigDescriptor->bNumInterfaces; + + // + // Iterate over the desciptors again, this time allocating an FxUsbInterface + // for each one and capturing the interface information. + // + RtlZeroMemory(descCountBitMap, sizeof(descCountBitMap)); + iInterface = 0; + numFound = 0; + + pInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( + m_ConfigDescriptor, + m_ConfigDescriptor->wTotalLength, + m_ConfigDescriptor, + USB_INTERFACE_DESCRIPTOR_TYPE + ); + + while (pInterfaceDescriptor != NULL && + iInterface < m_ConfigDescriptor->bNumInterfaces) { + + // + // This function will retun false if the bit wasn't already set + // + if (FxBitArraySet(descCountBitMap, + pInterfaceDescriptor->bInterfaceNumber) == FALSE) { + FxUsbInterface* pInterface; + + pInterface = new (GetDriverGlobals(), WDF_NO_OBJECT_ATTRIBUTES) + FxUsbInterface(pFxDriverGlobals, + this, + pInterfaceDescriptor); + + if (pInterface == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for interface object #%d, %!STATUS!", + iInterface, status); + goto Done; + } + + status = pInterface->Commit(WDF_NO_OBJECT_ATTRIBUTES, NULL, this); + + // + // This should never fail + // + ASSERT(NT_SUCCESS(status)); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = pInterface->CreateSettings(); + if (!NT_SUCCESS(status)) { + goto Done; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + status = pInterface->SetWinUsbHandle(iInterface); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = pInterface->MakeAndConfigurePipes(WDF_NO_OBJECT_ATTRIBUTES, + pInterfaceDescriptor->bNumEndpoints); + if (!NT_SUCCESS(status)) { + goto Done; + } +#endif + + m_Interfaces[iInterface] = pInterface; + + iInterface++; + } + + pInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( + m_ConfigDescriptor, + totalLength, + WDF_PTR_ADD_OFFSET(pInterfaceDescriptor, + pInterfaceDescriptor->bLength), + USB_INTERFACE_DESCRIPTOR_TYPE + ); + } + + // + // We cannot check for the error case of + // + // pInterfaceDescriptor != NULL && + // iInterface == m_ConfigDescriptor->bNumInterfaces + // + // Because if there are multiple alternative settings for the last interface + // in the config descriptor, we will have hit the limit of interfaces + // (correctly), but have found another pInterfaceDescriptor (the next alt + // setting). + // + + // + // We already logged and found the case where iInterface >= m_NumInterfaces. + // Check for the case where we found too few interfaces and when we found + // no interfaces even though the config descriptor says otherwise. + // + // + if (iInterface == 0 && m_NumInterfaces > 0) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Config descriptor indicated there were %d interfaces, but did not " + "find any interface descriptors in config descriptor %p, %!STATUS!", + m_NumInterfaces, m_ConfigDescriptor, status); + } + else if (pInterfaceDescriptor != NULL && m_NumInterfaces == 0) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_WARNING, TRACINGIOTARGET, + "Config descriptor indicated there were 0 interfaces, but an interface " + "descriptor was found"); + + m_MismatchedInterfacesInConfigDescriptor = TRUE; + } + else if (iInterface < m_NumInterfaces) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Config descriptor indicated there were %d interfaces, only found " + "%d interfaces", m_NumInterfaces, iInterface); + + // + // Instead of considering this an error, just use the number found. + // This will not have an adverse affect elsewhere and since the framework + // is probably more strict then previous USB code, this would have not + // been found earlier by a WDM driver. + // + m_NumInterfaces = iInterface; + } + +Done: + return status; +} + + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::GetPortStatus( + __out PULONG PortStatus + ) +{ + NTSTATUS status; + + FxInternalIoctlOthersContext context; + FxRequestBuffer args[FX_REQUEST_NUM_OTHER_PARAMS]; + FxSyncRequest syncRequest(GetDriverGlobals(), &context); + + // + // FxSyncRequest always succeesds for KM. + // + status = syncRequest.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + *PortStatus = 0; + args[0].SetBuffer(PortStatus, 0); + args[1].SetBuffer(NULL, 0); + args[2].SetBuffer(NULL, 0); + + status = FormatInternalIoctlOthersRequest(syncRequest.m_TrueRequest, + IOCTL_INTERNAL_USB_GET_PORT_STATUS, + args); + + if (NT_SUCCESS(status)) { + WDF_REQUEST_SEND_OPTIONS options; + + WDF_REQUEST_SEND_OPTIONS_INIT( + &options, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + status = SubmitSync(syncRequest.m_TrueRequest, &options); + } + + return status; +} + + + +BOOLEAN +FxUsbDevice::IsEnabled( + VOID + ) +{ + NTSTATUS status; + ULONG portStatus; + BOOLEAN enabled; + + enabled = TRUE; + status = GetPortStatus(&portStatus); + + // + // Inability to get STATUS_SUCCESS from GetPortStatus is more likely a resource + // issue rather than a device issue so return FALSE from this function only if + // we were able to read the PortStatus and the port was disabled. + // What you don't want is to continuosly reset the device (by returning FALSE) + // instead of resetting pipe (by returning TRUE) under low memory conditions. + // + if (NT_SUCCESS(status) && (portStatus & USBD_PORT_ENABLED) == 0) { + enabled = FALSE; + } + + return enabled; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::IsConnected( + VOID + ) +{ +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + + + + + return STATUS_UNSUCCESSFUL; +#elif (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + NTSTATUS status; + ULONG portStatus; + + status = GetPortStatus(&portStatus); + if (NT_SUCCESS(status) && (portStatus & USBD_PORT_CONNECTED) == 0) { + status = STATUS_DEVICE_DOES_NOT_EXIST; + } + + return status; +#endif +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::CyclePort( + VOID + ) +{ + FxIoContext context; + FxSyncRequest request(GetDriverGlobals(), &context); + NTSTATUS status; + + // + // FxSyncRequest always succeesds for KM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + status = FormatCycleRequest(request.m_TrueRequest); + + if (NT_SUCCESS(status)) { + CancelSentIo(); + status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); + // + // NOTE: CyclePort causes the device to be removed and re-enumerated so + // don't do anymore operations after this point. + // + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::FormatCycleRequest( + __in FxRequestBase* Request + ) +{ + FxRequestBuffer emptyBuffer; + + return FormatIoctlRequest(Request, + IOCTL_INTERNAL_USB_CYCLE_PORT, + TRUE, + &emptyBuffer, + &emptyBuffer); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::GetConfigDescriptor( + __out PVOID ConfigDescriptor, + __inout PUSHORT ConfigDescriptorLength + ) +{ + NTSTATUS status; + USHORT copyLength; + + if (ConfigDescriptor == NULL) { + // + // Caller wants length to allocate + // + *ConfigDescriptorLength = m_ConfigDescriptor->wTotalLength; + return STATUS_BUFFER_TOO_SMALL; + } + + if (*ConfigDescriptorLength < m_ConfigDescriptor->wTotalLength) { + // + // Valid ConfigDescriptor passed in, but its too small. Copy as many + // bytes as we can. + // + copyLength = *ConfigDescriptorLength; + status = STATUS_BUFFER_TOO_SMALL; + } + else { + copyLength = m_ConfigDescriptor->wTotalLength; + status = STATUS_SUCCESS; + } + + // + // Always indicate to the caller the number of required bytes or the + // number of bytes we copied. + // + RtlCopyMemory(ConfigDescriptor, m_ConfigDescriptor, copyLength); + *ConfigDescriptorLength = m_ConfigDescriptor->wTotalLength; + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfigDescriptor( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +{ + PUSBD_INTERFACE_LIST_ENTRY pInterfaces; + PURB urb; + NTSTATUS status; + ULONG i, size; + PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor; + PUSB_INTERFACE_DESCRIPTOR* interfaceDescriptors; + ULONG numInterfaces; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + configurationDescriptor = Params->Types.Descriptor.ConfigurationDescriptor; + interfaceDescriptors = Params->Types.Descriptor.InterfaceDescriptors; + numInterfaces = Params->Types.Descriptor.NumInterfaceDescriptors; + + for (i = 0; i < numInterfaces; i++) { + if (interfaceDescriptors[i] == NULL) { + return STATUS_INVALID_PARAMETER; + } + } + + // + // eventually size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (numInterfaces + 1) + // + status = RtlULongAdd(numInterfaces, 1, &size); + if (!NT_SUCCESS(status)) { + return status; + } + + status = RtlULongMult(size, sizeof(USBD_INTERFACE_LIST_ENTRY), &size); + if (!NT_SUCCESS(status)) { + return status; + } + + pInterfaces = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate( + pFxDriverGlobals, NonPagedPool, size); + + if (pInterfaces == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate array of USBD_INTERFACE_LIST_ENTRY, %!STATUS!", + status); + + return status; + } + + RtlZeroMemory(pInterfaces, size); + + for (i = 0; i < numInterfaces; i++) { + pInterfaces[i].InterfaceDescriptor = interfaceDescriptors[i]; + } + + if (configurationDescriptor == NULL) { + configurationDescriptor = m_ConfigDescriptor; + } + + // + // NOTE: + // + // Creating a config request using the caller's config descriptor does not + // currently work if the provided config descriptor is not the same as the + // descriptor reported by the device. It does not work because we try to + // validate the interface number in the URB against an existing + // FxUsbInterface (which is based on the config descriptor described by the + // device, not the provided one), and if that validation fails, we return + // !NT_SUCCESS from SelectConfig(). + // + urb = FxUsbCreateConfigRequest(GetDriverGlobals(), + configurationDescriptor, + pInterfaces, + GetDefaultMaxTransferSize()); + if (urb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + status = SelectConfig(PipesAttributes, urb, FxUrbTypeLegacy, NULL); + FxPoolFree(urb); + urb = NULL; + } + + FxPoolFree(pInterfaces); + pInterfaces = NULL; + + return status; +} + +struct FxInterfacePipeInformation { + // + // Array of pipes + // + FxUsbPipe** Pipes; + + // + // Number of entries in Pipes + // + ULONG NumPipes; +}; + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfig( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PURB Urb, + __in FX_URB_TYPE FxUrbType, + __out_opt PUCHAR NumConfiguredInterfaces + ) +/*++ + +Routine Description: + Selects the configuration as described by the parameter Urb. If there is a + previous active configuration, the WDFUSBPIPEs for it are stopped and + destroyed before the new configuration is selected + +Arguments: + PipesAttributes - object attributes to apply to each created WDFUSBPIPE + + Urb - the URB describing the configuration to select + +Return Value: + NTSTATUS + + --*/ +{ + WDF_REQUEST_SEND_OPTIONS options; + PUCHAR pCur, pEnd; + PUSBD_INTERFACE_INFORMATION pIface; + FxUsbPipe* pPipe; + PURB pSelectUrb; + NTSTATUS status; + ULONG iPipe; + USHORT maxNumPipes, size; + UCHAR numPipes; + FxInterfacePipeInformation* pPipeInfo; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbInterface * pUsbInterface ; + UCHAR intfIndex; + FxIrp* irp; + + pFxDriverGlobals = GetDriverGlobals(); + FxSyncRequest request(GetDriverGlobals(), NULL); + + pIface = NULL; + maxNumPipes = 0; + size = 0; + pPipeInfo = NULL; + pSelectUrb = NULL; + + // + // Callers to this function have guaranteed that there are interfaces + // reported on this device. + // + ASSERT(m_NumInterfaces != 0); + + if (NumConfiguredInterfaces != NULL) { + *NumConfiguredInterfaces = 0; + } + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + goto Done; + } + + // + // Allocate a PIRP for the select config and possible select interface(s) + // + status = request.m_TrueRequest->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Allocate a pool for storing the FxUsbPipe ** before we + // assign them to the Interfaces just in case all doesn't go well. + // + if (m_NumInterfaces == 0) { + // + // Use one in the zero case to make the logic simpler + // + size = sizeof(FxInterfacePipeInformation); + } + else { + size = m_NumInterfaces * sizeof(FxInterfacePipeInformation); + } + + pPipeInfo = (FxInterfacePipeInformation*) FxPoolAllocate( + pFxDriverGlobals, NonPagedPool, size + ); + + if (pPipeInfo == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not internal allocate tracking info for selecting a config on " + "WDFUSBDEVICE 0x%p, %!STATUS!", GetHandle(), status); + goto Done; + } + + RtlZeroMemory(pPipeInfo, size); + + // + // The following code and the one in select setting have a lot in common + // but can't leverage on that as that sends the select interface URB down + // Our goal is allocate the resources -- the pipes and the select setting URB + // before sending down the select config URB so that the tear down is simpler. + // + + // + // Each FxUsbInterface will need a FxUsbPipe* for each pipe contained in + // the interface. + // + pCur = (PUCHAR) &Urb->UrbSelectConfiguration.Interface; + pEnd = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length; + intfIndex = 0; + + for ( ; pCur < pEnd; pCur += pIface->Length, intfIndex++) { + FxUsbPipe** ppPipes; + + pIface = (PUSBD_INTERFACE_INFORMATION) pCur; + if (pIface->NumberOfPipes > UCHAR_MAX) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE supports a maximum of %d pipes per interface, " + "USBD_INTERFACE_INFORMATION %p specified %d, %!STATUS!", + UCHAR_MAX, pIface, pIface->NumberOfPipes, status); + goto Done; + } + + pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber); + if (pUsbInterface == NULL) { + status = STATUS_INVALID_DEVICE_REQUEST; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not find an instance of an interface descriptor with " + "InterfaceNumber %d, %!STATUS!", + pIface->InterfaceNumber, status); + goto Done; + } + + numPipes = (UCHAR) pIface->NumberOfPipes; + + // + // Track the maximum number of pipes we have seen in an interface in + // case we need to allocate a select interface URB. + // + if (numPipes > maxNumPipes) { + maxNumPipes = (USHORT) numPipes; + } + + if (numPipes > 0) { + size = numPipes * sizeof(FxUsbPipe *); + } + else { + // + // It is valid to have an interface with zero pipes in it. In that + // case, we just allocate one entry so that we have a valid array + // and keep the remaining code simple. + // + size = sizeof(FxUsbPipe*); + } + + ppPipes = (FxUsbPipe**) FxPoolAllocate( + pFxDriverGlobals, + NonPagedPool, + size + ); + + if (ppPipes == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for Pipes " + "InterfaceNumber %d, %!STATUS!", + pIface->InterfaceNumber, status); + goto Done; + } + + RtlZeroMemory(ppPipes, size); + + // + // We store the pointer to the newly allocated arary in a temporary b/c + // we can still fail and we don't want a half baked interface. + // + + pPipeInfo[intfIndex].Pipes = ppPipes; + pPipeInfo[intfIndex].NumPipes = numPipes; + + for (iPipe = 0; iPipe < numPipes; iPipe++) { + ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes) + FxUsbPipe(GetDriverGlobals(),this); + + if (ppPipes[iPipe] == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate a pipe object, %!STATUS!", status); + goto Done; + } + + pPipe = ppPipes[iPipe]; + status = pPipe->Init(m_Device); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not Init the pipe object, %!STATUS!", status); + goto Done; + } + + status = pPipe->Commit(PipesAttributes, NULL, pUsbInterface); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not commit the pipe object, %!STATUS!", status); + goto Done; + } + } + + + + + + + + + + if (pUsbInterface->IsInterfaceConfigured()) { + CleanupInterfacePipesAndDelete(pUsbInterface); + } + } + + // + // If we are selecting more then one interface and at least one of them + // has pipes in them, allocate a select interface URB that will be used + // after the select config to select each interface. The select interface + // URB will be big enough to select the largest interface in the group. + // + // The select interface URB is allocated before the select config so that + // we know once the select config has completed successfully, we can be + // guaranteed that we can select the interfaces we want and not have to + // handle undoing the select config upon URB allocation failure. + // + if (m_NumInterfaces > 1 && maxNumPipes > 0) { + size = GET_SELECT_INTERFACE_REQUEST_SIZE(maxNumPipes); + + pSelectUrb = (PURB) FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + size + ); + + if (pSelectUrb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate a select interface URB, %!STATUS!", status); + goto Done; + } + + RtlZeroMemory(pSelectUrb, size); + } + + // + // Send the select config to the usb core + // + WDF_REQUEST_SEND_OPTIONS_INIT(&options, + WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(2)); + + FxFormatUsbRequest(request.m_TrueRequest, Urb, FxUrbType, m_USBDHandle); + status = SubmitSync(request.m_TrueRequest, &options); + + if (NT_SUCCESS(status)) { + // + // Save the config handle and store off all the pipes + // + m_ConfigHandle = Urb->UrbSelectConfiguration.ConfigurationHandle; + + // + // Initialize the first interface + // + pIface = &Urb->UrbSelectConfiguration.Interface; + + pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber); + pUsbInterface->SetNumConfiguredPipes((UCHAR)pIface->NumberOfPipes); + + // + // The interface now owns the array of pipes + // + pUsbInterface->SetConfiguredPipes(pPipeInfo[0].Pipes); + pPipeInfo[0].Pipes = NULL; + pPipeInfo[0].NumPipes = 0; + + pUsbInterface->SetInfo(pIface); + + // + // Since this could be the only interface, set the index now, so if we + // return the number of configured interfaces, it will be valid for the + // single interface case. + // + intfIndex = 1; + + // + // If we have a more then one interface, we must select each of the addtional + // interfaces after the select config because usbccgp (the generic parent + // driver) didn't fill out all of the pipe info for IAD (interface + // association descriptor) devices. The first interface is filled out + // property, it is 2->N that are left blank. + // + // pSelectUrb can be equal to NULL and have more then one interface if + // all interfaces have no pipes associated with them. In that case, we + // still want to iterate over the remaining pipes so that we can + // initialize our structures properly. + // + if (m_NumInterfaces > 1) { + // + // Loop over the interfaces again. + // + pCur = (PUCHAR) &Urb->UrbSelectConfiguration.Interface; + pIface = (PUSBD_INTERFACE_INFORMATION) pCur; + pEnd = ((PUCHAR) Urb) + Urb->UrbSelectConfiguration.Hdr.Length; + + // + // Start at the 2nd one since the first is already selected + // + pCur += pIface->Length; + + for ( ; pCur < pEnd; pCur += pIface->Length, intfIndex++) { +#pragma prefast(suppress: __WARNING_UNUSED_POINTER_ASSIGNMENT, "pIface is used in the for loop in many places. It looks like a false positive") + pIface = (PUSBD_INTERFACE_INFORMATION) pCur; + ASSERT(pIface->NumberOfPipes <= maxNumPipes); + + pUsbInterface = GetInterfaceFromNumber(pIface->InterfaceNumber); + ASSERT(pUsbInterface != NULL); + + // + // Valid to have an interface with no pipes. If there are no + // pipes, GET_SELECT_INTERFACE_REQUEST_SIZE will compute value + // too small of a size to pass validation. + // + if (pIface->NumberOfPipes > 0) { + + pUsbInterface->FormatSelectSettingUrb( + pSelectUrb, + (USHORT) pIface->NumberOfPipes, + pIface->AlternateSetting + ); + irp = request.m_TrueRequest->GetSubmitFxIrp(); + irp->Reuse(STATUS_SUCCESS); + + request.m_TrueRequest->ClearFieldsForReuse(); + FxFormatUsbRequest(request.m_TrueRequest, + pSelectUrb, + FxUrbTypeLegacy, + NULL); + + status = SubmitSync(request.m_TrueRequest, &options); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB core failed Select Interface URB, %!STATUS!", + status); + goto Done; + } + + // + // Copy the info back into the original select config URB + // + + RtlCopyMemory(pIface, + &pSelectUrb->UrbSelectInterface.Interface, + pSelectUrb->UrbSelectInterface.Interface.Length); + } + + // + // Update the pointer to point to the new pipes with the pointer + // to the pipes stored earlier. + // + ASSERT(pPipeInfo[intfIndex].NumPipes == pIface->NumberOfPipes); + pUsbInterface->SetNumConfiguredPipes((UCHAR)pIface->NumberOfPipes); + + // + // The interface now owns the array of pipes + // + pUsbInterface->SetConfiguredPipes(pPipeInfo[intfIndex].Pipes); + pPipeInfo[intfIndex].Pipes = NULL; + pPipeInfo[intfIndex].NumPipes = 0; + + // + // SetInfo only after a successful select config so that we can + // copy the USBD_PIPE_INFORMATION . + // + pUsbInterface->SetInfo(pIface); + } + } + + if (NumConfiguredInterfaces != NULL) { + *NumConfiguredInterfaces = intfIndex; + } + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB core failed Select Configuration, %!STATUS!", status); + } + +Done: + if (pSelectUrb != NULL) { + FxPoolFree(pSelectUrb); + pSelectUrb = NULL; + } + + if (pPipeInfo != NULL) { + // + // Free all arrays that may have been allocated + // + for (intfIndex = 0; intfIndex < m_NumInterfaces; intfIndex++) { + // + // We can have NumPipes == 0 and still have an allocated array, so + // use the array != NULL as the check. + // + if (pPipeInfo[intfIndex].Pipes != NULL) { + // + // Delete any pipes that might have been created + // + for (iPipe = 0; iPipe < pPipeInfo[intfIndex].NumPipes; iPipe++) { + if (pPipeInfo[intfIndex].Pipes[iPipe] != NULL) { + pPipeInfo[intfIndex].Pipes[iPipe]->DeleteFromFailedCreate(); + pPipeInfo[intfIndex].Pipes[iPipe] = NULL; + } + } + + // + // Now free the array itself and clear out the count + // + FxPoolFree(pPipeInfo[intfIndex].Pipes); + pPipeInfo[intfIndex].Pipes = NULL; + pPipeInfo[intfIndex].NumPipes = 0; + } + } + + FxPoolFree(pPipeInfo); + pPipeInfo = NULL; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::Deconfig( + VOID + ) +{ + WDF_REQUEST_SEND_OPTIONS options; + _URB_SELECT_CONFIGURATION urb; + + FxSyncRequest request(GetDriverGlobals(), NULL); + NTSTATUS status; + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + status = request.m_TrueRequest->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // This will remove and free all interfaces and associated pipes + // + PipesGotoRemoveState(TRUE); + + RtlZeroMemory(&urb, sizeof(urb)); + +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team"); + UsbBuildSelectConfigurationRequest((PURB) &urb, sizeof(urb), NULL); +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team"); + FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL); + + WDF_REQUEST_SEND_OPTIONS_INIT( + &options, WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + status = SubmitSync(request.m_TrueRequest, &options); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfigInterfaces( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, + __in_ecount(NumInterfaces) PUSB_INTERFACE_DESCRIPTOR* InterfaceDescriptors, + __in ULONG NumInterfaces + ) +{ + PUSBD_INTERFACE_LIST_ENTRY pInterfaces; + PURB urb; + NTSTATUS status; + ULONG i, size; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + // + // eventually size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (NumInterfaces + 1) + // + status = RtlULongAdd(NumInterfaces, 1, &size); + if (!NT_SUCCESS(status)) { + return status; + } + + status = RtlULongMult(size, sizeof(USBD_INTERFACE_LIST_ENTRY), &size); + if (!NT_SUCCESS(status)) { + return status; + } + + for (i = 0; i < NumInterfaces; i++) { + if (InterfaceDescriptors[i] == NULL) { + return STATUS_INVALID_PARAMETER; + } + } + + pInterfaces = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate( + pFxDriverGlobals, + NonPagedPool, + size + ); + + if (pInterfaces == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate array of USBD_INTERFACE_LIST_ENTRY, %!STATUS!", + status); + + return status; + } + + RtlZeroMemory(pInterfaces, size); + + for (i = 0; i < NumInterfaces; i++) { + pInterfaces[i].InterfaceDescriptor = InterfaceDescriptors[i]; + } + + if (ConfigurationDescriptor == NULL) { + ConfigurationDescriptor = m_ConfigDescriptor; + } + + urb = FxUsbCreateConfigRequest(GetDriverGlobals(), + ConfigurationDescriptor, + pInterfaces, + GetDefaultMaxTransferSize()); + if (urb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + status = SelectConfig(PipesAttributes, urb, FxUrbTypeLegacy, NULL); + FxPoolFree(urb); + urb = NULL; + } + + FxPoolFree(pInterfaces); + pInterfaces = NULL; + + return status; +} + +FxUsbInterface * +FxUsbDevice::GetInterfaceFromIndex( + __in UCHAR InterfaceIndex + ) +{ + if (InterfaceIndex < m_NumInterfaces){ + return m_Interfaces[InterfaceIndex]; + } + + return NULL; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::GetInterfaceNumberFromInterface( + __in WDFUSBINTERFACE UsbInterface, + __out PUCHAR InterfaceNumber + ) +{ + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtr(GetDriverGlobals(), + UsbInterface, + FX_TYPE_USB_INTERFACE , + (PVOID*) &pUsbInterface); + + *InterfaceNumber = pUsbInterface->GetInterfaceNumber(); + + return STATUS_SUCCESS; +} + +FxUsbInterface * +FxUsbDevice::GetInterfaceFromNumber( + __in UCHAR InterfaceNumber + ) +{ + ULONG i; + + for (i = 0; i < m_NumInterfaces; i++) { + if (m_Interfaces[i]->GetInterfaceNumber() == InterfaceNumber) { + return m_Interfaces[i]; + } + } + + return NULL; +} + +VOID +FxUsbDevice::CleanupInterfacePipesAndDelete( + __in FxUsbInterface * UsbInterface + ) +{ + SINGLE_LIST_ENTRY sentHead; + LIST_ENTRY pendHead; + ULONG iPipe; + FxUsbPipe *pPipe; + KIRQL irql; + + sentHead.Next = NULL; + InitializeListHead(&pendHead); + + AcquireInterfaceIterationLock(); + + Lock(&irql); + for (iPipe = 0; iPipe < UsbInterface->m_NumberOfConfiguredPipes; iPipe++) { + BOOLEAN wait; + + wait = FALSE; + pPipe = UsbInterface->m_ConfiguredPipes[iPipe]; + pPipe->GotoRemoveState( + WdfIoTargetDeleted, + &pendHead, + &sentHead, + TRUE, + &wait); + } + Unlock(irql); + + _CleanupPipesRequests(&pendHead, &sentHead); + + for (iPipe = 0; iPipe < UsbInterface->m_NumberOfConfiguredPipes; iPipe++) { + pPipe = UsbInterface->m_ConfiguredPipes[iPipe]; + pPipe->WaitForSentIoToComplete(); + } + + UsbInterface->CleanUpAndDelete(FALSE); + + ReleaseInterfaceIterationLock(); +} + +VOID +FxUsbDevice::CancelSentIo( + VOID + ) +{ + FxUsbInterface *pUsbInterface; + ULONG iInterface, iPipe; + + for (iInterface = 0; iInterface < m_NumInterfaces; iInterface++) { + pUsbInterface = m_Interfaces[iInterface]; + + if (pUsbInterface->m_ConfiguredPipes != NULL) { + for (iPipe = 0; + iPipe < pUsbInterface->m_NumberOfConfiguredPipes; + iPipe++) { + + if (pUsbInterface->m_ConfiguredPipes[iPipe] != NULL) { + pUsbInterface->m_ConfiguredPipes[iPipe]->CancelSentIo(); + } + + } + } + } + __super::CancelSentIo(); +} + +__checkReturn +NTSTATUS +FxUsbDevice::CreateUrb( + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFMEMORY* UrbMemory, + __deref_opt_out_bcount(sizeof(URB)) + PURB* Urb + ) +{ + NTSTATUS status; + PURB urbLocal = NULL; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbUrb * pUrb = NULL; + WDFMEMORY hMemory; + FxObject* pParent; + + // + // Get the parent's globals if it is present, else use the ones for FxUsbDevice + // + pFxDriverGlobals = GetDriverGlobals(); + status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, Attributes); + + if (NT_SUCCESS(status)) { + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + + if (FALSE == IsObjectDisposedOnRemove(pParent)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Urb must be parented to FxDevice or an IoAllocated Request"); + status = STATUS_INVALID_PARAMETER; + goto Done; + } + + } + else if (status == STATUS_WDF_PARENT_NOT_SPECIFIED) { + + pFxDriverGlobals = GetDriverGlobals(); + pParent = this; + status = STATUS_SUCCESS; + + } + else { + + goto Done; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + if (!NT_SUCCESS(status)) { + goto Done; + } + + FxPointerNotNull(pFxDriverGlobals, UrbMemory); + + *UrbMemory = NULL; + + status = USBD_UrbAllocate(m_USBDHandle, &urbLocal); + + if (!NT_SUCCESS(status)) { + + urbLocal = NULL; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USBDEVICE Must have been created with Client Contract Version Info, %!STATUS!", + status); + + goto Done; + + } + + pUrb = new(pFxDriverGlobals, Attributes) + FxUsbUrb(pFxDriverGlobals, m_USBDHandle, urbLocal, sizeof(URB)); + + if (pUrb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + urbLocal = NULL; + + status = pUrb->Commit(Attributes, (WDFOBJECT*)&hMemory, pParent); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + *UrbMemory = hMemory; + + if (Urb) { + *Urb = (PURB) pUrb->GetBuffer(); + } + +Done: + + if (!NT_SUCCESS(status)) { + + if (pUrb) { + pUrb->DeleteFromFailedCreate(); + } + + if (urbLocal) { + USBD_UrbFree(m_USBDHandle, urbLocal); + } + + } + + return status; +} + +__checkReturn +NTSTATUS +FxUsbDevice::CreateIsochUrb( + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __in + ULONG NumberOfIsochPackets, + __out + WDFMEMORY* UrbMemory, + __deref_opt_out_bcount(GET_ISOCH_URB_SIZE(NumberOfIsochPackets)) + PURB* Urb + ) +{ + NTSTATUS status; + PURB urbLocal = NULL; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbUrb * pUrb = NULL; + WDFMEMORY hMemory; + ULONG size; + FxObject* pParent; + + // + // Get the parent's globals if it is present, else use the ones for FxUsbDevice + // + pFxDriverGlobals = GetDriverGlobals(); + status = FxValidateObjectAttributesForParentHandle(pFxDriverGlobals, Attributes); + + if (NT_SUCCESS(status)) { + + FxObjectHandleGetPtrAndGlobals(pFxDriverGlobals, + Attributes->ParentObject, + FX_TYPE_OBJECT, + (PVOID*)&pParent, + &pFxDriverGlobals); + + if (FALSE == IsObjectDisposedOnRemove(pParent)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Urb must be parented to FxDevice or IoAllocated Request"); + status = STATUS_INVALID_PARAMETER; + goto Done; + } + + } + else if (status == STATUS_WDF_PARENT_NOT_SPECIFIED) { + + pFxDriverGlobals = GetDriverGlobals(); + pParent = this; + status = STATUS_SUCCESS; + + } + else { + + goto Done; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, Attributes); + if (!NT_SUCCESS(status)) { + goto Done; + } + + FxPointerNotNull(pFxDriverGlobals, UrbMemory); + + *UrbMemory = NULL; + + status = USBD_IsochUrbAllocate(m_USBDHandle, NumberOfIsochPackets, &urbLocal); + + if (!NT_SUCCESS(status)) { + + urbLocal = NULL; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USBDEVICE Must have been created with Client Contract Version Info, %!STATUS!", + status); + + goto Done; + + } + + size = GET_ISO_URB_SIZE(NumberOfIsochPackets); + + pUrb = new(pFxDriverGlobals, Attributes) + FxUsbUrb(pFxDriverGlobals, m_USBDHandle, urbLocal, size); + + if (pUrb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + urbLocal = NULL; + + status = pUrb->Commit(Attributes, (WDFOBJECT*)&hMemory, pParent); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + *UrbMemory = hMemory; + + if (Urb) { + *Urb = (PURB) pUrb->GetBuffer(); + } + +Done: + + if (!NT_SUCCESS(status)) { + + if (pUrb) { + pUrb->DeleteFromFailedCreate(); + } + + if (urbLocal) { + USBD_UrbFree(m_USBDHandle, urbLocal); + } + + } + + return status; +} + +BOOLEAN +FxUsbDevice::IsObjectDisposedOnRemove( + __in FxObject* Object + ) +/*++ + +Routine Description: + This routine determines if the Object being passed is guranteed to be disposed on a + Pnp remove operation. + + The object will be disposed on Pnp remove operation if it is a somewhere in the child + tree of the FxDevice assocaited with this FxUsbDevice object, or in the child tree of an + Io Allocated Request. + +Arguments: + + Object - The Object being checked + +Return Value: + + TRUE if the Object is guranteed to be disposed on a pnp remove operation + FALSE otherwise. + + --*/ +{ + FxObject * obj; + FxObject * parent; + BOOLEAN isObjectDisposedOnRemove = FALSE; + + obj = Object; + + // + // By adding a reference now, we simulate what GetParentObjectReferenced + // does later, thus allowing simple logic on when/how to release the + // reference on exit. + // + obj->ADDREF(Object); + + while (obj != NULL) { + + if (obj == (FxObject*) m_Device) { + + isObjectDisposedOnRemove = TRUE; + break; + } + + if (FxObjectCheckType(obj, FX_TYPE_REQUEST)) { + + FxRequestBase* request = (FxRequestBase*) obj; + if (request->IsAllocatedFromIo()) { + + isObjectDisposedOnRemove = TRUE; + break; + } + } + + parent = obj->GetParentObjectReferenced(Object); + + // + // Release the reference previously taken by the top of the function + // or GetParentObjectReferenced in a previous pass in the loop. + // + obj->RELEASE(Object); + obj = parent; + } + + if (obj != NULL) { + + // + // Release the reference previously taken by the top of the function + // or GetParentObjectReferenced in a last pass in the loop. + // + obj->RELEASE(Object); + } + + return isObjectDisposedOnRemove; +} + +FX_URB_TYPE +FxUsbDevice::GetFxUrbTypeForRequest( + __in FxRequestBase* Request + ) +/*++ + +Routine Description: + This routine essentially determines whether this routine can use a urb allocated by + the USBD_xxxUrbAllocate APIs + + The USBD_xxxUrbAllocate APIs are only used for those requests that could be disposed at the + time the client driver devnode is being removed. + + If we cannot make that gurantee about that request, FxUrbTypeLegacy is returned and the + USBD_xxxUrbAllocate api's must not be used to allocate an Urb. + + Else FxUrbTypeUsbdAllocated is returned. + +Arguments: + + Request - FxRequest + +Return Value: + + FxUrbTypeUsbdAllocated, or FxUrbTypeLegacy + + --*/ +{ + if (m_UrbType == FxUrbTypeLegacy) { + return FxUrbTypeLegacy; + } + + if (Request->IsAllocatedFromIo()) { + return FxUrbTypeUsbdAllocated; + } + + if (IsObjectDisposedOnRemove((FxObject*) Request)) { + return FxUrbTypeUsbdAllocated; + } + + return FxUrbTypeLegacy; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbdeviceapi.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbdeviceapi.cpp new file mode 100644 index 00000000000..540f82b5436 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbdeviceapi.cpp @@ -0,0 +1,1428 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbDeviceAPI.cpp + +Abstract: + + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbDeviceAPI.tmh" +} + +// +// Extern "C" all APIs +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +FxUsbTargetDeviceCreate( + __in + PFX_DRIVER_GLOBALS FxDriverGlobals, + __in + FxDeviceBase* Device, + __in + ULONG USBDClientContractVersion, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFUSBDEVICE* UsbDevice + ) +/*++ + +Routine Description: + Creates a WDFUSBDEVICE handle for the client. + +Arguments: + + Device - FxDeviceBase object + + USBDClientContractVersion - The USBD Client Contract version of the client driver + + UsbDevice - Pointer which will receive the created handle + +Return Value: + STATUS_SUCCESS - success + STATUS_INSUFFICIENT_RESOURCES - no memory available + ... + + --*/ +{ + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + // + // Basic parameter validation + // + + FxPointerNotNull(FxDriverGlobals, UsbDevice); + *UsbDevice = NULL; + + status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(FxDriverGlobals, + Attributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + pUsbDevice = new(FxDriverGlobals, Attributes) FxUsbDevice(FxDriverGlobals); + if (pUsbDevice == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Perform all init and handle creation functions. Check for error at the + // end and clean up there. + // + status = pUsbDevice->Init(Device); + + if (NT_SUCCESS(status)) { + WDFOBJECT device; + + device = NULL; + + status = pUsbDevice->InitDevice(USBDClientContractVersion); + + if (NT_SUCCESS(status)) { + status = pUsbDevice->CreateInterfaces(); + } + + if (NT_SUCCESS(status)) { + status = Device->AddIoTarget(pUsbDevice); + } + + if (NT_SUCCESS(status)) { + status = pUsbDevice->Commit(Attributes, &device, Device); + } + + if (NT_SUCCESS(status)) { + *UsbDevice = (WDFUSBDEVICE) device; + } + } + + if (!NT_SUCCESS(status)) { + // + // And now free it + // + pUsbDevice->DeleteFromFailedCreate(); + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceCreate)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFUSBDEVICE* UsbDevice + ) +/*++ + +Routine Description: + Creates a WDFUSBDEVICE handle for the client. + +Arguments: + Device - WDFDEVICE handle to which we are attaching the WDFUSBDEVICE handle + to + PUsbDevice - Pointer which will receive the created handle + +Return Value: + STATUS_SUCCESS - success + STATUS_INSUFFICIENT_RESOURCES - no memory available + ... + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDeviceBase* pDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + return FxUsbTargetDeviceCreate(pFxDriverGlobals, + pDevice, + USBD_CLIENT_CONTRACT_VERSION_INVALID, + Attributes, + UsbDevice); +} + +__checkReturn +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFDEVICE Device, + __in + PWDF_USB_DEVICE_CREATE_CONFIG Config, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFUSBDEVICE* UsbDevice + ) +/*++ + +Routine Description: + Creates a WDFUSBDEVICE handle for the client. + +Arguments: + Device - WDFDEVICE handle to which we are attaching the WDFUSBDEVICE handle + to + PUsbDevice - Pointer which will receive the created handle + +Return Value: + STATUS_SUCCESS - success + STATUS_INSUFFICIENT_RESOURCES - no memory available + ... + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxDeviceBase* pDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Device, + FX_TYPE_DEVICE_BASE, + (PVOID*)&pDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Config); + + if (Config->Size != sizeof(WDF_USB_DEVICE_CREATE_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDF_USB_DEVICE_CREATE_CONFIG Size 0x%x, expected 0x%x, %!STATUS!", + Config->Size, sizeof(WDF_USB_DEVICE_CREATE_CONFIG), status); + + return status; + } + + return FxUsbTargetDeviceCreate(pFxDriverGlobals, + pDevice, + Config->USBDClientContractVersion, + Attributes, + UsbDevice); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __out + PWDF_USB_DEVICE_INFORMATION Information + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Information); + + if (Information->Size != sizeof(WDF_USB_DEVICE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Information size %d, expected %d %!STATUS!", + Information->Size, sizeof(WDF_USB_DEVICE_INFORMATION), + status); + return status; + } + + pUsbDevice->GetInformation(Information); + + return STATUS_SUCCESS; +} + +__drv_maxIRQL(PASSIVE_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __out + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, UsbDeviceDescriptor); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return; + } + + pUsbDevice->CopyDeviceDescriptor(UsbDeviceDescriptor); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __out_bcount_part_opt(*ConfigDescriptorLength, *ConfigDescriptorLength) + PVOID ConfigDescriptor, + __inout + PUSHORT ConfigDescriptorLength + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, ConfigDescriptorLength); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + return pUsbDevice->GetConfigDescriptor(ConfigDescriptor, + ConfigDescriptorLength); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceQueryString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __out_ecount_opt(*NumCharacters) + PUSHORT String, + __inout + PUSHORT NumCharacters, + __in + UCHAR StringIndex, + __in_opt + USHORT LangID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, NumCharacters); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pUsbDevice->GetString(String, + NumCharacters, + StringIndex, + LangID, + Request, + RequestOptions); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + __out + WDFMEMORY* StringMemory, + __out_opt + PUSHORT NumCharacters, + __in + UCHAR StringIndex, + __in_opt + USHORT LangID + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDFMEMORY hMemory; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + USHORT numChars = 0; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, StringMemory); + + *StringMemory = NULL; + if (NumCharacters != NULL) { + *NumCharacters = 0; + } + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, StringMemoryAttributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pUsbDevice->GetString(NULL, &numChars, StringIndex, LangID); + + if (NT_SUCCESS(status) && numChars > 0) { + FxMemoryObject* pBuffer; + + status = FxMemoryObject::_Create(pFxDriverGlobals, + StringMemoryAttributes, + NonPagedPool, + pFxDriverGlobals->Tag, + numChars * sizeof(WCHAR), + &pBuffer); + + if (!NT_SUCCESS(status)) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + status = pBuffer->Commit(StringMemoryAttributes, + (WDFOBJECT*)&hMemory); + + if (NT_SUCCESS(status)) { + status = pUsbDevice->GetString((PUSHORT) pBuffer->GetBuffer(), + &numChars, + StringIndex, + LangID); + + if (NT_SUCCESS(status)) { + if (NumCharacters != NULL) { + *NumCharacters = numChars; + } + *StringMemory = hMemory; + } + } + + if (!NT_SUCCESS(status)) { + // + // There can only be one context on this object right now, + // so just clear out the one. + // + pBuffer->DeleteFromFailedCreate(); + } + } + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in + WDFREQUEST Request, + __in + WDFMEMORY Memory, + __in_opt + PWDFMEMORY_OFFSET Offset, + __in + UCHAR StringIndex, + __in_opt + USHORT LangID + ) +/*++ + +Routine Description: + Formats a request so that it can be used to query for a string from the + device. + +Arguments: + UsbDevice - device to be queried + + Request - request to format + + Memory - memory to write the string into + + +Return Value: + + + --*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxMemory* pMemory; + FxUsbDevice* pUsbDevice; + FxRequestBuffer buf; + FxRequest* pRequest; + NTSTATUS status; + size_t bufferSize; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, WDFREQUEST %p, WDFMEMORY %p, StringIndex %d, LandID 0x%x", + UsbDevice, Request, Memory, StringIndex, LangID); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Memory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pMemory->ValidateMemoryOffsets(Offset); + if (!NT_SUCCESS(status)) { + return status; + } + + buf.SetMemory(pMemory, Offset); + + bufferSize = buf.GetBufferLength(); + + // + // the string descriptor is array of WCHARs so the buffer being used must be + // of an integral number of them. + // + if ((bufferSize % sizeof(WCHAR)) != 0) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFMEMORY %p length must be even number of WCHARs, but is %I64d in " + "length, %!STATUS!", + Memory, bufferSize, status); + + return status; + } + + // + // While the length in the descriptor (bLength) is a byte, so the requested + // buffer cannot be bigger then that, do not check the bufferSize < 0xFF. + // We don't check because the driver can be using the WDFMEMORY as a part + // of a larger structure. + // + + // + // Format the request + // + status = pUsbDevice->FormatStringRequest(pRequest, &buf, StringIndex, LangID); + + if (NT_SUCCESS(status)) { + FxUsbDeviceStringContext* pContext; + + pContext = (FxUsbDeviceStringContext*) pRequest->GetContext(); + pContext->m_UsbParameters.Parameters.DeviceString.Buffer = Memory; + pContext->m_UsbParameters.Parameters.DeviceString.StringIndex = StringIndex; + pContext->m_UsbParameters.Parameters.DeviceString.LangID = LangID; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, WDFREQUEST %p, WDFMEMORY %p, %!STATUS!", + UsbDevice, Request, Memory, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __inout + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Params); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Params->Size != sizeof(WDF_USB_DEVICE_SELECT_CONFIG_PARAMS)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Params size %d, expected %d %!STATUS!", + Params->Size, sizeof(WDF_USB_DEVICE_SELECT_CONFIG_PARAMS), + status); + return status; + } + + // + // Sanity check the Type value as well to be in range. + // + if (Params->Type < WdfUsbTargetDeviceSelectConfigTypeDeconfig + || + Params->Type > WdfUsbTargetDeviceSelectConfigTypeUrb) { + + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Params Type %d not a valid value, %!STATUS!", + Params->Size, status); + + return status; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + if ((Params->Type == WdfUsbTargetDeviceSelectConfigTypeDeconfig) || + (Params->Type == WdfUsbTargetDeviceSelectConfigTypeUrb) || + (Params->Type == WdfUsbTargetDeviceSelectConfigTypeInterfacesDescriptor)) { + status = STATUS_NOT_SUPPORTED; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Params Type %d not supported for UMDF, %!STATUS!", + Params->Type, status); + + return status; + + } +#endif + + status = FxValidateObjectAttributes(pFxDriverGlobals, + PipesAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + if (pUsbDevice->HasMismatchedInterfacesInConfigDescriptor()) { + // + // Config descriptor reported zero interfaces, but we found an + // interface descriptor in it. + // + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p number of interfaces found in the config descriptor " + "does not match bNumInterfaces in config descriptor, failing config " + "operation %!WdfUsbTargetDeviceSelectConfigType!, %!STATUS!", + UsbDevice, Params->Type, status); + + return status; + } + else if (pUsbDevice->GetNumInterfaces() == 0) { + // + // Special case the zero interface case and exit early + // + status = STATUS_SUCCESS; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p succeeding config operation " + "%!WdfUsbTargetDeviceSelectConfigType! on zero interfaces " + "immediately, %!STATUS!", UsbDevice, Params->Type, status); + + return status; + } + + switch (Params->Type) { + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + + case WdfUsbTargetDeviceSelectConfigTypeDeconfig: + status = pUsbDevice->Deconfig(); + break; + + case WdfUsbTargetDeviceSelectConfigTypeInterfacesDescriptor: + if (Params->Types.Descriptor.InterfaceDescriptors == NULL || + Params->Types.Descriptor.NumInterfaceDescriptors == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Either InterfaceDescriptor is NULL or NumInterfaceDescriptors is zero " + "WDFUSBDEVICE %p InterfaceDescriptor %p NumInterfaceDescriptors 0x%x" + "%!WdfUsbTargetDeviceSelectConfigType! %!STATUS!", UsbDevice, + Params->Types.Descriptor.InterfaceDescriptors, + Params->Types.Descriptor.NumInterfaceDescriptors, + Params->Type, + status); + + } + else { + status = pUsbDevice->SelectConfigDescriptor( + PipesAttributes, + Params); + } + break; + + case WdfUsbTargetDeviceSelectConfigTypeUrb: + // + // Since the USBD macro's dont include the USBD_PIPE_INFORMATION for 0 EP's, + // make the length check to use + // sizeof(struct _URB_SELECT_CONFIGURATION) - sizeof(USBD_PIPE_INFORMATION) + // + if (Params->Types.Urb.Urb == NULL || + Params->Types.Urb.Urb->UrbHeader.Function != URB_FUNCTION_SELECT_CONFIGURATION || + Params->Types.Urb.Urb->UrbHeader.Length < + (sizeof(struct _URB_SELECT_CONFIGURATION) - sizeof(USBD_PIPE_INFORMATION))) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Either URB passed in was NULL or the URB Function or Length was invalid " + " WDFUSBDEVICE %p Urb 0x%p " + "%!WdfUsbTargetDeviceSelectConfigType!" + " %!STATUS!", UsbDevice, + Params->Types.Urb.Urb, + Params->Type, + status); + + } + else { + status = pUsbDevice->SelectConfig( + PipesAttributes, + Params->Types.Urb.Urb, + FxUrbTypeLegacy, + NULL); + } + break; + +#endif + + + + + + case WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs: + if (Params->Types.MultiInterface.Pairs == NULL) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p SettingPairs Array passed is NULL, %!STATUS!", + pUsbDevice->GetHandle(),status); + + break; + } + else if (Params->Types.MultiInterface.NumberInterfaces != + pUsbDevice->GetNumInterfaces()) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p MultiInterface.NumberInterfaces %d != %d " + "(reported num interfaces), %!STATUS!", + pUsbDevice->GetHandle(), + Params->Types.MultiInterface.NumberInterfaces, + pUsbDevice->GetNumInterfaces(), status); + + break; + } + + // || || Fall through || || + // \/ \/ \/ \/ + case WdfUsbTargetDeviceSelectConfigTypeMultiInterface: + + // + // Validate SettingIndexes passed-in + // + for (ULONG i = 0; + i < Params->Types.MultiInterface.NumberInterfaces; + i++) { + + PWDF_USB_INTERFACE_SETTING_PAIR pair; + FxUsbInterface * pUsbInterface; + UCHAR numSettings; + + pair = &(Params->Types.MultiInterface.Pairs[i]); + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + pair->UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface); + + numSettings = pUsbInterface->GetNumSettings(); + + if (pair->SettingIndex >= numSettings) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p SettingPairs contains invalid SettingIndex" + " for WDFUSBINTERFACE %p. Setting index passed in: %d, " + "max index: %d, returning %!STATUS!", + pUsbDevice->GetHandle(), + pair->UsbInterface, + pair->SettingIndex, + pUsbInterface->GetNumSettings() - 1, + status); + + return status; + } + } + + status = pUsbDevice->SelectConfigMulti( + PipesAttributes, + Params); + break; + + case WdfUsbTargetDeviceSelectConfigTypeSingleInterface: + status = pUsbDevice->SelectConfigSingle( //vm changed name from SelectConfigAuto + PipesAttributes, + Params); + break; + + default: + status = STATUS_INVALID_PARAMETER; + } + + return status; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +UCHAR +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice + ) +{ + DDI_ENTRY(); + + FxUsbDevice* pUsbDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice); + + return pUsbDevice->GetNumInterfaces(); +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +USBD_CONFIGURATION_HANDLE +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceWdmGetConfigurationHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice + ) +{ + DDI_ENTRY(); + + FxUsbDevice* pUsbDevice; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice); + + return pUsbDevice->GetConfigHandle(); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + __in_opt + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + __out_opt + PULONG BytesTransferred + ) +/*++ + +Routine Description: + Synchronously sends a control transfer to the default control pipe on the + device. + +Arguments: + UsbDevice - the target representing the device + + Request - Request whose PIRP to use + + RequestOptions - options to use when sending the request + + SetupPacket - control setup packet to be used in the transfer + + MemoryDescriptor - memory to use in the transfer after the setup packet + + BytesTransferred - number of bytes sent to or by the device + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + FxRequestBuffer buf; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxUsbDeviceControlContext context(FxUrbTypeLegacy); + + FxSyncRequest request(pFxDriverGlobals, &context, Request); + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p control transfer sync", UsbDevice); + + FxPointerNotNull(pFxDriverGlobals, SetupPacket); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + return status; + } + + status = buf.ValidateMemoryDescriptor( + pFxDriverGlobals, + MemoryDescriptor, + MemoryDescriptorNullAllowed | MemoryDescriptorNoBufferAllowed + ); + + if (!NT_SUCCESS(status)) { + return status; + } + + status = pUsbDevice->FormatControlRequest(request.m_TrueRequest, + SetupPacket, + &buf); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, WDFREQUEST %p being submitted", + UsbDevice, request.m_TrueRequest->GetTraceObjectHandle()); + + status = pUsbDevice->SubmitSync(request.m_TrueRequest, RequestOptions); + + if (BytesTransferred != NULL) { + if (NT_SUCCESS(status)) { +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + *BytesTransferred = context.m_Urb->TransferBufferLength; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + *BytesTransferred = context.m_UmUrb.UmUrbControlTransfer.TransferBufferLength; +#endif + } + else { + *BytesTransferred = 0; + } + } + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, %!STATUS!", UsbDevice, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in + WDFREQUEST Request, + __in + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + __in_opt + WDFMEMORY TransferMemory, + __in_opt + PWDFMEMORY_OFFSET TransferOffset + ) +/*++ + +Routine Description: + Formats a request so that a control transfer can be sent to the device + after this call returns successfully. + +Arguments: + UsbDevice - the target representing the device + + Request - Request to format + + SetupPacket - control setup packet to be used in the transfer + + TransferMemory - memory to use in the transfer after the setup packet + + TransferOffset - offset into TransferMemory and size override for transfer + length + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxMemory* pMemory; + FxUsbDevice* pUsbDevice; + FxRequestBuffer buf; + FxRequest* pRequest; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, WDFREQUEST %p, WDFMEMORY %p", + UsbDevice, Request, TransferMemory); + + FxPointerNotNull(pFxDriverGlobals, SetupPacket); + + if (TransferMemory != NULL) { + FxObjectHandleGetPtr(pFxDriverGlobals, + TransferMemory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + status = pMemory->ValidateMemoryOffsets(TransferOffset); + if (!NT_SUCCESS(status)) { + return status; + } + + buf.SetMemory(pMemory, TransferOffset); + } + else { + pMemory = NULL; + } + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pUsbDevice->FormatControlRequest(pRequest, SetupPacket, &buf); + + if (NT_SUCCESS(status)) { + FxUsbDeviceControlContext* pContext; + + pContext = (FxUsbDeviceControlContext*) pRequest->GetContext(); + + RtlCopyMemory( + &pContext->m_UsbParameters.Parameters.DeviceControlTransfer.SetupPacket, + SetupPacket, + sizeof(*SetupPacket) + ); + + if (pMemory != NULL) { + pContext->m_UsbParameters.Parameters.DeviceControlTransfer.Buffer = + TransferMemory; + } + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "format control request WDFUSBDEVICE %p, WDFREQWUEST %p, WDFMEMORY %p, %!STATUS!", + UsbDevice, Request, TransferMemory, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pUsbDevice->Reset(); + + return status; +} + +#pragma warning(disable:28285) +__checkReturn +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceCreateIsochUrb)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __in + ULONG NumberOfIsochPackets, + __out + WDFMEMORY* UrbMemory, + __deref_opt_out_bcount(GET_ISOCH_URB_SIZE(NumberOfIsochPackets)) + PURB* Urb + ) +/*++ + +Routine Description: + Creates a WDFUSBDEVICE handle for the client. + +Arguments: + Attributes - Attributes associated with this object + + NumberOfIsochPacket - Maximum number of Isoch packets that will be programmed into this Urb + + UrbMemory - The returned handle to the caller for the allocated Urb + + Urb - (opt) Pointer to the associated urb buffer. + +Return Value: + STATUS_INVALID_PARAMETER - any required parameters are not present/invalid + + STATUS_INVALID_DEVICE_STATE - If the client did not specify a client contract verion while + creating the WDFUSBDEVICE + + STATUS_INSUFFICIENT_RESOURCES - could not allocated the object that backs + the handle + + STATUS_SUCCESS - success + + ... + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + // + // Basic parameter validation + // + FxPointerNotNull(pFxDriverGlobals, UrbMemory); + + if (pUsbDevice->GetUSBDHandle() == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USBDEVICE Must have been created with Client Contract Verion Info, %!STATUS!", + status); + + return status; + } + + status = pUsbDevice->CreateIsochUrb(Attributes, + NumberOfIsochPackets, + UrbMemory, + Urb); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFUSBINTERFACE +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceGetInterface)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in + UCHAR InterfaceIndex + ) +/*++ + +Routine Description: + + +Arguments: + +Return Value: + + + --*/ + +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + FxUsbInterface *pUsbInterface; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + pUsbInterface = pUsbDevice->GetInterfaceFromIndex(InterfaceIndex); + + if (pUsbInterface != NULL) { + return pUsbInterface->GetHandle(); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p has %d interfaces, index %d requested, returning " + "NULL handle", + UsbDevice, pUsbDevice->GetNumInterfaces(), InterfaceIndex); + + return NULL; + } +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in + CONST GUID* CapabilityType, + __in + ULONG CapabilityBufferLength, + __drv_when(CapabilityBufferLength == 0, __out_opt) + __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength)) + __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + __out_opt + __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength)) + PULONG ResultLength + ) +/*++ + +Routine Description: + Queries USB capability for the device. Such capabilities are available + only with USB 3.0 stack. On earlier stacks this API will fail with + STATUS_NOT_IMPLEMENTED + +Arguments: + UsbDevice - Device whose capability is to be queried. + + CapabilityType - Type of capability as defined by + IOCTL_INTERNAL_USB_GET_USB_CAPABILITY + + CapabilityBufferLength - Length of Capability buffer + + CapabilityBuffer - Buffer for capability. Can be NULL if + CapabilitiyBufferLength is 0 + + ResultLength - Actual length of the capability. This parameter is optional. + +Return Value: + STATUS_SUCCESS - success + STATUS_NOT_IMPLEMENTED - Capabilties are not supported by USB stack + STATUS_INSUFFICIENT_RESOURCES - no memory available + ... + + --*/ +{ + DDI_ENTRY(); + + NTSTATUS status; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + if (CapabilityBufferLength > 0) { + FxPointerNotNull(pFxDriverGlobals, CapabilityBuffer); + } + + status = pUsbDevice->QueryUsbCapability(CapabilityType, + CapabilityBufferLength, + CapabilityBuffer, + ResultLength); + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbinterface.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbinterface.cpp new file mode 100644 index 00000000000..dc4c58bb8d9 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbinterface.cpp @@ -0,0 +1,1168 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbInterface.cpp + +Abstract: + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbInterface.tmh" +} + +FxUsbInterface::FxUsbInterface( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxUsbDevice* UsbDevice, + __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ) : + FxNonPagedObject(FX_TYPE_USB_INTERFACE ,sizeof(FxUsbInterface), FxDriverGlobals), + m_UsbDevice(UsbDevice) +{ + m_UsbDevice->ADDREF(this); + + m_InterfaceNumber = InterfaceDescriptor->bInterfaceNumber; + m_Protocol = InterfaceDescriptor->bInterfaceProtocol; + m_Class = InterfaceDescriptor->bInterfaceClass; + m_SubClass = InterfaceDescriptor->bInterfaceSubClass; + + m_CurAlternateSetting = 0; + m_NumSettings = 0; + m_NumberOfConfiguredPipes = 0; + m_ConfiguredPipes = NULL; + m_Settings = NULL; + + MarkNoDeleteDDI(ObjectDoNotLock); +} + +FxUsbInterface::~FxUsbInterface() +{ + ULONG i; + + m_UsbDevice->RemoveDeletedInterface(this); + + for (i = 0; i < m_NumberOfConfiguredPipes; i++) { + ASSERT(m_ConfiguredPipes[i] == NULL); + } + + if (m_ConfiguredPipes != NULL) { + FxPoolFree(m_ConfiguredPipes); + m_ConfiguredPipes = NULL; + } + + m_NumberOfConfiguredPipes = 0; + + if (m_Settings != NULL) { + FxPoolFree(m_Settings); + m_Settings = NULL; + } + + // + // Release the reference taken in the constructor + // + m_UsbDevice->RELEASE(this); +} + +VOID +FxUsbInterface::CleanUpAndDelete( + __in BOOLEAN Failure + ) +/*++ + +Routine Description: + Deletes the pipes contained on the interface. + +Arguments: + Failure - if TRUE, the pipes were never exposed to the client, so any attributes + are cleared before deletion (via DeleteFromFailedCreate) + +Assumes: + FxUsbDevice::InterfaceIterationLock is held by the caller + +Return Value: + None + + --*/ +{ + FxUsbPipe** pPipes; + ULONG numPipes; + KIRQL irql; + ULONG i; + + // + // Capture the values, clear them out of the object and then clean them up + // outside of the lock. + // + m_UsbDevice->Lock(&irql); + + pPipes = m_ConfiguredPipes; + numPipes = m_NumberOfConfiguredPipes; + + m_ConfiguredPipes = NULL; + m_NumberOfConfiguredPipes = 0; + + m_UsbDevice->Unlock(irql); + + if (pPipes != NULL) { + for (i = 0; i < numPipes; i++) { + if (pPipes[i] != NULL) { + if (Failure) { + // + // FxIoTarget::Remove will be called in FxIoTarget::Dispose() + // + pPipes[i]->DeleteFromFailedCreate(); + } + else { + pPipes[i]->DeleteObject(); + } + } + else { + // + // No more pointers to delete, break out of the loop + // + break; + } + } + + FxPoolFree(pPipes); + pPipes = NULL; + } +} + +VOID +FxUsbInterface::RemoveDeletedPipe( + __in FxUsbPipe* Pipe + ) +{ + ULONG i; + + if (m_ConfiguredPipes == NULL) { + return; + } + + for (i = 0; i < m_NumberOfConfiguredPipes; i++) { + if (m_ConfiguredPipes[i] == Pipe) { + m_ConfiguredPipes[i] = NULL; + return; + } + } +} + +VOID +FxUsbInterface::SetInfo( + __in PUSBD_INTERFACE_INFORMATION InterfaceInfo + ) +/*++ + +Routine Description: + Captures the alternate from the interface information into this structure + and then assigns info to all the created pipes. + +Arguments: + InterfaceInfo - info to capture + +Return Value: + None + + --*/ +{ + UCHAR i; + + ASSERT(m_InterfaceNumber == InterfaceInfo->InterfaceNumber); + + m_CurAlternateSetting = InterfaceInfo->AlternateSetting; + + for (i = 0; i < m_NumberOfConfiguredPipes ; i++) { + m_ConfiguredPipes[i]->InitPipe(&InterfaceInfo->Pipes[i], + InterfaceInfo->InterfaceNumber, + this); + } +} + +_Must_inspect_result_ +NTSTATUS +FxUsbInterface::CreateSettings( + VOID + ) +/*++ + +Routine Description: + 1) Find the max number of settings for the interface + 2) Allocate an array for the settings + 3) Create a setting object for each setting and initialize + +Arguments: + None + +Return Value: + NTSTATUS + + --*/ +{ + PUSB_INTERFACE_DESCRIPTOR pDescriptor; + ULONG size; + UCHAR i; + + // + // No need to validate the size of the interface descriptor since FxUsbDevice::CreateInterfaces + // has already done so + // + pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( + m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength, + m_UsbDevice->m_ConfigDescriptor, + USB_INTERFACE_DESCRIPTOR_TYPE + ); + + // + // Calculate the number of settings for this interface + // + while (pDescriptor != NULL) { + if (m_InterfaceNumber == pDescriptor->bInterfaceNumber) { + m_NumSettings++; + } + pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( + m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength, + WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength), + USB_INTERFACE_DESCRIPTOR_TYPE + ); + } + size = sizeof(FxUsbInterfaceSetting) * m_NumSettings; + m_Settings = (FxUsbInterfaceSetting *) FxPoolAllocate( + GetDriverGlobals(), NonPagedPool, size); + + if (m_Settings == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate memory for %d settings for bInterfaceNumber %d " + "(Protocol %d, Class %d, SubClass %d), %!STATUS!", + m_NumSettings, m_InterfaceNumber, m_Protocol, m_Class, m_SubClass, + STATUS_INSUFFICIENT_RESOURCES); + + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(m_Settings, size); + + // + // Add all the settings for this interface + // + pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( + m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength, + m_UsbDevice->m_ConfigDescriptor, + USB_INTERFACE_DESCRIPTOR_TYPE + ); + + while (pDescriptor != NULL) { + if (m_InterfaceNumber == pDescriptor->bInterfaceNumber) { + if (pDescriptor->bAlternateSetting < m_NumSettings) { + m_Settings[pDescriptor->bAlternateSetting].InterfaceDescriptor = pDescriptor; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Interface Number %d does not have contiguous alternate settings," + "expected %d settings, found alt setting %d, %!STATUS!", + pDescriptor->bInterfaceNumber, m_NumSettings, + pDescriptor->bAlternateSetting, STATUS_INVALID_DEVICE_REQUEST); + + return STATUS_INVALID_DEVICE_REQUEST; + } + } + + pDescriptor = (PUSB_INTERFACE_DESCRIPTOR) FxUsbFindDescriptorType( + m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength, + WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength), + USB_INTERFACE_DESCRIPTOR_TYPE + ); + } + + for (i = 0; i < m_NumSettings; i++) { + + if (m_Settings[i].InterfaceDescriptor == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Interface Number %d does not have contiguous alternate settings," + "expected consecutive %d settings, but alt setting %d missing " + "%!STATUS!", m_InterfaceNumber, m_NumSettings, i, + STATUS_INVALID_DEVICE_REQUEST); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + // + // Only validate the endpoints if the interface reports it has some. We don't + // want to validate EP descriptors that may be after the interface descriptor + // that are never used because bNumEndpoints doesn't indicate they are present. + // + if (m_Settings[i].InterfaceDescriptor->bNumEndpoints > 0) { + PVOID pRelativeEnd; + NTSTATUS status; + + // + // Validate that each endpoint descriptor is the correct size for this alt setting. + // We will use the next inteface descriptor as the end, and if this is the last + // interface descriptor, use the end of the config descriptor as our end. + // + pRelativeEnd = FxUsbFindDescriptorType( + m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength, + m_Settings[i].InterfaceDescriptor, + USB_INTERFACE_DESCRIPTOR_TYPE + ); + + if (pRelativeEnd == NULL) { + // + // This is the last alt setting in the config descriptor, use the end of the + // config descriptor as our end + // + pRelativeEnd = WDF_PTR_ADD_OFFSET(m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength); + } + + // + // Limit the number of endpoints validated to bNumEndpoints. In theory + // there could be EP descriptors after N EP descriptors that are never + // used, thus we don't want to risk valdiating them and failing them + // (ie an app compat concern, in a perfect world we would validate them) + // + status = FxUsbValidateDescriptorType( + GetDriverGlobals(), + m_UsbDevice->m_ConfigDescriptor, + m_Settings[i].InterfaceDescriptor, + pRelativeEnd, + USB_ENDPOINT_DESCRIPTOR_TYPE, + sizeof(USB_ENDPOINT_DESCRIPTOR), + FxUsbValidateDescriptorOpAtLeast, + m_Settings[i].InterfaceDescriptor->bNumEndpoints + ); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Interface Number %d does not have a valid endpoint descriptor," + "%!STATUS!", m_InterfaceNumber, status); + + return status; + } + } + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbInterface::SelectSettingByIndex( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in UCHAR SettingIndex + ) +/*++ + +Routine Description: + Setlects a setting by alternate setting index. + +Arguments: + PipesAttributes - optional attributes to apply to each of the created pipes + + SettingIndex - alternate setting index to use + +Return Value: + NTSTATUS + + --*/ +{ +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + PURB urb; +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + UMURB urb; + PUSB_INTERFACE_DESCRIPTOR interfaceDesc; +#endif + FxUsbInterfaceSetting entry; + UCHAR numEP; + NTSTATUS status; + USHORT size; + + status = STATUS_SUCCESS; + + // + // We should have at least 1 setting on the interface + // + ASSERT(m_NumSettings != 0); + + // + // If m_NumberOfConfiguredPipes == 0 then it also tells us that + // the interface wasn't configured. So it can keep track of configuredness + // of the interface. Could there be a case when the selected setting has 0 + // EP's. Due to the above case we use m_InterfaceConfigured. + // + if (IsInterfaceConfigured() && m_CurAlternateSetting == SettingIndex) { + return STATUS_SUCCESS; + } + + // + // Check for an invalid alternate setting + // + if (SettingIndex >= m_NumSettings){ + return STATUS_INVALID_PARAMETER; + } + + RtlCopyMemory(&entry, &m_Settings[SettingIndex], sizeof(entry)); + + // + // Create the configured pipes + // + numEP = entry.InterfaceDescriptor->bNumEndpoints; + + size = GET_SELECT_INTERFACE_REQUEST_SIZE(numEP); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + urb = (PURB) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); + + if (urb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + FormatSelectSettingUrb(urb, numEP, SettingIndex); + + status = SelectSetting(PipesAttributes, urb); + + FxPoolFree(urb); + urb = NULL; + } +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + RtlZeroMemory(&urb, sizeof(UMURB)); + + urb.UmUrbSelectInterface.Hdr.InterfaceHandle = m_WinUsbHandle; + urb.UmUrbSelectInterface.Hdr.Function = UMURB_FUNCTION_SELECT_INTERFACE; + urb.UmUrbSelectInterface.Hdr.Length = sizeof(_UMURB_SELECT_INTERFACE); + + urb.UmUrbSelectInterface.AlternateSetting = SettingIndex; + + status = m_UsbDevice->SendSyncUmUrb(&urb, 2); + + if (NT_SUCCESS(status)) { + RtlZeroMemory(&urb, sizeof(UMURB)); + + urb.UmUrbInterfaceInformation.Hdr.InterfaceHandle = m_WinUsbHandle; + urb.UmUrbInterfaceInformation.Hdr.Function = UMURB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE; + urb.UmUrbInterfaceInformation.Hdr.Length = sizeof(_UMURB_INTERFACE_INFORMATION); + + urb.UmUrbInterfaceInformation.AlternateSetting = SettingIndex; + + status = m_UsbDevice->SendSyncUmUrb(&urb, 2); + + if (NT_SUCCESS(status)) { + interfaceDesc = &urb.UmUrbInterfaceInformation.UsbInterfaceDescriptor; + + m_Settings[SettingIndex].InterfaceDescriptorAlloc = *interfaceDesc; + + m_CurAlternateSetting = SettingIndex; + + MakeAndConfigurePipes(PipesAttributes, interfaceDesc->bNumEndpoints); + } + } +#endif + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbInterface::SelectSettingByDescriptor( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ) +/*++ + +Routine Description: + Selects an alternate setting by using a USB interface descriptor + +Arguments: + PipesAttributes - optional attributes to apply to each of the created pipes + +Return Value: + NTSTATUS + + --*/ +{ + PURB urb; + NTSTATUS status; + USHORT size; + + if (IsInterfaceConfigured() && + (m_CurAlternateSetting == InterfaceDescriptor->bAlternateSetting)) { + // + // Don't do anything + // + return STATUS_SUCCESS; + } + + if (InterfaceDescriptor->bInterfaceNumber != m_InterfaceNumber) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBINTERFACE %p has interface num %d, select setting by " + "descriptor specified interface num %d, %!STATUS!", + GetHandle(), m_InterfaceNumber, + InterfaceDescriptor->bInterfaceNumber, status + ); + + return status; + } + + size = GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints); + + urb = (PURB) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); + + if (urb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + FormatSelectSettingUrb( + urb, + InterfaceDescriptor->bNumEndpoints, + InterfaceDescriptor->bAlternateSetting + ); + + status = SelectSetting(PipesAttributes, urb); + + FxPoolFree(urb); + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbInterface::CheckAndSelectSettingByIndex( + __in UCHAR SettingIndex + ) +/*++ + +Routine Description: + Checks if the give SettingIndex is the current alternate setting + and if not, selects that setting + +Arguments: + SettingIndex - Alternate setting + +Return Value: + NTSTATUS + + --*/ +{ + if (GetConfiguredSettingIndex() != SettingIndex) { + return SelectSettingByIndex(NULL, + SettingIndex); + } + else { + return STATUS_SUCCESS; + } +} + +_Must_inspect_result_ +NTSTATUS +FxUsbInterface::SelectSetting( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PURB Urb + ) +/*++ + +Routine Description: + Worker function which all top level SelectSetting DDIs call into. This will + 1) preallocate all required objects so that we can return failure before + we make any undoable changes to the device's state + 2) send the select interface URB to the device + 3) initialize all created objects + +Arguments: + PipesAttributes - optional attributes to apply to all created pipes + + Urb - Urb to send to the device + +Return Value: + NTSTATUS + + --*/ +{ + FxSyncRequest request(GetDriverGlobals(), NULL); + LIST_ENTRY pendHead; + FxUsbPipe* pPipe; + NTSTATUS status; + UCHAR iPipe, numPipes; + WDF_REQUEST_SEND_OPTIONS options; + FxUsbPipe ** ppPipes; + ULONG size; + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + // + // Subtract the size of the embedded pipe. + // + const ULONG interfaceStructSize = sizeof(Urb->UrbSelectInterface.Interface) - + sizeof(USBD_PIPE_INFORMATION); + + // + // This check will happen twice for SelectSettingByInterface/Descriptor. + // + // We could just do it here, but the above two functions will unnecessarily + // have to build an URB. + // + if (IsInterfaceConfigured() && + m_CurAlternateSetting == + Urb->UrbSelectInterface.Interface.AlternateSetting) { + // + // don't do anything + // + return STATUS_SUCCESS; + } + + InitializeListHead(&pendHead); + numPipes = 0; + ppPipes = NULL; + + if (Urb->UrbSelectInterface.Hdr.Length < interfaceStructSize) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Urb header length 0x%x is less than expected 0x%x" + "%!STATUS!", Urb->UrbSelectInterface.Hdr.Length, interfaceStructSize,status + ); + return status; + } + + status = request.m_TrueRequest->ValidateTarget(m_UsbDevice); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Urb->UrbSelectInterface.Interface.NumberOfPipes is set when the URB + // completes. So, we must compute the number of pipes being requested based + // on the size of the structure and its Length (as set by the caller). + // To calculate the number of pipes we need to account for the + // embedded pipe in the structure. + // + numPipes = (UCHAR) ((Urb->UrbSelectInterface.Interface.Length - + interfaceStructSize) / + sizeof(USBD_PIPE_INFORMATION) + ); + + if (numPipes > 0) { + size = numPipes * sizeof(FxUsbPipe *); + } + else { + // + // It is valid to have an interface with zero pipes in it. In that + // case, we just allocate one entry so that we have a valid array + // and keep the remaining code simple. + // + size = sizeof(FxUsbPipe*); + } + + // + // If the interface is already configured don't do anything with the old + // settings till we allocate new. + // + ppPipes = (FxUsbPipe **) FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); + + if (ppPipes == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Unable to allocate memory %!STATUS!" + , status); + goto Done; + } + + RtlZeroMemory(ppPipes, size); + + for (iPipe = 0; iPipe < numPipes; iPipe++) { + ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes) + FxUsbPipe(GetDriverGlobals(),m_UsbDevice); + + if (ppPipes[iPipe] == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Unable to allocate memory for the pipes %!STATUS!", status); + goto Done; + } + + pPipe = ppPipes[iPipe]; + + status = pPipe->Init(m_UsbDevice->m_Device); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Init pipe failed %!STATUS!", status); + goto Done; + } + + status = pPipe->Commit(PipesAttributes, NULL, this); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Commit pipe failed %!STATUS!", status); + goto Done; + } + } + + if (IsInterfaceConfigured()) { + // + // Delete the old pipes + // + m_UsbDevice->CleanupInterfacePipesAndDelete(this); + } + + + WDF_REQUEST_SEND_OPTIONS_INIT(&options, + WDF_REQUEST_SEND_OPTION_IGNORE_TARGET_STATE); + + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(2)); + + FxFormatUsbRequest(request.m_TrueRequest, Urb, FxUrbTypeLegacy, NULL); + status = m_UsbDevice->SubmitSync(request.m_TrueRequest, &options, NULL); + + // + // If select interface URB fails we are at the point of no return and we + // will end up with no configured pipes. + // + if (NT_SUCCESS(status)) { + SetNumConfiguredPipes(numPipes); + SetConfiguredPipes(ppPipes); + SetInfo(&Urb->UrbSelectInterface.Interface); + } + +Done: + if (!NT_SUCCESS(status)) { + if (ppPipes != NULL) { + ASSERT(ppPipes != m_ConfiguredPipes); + + for (iPipe = 0; iPipe < numPipes; iPipe++) { + if (ppPipes[iPipe] != NULL) { + ppPipes[iPipe]->DeleteFromFailedCreate(); + } + } + + FxPoolFree(ppPipes); + ppPipes = NULL; + } + } + + return status; +} + +VOID +FxUsbInterface::FormatSelectSettingUrb( + __in_bcount(GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints)) PURB Urb, + __in USHORT NumEndpoints, + __in UCHAR SettingNumber + ) +/*++ + +Routine Description: + Format a URB for selecting an interface's new setting. Note this will setup + the URB header and all pipes' information in the URB's array of pipe infos. + + This function exists as a method of FxUsbDevice instead of FxUsbInterface + because in the case of a select config where we manually select setting 0 + on interfaces 2...N we don't have an FxUsbInterface pointer + +Arguments: + Urb - the URB to format. It is assumed the caller allocated a large enough + URB to contain NumEndpoints + + NumEndpoints - number of endpoints in the new setting + + InterfaceNum - interface number for the interface + + SettingNumber - setting number on the interface + + --*/ +{ + ULONG defaultMaxTransferSize; + USHORT size; + UCHAR i; + + size = GET_SELECT_INTERFACE_REQUEST_SIZE(NumEndpoints); + + RtlZeroMemory(Urb, size); + + // + // Setup the URB, format the request, and send it + // + UsbBuildSelectInterfaceRequest(Urb, + size, + m_UsbDevice->m_ConfigHandle, + m_InterfaceNumber, + SettingNumber); + + defaultMaxTransferSize = m_UsbDevice->GetDefaultMaxTransferSize(); + + Urb->UrbSelectInterface.Interface.Length = + GET_USBD_INTERFACE_SIZE(NumEndpoints); + + Urb->UrbSelectInterface.Interface.NumberOfPipes = NumEndpoints; + + for (i = 0; i < NumEndpoints; i++) { + + // + // Make sure that the Interface Length conveys the exact number of EP's + // + ASSERT( + &Urb->UrbSelectInterface.Interface.Pipes[i] < + WDF_PTR_ADD_OFFSET(&Urb->UrbSelectInterface.Interface, + Urb->UrbSelectInterface.Interface.Length) + ); + + Urb->UrbSelectInterface.Interface.Pipes[i].PipeFlags = 0x0; + Urb->UrbSelectInterface.Interface.Pipes[i].MaximumTransferSize = + defaultMaxTransferSize; + } +} + +VOID +FxUsbInterface::GetEndpointInformation( + __in UCHAR SettingIndex, + __in UCHAR EndpointIndex, + __in PWDF_USB_PIPE_INFORMATION PipeInfo + ) +/*++ + +Routine Description: + The layout of the config descriptor is such that each interface+setting pair + is followed by the endpoints for that interface+setting pair. Keep track of + the index. + +Arguments: + SettingIndex - alternate setting to get info for + + EndpointIndex - index into the number endpoints for this interface+setting + + PipeInfo - Info to return + +Return Value: + None + + --*/ +{ + PUCHAR pEnd, pCur; + PUSB_INTERFACE_DESCRIPTOR pInterfaceDesc; + PUSB_ENDPOINT_DESCRIPTOR pEndpointDesc; + UCHAR curEndpointIndex; + BOOLEAN endPointFound; + + pInterfaceDesc = NULL; + curEndpointIndex = 0; + endPointFound = FALSE; + + // + // Extract the interface descriptor for the alternate setting for the interface + // + pInterfaceDesc = GetSettingDescriptor(SettingIndex); + + if (pInterfaceDesc == NULL) { + return; + } + + pEnd = (PUCHAR) WDF_PTR_ADD_OFFSET( + m_UsbDevice->m_ConfigDescriptor, + m_UsbDevice->m_ConfigDescriptor->wTotalLength + ); + + // + // Start from the descriptor after current one + // + pCur = (PUCHAR) WDF_PTR_ADD_OFFSET(pInterfaceDesc, pInterfaceDesc->bLength); + + // + // Iterate through the list of EP descriptors following the interface descriptor + // we just found and get the endpoint descriptor which matches the endpoint + // index or we hit another interface descriptor + // + // We have already validated that the descriptor headers are well formed and within + // the config descriptor bounds + // + while (pCur < pEnd) { + PUSB_COMMON_DESCRIPTOR pCommonDesc = (PUSB_COMMON_DESCRIPTOR) pCur; + + // + // If we hit the next interface no way we can find the EndPoint + // + if (pCommonDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) { + break; + } + + if (pCommonDesc->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE) { + // + // Size of pEndpointDesc has been validated by CreateSettings() and + // is within the config descriptor + // + pEndpointDesc = (PUSB_ENDPOINT_DESCRIPTOR) pCommonDesc; + + if (EndpointIndex == curEndpointIndex) { + CopyEndpointFieldsFromDescriptor(PipeInfo, + pEndpointDesc, + SettingIndex); + break; + } + + curEndpointIndex++; + } + + // + // Advance past this descriptor + // + pCur += pCommonDesc->bLength; + } +} + +ULONG +FxUsbInterface::DetermineDefaultMaxTransferSize( + VOID + ) +/*++ + +Routine Description: + Returns the maximum transfer size of an endpoint + +Arguments: + None + +Return Value: + max transfer size + + --*/ +{ + if (m_UsbDevice->m_Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) { + return FxUsbPipeHighSpeedMaxTransferSize; + } + else { + return FxUsbPipeLowSpeedMaxTransferSize; + } +} + +VOID +FxUsbInterface::CopyEndpointFieldsFromDescriptor( + __in PWDF_USB_PIPE_INFORMATION PipeInfo, + __in PUSB_ENDPOINT_DESCRIPTOR EndpointDesc, + __in UCHAR SettingIndex + ) +/*++ + +Routine Description: + Copy informatoin out of the usb endpoint descriptor into this object + +Arguments: + PipeInfo - information to return + + EndpointDesc - descriptor to copy from + + SettingIndex - alternate setting this information is for + +Return Value: + None + + --*/ +{ + PipeInfo->MaximumPacketSize = EndpointDesc->wMaxPacketSize; + PipeInfo->EndpointAddress = EndpointDesc->bEndpointAddress; + PipeInfo->Interval = EndpointDesc->bInterval; + + // + // Extract the lower 2 bits which contain the EP type + // + PipeInfo->PipeType = FxUsbPipe::_UsbdPipeTypeToWdf( + (USBD_PIPE_TYPE) (EndpointDesc->bmAttributes & 0x03) + ); + + // + // Filling in a default value since the EndpointDescriptor doesn't contain it + // + if (PipeInfo->PipeType == WdfUsbPipeTypeControl) { + PipeInfo->MaximumTransferSize = FxUsbPipeControlMaxTransferSize; + } + else { + PipeInfo->MaximumTransferSize = DetermineDefaultMaxTransferSize(); + } + + PipeInfo->SettingIndex = SettingIndex; +} + +WDFUSBPIPE +FxUsbInterface::GetConfiguredPipe( + __in UCHAR PipeIndex, + __out_opt PWDF_USB_PIPE_INFORMATION PipeInfo + ) +/*++ + +Routine Description: + Return the WDFUSBPIPE for the given index + +Arguments: + PipeIndex - index into the number of configured pipes for the interface + + PipeInfo - optional information to return about the returned pipe + +Return Value: + valid WDFUSBPIPE handle or NULL on error + + --*/ +{ + if (PipeIndex >= m_NumberOfConfiguredPipes) { + return NULL; + } + else { + if (PipeInfo != NULL) { + m_ConfiguredPipes[PipeIndex]->GetInformation(PipeInfo); + } + + return m_ConfiguredPipes[PipeIndex]->GetHandle(); + } +} + +VOID +FxUsbInterface::GetDescriptor( + __in PUSB_INTERFACE_DESCRIPTOR UsbInterfaceDescriptor, + __in UCHAR SettingIndex + ) +/*++ + +Routine Description: + Copies the descriptor back to the caller + +Arguments: + UsbInterfaceDescriptor - descriptor pointer to fill in + + SettingIndex - alternate setting that the caller is interested in + +Return Value: + None + + --*/ +{ + if (SettingIndex >= m_NumSettings) { + RtlZeroMemory(UsbInterfaceDescriptor, + sizeof(*UsbInterfaceDescriptor)); + } + else { + RtlCopyMemory(UsbInterfaceDescriptor, + m_Settings[SettingIndex].InterfaceDescriptor, + sizeof(*UsbInterfaceDescriptor)); + } +} + +UCHAR +FxUsbInterface::GetConfiguredSettingIndex( + VOID + ) +/*++ + +Routine Description: + Returns the currently configured setting index for the interface + +Arguments: + None + +Return Value: + Currently configured Index + + --*/ + +{ + if (IsInterfaceConfigured()) { + return m_CurAlternateSetting; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBINTERFACE %p not configured, cannot retrieve configured " + "setting index", GetHandle()); + + FxVerifierDbgBreakPoint(GetDriverGlobals()); + + return 0; + } +} + +UCHAR +FxUsbInterface::GetNumEndpoints( + __in UCHAR SettingIndex + ) +/*++ + +Routine Description: + Returns the number of endpoints on a given alternate interface + +Arguments: + SettingIndex - index of the alternate setting + +Return Value: + Number of endpoints or 0 on error + + --*/ +{ + if (SettingIndex >= m_NumSettings) { + return 0; + } + else { + return m_Settings[SettingIndex].InterfaceDescriptor->bNumEndpoints; + } +} + +PUSB_INTERFACE_DESCRIPTOR +FxUsbInterface::GetSettingDescriptor( + __in UCHAR Setting + ) +/*++ + +Routine Description: + Returns the device's interface descriptor for the given alternate setting + +Arguments: + Setting - AlternateSetting desired + +Return Value: + USB interface descriptor or NULL on failure + + --*/ +{ + UCHAR i; + + for (i = 0; i < m_NumSettings; i++) { + if (m_Settings[i].InterfaceDescriptor->bAlternateSetting == Setting) { + return m_Settings[i].InterfaceDescriptor; + } + } + + return NULL; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbinterfaceapi.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbinterfaceapi.cpp new file mode 100644 index 00000000000..9ef42e3c8e5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbinterfaceapi.cpp @@ -0,0 +1,497 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbInterfaceAPI.cpp + +Abstract: + + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbInterfaceAPI.tmh" +} + +// +// Extern "C" all APIs +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbInterfaceSelectSetting)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface, + __in_opt + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ) +/*++ + +Routine Description: + Selects an alternate setting on a given interface number + +Arguments: + UsbInterface - the interface whose setting will be selected + + PipesAttributes - Attributes to apply to each of the new pipes on the setting + + Params - Strucutre indicating how to select a new setting + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbInterface* pUsbInterface; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Params); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + if (Params->Size != sizeof(WDF_USB_INTERFACE_SELECT_SETTING_PARAMS)) { + status = STATUS_INFO_LENGTH_MISMATCH; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Params size %d, expected %d %!STATUS!", Params->Size, + sizeof(WDF_USB_INTERFACE_SELECT_SETTING_PARAMS), status); + return status; + } + + status = FxValidateObjectAttributes(pFxDriverGlobals, + PipesAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + if (Params->Type != WdfUsbInterfaceSelectSettingTypeSetting) { + FX_VERIFY_WITH_NAME(INTERNAL, TRAPMSG("UMDF may only select settings by index."), + DriverGlobals->DriverName); + } +#endif + + switch (Params->Type) { + case WdfUsbInterfaceSelectSettingTypeDescriptor: + if (Params->Types.Descriptor.InterfaceDescriptor == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "InterfaceDescriptor passed in is NULL %!STATUS!", status); + + } + else { + status = pUsbInterface->SelectSettingByDescriptor( + PipesAttributes, + Params->Types.Descriptor.InterfaceDescriptor + ); + } + break; + + case WdfUsbInterfaceSelectSettingTypeSetting: + status = pUsbInterface->SelectSettingByIndex( + PipesAttributes, + Params->Types.Interface.SettingIndex + ); + break; + + case WdfUsbInterfaceSelectSettingTypeUrb: + if (Params->Types.Urb.Urb == NULL || + Params->Types.Urb.Urb->UrbHeader.Function != URB_FUNCTION_SELECT_INTERFACE || + (Params->Types.Urb.Urb->UrbHeader.Length < + sizeof(struct _URB_SELECT_INTERFACE) - sizeof(USBD_PIPE_INFORMATION)) ) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "URB or URB fields passed in are invalid Urb 0x%p %!STATUS!", + Params->Types.Urb.Urb, status); + + } + else { + status = pUsbInterface->SelectSetting(PipesAttributes, + Params->Types.Urb.Urb); + } + break; + + default: + status = STATUS_INVALID_PARAMETER; + break; + } + + return status; +} + + +__drv_maxIRQL(DISPATCH_LEVEL) +BYTE +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface + ) +/*++ + +Routine Description: + Returns the interface number of the given interface. The interface number + is not necessarily the same as the index of the interface. Once is specified + by the device, the other is where it is located within an internal array. + +Arguments: + UsbInterface - Interace whose number will be returned + +Return Value: + interface number + + --*/ +{ + DDI_ENTRY(); + + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface); + + return pUsbInterface->GetInterfaceNumber(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BYTE +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface, + __in + UCHAR SettingIndex + ) +/*++ + +Routine Description: + Returns the number of endpoints (not configured) for a given setting on the + given interface. + +Arguments: + UsbInterface - interface whose number of endpoints will be returned + + SettingsIndex - the index into the alternate setting array + +Return Value: + Number of endpoints + + --*/ +{ + DDI_ENTRY(); + + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE , + (PVOID*) &pUsbInterface); + + return pUsbInterface->GetNumEndpoints(SettingIndex); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface, + __in + UCHAR SettingIndex, + __in + UCHAR EndpointIndex, + __out + PWDF_USB_PIPE_INFORMATION EndpointInfo + ) +/*++ + +Routine Description: + Returns information on a given endpoint (unconfigured) for an interface + + alternate setting index. + +Arguments: + UsbInterface - interface which contains the endpoint + + SettingIndex - alternate setting index + + EndpointIndex - index into the endpoint array contained by interface+setting + + EndpointInfo - structure to be filled in with the info of the endpoint + +Return Value: + None + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, EndpointInfo); + + if (EndpointInfo->Size != sizeof(WDF_USB_PIPE_INFORMATION)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "EndpointInfo Size %d incorrect, expected %d, %!STATUS!", + EndpointInfo->Size, sizeof(WDF_USB_PIPE_INFORMATION), + STATUS_INFO_LENGTH_MISMATCH); + FxVerifierDbgBreakPoint(pFxDriverGlobals); + return; + } + + pUsbInterface->GetEndpointInformation(SettingIndex, + EndpointIndex, + EndpointInfo); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumSettings)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface + ) +/*++ + +Routine Description: + Returns the number of settings available on an interface. + +Arguments: + UsbInterface - the usb interface being queried + +Return Value: + Number of settings as described by the config descriptor + + --*/ +{ + DDI_ENTRY(); + + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface); + + return pUsbInterface->GetNumSettings(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetDescriptor)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface, + __in + UCHAR SettingIndex, + __out + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ) +/*++ + +Routine Description: + Returns the underlying USB interface descriptor for the given WDF handle + +Arguments: + UsbInterface - interface whose descriptor will be returned + + SettingIndex - alternatve setting whose interface should be returned + + InterfaceDescriptor - Pointer which will receive the descriptor + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, InterfaceDescriptor); + + pUsbInterface->GetDescriptor(InterfaceDescriptor, SettingIndex); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BYTE +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface + ) +/*++ + +Routine Description: + Returns the alternate setting index which is currently configured + +Arguments: + UsbInterface - interfase whose configured setting is being queried + +Return Value: + The current setting or 0 on failure + + --*/ +{ + DDI_ENTRY(); + + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE , + (PVOID*) &pUsbInterface); + + return pUsbInterface->GetConfiguredSettingIndex(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BYTE +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface + ) +/*++ + +Routine Description: + Returns the number of configured pipes on a given interface. + +Arguments: + UsbInterface - the configured interface + +Return Value: + Number of configured pipes or 0 on error + + --*/ +{ + DDI_ENTRY(); + + FxUsbInterface * pUsbInterface; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE , + (PVOID*) &pUsbInterface); + + return pUsbInterface->GetNumConfiguredPipes(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDFUSBPIPE +WDFAPI +WDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBINTERFACE UsbInterface, + __in + UCHAR PipeIndex, + __out_opt + PWDF_USB_PIPE_INFORMATION PipeInfo + ) +/*++ + +Routine Description: + Returns the WDFUSBPIPE handle for the configured interface + pipe index. + Optionally, information about the pipe is also returned. + +Arguments: + UsbInterface - configured interface + + PipeIndex - index into the number of pipes on the interface + + PipeInfo - information to be returned on the pipe + +Return Value: + valid WDFUSBPIPE or NULL on error + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbInterface * pUsbInterface; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbInterface, + FX_TYPE_USB_INTERFACE, + (PVOID*) &pUsbInterface, + &pFxDriverGlobals); + + if (PipeInfo != NULL && PipeInfo->Size != sizeof(WDF_USB_PIPE_INFORMATION)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "PipeInfo Size %d incorrect, expected %d, %!STATUS!", + PipeInfo->Size, sizeof(WDF_USB_PIPE_INFORMATION), status); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + + return NULL; + } + + return pUsbInterface->GetConfiguredPipe(PipeIndex, PipeInfo); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpch.hpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpch.hpp new file mode 100644 index 00000000000..62bf34a75fc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpch.hpp @@ -0,0 +1,16 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// + +#include "..\FxTargetsShared.hpp" + +#include "FxUsbDevice.hpp" +#include "FxUsbInterface.hpp" +#include "FxUsbPipe.hpp" + +#include "UsbUtil.hpp" + +#include "FxNPagedLookasideList.hpp" +#include "FxPagedLookasideList.hpp" + + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpipe.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpipe.cpp new file mode 100644 index 00000000000..ab20efe40b7 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpipe.cpp @@ -0,0 +1,1892 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbPipe.tmh" +} + +#include "Fxglobals.h" +// +// NOTE: There are 3 different paths Requests could be sent to the lower driver +// 1) In case of reposting a successfully completed Request use the Dpc which calls SendIo. +// 2) For a failed completion use a workitem which works if the IoTarget is in Started state. +// 3) On moving to the start state the Repeater requests are inserted into the +// Iotargets Pended Queue directly. +// +// The function ResubmitRepeater calls SubmitLocked. If the action we get back +// from SubmitLocked is "SubmitSend", (SubmitQueued is treated as failure because +// of WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND flag) we are guaranteed to +// call IoCallDriver in the workitem or the DPC and hence the completion routine +// being called. +// This is very important because we increment the m_IoCount in SubmitLocked and +// decrement in the completion routine. So if there was a code path where +// SubmitLocked was called and IoCallDriver(hence the completion routine) wasn't, +// the IoTarget could stop responding in Dispose. +// + + +FxUsbPipeContinuousReader::FxUsbPipeContinuousReader( + __in FxUsbPipe* Pipe, + __in UCHAR NumReaders + ) : + m_NumReaders(NumReaders), + m_NumFailedReaders(0) +{ + m_WorkItem = NULL; + m_WorkItemRerunContext = NULL; + m_WorkItemThread = NULL; + m_WorkItemFlags = 0; + m_WorkItemQueued = FALSE; + m_ReadersSubmitted = FALSE; + + m_Lookaside = NULL; + m_Pipe = Pipe; + + m_TargetDevice = m_Pipe->GetTargetDevice(); + + RtlZeroMemory(&m_Readers[0], m_NumReaders * sizeof(FxUsbPipeRepeatReader)); +} + +FxUsbPipeContinuousReader::~FxUsbPipeContinuousReader() +{ + LONG i; + + FxUsbPipeRepeatReader * reader = &m_Readers[0]; + + // + // It is impoortant to delete the requests before the lookaside because the + // requests may have outstanding references on memory objects allocated by + // the lookaside. The lookaside will not be truly deleted until the oustanding + // memory object allocations are also freed. + // + for (i = 0; i < m_NumReaders; i++) { + if (reader[i].Request != NULL) { + DeleteMemory(reader[i].Request); + + reader[i].Request->DeleteObject(); + reader[i].Request = NULL; + } + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + reader[i].ReadCompletedEvent.Uninitialize(); + reader[i].m_ReadWorkItem.Free(); +#endif + } + + if (m_Lookaside != NULL) { + m_Lookaside->DeleteObject(); + } + + if (m_WorkItem != NULL) { + m_WorkItem->DeleteObject(); + m_WorkItem = NULL; + } +} + +BOOLEAN +FxUsbPipeContinuousReader::QueueWorkItemLocked( + __in FxUsbPipeRepeatReader* Repeater + ) +{ + BOOLEAN queued; + PFX_DRIVER_GLOBALS fxDriverGlobals; + + queued = FALSE; + fxDriverGlobals = m_Pipe->GetDriverGlobals(); + + if (m_Pipe->m_State == WdfIoTargetStarted && m_WorkItemQueued == FALSE) { + // + // No item queued, queue it up now. + // + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader queueing work item to recover " + "from failed allocation", m_Pipe->GetHandle()); + + if (m_WorkItem->Enqueue(_FxUsbPipeRequestWorkItemThunk, Repeater)) { + m_WorkItemQueued = TRUE; + queued = TRUE; + } + else { + DoTraceLevelMessage(fxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not Queue workitem"); + } + } + + // + // We only want to queue the work item while the target is in the + // started state. If it is not started, then we are no longer sending + // i/o and we should not queue the work item to try to restart. + // + if (FALSE == queued) { + DoTraceLevelMessage( + fxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader not queueing work item," + "WorkItemQueued = %d, target state %!WDF_IO_TARGET_STATE!", + m_Pipe->GetHandle(), m_WorkItemQueued, m_Pipe->m_State); + } + + return queued; +} + +ULONG +FxUsbPipeContinuousReader::ResubmitRepeater( + __in FxUsbPipeRepeatReader* Repeater, + __out NTSTATUS* Status + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + NTSTATUS status; + ULONG action; + KIRQL irql; + + action = 0; + pFxDriverGlobals = m_Pipe->GetDriverGlobals(); + status = STATUS_UNSUCCESSFUL; + + // + // Reformat and allocate any new needed buffers + // + status = FormatRepeater(Repeater); + + m_Pipe->Lock(&irql); + + // + // Do not re-submit repeaters if there is a queued/running work-item to + // reset pipe. Work-item will restart this repeater later. + // This check needs to be done after the FormatRepeater() call above to + // prevent a race condition where we are not detecting when the repeater + // is cancelled. + // + if (m_WorkItemQueued) { + // + // Return an error and no action flags to let the caller know that + // this request was not sent. + // + status = STATUS_CANCELLED; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p is being reset, continuous reader %p FxRequest %p" + " PIRP %p is deferred for later.", + m_Pipe->GetHandle(), Repeater, Repeater->Request, + Repeater->RequestIrp); + } + else if (NT_SUCCESS(status)) { + // + // Get ready to re-submit the repeater. + // + action = m_Pipe->SubmitLocked( + Repeater->Request, + NULL, + WDF_REQUEST_SEND_INTERNAL_OPTION_FAIL_ON_PEND + ); + + if (action & SubmitSend) { + // + // Clear the event only if we are going to send the request + // + Repeater->ReadCompletedEvent.Clear(); + } + else if (action & SubmitQueued) { + // + // Request got canceled asynchronously. The other thread is now + // responsible for calling its completion callback. + // + status = STATUS_CANCELLED; + } + else { + // + // Submit failed (which is expected when we are changing the target + // state or when the request is canceled). It should always be an + // error. + // + status = Repeater->Request->GetFxIrp()->GetStatus(); + ASSERT(!NT_SUCCESS(status)); + } + } + else { + // + // Could not allocate a new buffer + // + Repeater->Request->GetFxIrp()->SetStatus(status); + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader, format failed, %!STATUS!, " + "repeater %p", m_Pipe->GetHandle(), status, Repeater); + + if (m_Pipe->m_State == WdfIoTargetStarted) { + m_NumFailedReaders++; + ASSERT(m_NumFailedReaders <= m_NumReaders); + + if (m_NumFailedReaders == m_NumReaders) { + // + // Queue a work item to clear problem. + // + QueueWorkItemLocked(Repeater); + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader, buffer alloc failed, but " + "there are %d readers left out of a max of %d", + m_Pipe->GetHandle(), m_NumReaders - m_NumFailedReaders, + m_NumReaders); + + // + // There are still other pending readers, just use those for + // now. + // + DO_NOTHING(); + } + } + else { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader, buffer alloc failed, but not " + "in started state", m_Pipe->GetHandle()); + } + } + + m_Pipe->Unlock(irql); + + *Status = status; + + return action; +} + +VOID +FxUsbPipeContinuousReader::_FxUsbPipeRequestComplete( + __in WDFREQUEST Request, + __in WDFIOTARGET Target, + __in PWDF_REQUEST_COMPLETION_PARAMS Params, + __in WDFCONTEXT Context + ) +{ + FxUsbPipeRepeatReader* pRepeater; + FxUsbPipeContinuousReader* pThis; + FxUsbPipe* pPipe; + NTSTATUS status; + ULONG action; + BOOLEAN readCompletedEventSet; + + UNREFERENCED_PARAMETER(Request); + UNREFERENCED_PARAMETER(Params); + + readCompletedEventSet = FALSE; + action = 0; + pRepeater = (FxUsbPipeRepeatReader*) Context; + pThis = (FxUsbPipeContinuousReader*) pRepeater->Parent; + pPipe = pThis->m_Pipe; + + status = pRepeater->Request->GetFxIrp()->GetStatus(); + + if (NT_SUCCESS(status)) { + PWDF_USB_REQUEST_COMPLETION_PARAMS params; + + params = pRepeater->Request->GetContext()-> + m_CompletionParams.Parameters.Usb.Completion; + + pThis->m_ReadCompleteCallback((WDFUSBPIPE) Target, + params->Parameters.PipeRead.Buffer, + params->Parameters.PipeRead.Length, + pThis->m_ReadCompleteContext); + + // + // This will release the reference on the read memory and allocate a new + // one + // + action = pThis->ResubmitRepeater(pRepeater, &status); + } + else if (status != STATUS_CANCELLED) { + KIRQL irql; + + DoTraceLevelMessage( + pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader FxRequest %p PIRP %p returned with " + "%!STATUS!", pPipe->GetHandle(), pRepeater->Request , + pRepeater->RequestIrp, status); + + + pPipe->Lock(&irql); + + pRepeater->ReadCompletedEvent.Set(); + readCompletedEventSet = TRUE; + + // + // Queue a work item to clear problem. + // + pThis->QueueWorkItemLocked(pRepeater); + + pPipe->Unlock(irql); + + ASSERT(!NT_SUCCESS(status)); + } + else { + // + // I/O was cancelled, which means internally it was cancelled so don't + // do anything. + // + DoTraceLevelMessage( + pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader %p FxRequest %p PIRP %p canceled", + pPipe->GetHandle(), pRepeater, pRepeater->Request , pRepeater->RequestIrp); + + DO_NOTHING(); + } + + if (action & SubmitSend) { + + // + // We don't want to recurse on the same stack and overflow it. + // This is especially true if the device is pushing a lot of data and + // usb is completing everything within its dpc as soon as we send the + // read down. Eventually on a chk build, we will be nailed for running + // in one DPC for too long. + // + // As a slower alternative, we could queue a work item and resubmit the + // read from there. + // + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + BOOLEAN result; + result = KeInsertQueueDpc(&pRepeater->Dpc, NULL, NULL); + + // + // The DPC should never be currently queued when we try to queue it. + // + ASSERT(result != FALSE); +#else + pRepeater->m_ReadWorkItem.Enqueue((PMX_WORKITEM_ROUTINE)_ReadWorkItem, pRepeater); +#endif + UNREFERENCED_PARAMETER(status); //for fre build + + } + else if (action & SubmitQueued) { + // + // I/O got canceled asynchronously; the other thread is now + // responsible for re-invoking this completion routine. + // + ASSERT(STATUS_CANCELLED == status); + + DoTraceLevelMessage( + pPipe->GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p continuous reader %p FxRequest %p PIRP %p got" + " asynchronously canceled", + pPipe->GetHandle(), pRepeater, pRepeater->Request , + pRepeater->RequestIrp); + + DO_NOTHING(); + } + else if (FALSE == readCompletedEventSet) { + ASSERT(!NT_SUCCESS(status)); + // + // We are not sending the request and it is not queued so signal that + // it is done. + // + pRepeater->ReadCompletedEvent.Set(); + } +} + +VOID +FxUsbPipeContinuousReader::FxUsbPipeRequestWorkItemHandler( + __in FxUsbPipeRepeatReader* FailedRepeater + ) +{ + FxUsbDevice* pDevice; + NTSTATUS status, failedStatus; + USBD_STATUS usbdStatus; + LONG i; + KIRQL irql; + BOOLEAN restart; + FxRequestContext* context; + PWDF_USB_REQUEST_COMPLETION_PARAMS usbCompletionParams; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = m_Pipe->GetDriverGlobals(); + + // + // Get failed info. + // + failedStatus = FailedRepeater->Request->GetStatus(); + + // + // Context is allocated at config time and gets reused so context + // will never be NULL. + // + context = FailedRepeater->Request->GetContext(); + usbCompletionParams = context->m_CompletionParams.Parameters.Usb.Completion; + + // + // In case FormatRepeater fails to allocate memory usbCompletionParams + // pointer is not set. + // + // usbCompletionParams are part of the context and + // not really allocated at the time of every Format but + // the pointer gets cleared by request->Reuse and gets set again by + // context->SetUsbType. + // + // In FormatRepeater, context->SetUsbType is skipped + // if a memory failure occurs before this step. + // + // Hence retrieve usbdStatus only when usbCompletionParams is set. + // + if (usbCompletionParams) { + usbdStatus = usbCompletionParams->UsbdStatus; + } + else { + // + // Set usbdStatus to success as we didn't receive a failure from + // USB stack. + // + // This path is reached during memory allocation failure. In such + // case failedStatus would already be set appropriately. (usbdStatus + // and failedStatus are passed to m_ReadersFailedCallback below.) + // + usbdStatus = STATUS_SUCCESS; + } + + // + // No read requests should be in progress when the framework calls the + // EvtUsbTargetPipeReadersFailed callback function. This is part of the + // contract so that the Driver doesn't need to bother with the + // Completion calllback while taking corrective action. + // + CancelRepeaters(); + pDevice = m_Pipe->m_UsbDevice; + + if (m_ReadersFailedCallback != NULL) { + // + // Save the current thread object pointer. This value is + // used for not deadlocking when misbehaved drivers (< v1.9) call + // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback + // + ASSERT(NULL == m_WorkItemThread); + m_WorkItemThread = Mx::MxGetCurrentThread(); + + restart = m_ReadersFailedCallback( + (WDFUSBPIPE) m_Pipe->GetHandle(), + failedStatus, + usbdStatus + ); + + m_WorkItemThread = NULL; + } + else { + // + // By default, we restart the readers + // + restart = TRUE; + } + + if (restart) { + status = pDevice->IsConnected(); + + if (NT_SUCCESS(status)) { + + // + // for v1.9 or higher use the error recovery procedure prescribed + // by the USB team. + // + if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { + + if (pDevice->IsEnabled()) { + // + // Reset the pipe if port status is enabled + // + m_Pipe->Reset(); + } + else { + // + // Reset the device if port status is disabled + // + status = pDevice->Reset(); + } + } + else { + // + // Reset the device if port status is disabled + // + status = pDevice->Reset(); + } + } + else { + // + // if port status is disconnected we would get back + // a !NT_SUCCESS. This would mean that we would not + // send the readers again and treat it like a failed reader. + // + DO_NOTHING(); + } + + } + else { + // + // By setting status to !NT_SUCCESS, we will not send the readers + // again and treat it like a failed reader. + // + status = STATUS_UNSUCCESSFUL; + } + + // + // Work item is no longer queued. We set this before resubmitting the + // repeaters so that if they all complete and fail, we will requeue the + // work item. + // + m_Pipe->Lock(&irql); + m_WorkItemQueued = FALSE; + m_Pipe->Unlock(irql); + + if (NT_SUCCESS(status)) { + ULONG action; + + // + // Reset the count to zero. This is safe since we stopped all the + // readers at the beginning of this function. + // + m_NumFailedReaders = 0; + + // + // restart the readers + // + for (i = 0; i < m_NumReaders; i++) { + FxUsbPipeRepeatReader* pRepeater; + + pRepeater = &m_Readers[i]; + + action = ResubmitRepeater(pRepeater, &status); + + if (action & SubmitSend) { + // + // Ignore the return value because once we have sent the + // request, we want all processing to be done in the + // completion routine. + // + (void) pRepeater->Request->GetSubmitFxIrp()->CallDriver(m_Pipe->m_TargetDevice); + } + } + } +} + +VOID +FxUsbPipeContinuousReader::_FxUsbPipeRequestWorkItemThunk( + __in PVOID Context + ) +/* + Only one work-item can be in-progress at any given time and + only one additional work-item can be queued at any given time. + This logic and m_WorkItemQueued makes this happen. +*/ +{ + FxUsbPipeRepeatReader* pFailedRepeater; + FxUsbPipeContinuousReader* pThis; + FxUsbPipe* pPipe; + KIRQL irql; + BOOLEAN rerun, inprogress; + + pFailedRepeater = (FxUsbPipeRepeatReader*) Context; + pThis = (FxUsbPipeContinuousReader*) pFailedRepeater->Parent; + pPipe = pThis->m_Pipe; + + // + // Check if a work item is already in progress. + // + pPipe->Lock(&irql); + if (pThis->m_WorkItemFlags & FX_USB_WORKITEM_IN_PROGRESS) { + // + // Yes, just let the other thread re-run this logic. + // + inprogress = TRUE; + + ASSERT((pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) == 0); + pThis->m_WorkItemFlags |= FX_USB_WORKITEM_RERUN; + + ASSERT(NULL == pThis->m_WorkItemRerunContext); + pThis->m_WorkItemRerunContext = Context; + } + else { + // + // No, it not running. + // + inprogress = FALSE; + + pThis->m_WorkItemFlags |= FX_USB_WORKITEM_IN_PROGRESS; + ASSERT((pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) == 0); + } + pPipe->Unlock(irql); + + if (inprogress) { + return; + } + + // + // OK, this thread is responsible for running the work item logic. + // + do { + // + // Cleanup and restart the repeters. + // + pThis->FxUsbPipeRequestWorkItemHandler(pFailedRepeater); + + // + // Check if callback needs to be re-run. + // + pPipe->Lock(&irql); + if (pThis->m_WorkItemFlags & FX_USB_WORKITEM_RERUN) { + // + // Yes, a new work item was requested while it was already running. + // + rerun = TRUE; + + pThis->m_WorkItemFlags &= ~FX_USB_WORKITEM_RERUN; + + ASSERT(pThis->m_WorkItemRerunContext != NULL); + pFailedRepeater = (FxUsbPipeRepeatReader*)pThis->m_WorkItemRerunContext; + pThis->m_WorkItemRerunContext = NULL; + + ASSERT(pThis == (FxUsbPipeContinuousReader*)pFailedRepeater->Parent); + } + else { + // + // No, all done. + // + rerun = FALSE; + + ASSERT(pThis->m_WorkItemFlags & FX_USB_WORKITEM_IN_PROGRESS); + pThis->m_WorkItemFlags &= ~FX_USB_WORKITEM_IN_PROGRESS; + + ASSERT(NULL == pThis->m_WorkItemRerunContext); + } + pPipe->Unlock(irql); + + } + while (rerun); +} + +PVOID +FxUsbPipeContinuousReader::operator new( + __in size_t Size, + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __range(1, NUM_PENDING_READS_MAX) ULONG NumReaders + ) +{ + ASSERT(NumReaders >= 1); + + return FxPoolAllocate( + FxDriverGlobals, + NonPagedPool, + Size + (NumReaders-1) * sizeof(FxUsbPipeRepeatReader) + ); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipeContinuousReader::FormatRepeater( + __in FxUsbPipeRepeatReader* Repeater + ) +{ + WDF_REQUEST_REUSE_PARAMS params; + FxRequestBuffer buf; + FxUsbPipeTransferContext* pContext; + FxMemoryObject* pMemory; + FxRequest* pRequest; + NTSTATUS status; + + pRequest = Repeater->Request; + // + // The repeater owns the request memory. If there is a memory on the + // context, delete it now. the memory will still be referencable since + // it will still have a reference against it until FormatTransferRequest is + // called or the request is freed and the context releases its references + // + DeleteMemory(pRequest); + + WDF_REQUEST_REUSE_PARAMS_INIT(¶ms, 0, STATUS_NOT_SUPPORTED); + + pRequest->Reuse(¶ms); + + // + // pMemory will be deleted when either + // a) The request completes + // or + // b) The continuous reader is destroyed and we delete the lookaside. since + // the lookaside is the parent object for pMemory, pMemory will be disposed + // of when the parent is Disposed + // + status = m_Lookaside->Allocate(&pMemory); + if (!NT_SUCCESS(status)) { + FxRequestContext* pContext; + + pContext = pRequest->GetContext(); + if (pContext != NULL ) { + pContext->m_RequestMemory = NULL; + } + + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(pMemory->GetBuffer(), pMemory->GetBufferSize()); + + buf.SetMemory(pMemory, &m_Offsets); + + status = m_Pipe->FormatTransferRequest( + pRequest, + &buf, + USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK + ); + + if (!NT_SUCCESS(status)) { + // + // In the case of failure, the context in the request will delete the + // memory. If there is no context, delete the memory here. + // + if (pRequest->GetContext() == NULL) { + // + // Use DeleteFromFailedCreate because the driver never saw the + // buffer, so they shouldn't be told about it going away. + // + pMemory->DeleteFromFailedCreate(); + } + + return status; + } + + pContext = (FxUsbPipeTransferContext*) pRequest->GetContext(); + pContext->SetUsbType(WdfUsbRequestTypePipeRead); + pContext->m_UsbParameters.Parameters.PipeRead.Buffer = (WDFMEMORY) + pMemory->GetObjectHandle(); + + pRequest->SetCompletionRoutine(_FxUsbPipeRequestComplete, Repeater); + return status; +} + + +VOID +FxUsbPipeContinuousReader::CancelRepeaters( + VOID + ) +{ + LONG i; + + Mx::MxEnterCriticalRegion(); + + for (i = 0; i < m_NumReaders; i++) { + m_Readers[i].Request->Cancel(); + m_Pipe->GetDriverGlobals()->WaitForSignal( + m_Readers[i].ReadCompletedEvent.GetSelfPointer(), + "waiting for continuous reader to finish, WDFUSBPIPE", + m_Pipe->GetHandle(), + m_Pipe->GetDriverGlobals()->FxVerifierDbgWaitForSignalTimeoutInSec, + WaitSignalBreakUnderVerifier); + + } + + Mx::MxLeaveCriticalRegion(); + // + // Checking for IO Count <= 1 is not a good idea here because there could be always other IO + // besides that from the continous reader going on the Read Pipe. + // +} + +FxUsbPipeTransferContext::FxUsbPipeTransferContext( + __in FX_URB_TYPE FxUrbType + ) : + FxUsbRequestContext(FX_RCT_USB_PIPE_XFER) +{ + m_UnlockPages = FALSE; + m_PartialMdl = NULL; + m_USBDHandle = NULL; + + if (FxUrbType == FxUrbTypeLegacy) { + m_Urb = &m_UrbLegacy; + } + else { + m_Urb = NULL; + } + +} + +FxUsbPipeTransferContext::~FxUsbPipeTransferContext( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)) { + USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); + } + m_Urb = NULL; + m_USBDHandle = NULL; +} + +__checkReturn +NTSTATUS +FxUsbPipeTransferContext::AllocateUrb( + __in USBD_HANDLE USBDHandle + ) +{ + NTSTATUS status; + + if (m_Urb) { + status = STATUS_INVALID_DEVICE_STATE; + goto Done; + } + + status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + m_USBDHandle = USBDHandle; + +Done: + return status; +} + +VOID +FxUsbPipeTransferContext::Dispose( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)){ + USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); + m_Urb = NULL; + m_USBDHandle = NULL; + } +} + +VOID +FxUsbPipeTransferContext::ReleaseAndRestore( + __in FxRequestBase* Request + ) +{ +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // Check now because Init will NULL out the field + // + if (m_PartialMdl != NULL) { + if (m_UnlockPages) { + MmUnlockPages(m_PartialMdl); + m_UnlockPages = FALSE; + } + + FxMdlFree(Request->GetDriverGlobals(), m_PartialMdl); + m_PartialMdl = NULL; + } +#endif + __super::ReleaseAndRestore(Request); +} + +VOID +FxUsbPipeTransferContext::CopyParameters( + __in FxRequestBase* Request + ) +{ + m_CompletionParams.IoStatus.Information = GetUrbTransferLength(); + + // + // If both are at the same offset, we don't have to compare type for + // Read or Write + // + WDFCASSERT(FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, + Parameters.PipeRead.Length) == + FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, + Parameters.PipeWrite.Length)); + + m_UsbParameters.Parameters.PipeRead.Length = GetUrbTransferLength(); + __super::CopyParameters(Request); +} + +VOID +FxUsbPipeTransferContext::SetUrbInfo( + __in USBD_PIPE_HANDLE PipeHandle, + __in ULONG TransferFlags + ) +{ + m_Urb->TransferFlags = TransferFlags; + m_Urb->PipeHandle = PipeHandle; +} + +USBD_STATUS +FxUsbPipeTransferContext::GetUsbdStatus( + VOID + ) +{ + return m_Urb->Hdr.Status; +} + +FxUsbUrbContext::FxUsbUrbContext( + VOID + ) : + FxUsbRequestContext(FX_RCT_USB_URB_REQUEST), + m_pUrb(NULL) +{ +} + +USBD_STATUS +FxUsbUrbContext::GetUsbdStatus( + VOID + ) +{ + return m_pUrb == NULL ? 0 : m_pUrb->UrbHeader.Status; +} + +VOID +FxUsbUrbContext::StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ) +{ + ULONG dummy; + + FxUsbRequestContext::StoreAndReferenceMemory(Buffer); + + // + // make sure it is framework managed memory or raw PVOID + // + ASSERT(Buffer->DataType == FxRequestBufferMemory || + Buffer->DataType == FxRequestBufferBuffer); + + Buffer->AssignValues((PVOID*) &m_pUrb, NULL, &dummy); +} + +VOID +FxUsbUrbContext::ReleaseAndRestore( + __in FxRequestBase* Request + ) +{ + m_pUrb = NULL; + __super::ReleaseAndRestore(Request); +} + + +FxUsbPipeRequestContext::FxUsbPipeRequestContext( + __in FX_URB_TYPE FxUrbType + ) : + FxUsbRequestContext(FX_RCT_USB_PIPE_REQUEST) +{ + m_USBDHandle = NULL; + + if (FxUrbType == FxUrbTypeLegacy) { + m_Urb = &m_UrbLegacy; + } + else { + m_Urb = NULL; + } +} + +FxUsbPipeRequestContext::~FxUsbPipeRequestContext( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)) { + USBD_UrbFree(m_USBDHandle, (PURB)m_Urb); + } + m_Urb = NULL; + m_USBDHandle = NULL; +} + +__checkReturn +NTSTATUS +FxUsbPipeRequestContext::AllocateUrb( + __in USBD_HANDLE USBDHandle + ) +{ + NTSTATUS status; + + if (m_Urb) { + status = STATUS_INVALID_DEVICE_STATE; + goto Done; + } + + status = USBD_UrbAllocate(USBDHandle, (PURB*)&m_Urb); + + if (!NT_SUCCESS(status)) { + goto Done; + } + + m_USBDHandle = USBDHandle; + +Done: + return status; +} + +VOID +FxUsbPipeRequestContext::Dispose( + VOID + ) +{ + if (m_Urb && (m_Urb != &m_UrbLegacy)){ + USBD_UrbFree(m_USBDHandle, (PURB) m_Urb); + m_Urb = NULL; + m_USBDHandle = NULL; + } +} + +VOID +FxUsbPipeRequestContext::SetInfo( + __in WDF_USB_REQUEST_TYPE Type, + __in USBD_PIPE_HANDLE PipeHandle, + __in USHORT Function + ) +{ + RtlZeroMemory(m_Urb, sizeof(*m_Urb)); + m_Urb->Hdr.Length = sizeof(*m_Urb); + m_Urb->Hdr.Function = Function; + m_Urb->PipeHandle = PipeHandle; + + SetUsbType(Type); +} + +USBD_STATUS +FxUsbPipeRequestContext::GetUsbdStatus( + VOID + ) +{ + return m_Urb->Hdr.Status; +} + +FxUsbPipe::FxUsbPipe( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxUsbDevice* UsbDevice + ) : + FxIoTarget(FxDriverGlobals, sizeof(FxUsbPipe), FX_TYPE_IO_TARGET_USB_PIPE), + m_UsbDevice(UsbDevice) +{ + InitializeListHead(&m_ListEntry); + RtlZeroMemory(&m_PipeInformation, sizeof(m_PipeInformation)); +#if (FX_CORE_MODE == FX_CORE_USER_MODE) + RtlZeroMemory(&m_PipeInformationUm, sizeof(m_PipeInformationUm)); +#endif + m_InterfaceNumber = 0; + m_Reader = NULL; + m_UsbInterface = NULL; + m_CheckPacketSize = TRUE; + m_USBDHandle = UsbDevice->m_USBDHandle; + m_UrbType = UsbDevice->m_UrbType; + + MarkNoDeleteDDI(ObjectDoNotLock); +} + +VOID +FxUsbPipe::InitPipe( + __in PUSBD_PIPE_INFORMATION PipeInfo, + __in UCHAR InterfaceNumber, + __in FxUsbInterface* UsbInterface + ) +{ + RtlCopyMemory(&m_PipeInformation, PipeInfo, sizeof(m_PipeInformation)); + m_InterfaceNumber = InterfaceNumber; + + if (m_UsbInterface != NULL) { + m_UsbInterface->RELEASE(this); + m_UsbInterface = NULL; + } + + m_UsbInterface = UsbInterface; + m_UsbInterface->ADDREF(this); +} + +FxUsbPipe::~FxUsbPipe() +{ + if (m_UsbInterface != NULL) { + m_UsbInterface->RemoveDeletedPipe(this); + m_UsbInterface->RELEASE(this); + } + + ASSERT(IsListEmpty(&m_ListEntry)); +} + +BOOLEAN +FxUsbPipe::Dispose() +{ + BOOLEAN callCleanup; + + // + // Call base class: callbacks, terminates I/Os, etc. + // + callCleanup = __super::Dispose(); + + // + // Don't need the reader anymore. The reader is deleted after calling the + // parent class Dispose() to preserve the existing deletion order (it was + // deleted in the Pipe's dtor() before this change). + // + if (m_Reader != NULL) + { + delete m_Reader; + + // + // By doing this assignment we prevent misbehaved drivers + // from crashing the system when they call WdfIoTargetStop from their + // usb pipe's destroy callback. + // + m_Reader = NULL; + } + + return callCleanup; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::GotoStartState( + __in PLIST_ENTRY RequestListHead, + __in BOOLEAN Lock + ) +{ + NTSTATUS status; + LONG i; + + if (m_Reader != NULL) { + if (m_Reader->m_ReadersSubmitted == FALSE) { + ASSERT(IsListEmpty(&m_SentIoListHead)); + + for (i = 0; i < m_Reader->m_NumReaders; i++) { + FxRequest* pRequest; + + pRequest = m_Reader->m_Readers[i].Request; + + UNREFERENCED_PARAMETER(pRequest); //for fre build + ASSERT(IsListEmpty(&pRequest->m_ListEntry)); + ASSERT(pRequest->m_DrainSingleEntry.Next == NULL); + } + } + } + + status = FxIoTarget::GotoStartState(RequestListHead, Lock); + + if (m_Reader == NULL || !NT_SUCCESS(status)) { + return status; + } + + // + // Add the repeater requests to the list head so that they are sent by the + // caller of this function when this function returns IFF they have not yet + // been queued. (They can be queued on a start -> start transition.) + // + if (m_Reader->m_ReadersSubmitted == FALSE) { + for (i = 0; i < m_Reader->m_NumReaders; i++) { + // + // This will clear ReadCompletedEvent as well + // + status = m_Reader->FormatRepeater(&m_Reader->m_Readers[i]); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + // + // Reset the number of failed readers in case we had failure in a + // previously started state. + // + m_Reader->m_NumFailedReaders = 0; + + for (i = 0; i < m_Reader->m_NumReaders; i++) { + FxRequest* pRequest; + + pRequest = m_Reader->m_Readers[i].Request; + pRequest->SetTarget(this); + pRequest->ADDREF(this); + + // + // NOTE: This is an elusive backdoor to send the Request down + // since it is inserted directly into the IoTargets pended list. + // The IoTarget is not started so we add the request to the + // pended list so that it is processed when the IoTarget starts. + // + m_Reader->m_Pipe->IncrementIoCount(); + InsertTailList(RequestListHead, &pRequest->m_ListEntry); + + // + // Clear the event only when we know it will be submitted to the + // target. It will be set when the request is submitted to the + // target and the submit fails or if it is cancelled. + // + m_Reader->m_Readers[i].ReadCompletedEvent.Clear(); + } + + m_Reader->m_ReadersSubmitted = TRUE; + } + + return status; +} + +VOID +FxUsbPipe::GotoStopState( + __in WDF_IO_TARGET_SENT_IO_ACTION Action, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ) +{ + KIRQL irql; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + irql = PASSIVE_LEVEL; + pFxDriverGlobals = GetDriverGlobals(); + + if (LockSelf) { + Lock(&irql); + } + + if (m_Reader != NULL) { + // + // If we are a continuous reader, always cancel the sent io so that we + // can resubmit it later on a restart. + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p converting stop action %!WDF_IO_TARGET_SENT_IO_ACTION!" + " to %!WDF_IO_TARGET_SENT_IO_ACTION!", GetHandle(), Action, + WdfIoTargetCancelSentIo); + + Action = WdfIoTargetCancelSentIo; + } + + __super::GotoStopState(Action, SentRequestListHead, Wait, FALSE); + + if (m_Reader != NULL) { + // + // The continuous reader requests are no longer enqueued. Remember that + // state, so when we restart, we resend them. + // + m_Reader->m_ReadersSubmitted = FALSE; + + // + // Log a message when misbehaved drivers call WdfIoTargetStop + // from EvtUsbTargetPipeReadersFailed callback. + // + if (m_Reader->m_WorkItemThread == Mx::MxGetCurrentThread()) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p is stopped from EvtUsbTargetPipeReadersFailed" + " callback", GetHandle()); + + if (pFxDriverGlobals->IsVerificationEnabled(1, 9, OkForDownLevel)) { + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + } + + // + // Do not deadlock when misbehaved drivers (< v1.9) call + // WdfIoTargetStop from EvtUsbTargetPipeReadersFailed callback. + // + if (m_Reader->m_WorkItemThread != Mx::MxGetCurrentThread() || + pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,9)) { + // + // Make sure work item is done. It is possible for the upper class + // to return wait = false if the list of sent requests is empty. We + // still want to wait anyway for making sure work item is not about + // to run or it is running. + // + *Wait = TRUE; + } + } + + if (LockSelf) { + Unlock(irql); + } +} + +VOID +FxUsbPipe::GotoPurgeState( + __in WDF_IO_TARGET_PURGE_IO_ACTION Action, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __out PBOOLEAN Wait, + __in BOOLEAN LockSelf + ) +{ + KIRQL irql; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + irql = PASSIVE_LEVEL; + pFxDriverGlobals = GetDriverGlobals(); + + if (LockSelf) { + Lock(&irql); + } + + if (m_Reader != NULL) { + // + // If we are a continuous reader, always wait for the sent io, so that we + // can resubmit it later on a restart. + // + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "WDFUSBPIPE %p converting purge action %!WDF_IO_TARGET_PURGE_IO_ACTION!" + " to %!WDF_IO_TARGET_PURGE_IO_ACTION!", GetHandle(), Action, + WdfIoTargetPurgeIoAndWait); + + Action = WdfIoTargetPurgeIoAndWait; + } + + __super::GotoPurgeState(Action, + PendedRequestListHead, + SentRequestListHead, + Wait, + FALSE); + + if (m_Reader != NULL) { + // + // The continuous reader requests are no longer enqueued. Remember that + // state, so when we restart, we resend them. + // + m_Reader->m_ReadersSubmitted = FALSE; + + // + // Log a message when misbehaved drivers call WdfIoTargetPurge + // from EvtUsbTargetPipeReadersFailed callback. + // + if (m_Reader->m_WorkItemThread == Mx::MxGetCurrentThread()) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p is purged from EvtUsbTargetPipeReadersFailed" + " callback", GetHandle()); + + FxVerifierDbgBreakPoint(pFxDriverGlobals); + } + + // + // Make sure work item is done. It is possible for the upper class + // to return wait = false if the list of sent requests is empty. We + // still want to wait anyway for making sure work item is not about + // to run or it is running. + // + *Wait = TRUE; + } + + if (LockSelf) { + Unlock(irql); + } +} + +VOID +FxUsbPipe::GotoRemoveState( + __in WDF_IO_TARGET_STATE NewState, + __in PLIST_ENTRY PendedRequestListHead, + __in PSINGLE_LIST_ENTRY SentRequestListHead, + __in BOOLEAN LockSelf, + __out PBOOLEAN Wait + ) +{ + KIRQL irql; + + irql = PASSIVE_LEVEL; + + if (LockSelf) { + Lock(&irql); + } + + if (m_Reader != NULL && m_Reader->m_ReadersSubmitted && + WdfIoTargetStarted == m_State) { + // + // Driver forgot to stop the pipe on D0Exit. + // + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p was not stopped in EvtDeviceD0Exit callback", + GetHandle()); + + if (GetDriverGlobals()->IsVerificationEnabled(1,9,OkForDownLevel)) { + FxVerifierDbgBreakPoint(GetDriverGlobals()); + } + } + + __super::GotoRemoveState(NewState, + PendedRequestListHead, + SentRequestListHead, + FALSE, + Wait); + if (m_Reader != NULL) { + // + // Make sure work item is done. It is possible for the upper class to + // return wait = false if the list of sent requests is empty. We still + // want to wait anyway for making sure work item is not about to run or + // it is running. + // + *Wait = TRUE; + } + + if (LockSelf) { + Unlock(irql); + } +} + +VOID +FxUsbPipe::WaitForSentIoToComplete( + VOID + ) +{ + if (m_Reader != NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, waiting for continuous reader work item to complete", + GetHandle()); + + // + // First, wait for the work item to complete if it is running. + // + // NOTE: We don't wait for the DPC to complete because + // they are flushed in FxUsbDevice::Dispose + // + m_Reader->m_WorkItem->WaitForExit(); + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, cancelling for continuous reader (max of %d)", + GetHandle(), m_Reader->m_NumReaders); + + // + // Now that the work item is not running, make sure all the readers are + // truly canceled and *NOT* in the pended queue. In between the call to + // GotoStopState and here, the work item could have run and retried to + // send the I/O. + // + m_Reader->CancelRepeaters(); + } + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, waiting for all i/o to complete", GetHandle()); + + // + // Finally, let the parent class wait for all I/O to complete + // + __super::WaitForSentIoToComplete(); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::InitContinuousReader( + __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, + __in size_t TotalBufferLength + ) +{ + FxUsbPipeContinuousReader* pReader; + NTSTATUS status; + UCHAR numReaders; + + pReader = NULL; + + if (m_Reader != NULL) { + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Continuous reader already initialized on WDFUSBPIPE %p %!STATUS!", + GetHandle(), status); + + return status; + } + + numReaders = Config->NumPendingReads; + + if (numReaders == 0) { + numReaders = NUM_PENDING_READS_DEFAULT; + } + else if (numReaders > NUM_PENDING_READS_MAX) { + numReaders = NUM_PENDING_READS_MAX; + } + + pReader = new(GetDriverGlobals(), numReaders) + FxUsbPipeContinuousReader(this, numReaders); + + if (pReader == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + // + // Allocate all of the structurs and objects required + // + status = pReader->Config(Config, TotalBufferLength); + + if (!NT_SUCCESS(status)) { + delete pReader; + return status; + } + + pReader->m_ReadCompleteCallback = Config->EvtUsbTargetPipeReadComplete; + pReader->m_ReadCompleteContext = Config->EvtUsbTargetPipeReadCompleteContext; + + pReader->m_ReadersFailedCallback = Config->EvtUsbTargetPipeReadersFailed; + + if (InterlockedCompareExchangePointer((PVOID*) &m_Reader, + pReader, + NULL) == NULL) { + // + // We set the field, do nothing. + // + DO_NOTHING(); + } + else { + // + // Some other thread came in and set the field, free our allocation. + // + delete pReader; + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::_FormatTransfer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFUSBPIPE Pipe, + __in WDFREQUEST Request, + __in_opt WDFMEMORY TransferMemory, + __in_opt PWDFMEMORY_OFFSET TransferOffsets, + __in ULONG Flags + ) +{ + FxRequestBuffer buf; + IFxMemory* pMemory; + FxUsbPipe* pUsbPipe; + FxRequest* pRequest; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &FxDriverGlobals); + + FxObjectHandleGetPtr(FxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + // + // We allow zero length transfers (which are indicated by TransferMemory == NULL) + // + if (TransferMemory != NULL) { + FxObjectHandleGetPtr(FxDriverGlobals, + TransferMemory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + status = pMemory->ValidateMemoryOffsets(TransferOffsets); + if (!NT_SUCCESS(status)) { + goto Done; + } + + buf.SetMemory(pMemory, TransferOffsets); + } + else { + pMemory = NULL; + } + + status = pUsbPipe->FormatTransferRequest(pRequest, &buf, Flags); + + if (NT_SUCCESS(status)) { + FxUsbPipeTransferContext* pContext; + + pContext = (FxUsbPipeTransferContext*) pRequest->GetContext(); + + // + // By assuming the fields are at the same offset, we can use simpler + // logic (w/out comparisons for type) to set them. + // + WDFCASSERT( + FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Buffer) == + FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Buffer) + ); + + WDFCASSERT( + FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeWrite.Offset) == + FIELD_OFFSET(WDF_USB_REQUEST_COMPLETION_PARAMS, Parameters.PipeRead.Offset) + ); + + pContext->m_UsbParameters.Parameters.PipeWrite.Buffer = TransferMemory; + pContext->m_UsbParameters.Parameters.PipeWrite.Length = buf.GetBufferLength(); + + pContext->m_UsbParameters.Parameters.PipeWrite.Offset = + (TransferOffsets != NULL) ? TransferOffsets->BufferOffset + : 0; + pContext->SetUsbType( + (Flags & USBD_TRANSFER_DIRECTION_IN) ? WdfUsbRequestTypePipeRead + : WdfUsbRequestTypePipeWrite + ); + } + +Done: + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p, WDFMEMORY %p, %!STATUS!", + Pipe, Request, TransferMemory, status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::_SendTransfer( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in WDFUSBPIPE Pipe, + __in_opt WDFREQUEST Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in_opt PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + __out_opt PULONG BytesTransferred, + __in ULONG Flags + ) +{ + FxRequestBuffer buf; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(FxDriverGlobals, + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &FxDriverGlobals); + + FxUsbPipeTransferContext context(FxUrbTypeLegacy); + + FxSyncRequest request(FxDriverGlobals, &context, Request); + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + if (BytesTransferred != NULL) { + *BytesTransferred = 0; + } + + status = FxVerifierCheckIrqlLevel(FxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(FxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // We allow zero length writes (which are indicated by MemoryDescriptor == NULL) + // + if (MemoryDescriptor != NULL) { + status = buf.ValidateMemoryDescriptor(FxDriverGlobals, MemoryDescriptor); + if (!NT_SUCCESS(status)) { + return status; + } + } + + status = pUsbPipe->FormatTransferRequest(request.m_TrueRequest, &buf, Flags); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p being submitted", + Pipe, request.m_TrueRequest->GetTraceObjectHandle()); + + status = pUsbPipe->SubmitSync(request.m_TrueRequest, RequestOptions); + + // + // Even on error we want to set this value. USBD should be clearing + // it if the transfer fails. + // + if (BytesTransferred != NULL) { + *BytesTransferred = context.GetUrbTransferLength(); + } + } + + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, %!STATUS!", Pipe, status); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::FormatAbortRequest( + __in FxRequestBase* Request + ) +{ + FxUsbPipeRequestContext* pContext; + NTSTATUS status; + FX_URB_TYPE urbType; + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, Request %p, setting target failed, " + "status %!STATUS!", this, Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_PIPE_REQUEST)) { + pContext = (FxUsbPipeRequestContext*) Request->GetContext(); + } + else { + + urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); + pContext = new(GetDriverGlobals()) FxUsbPipeRequestContext(urbType); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (urbType == FxUrbTypeUsbdAllocated) { + status = pContext->AllocateUrb(m_USBDHandle); + if (!NT_SUCCESS(status)) { + delete pContext; + return status; + } + // + // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is + // important to release those resorces before the devnode is removed. Those + // resoruces are removed at the time Request is disposed. + // + Request->EnableContextDisposeNotification(); + } +#endif + + Request->SetContext(pContext); + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + pContext->SetInfo(WdfUsbRequestTypePipeAbort, + m_PipeInformation.PipeHandle, + URB_FUNCTION_ABORT_PIPE); + + if (pContext->m_Urb == &pContext->m_UrbLegacy) { + urbType = FxUrbTypeLegacy; + } + else { + urbType = FxUrbTypeUsbdAllocated; + } + + FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + pContext->SetInfo(WdfUsbRequestTypePipeAbort, + m_UsbInterface->m_WinUsbHandle, + m_PipeInformationUm.PipeId, + UMURB_FUNCTION_ABORT_PIPE); + FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbPipeRequest.Hdr, m_UsbDevice->m_pHostTargetFile); +#endif + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::FormatResetRequest( + __in FxRequestBase* Request + ) +{ + FxUsbPipeRequestContext* pContext; + NTSTATUS status; + FX_URB_TYPE urbType; + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, Request %p, setting target failed, " + "status %!STATUS!", this, Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_PIPE_REQUEST)) { + pContext = (FxUsbPipeRequestContext*) Request->GetContext(); + } + else { + urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); + pContext = new(GetDriverGlobals()) FxUsbPipeRequestContext(urbType); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (urbType == FxUrbTypeUsbdAllocated) { + status = pContext->AllocateUrb(m_USBDHandle); + if (!NT_SUCCESS(status)) { + delete pContext; + return status; + } + // + // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is + // important to release those resorces before the devnode is removed. Those + // resoruces are removed at the time Request is disposed. + // + Request->EnableContextDisposeNotification(); + } +#endif + + Request->SetContext(pContext); + } + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + // + // URB_FUNCTION_RESET_PIPE and URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL + // are the same value + // + pContext->SetInfo(WdfUsbRequestTypePipeReset, + m_PipeInformation.PipeHandle, + URB_FUNCTION_RESET_PIPE); + + if (pContext->m_Urb == &pContext->m_UrbLegacy) { + urbType = FxUrbTypeLegacy; + } + else { + urbType = FxUrbTypeUsbdAllocated; + } + + FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + pContext->SetInfo(WdfUsbRequestTypePipeReset, + m_UsbInterface->m_WinUsbHandle, + m_PipeInformationUm.PipeId, + UMURB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL); + FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbPipeRequest.Hdr, m_UsbDevice->m_pHostTargetFile); +#endif + + return STATUS_SUCCESS; +} + +NTSTATUS +FxUsbPipe::Reset( + VOID + ) +{ + FxUsbPipeRequestContext context(FxUrbTypeLegacy); + + FxSyncRequest request(GetDriverGlobals(), &context); + NTSTATUS status; + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + status = FormatResetRequest(request.m_TrueRequest); + if (NT_SUCCESS(status)) { + if (m_Reader != NULL) { + // + // This assumes that no other I/O besides reader I/O is going on. + // + m_Reader->CancelRepeaters(); + } + else { + CancelSentIo(); + } + status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); + } + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpipeapi.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpipeapi.cpp new file mode 100644 index 00000000000..474db7a289f --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/fxusbpipeapi.cpp @@ -0,0 +1,862 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbPipeAPI.cpp + +Abstract: + + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbPipeAPI.tmh" +} + +// +// extern "C" the whole file since we are exporting the APIs by name +// +extern "C" { + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfUsbTargetPipeGetInformation)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __out + PWDF_USB_PIPE_INFORMATION PipeInformation + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbPipe* pUsbPipe; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, PipeInformation); + + pUsbPipe->GetInformation(PipeInformation); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFAPI +WDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe + ) +{ + DDI_ENTRY(); + + FxUsbPipe* pUsbPipe; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe); + + return pUsbPipe->IsInEndpoint(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +BOOLEAN +WDFAPI +WDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe + ) +{ + DDI_ENTRY(); + + FxUsbPipe* pUsbPipe; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe); + + return pUsbPipe->IsOutEndpoint(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +WDF_USB_PIPE_TYPE +WDFAPI +WDFEXPORT(WdfUsbTargetPipeGetType)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe + ) +{ + DDI_ENTRY(); + + FxUsbPipe* pUsbPipe; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe); + + return pUsbPipe->GetType(); +} + +__drv_maxIRQL(DISPATCH_LEVEL) +VOID +WDFAPI +WDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbPipe* pUsbPipe; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p", Pipe); + + pUsbPipe->SetNoCheckPacketSize(); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in_opt + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + __out_opt + PULONG BytesWritten + ) +{ + DDI_ENTRY(); + + DoTraceLevelMessage( + GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p", Pipe); + + return FxUsbPipe::_SendTransfer(GetFxDriverGlobals(DriverGlobals), + Pipe, + Request, + RequestOptions, + MemoryDescriptor, + BytesWritten, + 0); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in + WDFREQUEST Request, + __in_opt + WDFMEMORY WriteMemory, + __in_opt + PWDFMEMORY_OFFSET WriteOffsets + ) +{ + DDI_ENTRY(); + + DoTraceLevelMessage(GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p, WDFMEMORY %p", + Pipe, Request, WriteMemory); + + return FxUsbPipe::_FormatTransfer(GetFxDriverGlobals(DriverGlobals), + Pipe, + Request, + WriteMemory, + WriteOffsets, + 0); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in_opt + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + __out_opt + PULONG BytesRead + ) +{ + DDI_ENTRY(); + + DoTraceLevelMessage(GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p", Pipe); + + return FxUsbPipe::_SendTransfer( + GetFxDriverGlobals(DriverGlobals), + Pipe, + Request, + RequestOptions, + MemoryDescriptor, + BytesRead, + USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK + ); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in + WDFREQUEST Request, + __in_opt + WDFMEMORY ReadMemory, + __in_opt + PWDFMEMORY_OFFSET ReadOffsets + ) +{ + DDI_ENTRY(); + + DoTraceLevelMessage( + GetFxDriverGlobals(DriverGlobals), TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p, WDFMEMORY %p", + Pipe, Request, ReadMemory); + + return FxUsbPipe::_FormatTransfer( + GetFxDriverGlobals(DriverGlobals), + Pipe, + Request, + ReadMemory, + ReadOffsets, + USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK + ); +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + size_t total; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, Config); + + if (Config->Size != sizeof(WDF_USB_CONTINUOUS_READER_CONFIG)) { + status = STATUS_INFO_LENGTH_MISMATCH; + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Config %p incorrect size %d, expected %d %!STATUS!", + Config, Config->Size, sizeof(WDF_USB_CONTINUOUS_READER_CONFIG), + status); + + return status; + } + + if (Config->EvtUsbTargetPipeReadComplete == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "NULL EvtUsbTargetPipeReadComplete not allowed %!STATUS!", status); + return status; + } + + if (Config->TransferLength == 0) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "TransferLength of 0 not allowed %!STATUS!", status); + return status; + } + + status = RtlSizeTAdd(Config->HeaderLength, + Config->TransferLength, + &total); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "HeaderLength + TransferLength overflow %!STATUS!", status); + return status; + } + + status = RtlSizeTAdd(total, + Config->TrailerLength, + &total); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "HeaderLength + TransferLength + TrailerLength overflow %!STATUS!", + status); + return status; + } + + // + // Internally WDF will assign a parent to the memory, so do not allow the driver + // to do so. + // + status = FxValidateObjectAttributes(pFxDriverGlobals, + Config->BufferAttributes, + FX_VALIDATE_OPTION_PARENT_NOT_ALLOWED); + if (!NT_SUCCESS(status)) { + return status; + } + + // + // Only bulk or interrrupt is allowed for a continous reader + // + if ((pUsbPipe->IsType(WdfUsbPipeTypeBulk) || + pUsbPipe->IsType(WdfUsbPipeTypeInterrupt)) == FALSE) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p type %!WDF_USB_PIPE_TYPE!, only bulk or interrupt " + "pipes can be configured for continous readers, %!STATUS!", + Pipe, pUsbPipe->GetType(), status); + + return status; + } + + if (pUsbPipe->IsOutEndpoint()) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p, wrong direction for continuous reader, %!STATUS!", + Pipe, status); + + return status; + } + + status = pUsbPipe->ValidateTransferLength(Config->TransferLength); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "TransferLength %I64d not a valid transer length (not integral of max " + "packet size %d) %!STATUS!", Config->TransferLength, + pUsbPipe->GetMaxPacketSize(), status); + return status; + } + + status = pUsbPipe->InitContinuousReader(Config, total); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + FxUsbPipeRequestContext context(FxUrbTypeLegacy); + + FxSyncRequest request(pFxDriverGlobals, &context, Request); + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p", Pipe); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Invalid request options"); + return status; + } + + status = pUsbPipe->FormatAbortRequest(request.m_TrueRequest); + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p being submitted", + Pipe, request.m_TrueRequest->GetTraceObjectHandle()); + + status = pUsbPipe->SubmitSync(request.m_TrueRequest, RequestOptions); + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, %!STATUS!", Pipe, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in + WDFREQUEST Request + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p, Request %p", Pipe, Request); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pUsbPipe->FormatAbortRequest(pRequest); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p, Request %p, status %!STATUS!", + Pipe, Request, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + FxUsbPipeRequestContext context(FxUrbTypeLegacy); + + FxSyncRequest request(pFxDriverGlobals, &context, Request); + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p reset", Pipe); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Invalid request options"); + return status; + } + + status = pUsbPipe->FormatResetRequest(request.m_TrueRequest); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p being submitted", + Pipe, request.m_TrueRequest->GetTraceObjectHandle()); + + pUsbPipe->CancelSentIo(); + + // + // Even if the previous state of the target was stopped let this IO go through by + // ignoring target state. + // + status = pUsbPipe->SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, RequestOptions); + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p reset, %!STATUS!", Pipe, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in + WDFREQUEST Request + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequest* pRequest; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p, Request %p", Pipe, Request); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pUsbPipe->FormatResetRequest(pRequest); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p, Request %p = 0x%x", + Pipe, Request, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeSendUrbSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in_xcount("union bug in SAL") + PURB Urb + ) +{ + DDI_ENTRY(); + + FxRequestBuffer buf; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbPipe* pUsbPipe; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + FxUsbUrbContext context; + FxSyncRequest request(pFxDriverGlobals, &context, Request); + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, Urb %p", Pipe, Urb); + + FxPointerNotNull(pFxDriverGlobals, Urb); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + return status; + } + + buf.SetBuffer(Urb, 0); + + status = FxFormatUrbRequest(pFxDriverGlobals, + pUsbPipe, + request.m_TrueRequest, + &buf, + pUsbPipe->GetUrbType(), + pUsbPipe->GetUSBDHandle()); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, WDFREQUEST %p being submitted", + Pipe, request.m_TrueRequest->GetTraceObjectHandle()); + + status = pUsbPipe->SubmitSync(request.m_TrueRequest, RequestOptions); + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBPIPE %p, Urb %p, %!STATUS!", + Pipe, Urb, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetPipeFormatRequestForUrb)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE Pipe, + __in + WDFREQUEST Request, + __in + WDFMEMORY UrbMemory, + __in_opt + PWDFMEMORY_OFFSET UrbOffsets + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxMemory* pMemory; + FxUsbPipe* pUsbPipe; + FxRequest* pRequest; + FxRequestBuffer buf; + NTSTATUS status; + size_t bufferSize; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + Pipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p, Request %p, Memory %p", + Pipe, Request, UrbMemory); + + FxObjectHandleGetPtr(pFxDriverGlobals, + UrbMemory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pMemory->ValidateMemoryOffsets(UrbOffsets); + if (!NT_SUCCESS(status)) { + return status; + } + + bufferSize = pMemory->GetBufferSize(); + if (UrbOffsets != NULL && UrbOffsets->BufferOffset > 0) { + bufferSize -= UrbOffsets->BufferOffset; + } + + if (bufferSize < sizeof(_URB_HEADER)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "UrbMemory %p buffer size, %I64d, smaller then " + "_URB_HEADER, %!STATUS!", UrbMemory, + pMemory->GetBufferSize(), status); + return status; + } + + buf.SetMemory(pMemory, UrbOffsets); + + status = FxFormatUrbRequest(pFxDriverGlobals, + pUsbPipe, + pRequest, + &buf, + pUsbPipe->GetUrbType(), + pUsbPipe->GetUSBDHandle()); + + if (NT_SUCCESS(status)) { + FxUsbUrbContext* pContext; + pContext = (FxUsbUrbContext*) pRequest->GetContext(); + + pContext->SetUsbType(WdfUsbRequestTypePipeUrb); + pContext->m_UsbParameters.Parameters.PipeUrb.Buffer = UrbMemory; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Pipe %p, Request %p, Memory %p, status %!STATUS!", + Pipe, Request, UrbMemory, status); + + return status; +} + +__drv_maxIRQL(DISPATCH_LEVEL) +USBD_PIPE_HANDLE +WDFAPI +WDFEXPORT(WdfUsbTargetPipeWdmGetPipeHandle)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBPIPE UsbPipe + ) +/*++ + +Routine Description: + Returns the underlying WDM USBD pipe handle + +Arguments: + UsbPipe - the WDF pipe whose WDM handle will be returned + +Return Value: + valid handle value or NULL on error + + --*/ +{ + DDI_ENTRY(); + + FxUsbPipe* pUsbPipe; + + FxObjectHandleGetPtr(GetFxDriverGlobals(DriverGlobals), + UsbPipe, + FX_TYPE_IO_TARGET_USB_PIPE, + (PVOID*) &pUsbPipe); + + return pUsbPipe->WdmGetPipeHandle(); +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbdeviceapikm.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbdeviceapikm.cpp new file mode 100644 index 00000000000..39d8055e5a8 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbdeviceapikm.cpp @@ -0,0 +1,445 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbDeviceAPI.cpp + +Abstract: + + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbDeviceApiKm.tmh" +} + +// +// Extern "C" all APIs +// +extern "C" { + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceRetrieveCurrentFrameNumber)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __out + PULONG CurrentFrameNumber + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxPointerNotNull(pFxDriverGlobals, CurrentFrameNumber); + + return pUsbDevice->GetCurrentFrameNumber(CurrentFrameNumber); +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceSendUrbSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + WDFREQUEST Request, + __in_opt + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + __in_xcount("union bug in SAL") + PURB Urb + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxRequestBuffer buf; + NTSTATUS status; + FxUsbDevice* pUsbDevice; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxUsbUrbContext context; + FxSyncRequest request(pFxDriverGlobals, &context, Request); + + // + // FxSyncRequest always succeesds for KM but can fail for UM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Urb %p", UsbDevice, Urb); + + FxPointerNotNull(pFxDriverGlobals, Urb); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxValidateRequestOptions(pFxDriverGlobals, RequestOptions); + if (!NT_SUCCESS(status)) { + return status; + } + + buf.SetBuffer(Urb, 0); + + status = FxFormatUrbRequest(pFxDriverGlobals, + pUsbDevice, + request.m_TrueRequest, + &buf, + pUsbDevice->GetUrbType(), + pUsbDevice->GetUSBDHandle()); + + if (NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, WDFREQUEST %p being submitted", + UsbDevice, request.m_TrueRequest->GetTraceObjectHandle()); + + status = pUsbDevice->SubmitSync(request.m_TrueRequest, RequestOptions); + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "Device %p, Urb %p, %!STATUS!", + UsbDevice, Urb, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForUrb)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in + WDFREQUEST Request, + __in + WDFMEMORY UrbMemory, + __in_opt + PWDFMEMORY_OFFSET UrbOffsets + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + IFxMemory* pMemory; + FxUsbDevice* pUsbDevice; + FxRequestBuffer buf; + FxRequest* pRequest; + NTSTATUS status; + size_t bufferSize; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Request %p, Memory %p", + UsbDevice, Request, UrbMemory); + + FxPointerNotNull(pFxDriverGlobals, UrbMemory); + + FxObjectHandleGetPtr(pFxDriverGlobals, + UrbMemory, + IFX_TYPE_MEMORY, + (PVOID*) &pMemory); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pMemory->ValidateMemoryOffsets(UrbOffsets); + if (!NT_SUCCESS(status)) { + return status; + } + + bufferSize = pMemory->GetBufferSize(); + if (UrbOffsets != NULL && UrbOffsets->BufferOffset > 0) { + bufferSize -= UrbOffsets->BufferOffset; + } + + if (bufferSize < sizeof(_URB_HEADER)) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "UrbMemory %p buffer size, %I64d, smaller then" + "_URB_HEADER, %!STATUS!", + UrbMemory, pMemory->GetBufferSize(), status); + return status; + } + + buf.SetMemory(pMemory, UrbOffsets); + + status = FxFormatUrbRequest(pFxDriverGlobals, + pUsbDevice, + pRequest, + &buf, + pUsbDevice->GetUrbType(), + pUsbDevice->GetUSBDHandle()); + + if (NT_SUCCESS(status)) { + FxUsbUrbContext* pContext; + pContext = (FxUsbUrbContext*) pRequest->GetContext(); + + pContext->SetUsbType(WdfUsbRequestTypeDeviceUrb); + pContext->m_UsbParameters.Parameters.DeviceUrb.Buffer = UrbMemory; + } + + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Request %p, Memory %p, %!STATUS!", + UsbDevice, Request, UrbMemory, status); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceIsConnectedSynchronous)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice + ) +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pUsbDevice->IsConnected(); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(PASSIVE_LEVEL) +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCyclePortSynchronously)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice + ) +/*++ + +Routine Description: + Synchronously cycles a device on a USB port. This will cause the device + to be surprise removed and reenumerated. Very similar to the reenumerate + interface we use in the pnp state machine. Usually a driver will do this + after it has downloaded firmware and wants to be reenumerated as a new + device. + + + + +Arguments: + UsbDevice - the IOTARGET representing the device + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + status = FxVerifierCheckIrqlLevel(pFxDriverGlobals, PASSIVE_LEVEL); + if (!NT_SUCCESS(status)) { + return status; + } + + status = pUsbDevice->CyclePort(); + + return status; +} + +_Must_inspect_result_ +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForCyclePort)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in + WDFREQUEST Request + ) +/*++ + +Routine Description: + Formats a WDFREQUEST so that it will cycle the port and reenumerate the + device when sent. + +Arguments: + UsbDevice - the IOTARGET representing the device that will be reenumerated + + Request - the request which will be formatted + +Return Value: + NTSTATUS + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + FxRequest* pRequest; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + FxObjectHandleGetPtr(pFxDriverGlobals, + Request, + FX_TYPE_REQUEST, + (PVOID*) &pRequest); + + status = pUsbDevice->FormatCycleRequest(pRequest); + + return status; +} + +__checkReturn +__drv_maxIRQL(DISPATCH_LEVEL) +NTSTATUS +WDFAPI +WDFEXPORT(WdfUsbTargetDeviceCreateUrb)( + __in + PWDF_DRIVER_GLOBALS DriverGlobals, + __in + WDFUSBDEVICE UsbDevice, + __in_opt + PWDF_OBJECT_ATTRIBUTES Attributes, + __out + WDFMEMORY* UrbMemory, + __deref_opt_out_bcount(sizeof(URB)) + PURB* Urb + ) +/*++ + +Routine Description: + Creates a WDFUSBDEVICE handle for the client. + +Arguments: + Attributes - Attributes associated with this object + + UrbMemory - The returned handle to the caller for the allocated Urb + + Urb - (opt) Pointer to the associated urb buffer. + +Return Value: + STATUS_INVALID_PARAMETER - any required parameters are not present/invalid + + STATUS_INVALID_DEVICE_STATE - If the client did not specify a client contract verion while + creating the WDFUSBDEVICE + + STATUS_INSUFFICIENT_RESOURCES - could not allocated the object that backs + the handle + + STATUS_SUCCESS - success + + ... + + --*/ +{ + DDI_ENTRY(); + + PFX_DRIVER_GLOBALS pFxDriverGlobals; + FxUsbDevice* pUsbDevice; + NTSTATUS status; + + FxObjectHandleGetPtrAndGlobals(GetFxDriverGlobals(DriverGlobals), + UsbDevice, + FX_TYPE_IO_TARGET_USB_DEVICE, + (PVOID*) &pUsbDevice, + &pFxDriverGlobals); + + // + // Basic parameter validation + // + FxPointerNotNull(pFxDriverGlobals, UrbMemory); + + if (pUsbDevice->GetUSBDHandle() == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USBDEVICE Must have been created with Client Contract Verion Info, %!STATUS!", + status); + + return status; + } + + status = pUsbDevice->CreateUrb(Attributes, UrbMemory, Urb); + + return status; +} + +} // extern "C" diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbdevicekm.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbdevicekm.cpp new file mode 100644 index 00000000000..1fa99641b45 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbdevicekm.cpp @@ -0,0 +1,1107 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbDeviceKm.cpp + +Abstract: + +Author: + +Environment: + + kernel mode only + +Revision History: + +--*/ + +extern "C" { +#include +} + +#include "fxusbpch.hpp" + + +extern "C" { +#include "FxUsbDeviceKm.tmh" +} + + + + + + + +#define UCHAR_MAX (0xff) + + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::InitDevice( + __in ULONG USBDClientContractVersionForWdfClient + ) +{ + URB urb; + FxSyncRequest request(GetDriverGlobals(), NULL); + WDF_REQUEST_SEND_OPTIONS options; + NTSTATUS status; + ULONG size; + + RtlZeroMemory(&urb, sizeof(urb)); + + if (USBDClientContractVersionForWdfClient != USBD_CLIENT_CONTRACT_VERSION_INVALID) { + + // + // Register with USBDEX.lib + // + status = USBD_CreateHandle(m_InStackDevice, + m_TargetDevice, + USBDClientContractVersionForWdfClient, + GetDriverGlobals()->Tag, + &m_USBDHandle); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USBD_CreateHandle failed, %!STATUS!", status); + goto Done; + } + + m_UrbType = FxUrbTypeUsbdAllocated; + } + + status = request.m_TrueRequest->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + goto Done; + } + + UsbBuildGetDescriptorRequest(&urb, + sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST), + USB_DEVICE_DESCRIPTOR_TYPE, + 0, + 0, + &m_DeviceDescriptor, + NULL, + sizeof(m_DeviceDescriptor), + NULL); + + FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); + + WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(5)); + + status = SubmitSync(request.m_TrueRequest, &options); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve device descriptor, %!STATUS!", status); + goto Done; + } + + // + // After successfully completing any default control URB, USBD/usbport fills + // in the PipeHandle field of the URB (it is the same offset in every URB, + // which this CASSERT verifies. Since USBD_DEFAULT_PIPE_TRANSFER is not + // supported by USBD (it is by USBPORT), this is the prescribed way of getting + // the default control pipe so that you can set the PipeHandle field in + // _URB_CONTROL_TRANSFER. + // + WDFCASSERT(FIELD_OFFSET(_URB_CONTROL_TRANSFER, PipeHandle) == + FIELD_OFFSET(_URB_CONTROL_DESCRIPTOR_REQUEST, Reserved)); + + m_ControlPipe = urb.UrbControlDescriptorRequest.Reserved; + + USB_CONFIGURATION_DESCRIPTOR config; + + RtlZeroMemory(&config, sizeof(config)); + size = sizeof(config); + + UsbBuildGetDescriptorRequest(&urb, + sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), + USB_CONFIGURATION_DESCRIPTOR_TYPE, + 0, + 0, + &config, + NULL, + size, + NULL); + + request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); + request.m_TrueRequest->ClearFieldsForReuse(); + FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); + + status = SubmitSync(request.m_TrueRequest, &options); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve config descriptor size, %!STATUS!", status); + goto Done; + } + else if (urb.UrbControlDescriptorRequest.TransferBufferLength == 0) { + // + // Not enough info returned + // + status = STATUS_UNSUCCESSFUL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve config descriptor size, zero bytes transferred, " + " %!STATUS!", status); + + goto Done; + } + else if (config.wTotalLength < size) { + // + // Not enough info returned + // + status = STATUS_UNSUCCESSFUL; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve config descriptor size, config.wTotalLength %d < " + "sizeof(config descriptor) (%d), %!STATUS!", + config.wTotalLength, size, status); + + goto Done; + } + + // + // Allocate an additional memory at the end of the buffer so if we + // accidentily access fields beyond the end of the buffer we don't crash + + // + + + + + + size = config.wTotalLength; + ULONG paddedSize = size + sizeof(USB_DEVICE_DESCRIPTOR); + + m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) + FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + paddedSize); + + if (m_ConfigDescriptor == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate %d bytes for config descriptor, %!STATUS!", + paddedSize, status); + + goto Done; + } + + RtlZeroMemory(m_ConfigDescriptor, paddedSize); + + UsbBuildGetDescriptorRequest(&urb, + sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), + USB_CONFIGURATION_DESCRIPTOR_TYPE, + 0, + 0, + m_ConfigDescriptor, + NULL, + size, + NULL); + + request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); + request.m_TrueRequest->ClearFieldsForReuse(); + FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); + + status = SubmitSync(request.m_TrueRequest, &options); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve config descriptor, %!STATUS!", status); + goto Done; + } else if(m_ConfigDescriptor->wTotalLength != size) { + // + // Invalid wTotalLength + // + status = STATUS_DEVICE_DATA_ERROR; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Defective USB device reported two different config descriptor " + "wTotalLength values: %d and %d, %!STATUS!", + size, m_ConfigDescriptor->wTotalLength, status); + goto Done; + } + + // + // Check to see if we are wait wake capable + // + if (m_ConfigDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { + m_Traits |= WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + } + + // + // Check to see if we are self or bus powered + // + USHORT deviceStatus; + + UsbBuildGetStatusRequest(&urb, + URB_FUNCTION_GET_STATUS_FROM_DEVICE, + 0, + &deviceStatus, + NULL, + NULL); + + request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); + request.m_TrueRequest->ClearFieldsForReuse(); + FxFormatUsbRequest(request.m_TrueRequest, &urb, FxUrbTypeLegacy, NULL); + + status = SubmitSync(request.m_TrueRequest, &options); + if (NT_SUCCESS(status) && (deviceStatus & USB_GETSTATUS_SELF_POWERED)) { + m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED; + } + + // + // Revert back to success b/c we don't care if the usb device get status + // fails + // + status = STATUS_SUCCESS; + + USB_BUS_INTERFACE_USBDI_V1 busIf; + + RtlZeroMemory(&busIf, sizeof(busIf)); + + // + // All PNP irps must have this initial status + // + request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED); + request.m_TrueRequest->ClearFieldsForReuse(); + + FxQueryInterface::_FormatIrp( + request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(), + &USB_BUS_INTERFACE_USBDI_GUID, + (PINTERFACE) &busIf, + sizeof(busIf), + USB_BUSIF_USBDI_VERSION_1); + + request.m_TrueRequest->VerifierSetFormatted(); + + status = SubmitSync(request.m_TrueRequest); + + if (!NT_SUCCESS(status)) { + // + // Retry with the older interface + // + RtlZeroMemory(&busIf, sizeof(busIf)); + + // + // All PNP irps must have this initial status + // + + request.m_TrueRequest->GetSubmitFxIrp()->Reuse(STATUS_NOT_SUPPORTED); + request.m_TrueRequest->ClearFieldsForReuse(); + + FxQueryInterface::_FormatIrp( + request.m_TrueRequest->GetSubmitFxIrp()->GetIrp(), + &USB_BUS_INTERFACE_USBDI_GUID, + (PINTERFACE) &busIf, + sizeof(USB_BUS_INTERFACE_USBDI_V0), + USB_BUSIF_USBDI_VERSION_0); + + request.m_TrueRequest->VerifierSetFormatted(); + + status = SubmitSync(request.m_TrueRequest); + } + + if (NT_SUCCESS(status)) { + // + // Need to check for NULL b/c we may have only retrieved the V0 interface + // + if (busIf.IsDeviceHighSpeed != NULL && + busIf.IsDeviceHighSpeed(busIf.BusContext)) { + m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED; + } + + // + // Stash these off for later + // + m_QueryBusTime = busIf.QueryBusTime; + m_BusInterfaceContext = busIf.BusContext; + m_BusInterfaceDereference = busIf.InterfaceDereference; + + ASSERT(busIf.GetUSBDIVersion != NULL); + busIf.GetUSBDIVersion(busIf.BusContext, + &m_UsbdVersionInformation, + &m_HcdPortCapabilities); + } + else if (status == STATUS_NOT_SUPPORTED) { + // + // We will only use m_ControlPipe on stacks which do not support + // USBD_DEFAULT_PIPE_TRANSFER. If all the QIs failed, then we know + // definitively that we are running on USBD and we need m_ControlPipe + // to be != NULL for later control transfers + // + ASSERT(m_ControlPipe != NULL); + + m_OnUSBD = TRUE; + + // + // The QI failed with not supported, do not return error + // + status = STATUS_SUCCESS; + } + else { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Query Interface for bus returned error, %!STATUS!", status); + } + +Done: + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::GetString( + __in_ecount(*NumCharacters) PUSHORT String, + __in PUSHORT NumCharacters, + __in UCHAR StringIndex, + __in_opt USHORT LangID, + __in_opt WDFREQUEST Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options + ) +{ + PUSB_STRING_DESCRIPTOR pDescriptor; + PVOID buffer; + _URB_CONTROL_DESCRIPTOR_REQUEST urb; + WDF_REQUEST_SEND_OPTIONS options, *pOptions; + USB_COMMON_DESCRIPTOR common; + ULONG length; + NTSTATUS status; + + FxSyncRequest request(GetDriverGlobals(), NULL, Request); + + // + // FxSyncRequest always succeesds for KM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + buffer = NULL; + + status = request.m_TrueRequest->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + goto Done; + } + + RtlZeroMemory(&urb, sizeof(urb)); + + if (String != NULL) { + length = sizeof(USB_STRING_DESCRIPTOR) + (*NumCharacters - 1) * sizeof(WCHAR); + + buffer = FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + length); + + if (buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + RtlZeroMemory(buffer, length); + pDescriptor = (PUSB_STRING_DESCRIPTOR) buffer; + } + else { + RtlZeroMemory(&common, sizeof(common)); + + length = sizeof(USB_COMMON_DESCRIPTOR); + pDescriptor = (PUSB_STRING_DESCRIPTOR) &common; + } + + UsbBuildGetDescriptorRequest((PURB) &urb, + sizeof(_URB_CONTROL_DESCRIPTOR_REQUEST), + USB_STRING_DESCRIPTOR_TYPE, + StringIndex, + LangID, + pDescriptor, + NULL, + length, + NULL); + + if (Options != NULL) { + pOptions = Options; + } + else { + WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, + WDF_REL_TIMEOUT_IN_SEC(2)); + + pOptions = &options; + } +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "this annotation change in usb.h is communicated to usb team") + FxFormatUsbRequest(request.m_TrueRequest, (PURB) &urb, FxUrbTypeLegacy, NULL); + status = SubmitSync(request.m_TrueRequest, pOptions); + + if (NT_SUCCESS(status)) { + USHORT numChars; + + // + // Make sure we got an even number of bytes and that we got a header + // + if ((pDescriptor->bLength & 0x1) || + pDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) { + status = STATUS_DEVICE_DATA_ERROR; + } + else { + // + // bLength is the length of the entire descriptor. Subtract off + // the descriptor header and then divide by the size of a WCHAR. + // + numChars = + (pDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR); + + if (String != NULL) { + if (*NumCharacters >= numChars) { + length = numChars * sizeof(WCHAR); + } + else { + length = *NumCharacters * sizeof(WCHAR); + status = STATUS_BUFFER_OVERFLOW; + } + + *NumCharacters = numChars; + RtlCopyMemory(String, pDescriptor->bString, length); + } + else { + *NumCharacters = numChars; + } + } + } + + if (buffer != NULL) { + FxPoolFree(buffer); + } + +Done: + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::FormatStringRequest( + __in FxRequestBase* Request, + __in FxRequestBuffer *RequestBuffer, + __in UCHAR StringIndex, + __in USHORT LangID + ) +/*++ + +Routine Description: + Formats a request to retrieve a string from a string descriptor + +Arguments: + Request - request to format + + RequestBuffer - Buffer to be filled in when the request has completed + + StringIndex - index of the string + + LandID - language ID of the string to be retrieved + +Return Value: + NTSTATUS + + --*/ +{ + FxUsbDeviceStringContext* pContext; + NTSTATUS status; + FX_URB_TYPE urbType; + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Request %p, setting target failed, " + "%!STATUS!", GetHandle(), Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_STRING_REQUEST)) { + pContext = (FxUsbDeviceStringContext*) Request->GetContext(); + } + else { + + urbType = GetFxUrbTypeForRequest(Request); + pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(urbType); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (urbType == FxUrbTypeUsbdAllocated) { + status = pContext->AllocateUrb(m_USBDHandle); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "FxUsbDeviceStringContext::AllocateUrb failed, %!STATUS!", status); + delete pContext; + return status; + } + + // + // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is + // important to release those resorces before the devnode is removed. Those + // resoruces are removed at the time Request is disposed. + // + Request->EnableContextDisposeNotification(); + } + + Request->SetContext(pContext); + } + + status = pContext->AllocateDescriptor(GetDriverGlobals(), + RequestBuffer->GetBufferLength()); + if (!NT_SUCCESS(status)) { + return status; + } + + pContext->StoreAndReferenceMemory(RequestBuffer); + pContext->SetUrbInfo(StringIndex, LangID); + + if (pContext->m_Urb == &pContext->m_UrbLegacy) { + urbType = FxUrbTypeLegacy; + } + else { + urbType = FxUrbTypeUsbdAllocated; + } + + FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::FormatControlRequest( + __in FxRequestBase* Request, + __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + __in FxRequestBuffer *RequestBuffer + ) +{ + FxUsbDeviceControlContext* pContext; + NTSTATUS status; + size_t bufferSize; + FX_URB_TYPE urbType; + + bufferSize = RequestBuffer->GetBufferLength(); + + // + // We can only transfer 2 bytes worth of data, so if the buffer is larger, + // fail here. + // + if (bufferSize > 0xFFFF) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Control transfer buffer is limited to 0xFFFF bytes in size, " + "%I64d requested ", bufferSize); + + return STATUS_INVALID_PARAMETER; + } + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Request %p, setting target failed, " + "%!STATUS!", GetHandle(), Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_CONTROL_REQUEST)) { + pContext = (FxUsbDeviceControlContext*) Request->GetContext(); + } + else { + + urbType = GetFxUrbTypeForRequest(Request); + pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(urbType); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (urbType == FxUrbTypeUsbdAllocated) { + status = pContext->AllocateUrb(m_USBDHandle); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "FxUsbDeviceControlContext::AllocateUrb Failed, %!STATUS!", status); + + delete pContext; + return status; + } + // + // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is + // important to release those resorces before the devnode is removed. Those + // resoruces are removed at the time Request is disposed. + // + Request->EnableContextDisposeNotification(); + } + + Request->SetContext(pContext); + } + + if (RequestBuffer->HasMdl()) { + PMDL pMdl; + + pMdl = NULL; + ASSERT(pContext->m_PartialMdl == NULL); + + status = RequestBuffer->GetOrAllocateMdl(GetDriverGlobals(), + &pMdl, + &pContext->m_PartialMdl, + &pContext->m_UnlockPages, + IoModifyAccess); + + if (!NT_SUCCESS(status)) { + return status; + } + + ASSERT(pMdl != NULL); + } + + pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket); + + if (pContext->m_Urb == &pContext->m_UrbLegacy) { + urbType = FxUrbTypeLegacy; + } + else { + urbType = FxUrbTypeUsbdAllocated; + } + + FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); + + return STATUS_SUCCESS; +} + +VOID +FxUsbDeviceControlContext::StoreAndReferenceMemory( + __in FxUsbDevice* Device, + __in FxRequestBuffer* Buffer, + __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket + ) +{ + SetUsbType(WdfUsbRequestTypeDeviceControlTransfer); + + RtlZeroMemory(m_Urb, sizeof(*m_Urb)); + + m_Urb->Hdr.Function = URB_FUNCTION_CONTROL_TRANSFER; + m_Urb->Hdr.Length = sizeof(*m_Urb); + + __super::StoreAndReferenceMemory(Buffer); + + // + // Set the values using what is stored in the buffer + // + Buffer->AssignValues(&m_Urb->TransferBuffer, + &m_Urb->TransferBufferMDL, + &m_Urb->TransferBufferLength); + + RtlCopyMemory(&m_Urb->SetupPacket[0], + &SetupPacket->Generic.Bytes[0], + sizeof(m_Urb->SetupPacket)); + + // + // also indicate the length of the buffer in the header + // + ((PWDF_USB_CONTROL_SETUP_PACKET) &m_Urb->SetupPacket[0])->Packet.wLength = + (USHORT) m_Urb->TransferBufferLength; + + // + // Control transfers are always short OK. USBD_TRANSFER_DIRECTION_IN may + // be OR'ed in later. + // + m_Urb->TransferFlags = USBD_SHORT_TRANSFER_OK; + + // + // Get the direction out of the setup packet + // + if (SetupPacket->Packet.bm.Request.Dir == BMREQUEST_DEVICE_TO_HOST) { + m_Urb->TransferFlags |= USBD_TRANSFER_DIRECTION_IN; + } + + if (Device->OnUSBD()) { + m_Urb->PipeHandle = Device->GetControlPipeHandle(); + } + else { + // + // USBPORT supports this flag + // + m_Urb->TransferFlags |= USBD_DEFAULT_PIPE_TRANSFER; + } + + // + // If we have built a partial MDL, use that instead. TransferBufferLength + // is still valid because the Offsets or length in Buffer will have been + // used to create this PartialMdl by the caller. + // + if (m_PartialMdl != NULL) { + m_Urb->TransferBufferMDL = m_PartialMdl; + } +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::QueryUsbCapability( + __in + CONST GUID* CapabilityType, + __in + ULONG CapabilityBufferLength, + __drv_when(CapabilityBufferLength == 0, __out_opt) + __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength)) + __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + __out_opt + __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength)) + PULONG ResultLength + ) +{ + NTSTATUS status; + + if (ResultLength != NULL) { + *ResultLength = 0; + } + + if (GetUSBDHandle() == NULL) { + status = STATUS_INVALID_DEVICE_STATE; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE must have been created using WdfUsbTargetDeviceCreateWithParameters, %!STATUS!", + status); + + return status; + } + + status = USBD_QueryUsbCapability(m_USBDHandle, + CapabilityType, + CapabilityBufferLength, + (PUCHAR) CapabilityBuffer, + ResultLength); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve capability %!GUID!, %!STATUS!", + CapabilityType, status); + goto exit; + } + +exit: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfigSingle( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +/*++ + +Routine Description: + This will configure the single inteface case and pick up the first available + setting. If there are multiple settings on a single interface device + and the driver wants to pick one then the driver should use the multinterface + option to initialize. + + This takes care of the simplest case only. Configuring a multi interface + device as a single interface device would be treated as an error. There is + duplication of code with the multi case but it is better to keep these two + separate especially if more gets added. + +Arguments: + + +Return Value: + NTSTATUS + + --*/ +{ + // + // The array needs an extra element which is zero'd out to mark the end + // + USBD_INTERFACE_LIST_ENTRY listEntry[2]; + PURB urb; + NTSTATUS status; + + RtlZeroMemory(&Params->Types.SingleInterface, + sizeof(Params->Types.SingleInterface)); + + if (m_NumInterfaces > 1) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p cannot be auto configured for a single interface " + "since there are %d interfaces on the device, %!STATUS!", + GetHandle(), m_NumInterfaces, status); + + return status; + } + + RtlZeroMemory(&listEntry[0], sizeof(listEntry)); + + // + // Use AlternateSetting 0 by default + // + listEntry[0].InterfaceDescriptor = m_Interfaces[0]->GetSettingDescriptor(0); + + if (listEntry[0].InterfaceDescriptor == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for " + "bInterfaceNumber %d", GetHandle(), + m_Interfaces[0]->m_InterfaceNumber); + + return STATUS_INVALID_PARAMETER; + } + + urb = FxUsbCreateConfigRequest(GetDriverGlobals(), + m_ConfigDescriptor, + &listEntry[0], + GetDefaultMaxTransferSize()); + + if (urb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + status = SelectConfig(PipeAttributes, urb, FxUrbTypeLegacy, NULL); + + if (NT_SUCCESS(status)) { + Params->Types.SingleInterface.NumberConfiguredPipes = + m_Interfaces[0]->GetNumConfiguredPipes(); + + Params->Types.SingleInterface.ConfiguredUsbInterface = + m_Interfaces[0]->GetHandle(); + } + + FxPoolFree(urb); + urb = NULL; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfigMulti( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +/*++ + +Routine Description: + Selects the configuration as described by the parameter Params. If there is a + previous active configuration, the WDFUSBPIPEs for it are stopped and + destroyed before the new configuration is selected + +Arguments: + PipesAttributes - object attributes to apply to each created WDFUSBPIPE + + Params - + +Return Value: + NTSTATUS + + --*/ +{ + PUSBD_INTERFACE_LIST_ENTRY pList; + PURB urb; + NTSTATUS status; + ULONG size; + UCHAR i; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0; + + // + // The array needs an extra element which is zero'd out to mark the end + // + size = sizeof(USBD_INTERFACE_LIST_ENTRY) * (m_NumInterfaces + 1); + pList = (PUSBD_INTERFACE_LIST_ENTRY) FxPoolAllocate( + pFxDriverGlobals, + NonPagedPool, + size + ); + + if (pList == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(pList, size); + + if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) { + for (i = 0; i < m_NumInterfaces; i++) { + pList[i].InterfaceDescriptor = + m_Interfaces[i]->GetSettingDescriptor(0); + + if (pList[i].InterfaceDescriptor == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for " + "bInterfaceNumber %d", GetHandle(), + m_Interfaces[i]->m_InterfaceNumber); + + status = STATUS_INVALID_PARAMETER; + goto Done; + } + } + } + else { + // + // Type is WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs + // + UCHAR interfacePairsNum = 0; + UCHAR bitArray[UCHAR_MAX/sizeof(UCHAR)]; + + // + // initialize the bit array + // + RtlZeroMemory(bitArray, sizeof(bitArray)); + // + // Build a list of descriptors from the Setting pairs + // passed in by the user. There could be interfaces not + // covered in the setting/interface pairs array passed. + // If that is the case return STATUS_INVALID_PARAMETER + // + for (i = 0; i < Params->Types.MultiInterface.NumberInterfaces ; i++) { + PWDF_USB_INTERFACE_SETTING_PAIR settingPair; + UCHAR interfaceNumber; + UCHAR altSettingIndex; + + settingPair = &Params->Types.MultiInterface.Pairs[i]; + + status = GetInterfaceNumberFromInterface( + settingPair->UsbInterface, + &interfaceNumber + ); + + // + //convert the interface handle to interface number + // + if (NT_SUCCESS(status)) { + altSettingIndex = settingPair->SettingIndex; + + // + // do the following only if the bit is not already set + // + if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) { + pList[interfacePairsNum].InterfaceDescriptor = + FxUsbParseConfigurationDescriptor( + m_ConfigDescriptor, + interfaceNumber, + altSettingIndex + ); + + if (pList[interfacePairsNum].InterfaceDescriptor == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGIOTARGET, + "WDFUSBDEVICE %p could not retrieve " + "AlternateSetting %d for " + "bInterfaceNumber %d, returning %!STATUS!", + GetHandle(), + altSettingIndex, interfaceNumber, status); + goto Done; + } + + interfacePairsNum++; + } + } + else { + goto Done; + } + } + + // + // Check if there are any interfaces not specified by the array. If + // there are, then select setting 0 for them. + // + if (m_NumInterfaces > interfacePairsNum) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p interface pairs set (%d) is not equal to actual " + "# of interfaces (%d) reported by the device, %!STATUS!", + GetObjectHandle(), interfacePairsNum, m_NumInterfaces, status); + goto Done; + } + } //WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs + + urb = FxUsbCreateConfigRequest( + GetDriverGlobals(), + m_ConfigDescriptor, + pList, + GetDefaultMaxTransferSize() + ); + + if (urb == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } + else { + status = SelectConfig( + PipesAttributes, + urb, + FxUrbTypeLegacy, + &Params->Types.MultiInterface.NumberOfConfiguredInterfaces); + + FxPoolFree(urb); + urb = NULL; + } + +Done: + FxPoolFree(pList); + pList = NULL; + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::Reset( + VOID + ) +{ + FxIoContext context; + FxSyncRequest request(GetDriverGlobals(), &context); + FxRequestBuffer emptyBuffer; + NTSTATUS status; + + // + // FxSyncRequest always succeesds for KM. + // + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + status = FormatIoctlRequest(request.m_TrueRequest, + IOCTL_INTERNAL_USB_RESET_PORT, + TRUE, + &emptyBuffer, + &emptyBuffer); + if (NT_SUCCESS(status)) { + CancelSentIo(); + status = SubmitSyncRequestIgnoreTargetState(request.m_TrueRequest, NULL); + } + + return status; +} + + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbpipekm.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbpipekm.cpp new file mode 100644 index 00000000000..acae3b57e4e --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/km/fxusbpipekm.cpp @@ -0,0 +1,379 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbPipeKm.tmh" +} + +#include "Fxglobals.h" + +VOID +FxUsbPipeTransferContext::StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ) +/*++ + +Routine Description: + virtual function which stores and references memory if it is an FxObject + and then fills in the appropriate fields in the URB. + +Arguments: + Buffer - union which can be many types of memory + +Return Value: + None + + --*/ +{ + RtlZeroMemory(m_Urb, sizeof(*m_Urb)); + + m_Urb->Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; + m_Urb->Hdr.Length = sizeof(*m_Urb); + + __super::StoreAndReferenceMemory(Buffer); + + Buffer->AssignValues(&m_Urb->TransferBuffer, + &m_Urb->TransferBufferMDL, + &m_Urb->TransferBufferLength); + + // + // If we have built a partial MDL, use that instead. TransferBufferLength + // is still valid because the Offsets or length in Buffer will have been + // used to create this PartialMdl by the caller. + // + if (m_PartialMdl != NULL) { + m_Urb->TransferBufferMDL = m_PartialMdl; + } +} + +__drv_functionClass(KDEFERRED_ROUTINE) +__drv_maxIRQL(DISPATCH_LEVEL) +__drv_minIRQL(DISPATCH_LEVEL) +__drv_requiresIRQL(DISPATCH_LEVEL) +__drv_sameIRQL +VOID +FxUsbPipeContinuousReader::_FxUsbPipeContinuousReadDpc( + __in struct _KDPC *Dpc, + __in_opt PVOID DeferredContext, + __in_opt PVOID SystemArgument1, + __in_opt PVOID SystemArgument2 + ) +{ + FxUsbPipeRepeatReader* pRepeater; + FxUsbPipe* pPipe; + + UNREFERENCED_PARAMETER(DeferredContext); + UNREFERENCED_PARAMETER(SystemArgument1); + UNREFERENCED_PARAMETER(SystemArgument2); + + #pragma prefast(push); + + + pRepeater = CONTAINING_RECORD(Dpc, FxUsbPipeRepeatReader, Dpc); + pPipe = pRepeater->Parent->m_Pipe; + + // + // Ignore the return value because once we have sent the request, we + // want all processing to be done in the completion routine. + // + (void) IoCallDriver(pPipe->m_TargetDevice, + pRepeater->Request->GetSubmitIrp()); + #pragma prefast(pop); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipeContinuousReader::Config( + __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, + __in size_t TotalBufferLength + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + LONG i; + + pFxDriverGlobals = m_Pipe->GetDriverGlobals(); + + if (TotalBufferLength <= MAXUSHORT) { + m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxNPagedLookasideList(pFxDriverGlobals, pFxDriverGlobals->Tag); + } + else { + m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxNPagedLookasideListFromPool(pFxDriverGlobals, pFxDriverGlobals->Tag); + } + + if (m_Lookaside == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (Config->BufferAttributes == NULL) { + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + } + else { + RtlCopyMemory(&attributes, + Config->BufferAttributes, + sizeof(WDF_OBJECT_ATTRIBUTES)); + } + + // + // By specifying the loookaside as the parent for the memory objects that + // will be created, when we destroy the lookaside list, we will destroy any + // outstanding memory objects that have been allocated. This can happen if + // we initialize the repeater, but never send any i/o. (Normally the + // memory object would be freed when the read completes.) + // + attributes.ParentObject = m_Lookaside->GetObjectHandle(); + + status = m_Lookaside->Initialize(TotalBufferLength, &attributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxSystemWorkItem::_Create(pFxDriverGlobals, + m_Pipe->m_Device->GetDeviceObject(), + &m_WorkItem + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not allocate workitem: %!STATUS!", status); + return status; + } + + m_Offsets.BufferLength = Config->TransferLength; + m_Offsets.BufferOffset = Config->HeaderLength; + + for (i = 0; i < m_NumReaders; i++) { + FxUsbPipeRepeatReader* pRepeater; + + pRepeater = &m_Readers[i]; + + pRepeater->Parent = this; + + KeInitializeDpc(&pRepeater->Dpc, _FxUsbPipeContinuousReadDpc, NULL); + + // + // This will allocate the PIRP + // + status = FxRequest::_Create(pFxDriverGlobals, + WDF_NO_OBJECT_ATTRIBUTES, + NULL, + m_Pipe, + FxRequestOwnsIrp, + FxRequestConstructorCallerIsFx, + &pRepeater->Request); + + if (!NT_SUCCESS(status)) { + return status; + } + + pRepeater->RequestIrp = pRepeater->Request->GetSubmitIrp(); + + // + // Initialize the event before FormatRepeater clears it + // + status = pRepeater->ReadCompletedEvent.Initialize(NotificationEvent, TRUE); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "Could not initialize ReadCompletedEvent: %!STATUS!", + status); + + return status; + } + + // + // This will allocate the context + // + status = FormatRepeater(pRepeater); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::FormatTransferRequest( + __in FxRequestBase* Request, + __in FxRequestBuffer* Buffer, + __in ULONG TransferFlags + ) +{ + FxUsbPipeTransferContext* pContext; + NTSTATUS status; + size_t bufferSize; + ULONG dummyLength; + FX_URB_TYPE urbType; + + // + // Make sure request is for the right type + // + if (!(IsType(WdfUsbPipeTypeBulk) || IsType(WdfUsbPipeTypeInterrupt))) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p not the right type, %!STATUS!", + GetHandle(), status); + + return status; + } + + bufferSize = Buffer->GetBufferLength(); + + status = RtlSizeTToULong(bufferSize, &dummyLength); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p, buffer size truncated, %!STATUS!", + GetHandle(), status); + return status; + } + + // + // On reads, check to make sure the read in value is an integral number of + // packet sizes + // + if (TransferFlags & USBD_TRANSFER_DIRECTION_IN) { + if (IsInEndpoint() == FALSE) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, sending __in transaction on a __out endpoint", + this); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (m_CheckPacketSize && + (bufferSize % m_PipeInformation.MaximumPacketSize) != 0) { + return STATUS_INVALID_BUFFER_SIZE; + } + } + else { + if (IsOutEndpoint() == FALSE) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, sending __out transaction on an __in endpoint", + this); + + return STATUS_INVALID_DEVICE_REQUEST; + } + } + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, Request %p, setting target failed, " + "status %!STATUS!", this, Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_PIPE_XFER)) { + pContext = (FxUsbPipeTransferContext*) Request->GetContext(); + } + else { + urbType = m_UsbDevice->GetFxUrbTypeForRequest(Request); + + pContext = new(GetDriverGlobals()) FxUsbPipeTransferContext(urbType); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (urbType == FxUrbTypeUsbdAllocated) { + status = pContext->AllocateUrb(m_USBDHandle); + if (!NT_SUCCESS(status)) { + delete pContext; + return status; + } + // + // Since the AllocateUrb routine calls USBD_xxxUrbAllocate APIs to allocate an Urb, it is + // important to release those resorces before the devnode is removed. Those + // resoruces are removed at the time Request is disposed. + // + Request->EnableContextDisposeNotification(); + } + + Request->SetContext(pContext); + } + + // + // Always set the memory after determining the context. This way we can + // free a previously referenced memory object if necessary. + // + if (Buffer->HasMdl()) { + PMDL pMdl; + + pMdl=NULL; + ASSERT(pContext->m_PartialMdl == NULL); + + // + // If it is an __in endpoint, the buffer will be written to by the + // controller, so request IoWriteAccess locking. + // + status = Buffer->GetOrAllocateMdl( + GetDriverGlobals(), + &pMdl, + &pContext->m_PartialMdl, + &pContext->m_UnlockPages, + IsInEndpoint() ? IoWriteAccess : IoReadAccess); + + if (!NT_SUCCESS(status)) { + return status; + } + + ASSERT(pMdl != NULL); + } + + pContext->StoreAndReferenceMemory(Buffer); + + pContext->SetUrbInfo(m_PipeInformation.PipeHandle, TransferFlags); + + if (pContext->m_Urb == &pContext->m_UrbLegacy) { + urbType = FxUrbTypeLegacy; + } + else { + urbType = FxUrbTypeUsbdAllocated; + } + + FxFormatUsbRequest(Request, (PURB)pContext->m_Urb, urbType, m_USBDHandle); + + return STATUS_SUCCESS; +} + +VOID +FxUsbPipe::GetInformation( + __out PWDF_USB_PIPE_INFORMATION PipeInformation + ) +{ + // + // Do a field by field copy for the WDF structure, since fields could change. + // + PipeInformation->MaximumPacketSize = m_PipeInformation.MaximumPacketSize; + PipeInformation->EndpointAddress = m_PipeInformation.EndpointAddress; + PipeInformation->Interval = m_PipeInformation.Interval; + PipeInformation->PipeType = _UsbdPipeTypeToWdf(m_PipeInformation.PipeType); + PipeInformation->MaximumTransferSize = m_PipeInformation.MaximumTransferSize; + PipeInformation->SettingIndex = m_UsbInterface->GetConfiguredSettingIndex(); +} + +WDF_USB_PIPE_TYPE +FxUsbPipe::GetType( + VOID + ) +{ + return _UsbdPipeTypeToWdf(m_PipeInformation.PipeType); +} + +BOOLEAN +FxUsbPipe::IsType( + __in WDF_USB_PIPE_TYPE Type + ) +{ + return _UsbdPipeTypeToWdf(m_PipeInformation.PipeType) == Type ? TRUE : FALSE; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbdeviceum.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbdeviceum.cpp new file mode 100644 index 00000000000..e339fd06ef2 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbdeviceum.cpp @@ -0,0 +1,923 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbDeviceUm.cpp + +Abstract: + +Author: + +Environment: + + User mode only + +Revision History: + +--*/ +extern "C" { +#include + +} +#include "fxusbpch.hpp" +extern "C" { +#include "FxUsbDeviceUm.tmh" +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SendSyncRequest( + __in FxSyncRequest* Request, + __in ULONGLONG Time + ) +{ + NTSTATUS status; + WDF_REQUEST_SEND_OPTIONS options; + + WDF_REQUEST_SEND_OPTIONS_INIT(&options, 0); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&options, WDF_REL_TIMEOUT_IN_SEC(Time)); + + status = SubmitSync(Request->m_TrueRequest, &options); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "FxUsbDevice SubmitSync failed"); + goto Done; + } + +Done: + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SendSyncUmUrb( + __inout PUMURB Urb, + __in ULONGLONG Time, + __in_opt WDFREQUEST Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options + ) +{ + NTSTATUS status; + WDF_REQUEST_SEND_OPTIONS options; + FxSyncRequest request(GetDriverGlobals(), NULL, Request); + + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + return status; + } + + if (NULL == Options) { + Options = &options; + } + + WDF_REQUEST_SEND_OPTIONS_INIT(Options, 0); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(Options, WDF_REL_TIMEOUT_IN_SEC(Time)); + + status = request.m_TrueRequest->ValidateTarget(this); + if (NT_SUCCESS(status)) { + FxUsbUmFormatRequest(request.m_TrueRequest, &Urb->UmUrbHeader, m_pHostTargetFile); + status = SubmitSync(request.m_TrueRequest, Options); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "FxUsbDevice SubmitSync failed"); + return status; + } + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::InitDevice( + __in ULONG USBDClientContractVersionForWdfClient + ) +{ + HRESULT hr = S_OK; + NTSTATUS status = STATUS_SUCCESS; + + IWudfDevice* device = NULL; + IWudfDeviceStack2* devstack2 = NULL; + + UMURB urb; + USB_CONFIGURATION_DESCRIPTOR config; + USHORT wTotalLength = 0; + + FxRequestBuffer buf; + FxUsbDeviceControlContext context(FxUrbTypeLegacy); + + WDF_USB_CONTROL_SETUP_PACKET setupPacket; + USHORT deviceStatus = 0; + UCHAR deviceSpeed = 0; + + FxSyncRequest request(GetDriverGlobals(), NULL); + FxSyncRequest request2(GetDriverGlobals(), &context); + + + + + UNREFERENCED_PARAMETER(USBDClientContractVersionForWdfClient); + + status = request.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize FxSyncRequest"); + goto Done; + } + + status = request2.Initialize(); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to initialize second FxSyncRequest"); + goto Done; + } + + status = request.m_TrueRequest->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to validate FxSyncRequest target"); + goto Done; + } + + status = request2.m_TrueRequest->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to validate second FxSyncRequest target"); + goto Done; + } + + RtlZeroMemory(&urb, sizeof(urb)); + + device = m_DeviceBase->GetDeviceObject(); + devstack2 = m_Device->GetDeviceStack2(); + + if (m_pHostTargetFile == NULL) { + + // + // Opens a handle on the reflector for USB side-band communication + // based on the currently selected dispatcher type. + // + hr = devstack2->OpenUSBCommunicationChannel(device, + device->GetAttachedDevice(), + &m_pHostTargetFile); + + if (SUCCEEDED(hr)) { + m_WinUsbHandle = (WINUSB_INTERFACE_HANDLE)m_pHostTargetFile->GetCreateContext(); + } + } + + // + // Get USB device descriptor + // + FxUsbUmInitDescriptorUrb(&urb, + m_WinUsbHandle, + USB_DEVICE_DESCRIPTOR_TYPE, + sizeof(m_DeviceDescriptor), + &m_DeviceDescriptor); + FxUsbUmFormatRequest(request.m_TrueRequest, + &urb.UmUrbHeader, + m_pHostTargetFile, + TRUE); + status = SendSyncRequest(&request, 5); + if (!NT_SUCCESS(status)) { + goto Done; + } + + // + // Get USB configuration descriptor + // + FxUsbUmInitDescriptorUrb(&urb, + m_WinUsbHandle, + USB_CONFIGURATION_DESCRIPTOR_TYPE, + sizeof(config), + &config); + FxUsbUmFormatRequest(request.m_TrueRequest, + &urb.UmUrbHeader, + m_pHostTargetFile, + TRUE); + status = SendSyncRequest(&request, 5); + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (config.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR)) { + + // + // Not enough info returned + // + status = STATUS_UNSUCCESSFUL; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not retrieve config descriptor size, config.wTotalLength %d < " + "sizeof(config descriptor) (%d), %!STATUS!", + config.wTotalLength, sizeof(USB_CONFIGURATION_DESCRIPTOR), status); + goto Done; + } + + wTotalLength = config.wTotalLength; + m_ConfigDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR) + FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + wTotalLength); + if (NULL == m_ConfigDescriptor) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Could not allocate %d bytes for config descriptor, %!STATUS!", + sizeof(USB_CONFIGURATION_DESCRIPTOR), status); + goto Done; + } + + // + // Get USB configuration descriptor and subsequent interface descriptors, etc. + // + FxUsbUmInitDescriptorUrb(&urb, + m_WinUsbHandle, + USB_CONFIGURATION_DESCRIPTOR_TYPE, + wTotalLength, + m_ConfigDescriptor); + FxUsbUmFormatRequest(request.m_TrueRequest, + &urb.UmUrbHeader, + m_pHostTargetFile, + TRUE); + status = SendSyncRequest(&request, 5); + if (!NT_SUCCESS(status)) { + goto Done; + } else if (m_ConfigDescriptor->wTotalLength != wTotalLength) { + // + // Invalid wTotalLength + // + status = STATUS_DEVICE_DATA_ERROR; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Defective USB device reported two different config descriptor " + "wTotalLength values: %d and %d, %!STATUS!", + wTotalLength, m_ConfigDescriptor->wTotalLength, status); + goto Done; + } + + m_NumInterfaces = m_ConfigDescriptor->bNumInterfaces; + + // + // Check to see if we are wait wake capable + // + if (m_ConfigDescriptor->bmAttributes & USB_CONFIG_REMOTE_WAKEUP) { + m_Traits |= WDF_USB_DEVICE_TRAIT_REMOTE_WAKE_CAPABLE; + } + + // + // Get the device status to check if device is self-powered. + // + WDF_USB_CONTROL_SETUP_PACKET_INIT_GET_STATUS(&setupPacket, + BmRequestToDevice, + 0); // Device status + + buf.SetBuffer(&deviceStatus, sizeof(USHORT)); + + status = FormatControlRequest(request2.m_TrueRequest, + &setupPacket, + &buf); + if (!NT_SUCCESS(status)) { + goto Done; + } + + status = SendSyncRequest(&request2, 5); + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (deviceStatus & USB_GETSTATUS_SELF_POWERED) { + m_Traits |= WDF_USB_DEVICE_TRAIT_SELF_POWERED; + } + + // + // Get device speed information. + // + FxUsbUmInitInformationUrb(&urb, + m_WinUsbHandle, + sizeof(UCHAR), + &deviceSpeed); + FxUsbUmFormatRequest(request.m_TrueRequest, + &urb.UmUrbHeader, + m_pHostTargetFile, + TRUE); + status = SendSyncRequest(&request, 5); + if (!NT_SUCCESS(status)) { + goto Done; + } + + if (deviceSpeed == 3) { + m_Traits |= WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED; + } + + // + // User-mode events must be initialized manually. + // + status = m_InterfaceIterationLock.Initialize(); + if (!NT_SUCCESS(status)) { + goto Done; + } + +Done: + return status; +} + + + + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::GetString( + __in_ecount(*NumCharacters) PUSHORT String, + __in PUSHORT NumCharacters, + __in UCHAR StringIndex, + __in_opt USHORT LangID, + __in_opt WDFREQUEST Request, + __in_opt PWDF_REQUEST_SEND_OPTIONS Options + ) +{ + UMURB urb; + PUSB_STRING_DESCRIPTOR pDescriptor; + PVOID buffer = NULL; + USB_COMMON_DESCRIPTOR common; + ULONG length; + NTSTATUS status; + + if (String != NULL) { + length = sizeof(USB_STRING_DESCRIPTOR) + (*NumCharacters - 1) * sizeof(WCHAR); + + buffer = FxPoolAllocate(GetDriverGlobals(), + NonPagedPool, + length); + + if (buffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + RtlZeroMemory(buffer, length); + pDescriptor = (PUSB_STRING_DESCRIPTOR) buffer; + } + else { + RtlZeroMemory(&common, sizeof(common)); + + length = sizeof(USB_COMMON_DESCRIPTOR); + pDescriptor = (PUSB_STRING_DESCRIPTOR) &common; + } + + FxUsbUmInitDescriptorUrb(&urb, + m_WinUsbHandle, + USB_STRING_DESCRIPTOR_TYPE, + length, + pDescriptor); + urb.UmUrbDescriptorRequest.Index = StringIndex; + urb.UmUrbDescriptorRequest.LanguageID = LangID; + + status = SendSyncUmUrb(&urb, 2, Request, Options); + if (NT_SUCCESS(status)) { + USHORT numChars; + + // + // Make sure we got an even number of bytes and that we got a header + // + if ((pDescriptor->bLength & 0x1) || + pDescriptor->bLength < sizeof(USB_COMMON_DESCRIPTOR)) { + status = STATUS_DEVICE_DATA_ERROR; + } + else { + // + // bLength is the length of the entire descriptor. Subtract off + // the descriptor header and then divide by the size of a WCHAR. + // + numChars = + (pDescriptor->bLength - sizeof(USB_COMMON_DESCRIPTOR)) / sizeof(WCHAR); + + if (String != NULL) { + if (*NumCharacters >= numChars) { + length = numChars * sizeof(WCHAR); + } + else { + length = *NumCharacters * sizeof(WCHAR); + status = STATUS_BUFFER_OVERFLOW; + } + + *NumCharacters = numChars; + RtlCopyMemory(String, pDescriptor->bString, length); + } + else { + *NumCharacters = numChars; + } + } + } + + if (buffer != NULL) { + FxPoolFree(buffer); + } + +Done: + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::FormatStringRequest( + __in FxRequestBase* Request, + __in FxRequestBuffer *RequestBuffer, + __in UCHAR StringIndex, + __in USHORT LangID + ) +/*++ + +Routine Description: + Formats a request to retrieve a string from a string descriptor + +Arguments: + Request - request to format + + RequestBuffer - Buffer to be filled in when the request has completed + + StringIndex - index of the string + + LandID - language ID of the string to be retrieved + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + FxUsbDeviceStringContext* pContext; + + status = Request->ValidateTarget(this); + if (NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Request %p, setting target failed, " + "%!STATUS!", GetHandle(), Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_STRING_REQUEST)) { + pContext = (FxUsbDeviceStringContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxUsbDeviceStringContext(FxUrbTypeLegacy); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + FxUsbUmInitDescriptorUrb(&pContext->m_UmUrb, + m_WinUsbHandle, + USB_STRING_DESCRIPTOR_TYPE, + 0, + NULL); + + status = pContext->AllocateDescriptor(GetDriverGlobals(), + RequestBuffer->GetBufferLength()); + if (!NT_SUCCESS(status)) { + return status; + } + + pContext->StoreAndReferenceMemory(RequestBuffer); + pContext->SetUrbInfo(StringIndex, LangID); + + FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_pHostTargetFile); + + return STATUS_SUCCESS; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::FormatControlRequest( + __in FxRequestBase* Request, + __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + __in FxRequestBuffer *RequestBuffer + ) +{ + FxUsbDeviceControlContext* pContext; + NTSTATUS status; + size_t bufferSize; + + bufferSize = RequestBuffer->GetBufferLength(); + + // + // We can only transfer 2 bytes worth of data, so if the buffer is larger, + // fail here. + // + if (bufferSize > 0xFFFF) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Control transfer buffer is limited to 0xFFFF bytes in size, " + "%I64d requested ", bufferSize); + + return STATUS_INVALID_PARAMETER; + } + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p, Request %p, setting target failed, " + "%!STATUS!", GetHandle(), Request, status); + return status; + } + + if (Request->HasContextType(FX_RCT_USB_CONTROL_REQUEST)) { + pContext = (FxUsbDeviceControlContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxUsbDeviceControlContext(FxUrbTypeLegacy); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + FxUsbUmInitControlTransferUrb(&pContext->m_UmUrb, + m_WinUsbHandle, + 0, + NULL); + + pContext->StoreAndReferenceMemory(this, RequestBuffer, SetupPacket); + + FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_pHostTargetFile); + + return STATUS_SUCCESS; +} + +VOID +FxUsbDeviceControlContext::StoreAndReferenceMemory( + __in FxUsbDevice* Device, + __in FxRequestBuffer* Buffer, + __in PWDF_USB_CONTROL_SETUP_PACKET SetupPacket + ) +{ + SetUsbType(WdfUsbRequestTypeDeviceControlTransfer); + + __super::StoreAndReferenceMemory(Buffer); + + // + // Convert WDF_USB_CONTROL_SETUP_PACKET to WINUSB_SETUP_PACKET + // + m_UmUrb.UmUrbControlTransfer.SetupPacket.RequestType = SetupPacket->Packet.bm.Byte; + m_UmUrb.UmUrbControlTransfer.SetupPacket.Request = SetupPacket->Packet.bRequest; + m_UmUrb.UmUrbControlTransfer.SetupPacket.Value = SetupPacket->Packet.wValue.Value; + m_UmUrb.UmUrbControlTransfer.SetupPacket.Index = SetupPacket->Packet.wIndex.Value; + + // + // Set the TransferBuffer values using what is stored in the Buffer + // + Buffer->AssignValues(&m_UmUrb.UmUrbControlTransfer.TransferBuffer, + NULL, + &m_UmUrb.UmUrbControlTransfer.TransferBufferLength); + + m_UmUrb.UmUrbControlTransfer.SetupPacket.Length = + (USHORT)m_UmUrb.UmUrbControlTransfer.TransferBufferLength; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::QueryUsbCapability( + __in + CONST GUID* CapabilityType, + __in + ULONG CapabilityBufferLength, + __drv_when(CapabilityBufferLength == 0, __out_opt) + __drv_when(CapabilityBufferLength != 0 && ResultLength == NULL, __out_bcount(CapabilityBufferLength)) + __drv_when(CapabilityBufferLength != 0 && ResultLength != NULL, __out_bcount_part_opt(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + __out_opt + __drv_when(ResultLength != NULL,__deref_out_range(<=,CapabilityBufferLength)) + PULONG ResultLength + ) +{ + NTSTATUS status; + + if (ResultLength != NULL) { + *ResultLength = 0; + } + + // + // We cannot send an actual query to the USB stack through winusb. + // However, we have the information to handle this query. It is not + // ideal to implement this API in this manner because we are making + // assumptions about the behavior of USB stack that can change in future. + // However, it is too late in the OS cycle to implement a correct solution. + // The ideal way is for winusb to expose this information. We should + // revisit this API in blue+1 + // + if (RtlCompareMemory(CapabilityType, + &GUID_USB_CAPABILITY_DEVICE_CONNECTION_HIGH_SPEED_COMPATIBLE, + sizeof(GUID)) == sizeof(GUID)) { + if (m_Traits & WDF_USB_DEVICE_TRAIT_AT_HIGH_SPEED) { + status = STATUS_SUCCESS; + } else { + status = STATUS_NOT_SUPPORTED; + } + } + else if (RtlCompareMemory(CapabilityType, + &GUID_USB_CAPABILITY_DEVICE_CONNECTION_SUPER_SPEED_COMPATIBLE, + sizeof(GUID)) == sizeof(GUID)) { + if (m_DeviceDescriptor.bcdUSB >= 0x300) { + status = STATUS_SUCCESS; + } else { + status = STATUS_NOT_SUPPORTED; + } + } + else if (RtlCompareMemory(CapabilityType, + &GUID_USB_CAPABILITY_SELECTIVE_SUSPEND, + sizeof(GUID)) == sizeof(GUID)) { + // + // Both EHCI as well as XHCI stack support selective suspend. + // Since XHCI UCX interface is not open, there aren't any + // third party controller drivers to worry about. This can + // of course change in future + // + status = STATUS_SUCCESS; + } + else if (RtlCompareMemory(CapabilityType, + &GUID_USB_CAPABILITY_FUNCTION_SUSPEND, + sizeof(GUID)) == sizeof(GUID)) { + // + // Note that a SuperSpeed device will report a bcdUSB of 2.1 + // when working on a 2.0 port. Therefore a bcdUSB of 3.0 also + // indicates that the device is actually working on 3.0, in + // which case we always support function suspend + // + if (m_DeviceDescriptor.bcdUSB >= 0x300) { + status = STATUS_SUCCESS; + } else { + status = STATUS_NOT_SUPPORTED; + } + } + else { + // + // We do not support chained MDLs or streams for a UMDF driver + // GUID_USB_CAPABILITY_CHAINED_MDLS + // GUID_USB_CAPABILITY_STATIC_STREAMS + // + status = STATUS_NOT_SUPPORTED; + } + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfigSingle( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +/*++ + +Routine Description: + Since the device is already configured, all this routine + does is to make sure the alternate setting 0 is selected, + in case the client driver selected some other alternate + setting after the initial configuration + +Arguments: + + +Return Value: + NTSTATUS + + --*/ +{ + NTSTATUS status; + + RtlZeroMemory(&Params->Types.SingleInterface, + sizeof(Params->Types.SingleInterface)); + + if (m_NumInterfaces > 1) { + status = STATUS_INVALID_PARAMETER; + + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p cannot be auto configured for a single interface " + "since there are %d interfaces on the device, %!STATUS!", + GetHandle(), m_NumInterfaces, status); + + return status; + } + + // + // Use AlternateSetting 0 by default + // + if (m_Interfaces[0]->GetSettingDescriptor(0) == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for " + "bInterfaceNumber %d", GetHandle(), + m_Interfaces[0]->m_InterfaceNumber); + + return STATUS_INVALID_PARAMETER; + } + + status = m_Interfaces[0]->CheckAndSelectSettingByIndex(0); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p set AlternateSetting 0 for interface 0" + "failed, %!STATUS!", GetHandle(), status); + + return status; + } + + if (PipeAttributes) { + status = m_Interfaces[0]->UpdatePipeAttributes(PipeAttributes); + } + + Params->Types.SingleInterface.ConfiguredUsbInterface = + m_Interfaces[0]->GetHandle(); + + Params->Types.SingleInterface.NumberConfiguredPipes = + m_Interfaces[0]->GetNumConfiguredPipes(); + + return status; +} + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::SelectConfigMulti( + __in PWDF_OBJECT_ATTRIBUTES PipeAttributes, + __in PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ) +/*++ + +Routine Description: + Since the device is already configured, all this routine + does is to make sure the alternate setting 0 is selected + for all interfaces, in case the client driver selected some + other alternate setting after the initial configuration + + +Arguments: + PipeAttributes - Should be NULL + + Params - + +Return Value: + NTSTATUS + + --*/ +{ + FxUsbInterface * pUsbInterface; + NTSTATUS status; + UCHAR i; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + pFxDriverGlobals = GetDriverGlobals(); + + Params->Types.MultiInterface.NumberOfConfiguredInterfaces = 0; + + if (Params->Type == WdfUsbTargetDeviceSelectConfigTypeMultiInterface) { + for (i = 0; i < m_NumInterfaces; i++) { + + if (m_Interfaces[i]->GetSettingDescriptor(0) == NULL) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p could not retrieve AlternateSetting 0 for " + "bInterfaceNumber %d", GetHandle(), + m_Interfaces[i]->m_InterfaceNumber); + + status = STATUS_INVALID_PARAMETER; + goto Done; + } + + status = m_Interfaces[i]->CheckAndSelectSettingByIndex(0); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p set AlternateSetting 0 for bInterfaceNumber %d" + "failed, %!STATUS!", + GetHandle(), m_Interfaces[i]->m_InterfaceNumber, status); + goto Done; + } + if (PipeAttributes) { + status = m_Interfaces[i]->UpdatePipeAttributes(PipeAttributes); + } + } + } + else { + // + // Type is WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs + // + UCHAR interfacePairsNum = 0; + UCHAR bitArray[UCHAR_MAX/sizeof(UCHAR)]; + + // + // initialize the bit array + // + RtlZeroMemory(bitArray, sizeof(bitArray)); + // + // Build a list of descriptors from the Setting pairs + // passed in by the user. There could be interfaces not + // covered in the setting/interface pairs array passed. + // If that is the case return STATUS_INVALID_PARAMETER + // + for (i = 0; i < Params->Types.MultiInterface.NumberInterfaces ; i++) { + PWDF_USB_INTERFACE_SETTING_PAIR settingPair; + UCHAR interfaceNumber; + UCHAR altSettingIndex; + + settingPair = &Params->Types.MultiInterface.Pairs[i]; + + FxObjectHandleGetPtr(GetDriverGlobals(), + settingPair->UsbInterface, + FX_TYPE_USB_INTERFACE , + (PVOID*) &pUsbInterface); + + interfaceNumber = pUsbInterface->GetInterfaceNumber(); + altSettingIndex = settingPair->SettingIndex; + + // + // do the following only if the bit is not already set + // + if (FxBitArraySet(&bitArray[0], interfaceNumber) == FALSE) { + + if (pUsbInterface->GetSettingDescriptor(altSettingIndex) == NULL) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, + TRACINGIOTARGET, + "WDFUSBDEVICE %p could not retrieve " + "AlternateSetting %d for " + "bInterfaceNumber %d, returning %!STATUS!", + GetHandle(), + altSettingIndex, interfaceNumber, status); + goto Done; + } + + interfacePairsNum++; + + // + // Ensure alternate setting 0 is selected + // + status = pUsbInterface->CheckAndSelectSettingByIndex( + settingPair->SettingIndex); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p set AlternateSetting %d for bInterfaceNumber %d" + "failed, %!STATUS!", + GetHandle(), altSettingIndex, m_Interfaces[i]->m_InterfaceNumber, + status); + goto Done; + } + + if (PipeAttributes) { + status = pUsbInterface->UpdatePipeAttributes(PipeAttributes); + } + } + + } + + if (m_NumInterfaces > interfacePairsNum) { + status = STATUS_INVALID_PARAMETER; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBDEVICE %p interface pairs set (%d) is not equal to actual " + "# of interfaces (%d) reported by the device, %!STATUS!", + GetObjectHandle(), interfacePairsNum, m_NumInterfaces, status); + goto Done; + } + } //WdfUsbTargetDeviceSelectConfigTypeInterfacesPairs + + status = STATUS_SUCCESS; + Params->Types.MultiInterface.NumberOfConfiguredInterfaces = m_NumInterfaces; + +Done: + return status; +} + + +_Must_inspect_result_ +NTSTATUS +FxUsbDevice::Reset( + VOID + ) +{ + UMURB urb; + NTSTATUS status; + + RtlZeroMemory(&urb, sizeof(UMURB)); + + urb.UmUrbSelectInterface.Hdr.Function = UMURB_FUNCTION_RESET_PORT; + urb.UmUrbSelectInterface.Hdr.Length = sizeof(_UMURB_HEADER); + + status = SendSyncUmUrb(&urb, 2); + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbinterfaceum.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbinterfaceum.cpp new file mode 100644 index 00000000000..ab9e1895c10 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbinterfaceum.cpp @@ -0,0 +1,234 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxUsbInterfaceUm.cpp + +Abstract: + +Author: + +Environment: + + user mode only + +Revision History: + +--*/ + +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbInterfaceUm.tmh" +} + +NTSTATUS +FxUsbInterface::SetWinUsbHandle( + _In_ UCHAR FrameworkInterfaceIndex +) +{ + NTSTATUS status = STATUS_SUCCESS; + UMURB urb; + + if (m_InterfaceNumber != FrameworkInterfaceIndex) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "Composite device detected: Converting absolute interface " + "index %d to relative interface index %d", m_InterfaceNumber, + FrameworkInterfaceIndex); + } + + if (FrameworkInterfaceIndex == 0) { + m_WinUsbHandle = m_UsbDevice->m_WinUsbHandle; + } + else { + RtlZeroMemory(&urb, sizeof(UMURB)); + + urb.UmUrbGetAssociatedInterface.Hdr.InterfaceHandle = m_UsbDevice->m_WinUsbHandle; + urb.UmUrbGetAssociatedInterface.Hdr.Function = UMURB_FUNCTION_GET_ASSOCIATED_INTERFACE; + urb.UmUrbGetAssociatedInterface.Hdr.Length = sizeof(_UMURB_GET_ASSOCIATED_INTERFACE); + + // + // If this is using the WinUSB dispatcher, this will ultimately call + // WinUsb_GetAssociatedInterface which expects a 0-based index but starts + // counting from index 1. To get the handle for interface n, we pass n-1 + // and WinUSB will return the handle for (n-1)+1. + // + // The NativeUSB dispatcher ultimately calls WdfUsbTargetDeviceGetInterface. + // Unlike WinUSB.sys, this starts counting from index zero. The NativeUSB + // dispatcher expects this framework quirk and adjusts accordingly. See + // WudfNativeUsbDispatcher.cpp for more information. + // + // The actual interface number may differ from the interface index in + // composite devices. In all cases, the interface index (starting from zero) + // must be used. + // + urb.UmUrbGetAssociatedInterface.InterfaceIndex = FrameworkInterfaceIndex - 1; + + status = m_UsbDevice->SendSyncUmUrb(&urb, 5); + + if (NT_SUCCESS(status)) { + m_WinUsbHandle = urb.UmUrbGetAssociatedInterface.InterfaceHandle; + } + else { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Failed to retrieve WinUsb interface handle"); + m_WinUsbHandle = NULL; + } + } + + return status; +} + +NTSTATUS +FxUsbInterface::MakeAndConfigurePipes( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes, + __in UCHAR NumPipes + ) +{ + NTSTATUS status = STATUS_SUCCESS; + UCHAR iPipe; + FxUsbPipe* pPipe; + FxUsbPipe** ppPipes; + // + // Zero pipes are a valid configuration, this simplifies the code below. + // + ULONG size = (NumPipes == 0 ? 1 : NumPipes) * sizeof(FxUsbPipe*); + UMURB urb; + + ppPipes = (FxUsbPipe**)FxPoolAllocate(GetDriverGlobals(), NonPagedPool, size); + if (ppPipes == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Unable to allocate memory %!STATUS!", status); + goto Done; + } + + RtlZeroMemory(ppPipes, size); + + for (iPipe = 0; iPipe < NumPipes; iPipe++) { + ppPipes[iPipe] = new (GetDriverGlobals(), PipesAttributes) + FxUsbPipe(GetDriverGlobals(), m_UsbDevice); + + if (ppPipes[iPipe] == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Unable to allocate memory for the pipes %!STATUS!", status); + goto Done; + } + + pPipe = ppPipes[iPipe]; + + status = pPipe->Init(m_UsbDevice->m_Device); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Init pipe failed %!STATUS!", status); + goto Done; + } + + status = pPipe->Commit(PipesAttributes, NULL, this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Commit pipe failed %!STATUS!", status); + goto Done; + } + } + + if (IsInterfaceConfigured()) { + // + // Delete the old pipes + // + m_UsbDevice->CleanupInterfacePipesAndDelete(this); + } + + SetNumConfiguredPipes(NumPipes); + SetConfiguredPipes(ppPipes); + + for (iPipe = 0; iPipe < m_NumberOfConfiguredPipes ; iPipe++) { + RtlZeroMemory(&urb, sizeof(UMURB)); + + urb.UmUrbQueryPipe.Hdr.InterfaceHandle = m_WinUsbHandle; + urb.UmUrbQueryPipe.Hdr.Function = UMURB_FUNCTION_QUERY_PIPE; + urb.UmUrbQueryPipe.Hdr.Length = sizeof(_UMURB_QUERY_PIPE); + + urb.UmUrbQueryPipe.AlternateSetting = m_CurAlternateSetting; + urb.UmUrbQueryPipe.PipeID = iPipe; + + status = m_UsbDevice->SendSyncUmUrb(&urb, 2); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Send UMURB_FUNCTION_QUERY_PIPE failed %!STATUS!", status); + goto Done; + } + + m_ConfiguredPipes[iPipe]->InitPipe(&urb.UmUrbQueryPipe.PipeInformation, + m_InterfaceNumber, + this); + } + +Done: + if (!NT_SUCCESS(status)) { + if (ppPipes != NULL) { + ASSERT(ppPipes != m_ConfiguredPipes); + + for (iPipe = 0; iPipe < NumPipes; iPipe++) { + if (ppPipes[iPipe] != NULL) { + ppPipes[iPipe]->DeleteFromFailedCreate(); + } + } + + FxPoolFree(ppPipes); + ppPipes = NULL; + } + } + + return status; +} + +NTSTATUS +FxUsbInterface::UpdatePipeAttributes( + __in PWDF_OBJECT_ATTRIBUTES PipesAttributes + ) +{ + NTSTATUS status = STATUS_SUCCESS; + UCHAR iPipe; + FxUsbPipe** ppPipes; + UCHAR numberOfPipes; + + numberOfPipes = m_NumberOfConfiguredPipes; + ppPipes = m_ConfiguredPipes; + + for (iPipe = 0; iPipe < numberOfPipes; iPipe++) { + status = FxObjectAllocateContext(ppPipes[iPipe], + PipesAttributes, + TRUE, + NULL); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "UpdatePipeAttributes failed %!STATUS!", status); + break; + } + } + + // + // Pipe attributes are updated as part of select + // config and it is ok for the client driver to configure + // twice with the same attributes. In a similar scenario, + // KMDF will return STATUS_SUCCESS, so we should do the + // same for UMDF for consistency + // + if (status == STATUS_OBJECT_NAME_EXISTS) { + status = STATUS_SUCCESS; + } + + return status; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbpipeum.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbpipeum.cpp new file mode 100644 index 00000000000..c7f420dcfe3 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/um/fxusbpipeum.cpp @@ -0,0 +1,345 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include "fxusbpch.hpp" + +extern "C" { +#include "FxUsbPipeUm.tmh" +} + +#include "Fxglobals.h" + +VOID +FxUsbPipeRequestContext::SetInfo( + __in WDF_USB_REQUEST_TYPE Type, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in UCHAR PipeId, + __in USHORT Function + ) +{ + RtlZeroMemory(&m_UmUrb, sizeof(m_UmUrb)); + + m_UmUrb.UmUrbPipeRequest.Hdr.InterfaceHandle = WinUsbHandle; + m_UmUrb.UmUrbPipeRequest.Hdr.Function = Function; + m_UmUrb.UmUrbPipeRequest.Hdr.Length = sizeof(m_UmUrb.UmUrbPipeRequest); + + m_UmUrb.UmUrbPipeRequest.PipeID = PipeId; + + SetUsbType(Type); +} + +VOID +FxUsbPipeTransferContext::StoreAndReferenceMemory( + __in FxRequestBuffer* Buffer + ) +/*++ + +Routine Description: + virtual function which stores and references memory if it is an FxObject + and then fills in the appropriate fields in the URB. + +Arguments: + Buffer - union which can be many types of memory + +Return Value: + None + + --*/ +{ + RtlZeroMemory(&m_UmUrb, sizeof(m_UmUrb)); + + m_UmUrb.UmUrbHeader.Function = UMURB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; + m_UmUrb.UmUrbHeader.Length = sizeof(_UMURB_BULK_OR_INTERRUPT_TRANSFER); + + __super::StoreAndReferenceMemory(Buffer); + + Buffer->AssignValues(&m_UmUrb.UmUrbBulkOrInterruptTransfer.TransferBuffer, + NULL, + &m_UmUrb.UmUrbBulkOrInterruptTransfer.TransferBufferLength); +} + +VOID +FxUsbPipeContinuousReader::_ReadWorkItem( + __in MdDeviceObject /*DeviceObject*/, + __in_opt PVOID Context + ) +{ + FxUsbPipeRepeatReader * pRepeater; + pRepeater = (FxUsbPipeRepeatReader *)Context; + + pRepeater->RequestIrp->Forward(); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipeContinuousReader::Config( + __in PWDF_USB_CONTINUOUS_READER_CONFIG Config, + __in size_t TotalBufferLength + ) +{ + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WDF_OBJECT_ATTRIBUTES attributes; + NTSTATUS status; + LONG i; + + pFxDriverGlobals = m_Pipe->GetDriverGlobals(); + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + if (TotalBufferLength <= MAXUSHORT) { + m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxNPagedLookasideList(pFxDriverGlobals, pFxDriverGlobals->Tag); + } + else { + m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxNPagedLookasideListFromPool(pFxDriverGlobals, pFxDriverGlobals->Tag); + } +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + m_Lookaside = new(pFxDriverGlobals, WDF_NO_OBJECT_ATTRIBUTES) + FxNPagedLookasideList(pFxDriverGlobals, pFxDriverGlobals->Tag); +#endif + + if (m_Lookaside == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + if (Config->BufferAttributes == NULL) { + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + } + else { + RtlCopyMemory(&attributes, + Config->BufferAttributes, + sizeof(WDF_OBJECT_ATTRIBUTES)); + } + + // + // By specifying the loookaside as the parent for the memory objects that + // will be created, when we destroy the lookaside list, we will destroy any + // outstanding memory objects that have been allocated. This can happen if + // we initialize the repeater, but never send any i/o. (Normally the + // memory object would be freed when the read completes.) + // + attributes.ParentObject = m_Lookaside->GetObjectHandle(); + + status = m_Lookaside->Initialize(TotalBufferLength, &attributes); + if (!NT_SUCCESS(status)) { + return status; + } + + status = FxSystemWorkItem::_Create(pFxDriverGlobals, + m_Pipe->m_Device->GetDeviceObject(), + &m_WorkItem + ); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIO, + "Could not allocate workitem: %!STATUS!", status); + return status; + } + + m_Offsets.BufferLength = Config->TransferLength; + m_Offsets.BufferOffset = Config->HeaderLength; + + for (i = 0; i < m_NumReaders; i++) { + FxUsbPipeRepeatReader* pRepeater; + + pRepeater = &m_Readers[i]; + + pRepeater->Parent = this; + +#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE) + KeInitializeDpc(&pRepeater->Dpc, _FxUsbPipeContinuousReadDpc, NULL); +#elif (FX_CORE_MODE == FX_CORE_USER_MODE) + pRepeater->m_ReadWorkItem.Allocate(m_Pipe->m_Device->GetDeviceObject()); +#endif + + // + // This will allocate the PIRP + // + status = FxRequest::_Create(pFxDriverGlobals, + WDF_NO_OBJECT_ATTRIBUTES, + NULL, + m_Pipe, + FxRequestOwnsIrp, + FxRequestConstructorCallerIsFx, + &pRepeater->Request); + + if (!NT_SUCCESS(status)) { + return status; + } + + pRepeater->RequestIrp = pRepeater->Request->GetSubmitIrp(); + + // + // Initialize the event before FormatRepeater clears it + // + status = pRepeater->ReadCompletedEvent.Initialize(NotificationEvent, TRUE); + + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + pFxDriverGlobals, TRACE_LEVEL_INFORMATION, TRACINGIOTARGET, + "Could not initialize ReadCompletedEvent: %!STATUS!", + status); + + return status; + } + + // + // This will allocate the context + // + status = FormatRepeater(pRepeater); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + return STATUS_SUCCESS; +} + +VOID +FxUsbPipe::InitPipe( + __in PWINUSB_PIPE_INFORMATION PipeInfo, + __in UCHAR InterfaceNumber, + __in FxUsbInterface* UsbInterface + ) +{ + RtlCopyMemory(&m_PipeInformationUm, PipeInfo, sizeof(m_PipeInformationUm)); + m_InterfaceNumber = InterfaceNumber; + + if (m_UsbInterface != NULL) { + m_UsbInterface->RELEASE(this); + m_UsbInterface = NULL; + } + + m_UsbInterface = UsbInterface; + m_UsbInterface->ADDREF(this); +} + +_Must_inspect_result_ +NTSTATUS +FxUsbPipe::FormatTransferRequest( + __in FxRequestBase* Request, + __in FxRequestBuffer* Buffer, + __in ULONG TransferFlags + ) +{ + FxUsbPipeTransferContext* pContext; + NTSTATUS status; + size_t bufferSize; + ULONG dummyLength; + + // + // Make sure request is for the right type + // + if (!(IsType(WdfUsbPipeTypeBulk) || IsType(WdfUsbPipeTypeInterrupt))) { + status = STATUS_INVALID_DEVICE_REQUEST; + + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p not the right type, %!STATUS!", + GetHandle(), status); + + return status; + } + + bufferSize = Buffer->GetBufferLength(); + + status = RtlSizeTToULong(bufferSize, &dummyLength); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "WDFUSBPIPE %p, buffer size truncated, %!STATUS!", + GetHandle(), status); + return status; + } + + // + // On reads, check to make sure the read in value is an integral number of + // packet sizes + // + if (TransferFlags & USBD_TRANSFER_DIRECTION_IN) { + if (IsInEndpoint() == FALSE) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, sending __in transaction on a __out endpoint", + this); + + return STATUS_INVALID_DEVICE_REQUEST; + } + + if (m_CheckPacketSize && + (bufferSize % m_PipeInformationUm.MaximumPacketSize) != 0) { + return STATUS_INVALID_BUFFER_SIZE; + } + } + else { + if (IsOutEndpoint() == FALSE) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, sending __out transaction on an __in endpoint", + this); + + return STATUS_INVALID_DEVICE_REQUEST; + } + } + + status = Request->ValidateTarget(this); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "Pipe %p, Request %p, setting target failed, " + "status %!STATUS!", this, Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_PIPE_XFER)) { + pContext = (FxUsbPipeTransferContext*) Request->GetContext(); + } + else { + pContext = new(GetDriverGlobals()) FxUsbPipeTransferContext(FxUrbTypeLegacy); + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + pContext->StoreAndReferenceMemory(Buffer); + + pContext->m_UmUrb.UmUrbHeader.InterfaceHandle = m_UsbInterface->m_WinUsbHandle; + + pContext->m_UmUrb.UmUrbBulkOrInterruptTransfer.PipeID = m_PipeInformationUm.PipeId; + pContext->m_UmUrb.UmUrbBulkOrInterruptTransfer.InPipe = IsInEndpoint(); + + FxUsbUmFormatRequest(Request, &pContext->m_UmUrb.UmUrbHeader, m_UsbDevice->m_pHostTargetFile); + + return STATUS_SUCCESS; +} + +VOID +FxUsbPipe::GetInformation( + __out PWDF_USB_PIPE_INFORMATION PipeInformation + ) +{ + + + + + PipeInformation->MaximumPacketSize = m_PipeInformationUm.MaximumPacketSize; + PipeInformation->EndpointAddress = m_PipeInformationUm.PipeId; + PipeInformation->Interval = m_PipeInformationUm.Interval; + PipeInformation->PipeType = _UsbdPipeTypeToWdf(m_PipeInformationUm.PipeType); + PipeInformation->SettingIndex = m_UsbInterface->GetConfiguredSettingIndex(); +} + +WDF_USB_PIPE_TYPE +FxUsbPipe::GetType( + VOID + ) +{ + return _UsbdPipeTypeToWdf(m_PipeInformationUm.PipeType); +} + +BOOLEAN +FxUsbPipe::IsType( + __in WDF_USB_PIPE_TYPE Type + ) +{ + return _UsbdPipeTypeToWdf(m_PipeInformationUm.PipeType) == Type ? TRUE : FALSE; +} + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/um/usbstubum.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/um/usbstubum.cpp new file mode 100644 index 00000000000..0ba077e9fa5 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/um/usbstubum.cpp @@ -0,0 +1,147 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + UsbStubUm.cpp + +Abstract: + +Author: + +Environment: + + +Revision History: + +--*/ + +extern "C" { +#define INITGUID +#include + +// {B1A96A13-3DE0-4574-9B01-C08FEAB318D6} +DEFINE_GUID(USB_BUS_INTERFACE_USBDI_GUID, +0xb1a96a13, 0x3de0, 0x4574, 0x9b, 0x1, 0xc0, 0x8f, 0xea, 0xb3, 0x18, 0xd6); + +} + +#include "fxusbpch.hpp" + +VOID +USBD_UrbFree( + _In_ USBD_HANDLE USBDHandle, + _In_ PURB Urb +) +{ + UNREFERENCED_PARAMETER(USBDHandle); + UNREFERENCED_PARAMETER(Urb); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + + +NTSTATUS +USBD_UrbAllocate( + _In_ USBD_HANDLE USBDHandle, + _Outptr_result_bytebuffer_(sizeof(URB)) PURB *Urb +) +{ + UNREFERENCED_PARAMETER(USBDHandle); + UNREFERENCED_PARAMETER(Urb); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_SUCCESS; +} + +NTSTATUS +USBD_IsochUrbAllocate( + _In_ USBD_HANDLE USBDHandle, + _In_ ULONG NumberOfIsochPacket, + _Outptr_result_bytebuffer_(sizeof(struct _URB_ISOCH_TRANSFER) + + (NumberOfIsochPackets * sizeof(USBD_ISO_PACKET_DESCRIPTOR)) + - sizeof(USBD_ISO_PACKET_DESCRIPTOR)) + PURB *Urb +) +{ + UNREFERENCED_PARAMETER(USBDHandle); + UNREFERENCED_PARAMETER(NumberOfIsochPacket); + UNREFERENCED_PARAMETER(Urb); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_SUCCESS; +} + + +VOID +USBD_CloseHandle( + _In_ USBD_HANDLE USBDHandle +) +{ + UNREFERENCED_PARAMETER(USBDHandle); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} + +NTSTATUS +USBD_CreateHandle( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PDEVICE_OBJECT TargetDeviceObject, + _In_ ULONG USBDClientContractVersion, + _In_ ULONG PoolTag, + _Out_ USBD_HANDLE *USBDHandle +) +{ + UNREFERENCED_PARAMETER(DeviceObject); + UNREFERENCED_PARAMETER(TargetDeviceObject); + UNREFERENCED_PARAMETER(USBDClientContractVersion); + UNREFERENCED_PARAMETER(PoolTag); + UNREFERENCED_PARAMETER(USBDHandle); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_SUCCESS; + +} + +NTSTATUS +USBD_QueryUsbCapability( + _In_ USBD_HANDLE USBDHandle, + _In_ const GUID* CapabilityType, + _In_ ULONG OutputBufferLength, + _When_(OutputBufferLength == 0, _Pre_null_) + _When_(OutputBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(OutputBufferLength)) + _When_(OutputBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultLength)) + PUCHAR OutputBuffer, + _Out_opt_ + _When_(ResultLength != NULL, _Deref_out_range_(<=,OutputBufferLength)) + PULONG ResultLength +) +{ + UNREFERENCED_PARAMETER(USBDHandle); + UNREFERENCED_PARAMETER(CapabilityType); + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(OutputBuffer); + UNREFERENCED_PARAMETER(ResultLength); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); + + return STATUS_SUCCESS; +} + +VOID +USBD_AssignUrbToIoStackLocation( + _In_ USBD_HANDLE USBDHandle, + _In_ PIO_STACK_LOCATION IoStackLocation, + _In_ PURB Urb +) +{ + UNREFERENCED_PARAMETER(USBDHandle); + UNREFERENCED_PARAMETER(IoStackLocation); + UNREFERENCED_PARAMETER(Urb); + + ASSERTMSG("Not implemented for UMDF\n", FALSE); +} diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/usbutil.cpp b/sdk/lib/drivers/wdf/shared/targets/usb/usbutil.cpp new file mode 100644 index 00000000000..e3bfe0e75bc --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/usbutil.cpp @@ -0,0 +1,614 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + usbutil.cpp + +Abstract: + + +Author: + +Environment: + + Both kernel and user mode + +Revision History: + +--*/ + +#include "fxusbpch.hpp" + +extern "C" { +#include "UsbUtil.tmh" +} + +VOID +FxFormatUsbRequest( + __in FxRequestBase* Request, + __in PURB Urb, + __in FX_URB_TYPE FxUrbType, + __drv_when(FxUrbType == FxUrbTypeUsbdAllocated, __in) + __drv_when(FxUrbType != FxUrbTypeUsbdAllocated, __in_opt) + USBD_HANDLE UsbdHandle + ) +{ + FxIrp* irp; + + ASSERT(Urb->UrbHeader.Length >= sizeof(_URB_HEADER)); + + irp = Request->GetSubmitFxIrp(); + irp->ClearNextStackLocation(); + irp->SetMajorFunction(IRP_MJ_INTERNAL_DEVICE_CONTROL); + irp->SetParameterIoctlCode(IOCTL_INTERNAL_USB_SUBMIT_URB); + + + + + + if (FxUrbType == FxUrbTypeUsbdAllocated) { + USBD_AssignUrbToIoStackLocation(UsbdHandle, irp->GetNextIrpStackLocation(), Urb); + } + else { + irp->SetNextStackParameterOthersArgument1(Urb); + } + + Request->VerifierSetFormatted(); +} + +NTSTATUS +FxFormatUrbRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxIoTarget* Target, + __in FxRequestBase* Request, + __in FxRequestBuffer* Buffer, + __in FX_URB_TYPE FxUrbType, + __drv_when(FxUrbType == FxUrbTypeUsbdAllocated, __in) + __drv_when(FxUrbType != FxUrbTypeUsbdAllocated, __in_opt) + USBD_HANDLE UsbdHandle + ) +{ + FxUsbUrbContext* pContext; + NTSTATUS status; + + status = Request->ValidateTarget(Target); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGIOTARGET, + "FormatUrbRequest: Target %p, Request %p, " + "setting target failed, %!STATUS!", + Target, Request, status); + + return status; + } + + if (Request->HasContextType(FX_RCT_USB_URB_REQUEST)) { + pContext = (FxUsbUrbContext*) Request->GetContext(); + } + else { + pContext = new(Target->GetDriverGlobals()) FxUsbUrbContext(); + + if (pContext == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + Request->SetContext(pContext); + } + + // + // Always set the memory after determining the context. This way we can + // free a previously referenced memory object if necessary. + // + pContext->StoreAndReferenceMemory(Buffer); + + FxFormatUsbRequest(Request, pContext->m_pUrb, FxUrbType, UsbdHandle); + + return STATUS_SUCCESS; +} + +NTSTATUS +FxUsbValidateConfigDescriptorHeaders( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, + __in size_t ConfigDescriptorLength + ) +{ + PUCHAR pCur, pEnd; + + pCur = (PUCHAR) ConfigDescriptor; + pEnd = pCur + ConfigDescriptorLength; + + while (pCur < pEnd) { + PUSB_COMMON_DESCRIPTOR pDescriptor = (PUSB_COMMON_DESCRIPTOR) pCur; + + // + // Make sure we can safely deref bLength, bDescriptorType + // + if (pCur + sizeof(USB_COMMON_DESCRIPTOR) > pEnd) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB Configuration packet contains bad data, expected " + "at least %d remaining bytes in config descriptor at " + "offset %I64d, total size is %I64d", + sizeof(USB_COMMON_DESCRIPTOR), pCur-(PUCHAR)ConfigDescriptor, + ConfigDescriptorLength + ); + return STATUS_INVALID_PARAMETER; + } + + // + // Make sure bLength is within bounds of the config descriptor + // + if ((pCur + pDescriptor->bLength) > pEnd) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB Configuration packet contains bad data, descriptor at offset " + "%I64d specified bLength %d, only %I64d bytes remaining in config " + "descriptor, total size is %I64d", + pCur-(PUCHAR)ConfigDescriptor, pDescriptor->bLength, pEnd-pCur, + ConfigDescriptorLength + ); + return STATUS_INVALID_PARAMETER; + } + + if (pDescriptor->bLength == 0) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB Configuration packet contains bad data, descriptor at offset " + "%I64d contains bLength == 0, this is due to a broken device or driver", + pCur - (PUCHAR) ConfigDescriptor + ); + return STATUS_INVALID_PARAMETER; + } + + + pCur += pDescriptor->bLength; + } + + return STATUS_SUCCESS; +} + + +PUSB_COMMON_DESCRIPTOR +FxUsbFindDescriptorType( + __in PVOID Buffer, + __in size_t BufferLength, + __in PVOID Start, + __in LONG DescriptorType + ) +{ + PUSB_COMMON_DESCRIPTOR descriptor; + PUCHAR pCur, pEnd; + + pCur = (PUCHAR) Start; + pEnd = ((PUCHAR) Buffer) + BufferLength; + + while (pCur < pEnd) { + // + // Check to see if the current point is the desired descriptor type + // + descriptor = (PUSB_COMMON_DESCRIPTOR) pCur; + + if (descriptor->bDescriptorType == DescriptorType) { + return descriptor; + } + + pCur += descriptor->bLength; + } + + // + // Iterated to the end and found nothing + // + return NULL; +} + +NTSTATUS +FxUsbValidateDescriptorType( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, + __in PVOID Start, + __in PVOID End, + __in LONG DescriptorType, + __in size_t SizeToValidate, + __in FxUsbValidateDescriptorOp Op, + __in ULONG MaximumNumDescriptorsToValidate + ) +/*++ + +Routine Description: + Validates the size of all descriptors within [Start, End] are of the correct + size. Correct can either be == or >= SizeToValidate. Furthermore, the caller + can specify that validation only occur for the first N descriptors found + +Arguments: + FxDriverDriverGlobals - client driver globals + ConfigDescriptor - the entire config descriptor of the usb device + Start - the beginning of the buffer to start to validating descriptors within + End - end of the buffer of validation + DescriptorType - the type of descriptor to validate + SizeToValidate - the size of the descriptor required. Op determines if the + check is == or >= + Op - the operation, == or >=, to perform for the size validation + MaximumNumDescriptorsToValidate - limit of the number of descriptors to validate, + if zero, all instances are validated + +Return Value: + NTSTATUS - !NT_SUCCESS if validation fails, NT_SUCCESS upon success + +--*/ +{ + PUSB_COMMON_DESCRIPTOR pDescriptor = NULL; + PVOID pCur = Start; + ULONG i = 1; + + while ((pDescriptor = FxUsbFindDescriptorType(Start, + (PUCHAR)End-(PUCHAR)Start, + pCur, + DescriptorType + )) != NULL) { + // + // Make sure bLength is the correct value + // + if (Op == FxUsbValidateDescriptorOpEqual) { + if (pDescriptor->bLength != SizeToValidate) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB Configuration packet contains bad data, found descriptor " + "#%d of type %d at offset %I64d, expected bLength of %I64d, found %d", + i, DescriptorType, ((PUCHAR)pDescriptor)-((PUCHAR)ConfigDescriptor), + SizeToValidate, pDescriptor->bLength + ); + return STATUS_INVALID_PARAMETER; + } + } + else if (Op == FxUsbValidateDescriptorOpAtLeast) { + if (pDescriptor->bLength < SizeToValidate) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "USB Configuration packet contains bad data, found descriptor " + "#%d of type %d at offset %I64d, expected minimum bLength of %I64d, " + "found %d", + i, DescriptorType, ((PUCHAR)pDescriptor)-((PUCHAR)ConfigDescriptor), + SizeToValidate, pDescriptor->bLength + ); + return STATUS_INVALID_PARAMETER; + } + } + + // + // No need to validate WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength) > End + // because FxUsbValidateConfigDescriptorHeaders already has done so. End is either + // 1) == end of the config descriptor, in which case FxUsbValidateConfigDescriptorHeaders + // directly validated bLength + // or + // 2) End is somewere in the middle of the config descriptor and ASSUMED to be the start + // of a common descriptor header. To find that value of End, we would have had to use + // pDescriptor->bLength to get to End, we would not overrun + // + + // + // i is one based, so the current value is Nth descriptor we have validated. If + // the caller wants to limit the number of descriptors validated by indicating a + // Max > 0, stop with success if the condition is met. + // + if (MaximumNumDescriptorsToValidate > 0 && i == MaximumNumDescriptorsToValidate) { + break; + } + + pCur = WDF_PTR_ADD_OFFSET(pDescriptor, pDescriptor->bLength); + i++; + } + + return STATUS_SUCCESS; +} + +PUSB_INTERFACE_DESCRIPTOR +FxUsbParseConfigurationDescriptor( + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + __in UCHAR InterfaceNumber, + __in UCHAR AlternateSetting + ) +{ + PUSB_INTERFACE_DESCRIPTOR found, usbInterface; + PVOID pStart; + + found = NULL, + + ASSERT(ConfigDesc->bDescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE); + + // + // Walk the table of descriptors looking for an interface descriptor with + // parameters matching those passed in. + // + pStart = ConfigDesc; + + do { + // + // Search for descriptor type 'interface' + // + usbInterface = (PUSB_INTERFACE_DESCRIPTOR) + FxUsbFindDescriptorType(ConfigDesc, + ConfigDesc->wTotalLength, + pStart, + USB_INTERFACE_DESCRIPTOR_TYPE); + + // + // Check to see if have a matching descriptor by eliminating mismatches + // + if (usbInterface != NULL) { + found = usbInterface; + + if (InterfaceNumber != -1 && + usbInterface->bInterfaceNumber != InterfaceNumber) { + found = NULL; + } + + if (AlternateSetting != -1 && + usbInterface->bAlternateSetting != AlternateSetting) { + found = NULL; + } + + pStart = ((PUCHAR)usbInterface) + usbInterface->bLength; + } + + if (found != NULL) { + break; + } + } while (usbInterface!= NULL); + + return found; +} + +PURB +FxUsbCreateConfigRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + __in PUSBD_INTERFACE_LIST_ENTRY InterfaceList, + __in ULONG DefaultMaxPacketSize + ) +{ + PURB urb; + PUSBD_INTERFACE_LIST_ENTRY pList; + USHORT size; + + // + // Our mission here is to construct a URB of the proper + // size and format for a select_configuration request. + // + // This function uses the configuration descriptor as a + // reference and builds a URB with interface_information + // structures for each interface requested in the interface + // list passed in + // + // NOTE: the config descriptor may contain interfaces that + // the caller does not specify in the list -- in this case + // the other interfaces will be ignored. + // + + // + // First figure out how many interfaces we are dealing with + // + pList = InterfaceList; + + // + // For a multiple interface configuration, GET_SELECT_CONFIGURATION_REQUEST_SIZE + // doesn't work as expected. This is because it subtracts one from totalPipes + // to compensate for the embedded USBD_PIPE_INFORMATION in USBD_INTERFACE_INFORMATION. + // A multiple interface device will have more then one embedded + // USBD_PIPE_INFORMATION in its configuration request and any of these interfaces + // might not have any pipes on them. + // + // To fix, just iterate and compute the size incrementally. + // + if (InterfaceList[0].InterfaceDescriptor != NULL) { + size = sizeof(_URB_SELECT_CONFIGURATION) - sizeof(USBD_INTERFACE_INFORMATION); + + while (pList->InterfaceDescriptor != NULL) { + NTSTATUS status; + + status = RtlUShortAdd(size, + GET_USBD_INTERFACE_SIZE( + pList->InterfaceDescriptor->bNumEndpoints), + &size); + if (!NT_SUCCESS(status)) { + DoTraceLevelMessage( + FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGIOTARGET, + "InterfaceList %p, NumEndPoints 0x%x, " + "Integer overflow while calculating interface size, %!STATUS!", + InterfaceList, + pList->InterfaceDescriptor->bNumEndpoints, + status); + return NULL; + } + pList++; + } + } + else { + size = sizeof(_URB_SELECT_CONFIGURATION); + } + + // + // Make sure we are dealing with a value that fits into a USHORT + // + ASSERT(size <= 0xFFFF); + + urb = (PURB) FxPoolAllocate(FxDriverGlobals, NonPagedPool, size); + + if (urb != NULL) { + PUCHAR pCur; + + // + // now all we have to do is initialize the urb + // + RtlZeroMemory(urb, size); + + pList = InterfaceList; + + pCur = (PUCHAR) &urb->UrbSelectConfiguration.Interface; + while (pList->InterfaceDescriptor != NULL) { + PUSB_INTERFACE_DESCRIPTOR pInterfaceDesc; + PUSBD_INTERFACE_INFORMATION pInterfaceInfo; + + pInterfaceDesc = pList->InterfaceDescriptor; + + pInterfaceInfo = (PUSBD_INTERFACE_INFORMATION) pCur; +#pragma prefast(suppress: __WARNING_BUFFER_OVERFLOW, "Esp:675"); + pInterfaceInfo->InterfaceNumber = pInterfaceDesc->bInterfaceNumber; + pInterfaceInfo->AlternateSetting = pInterfaceDesc->bAlternateSetting; + pInterfaceInfo->NumberOfPipes = pInterfaceDesc->bNumEndpoints; + pInterfaceInfo->Length = (USHORT) + GET_USBD_INTERFACE_SIZE(pInterfaceDesc->bNumEndpoints); + + for (LONG j = 0; j < pInterfaceDesc->bNumEndpoints; j++) { + pInterfaceInfo->Pipes[j].PipeFlags = 0; + pInterfaceInfo->Pipes[j].MaximumTransferSize = DefaultMaxPacketSize; + } + + ASSERT(pCur + pInterfaceInfo->Length <= ((PUCHAR) urb) + size); + + pList->Interface = pInterfaceInfo; + + pList++; + pCur += pInterfaceInfo->Length; + } + + urb->UrbHeader.Length = size; + urb->UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION; + urb->UrbSelectConfiguration.ConfigurationDescriptor = ConfigDesc; + } + + return urb; +} + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +VOID +FxUsbUmFormatRequest( + __in FxRequestBase* Request, + __in_xcount(Urb->Length) PUMURB_HEADER Urb, + __in IWudfFile* HostFile, + __in BOOLEAN Reuse + ) +/*++ + +Routine Description: + Formats a request to become a USB request. + The next stack location is formatted with the UM URB + and dispatcher is set to be the USB dispatcher + +Arguments: + Request - Request to be formatted + Urb - UM URB the Request is to be formatted with + the pointer is passed as the header so + that SAL checkers don't complain on bigger size usage than what's passed in + (Total size of the URB union can be more than the the specific member that is passed in) + File - The host file used for internal I/O. + +Return Value: + None + +--*/ +{ + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(Request)); + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(Urb)); + FX_VERIFY(INTERNAL, CHECK_TODO(Urb->Length >= sizeof(_UMURB_HEADER))); + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(HostFile)); + + IWudfIoIrp* pIoIrp = NULL; + IWudfIrp* pIrp = Request->GetSubmitIrp(); + + if (Reuse) { + // + // This allows us to use the same FxSyncRequest + // stack object multiple times. + // + Request->GetSubmitFxIrp()->Reuse(STATUS_SUCCESS); + Request->ClearFieldsForReuse(); + } + + HRESULT hrQI = pIrp->QueryInterface(IID_IWudfIoIrp, (PVOID*)&pIoIrp); + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, pIoIrp)); + + pIoIrp->SetTypeForNextStackLocation(UMINT::WdfRequestInternalIoctl); + + + + + pIoIrp->SetDeviceIoControlParametersForNextStackLocation(IOCTL_INETRNAL_USB_SUBMIT_UMURB, + 0, + 0); + + pIoIrp->SetOtherParametersForNextStackLocation((PVOID*)&Urb, + NULL, + NULL, + NULL); + + pIoIrp->SetFileForNextIrpStackLocation(HostFile); + + // + // Release reference taken by QI + // + SAFE_RELEASE(pIoIrp); + Request->VerifierSetFormatted(); +} + +VOID +FxUsbUmInitDescriptorUrb( + __inout PUMURB UmUrb, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in UCHAR DescriptorType, + __in ULONG BufferLength, + __in PVOID Buffer + ) +{ + RtlZeroMemory(UmUrb, sizeof(UMURB)); + + UmUrb->UmUrbDescriptorRequest.Hdr.InterfaceHandle = WinUsbHandle; + UmUrb->UmUrbDescriptorRequest.Hdr.Function = UMURB_FUNCTION_GET_DESCRIPTOR; + UmUrb->UmUrbDescriptorRequest.Hdr.Length = sizeof(_UMURB_DESCRIPTOR_REQUEST); + + UmUrb->UmUrbDescriptorRequest.DescriptorType = DescriptorType; + UmUrb->UmUrbDescriptorRequest.Index = 0; + UmUrb->UmUrbDescriptorRequest.LanguageID = 0; + UmUrb->UmUrbDescriptorRequest.BufferLength = BufferLength; + UmUrb->UmUrbDescriptorRequest.Buffer = Buffer; +} + +VOID +FxUsbUmInitControlTransferUrb( + __inout PUMURB UmUrb, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in ULONG BufferLength, + __in PVOID Buffer + ) +{ + RtlZeroMemory(UmUrb, sizeof(UMURB)); + + UmUrb->UmUrbControlTransfer.Hdr.InterfaceHandle = WinUsbHandle; + UmUrb->UmUrbControlTransfer.Hdr.Function = UMURB_FUNCTION_CONTROL_TRANSFER; + UmUrb->UmUrbControlTransfer.Hdr.Length = sizeof(_UMURB_CONTROL_TRANSFER); + + UmUrb->UmUrbControlTransfer.TransferBufferLength = BufferLength; + UmUrb->UmUrbControlTransfer.TransferBuffer = Buffer; +} + +VOID +FxUsbUmInitInformationUrb( + __inout PUMURB UmUrb, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in ULONG BufferLength, + __in PVOID Buffer + ) +{ + RtlZeroMemory(UmUrb, sizeof(UMURB)); + + UmUrb->UmUrbDeviceInformation.Hdr.InterfaceHandle = WinUsbHandle; + UmUrb->UmUrbDeviceInformation.Hdr.Function = UMURB_FUNCTION_GET_DEVICE_INFORMATION; + UmUrb->UmUrbDeviceInformation.Hdr.Length = sizeof(_UMURB_DEVICE_INFORMATION); + + UmUrb->UmUrbDeviceInformation.InformationType = DEVICE_SPEED; + UmUrb->UmUrbDeviceInformation.BufferLength = BufferLength; + UmUrb->UmUrbDeviceInformation.Buffer = Buffer; +} +#endif + diff --git a/sdk/lib/drivers/wdf/shared/targets/usb/usbutil.hpp b/sdk/lib/drivers/wdf/shared/targets/usb/usbutil.hpp new file mode 100644 index 00000000000..a05ea7b1024 --- /dev/null +++ b/sdk/lib/drivers/wdf/shared/targets/usb/usbutil.hpp @@ -0,0 +1,178 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef __FX_USB_UTIL_H__ +#define __FX_USB_UTIL_H__ + +BOOLEAN +__inline +FxBitArraySet( + __inout_xcount((BitNumber / sizeof(UCHAR)) + 1) PUCHAR BitArray, + __in UCHAR BitNumber + ) +/*++ + +Routine Description: + The following function sets a bit in the array and returns a value indicating + the bits previous state. + +Arguments: + BitArray - the array to check + + BitNumber - zero based index into BitArray + +Return Value: + TRUE if the bit was already set + FALSE if was previously clear + + --*/ +{ + UCHAR index; + UCHAR bit; + + index = (BitNumber) / sizeof(UCHAR); + bit = (UCHAR) (1 << (BitNumber % sizeof(UCHAR)) ); + + if ((BitArray[index] & bit) == 0x0) { + // + // bit not set + // + BitArray[index] |= bit; + return FALSE; + } + + return TRUE; +} + +VOID +__inline +FxBitArrayClear( + __inout_xcount((BitNumber / sizeof(UCHAR)) + 1) PUCHAR BitArray, + __in UCHAR BitNumber + ) +/*++ + +Routine Description: + Clear the bit in the BitArray + +Arguments: + BitArray - bit array to change + + BitNumber - zero based bit index into the array to clear + + --*/ +{ + UCHAR index; + UCHAR bit; + + index = BitNumber / sizeof(UCHAR); + bit = (UCHAR) (1 << (BitNumber % sizeof(UCHAR)) ); + + BitArray[index] &= ~bit; +} + +VOID +FxFormatUsbRequest( + __in FxRequestBase* Request, + __in PURB Urb, + __in FX_URB_TYPE FxUrbType, + __drv_when(FxUrbType == FxUrbTypeUsbdAllocated, __in) + __drv_when(FxUrbType != FxUrbTypeUsbdAllocated, __in_opt) + USBD_HANDLE UsbdHandle + ); + +NTSTATUS +FxFormatUrbRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in FxIoTarget* Target, + __in FxRequestBase* Request, + __in FxRequestBuffer* Buffer, + __in FX_URB_TYPE FxUrbType, + __drv_when(FxUrbType == FxUrbTypeUsbdAllocated, __in) + __drv_when(FxUrbType != FxUrbTypeUsbdAllocated, __in_opt) + USBD_HANDLE UsbdHandle + ); + +PUSB_INTERFACE_DESCRIPTOR +FxUsbParseConfigurationDescriptor( + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + __in UCHAR InterfaceNumber = -1, + __in UCHAR AlternateSetting = 1 + ); + +PURB +FxUsbCreateConfigRequest( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDesc, + __in PUSBD_INTERFACE_LIST_ENTRY InterfaceList, + __in ULONG DefaultMaxPacketSize + ); + +NTSTATUS +FxUsbValidateConfigDescriptorHeaders( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, + __in size_t ConfigDescriptorLength + ); + +PUSB_COMMON_DESCRIPTOR +FxUsbFindDescriptorType( + __in PVOID Buffer, + __in size_t BufferLength, + __in PVOID Start, + __in LONG DescriptorType + ); + +enum FxUsbValidateDescriptorOp { + FxUsbValidateDescriptorOpEqual, + FxUsbValidateDescriptorOpAtLeast +}; + +NTSTATUS +FxUsbValidateDescriptorType( + __in PFX_DRIVER_GLOBALS FxDriverGlobals, + __in PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptor, + __in PVOID Start, + __in PVOID End, + __in LONG DescriptorType, + __in size_t SizeToValidate, + __in FxUsbValidateDescriptorOp Op, + __in ULONG MaximumNumDescriptorsToValidate + ); + +#if (FX_CORE_MODE == FX_CORE_USER_MODE) +VOID +FxUsbUmFormatRequest( + __in FxRequestBase* Request, + __in_xcount(Urb->Length) PUMURB_HEADER Urb, + __in IWudfFile* HostFile, + __in BOOLEAN Reuse = FALSE + ); + +VOID +FxUsbUmInitDescriptorUrb( + __inout PUMURB UmUrb, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in UCHAR DescriptorType, + __in ULONG BufferLength, + __in PVOID Buffer + ); + +VOID +FxUsbUmInitControlTransferUrb( + __inout PUMURB UmUrb, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in ULONG BufferLength, + __in PVOID Buffer + ); + +VOID +FxUsbUmInitInformationUrb( + __inout PUMURB UmUrb, + __in WINUSB_INTERFACE_HANDLE WinUsbHandle, + __in ULONG BufferLength, + __in PVOID Buffer + ); +#endif // (FX_CORE_MODE == FX_CORE_USER_MODE) + +#endif // __FX_USB_UTIL_H__ diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/umdfstub.h b/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/umdfstub.h new file mode 100644 index 00000000000..2b84eeacd37 --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/umdfstub.h @@ -0,0 +1,62 @@ +/*++ + +Copyright (c) Microsoft Corporation + +ModuleName: + + UMDFStubs.h + +Abstract: + + Contains declarations for functions implemented by WdfStubUm.lib and + WdfVersionUm.lib + + These are called by UMDF framework (in WUDF.cpp) + +Author: + + + +Revision History: + + + +--*/ + +// +// Functions implemented by version\version.cpp +// +extern "C" +NTSTATUS +LibraryDriverEntry( + __in PUNICODE_STRING RegistryPath + ); + +extern "C" +VOID +LibraryUnload( + ); + +// +// Functions implemented by stub\stub.cpp +// +extern "C" +NTSTATUS +FxDriverEntry( + __in PWDF_DRIVER_GLOBALS * WdfDriverGlobals + ); + +extern "C" +VOID +DriverUnload( + __in PWDF_DRIVER_GLOBALS WdfDriverGlobals + ); + +// +// Functions implemented by version\FxLibraryCommon.cpp +// + +VOID +FxIFRStop( + __in PFX_DRIVER_GLOBALS FxDriverGlobals + ); diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/wdf20.h b/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/wdf20.h new file mode 100644 index 00000000000..1b7f06a194a --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/wdf20.h @@ -0,0 +1,2977 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// +#ifndef _WDF_V2_0_TYPES_H_ +#define _WDF_V2_0_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V2_0 { + WdfFunctionTableNumEntries_V2_0 = 248, +} WDFFUNCENUM_V2_0; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_0 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_0; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_0 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_0; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V2_0 *PWDF_QUEUE_FATAL_ERROR_DATA_V2_0; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V2_0 *PCWDF_QUEUE_FATAL_ERROR_DATA_V2_0; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V2_0 *PWDF_CHILD_RETRIEVE_INFO_V2_0; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V2_0 *PCWDF_CHILD_RETRIEVE_INFO_V2_0; +typedef struct _WDF_CHILD_LIST_CONFIG_V2_0 *PWDF_CHILD_LIST_CONFIG_V2_0; +typedef const struct _WDF_CHILD_LIST_CONFIG_V2_0 *PCWDF_CHILD_LIST_CONFIG_V2_0; +typedef struct _WDF_CHILD_LIST_ITERATOR_V2_0 *PWDF_CHILD_LIST_ITERATOR_V2_0; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V2_0 *PCWDF_CHILD_LIST_ITERATOR_V2_0; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V2_0 *PWDF_COMMON_BUFFER_CONFIG_V2_0; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V2_0 *PCWDF_COMMON_BUFFER_CONFIG_V2_0; +typedef struct _WDFCX_FILEOBJECT_CONFIG_V2_0 *PWDFCX_FILEOBJECT_CONFIG_V2_0; +typedef const struct _WDFCX_FILEOBJECT_CONFIG_V2_0 *PCWDFCX_FILEOBJECT_CONFIG_V2_0; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V2_0 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V2_0; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V2_0 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V2_0; +typedef struct _WDF_CLASS_VERSION_V2_0 *PWDF_CLASS_VERSION_V2_0; +typedef const struct _WDF_CLASS_VERSION_V2_0 *PCWDF_CLASS_VERSION_V2_0; +typedef struct _WDF_CLASS_BIND_INFO_V2_0 *PWDF_CLASS_BIND_INFO_V2_0; +typedef const struct _WDF_CLASS_BIND_INFO_V2_0 *PCWDF_CLASS_BIND_INFO_V2_0; +typedef struct _WDF_CLASS_LIBRARY_INFO_V2_0 *PWDF_CLASS_LIBRARY_INFO_V2_0; +typedef const struct _WDF_CLASS_LIBRARY_INFO_V2_0 *PCWDF_CLASS_LIBRARY_INFO_V2_0; +typedef struct _WDF_FILEOBJECT_CONFIG_V2_0 *PWDF_FILEOBJECT_CONFIG_V2_0; +typedef const struct _WDF_FILEOBJECT_CONFIG_V2_0 *PCWDF_FILEOBJECT_CONFIG_V2_0; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_0 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V2_0; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_0 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V2_0; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_0 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V2_0; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_0 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V2_0; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_0 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_0; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_0 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_0; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V2_0 *PWDF_PNPPOWER_EVENT_CALLBACKS_V2_0; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V2_0 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V2_0; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V2_0 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V2_0; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V2_0 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V2_0; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0; +typedef struct _WDF_DEVICE_STATE_V2_0 *PWDF_DEVICE_STATE_V2_0; +typedef const struct _WDF_DEVICE_STATE_V2_0 *PCWDF_DEVICE_STATE_V2_0; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V2_0 *PWDF_DEVICE_PNP_CAPABILITIES_V2_0; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V2_0 *PCWDF_DEVICE_PNP_CAPABILITIES_V2_0; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V2_0 *PWDF_DEVICE_POWER_CAPABILITIES_V2_0; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V2_0 *PCWDF_DEVICE_POWER_CAPABILITIES_V2_0; +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V2_0 *PWDF_REMOVE_LOCK_OPTIONS_V2_0; +typedef const struct _WDF_REMOVE_LOCK_OPTIONS_V2_0 *PCWDF_REMOVE_LOCK_OPTIONS_V2_0; +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V2_0 *PWDF_POWER_FRAMEWORK_SETTINGS_V2_0; +typedef const struct _WDF_POWER_FRAMEWORK_SETTINGS_V2_0 *PCWDF_POWER_FRAMEWORK_SETTINGS_V2_0; +typedef struct _WDF_IO_TYPE_CONFIG_V2_0 *PWDF_IO_TYPE_CONFIG_V2_0; +typedef const struct _WDF_IO_TYPE_CONFIG_V2_0 *PCWDF_IO_TYPE_CONFIG_V2_0; +typedef struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0 *PWDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0; +typedef const struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0 *PCWDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0; +typedef struct _WDF_DEVICE_PROPERTY_DATA_V2_0 *PWDF_DEVICE_PROPERTY_DATA_V2_0; +typedef const struct _WDF_DEVICE_PROPERTY_DATA_V2_0 *PCWDF_DEVICE_PROPERTY_DATA_V2_0; +typedef struct _WDF_DMA_ENABLER_CONFIG_V2_0 *PWDF_DMA_ENABLER_CONFIG_V2_0; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V2_0 *PCWDF_DMA_ENABLER_CONFIG_V2_0; +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V2_0 *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V2_0; +typedef const struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V2_0 *PCWDF_DMA_SYSTEM_PROFILE_CONFIG_V2_0; +typedef struct _WDF_DPC_CONFIG_V2_0 *PWDF_DPC_CONFIG_V2_0; +typedef const struct _WDF_DPC_CONFIG_V2_0 *PCWDF_DPC_CONFIG_V2_0; +typedef struct _WDF_DRIVER_CONFIG_V2_0 *PWDF_DRIVER_CONFIG_V2_0; +typedef const struct _WDF_DRIVER_CONFIG_V2_0 *PCWDF_DRIVER_CONFIG_V2_0; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V2_0 *PWDF_FDO_EVENT_CALLBACKS_V2_0; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V2_0 *PCWDF_FDO_EVENT_CALLBACKS_V2_0; +typedef struct _WDF_DRIVER_GLOBALS_V2_0 *PWDF_DRIVER_GLOBALS_V2_0; +typedef const struct _WDF_DRIVER_GLOBALS_V2_0 *PCWDF_DRIVER_GLOBALS_V2_0; +typedef struct _WDF_INTERRUPT_CONFIG_V2_0 *PWDF_INTERRUPT_CONFIG_V2_0; +typedef const struct _WDF_INTERRUPT_CONFIG_V2_0 *PCWDF_INTERRUPT_CONFIG_V2_0; +typedef struct _WDF_INTERRUPT_INFO_V2_0 *PWDF_INTERRUPT_INFO_V2_0; +typedef const struct _WDF_INTERRUPT_INFO_V2_0 *PCWDF_INTERRUPT_INFO_V2_0; +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V2_0 *PWDF_INTERRUPT_EXTENDED_POLICY_V2_0; +typedef const struct _WDF_INTERRUPT_EXTENDED_POLICY_V2_0 *PCWDF_INTERRUPT_EXTENDED_POLICY_V2_0; +typedef struct _WDF_IO_QUEUE_CONFIG_V2_0 *PWDF_IO_QUEUE_CONFIG_V2_0; +typedef const struct _WDF_IO_QUEUE_CONFIG_V2_0 *PCWDF_IO_QUEUE_CONFIG_V2_0; +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0 *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0; +typedef const struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0 *PCWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V2_0 *PWDF_IO_TARGET_OPEN_PARAMS_V2_0; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V2_0 *PCWDF_IO_TARGET_OPEN_PARAMS_V2_0; +typedef struct _WDFMEMORY_OFFSET_V2_0 *PWDFMEMORY_OFFSET_V2_0; +typedef const struct _WDFMEMORY_OFFSET_V2_0 *PCWDFMEMORY_OFFSET_V2_0; +typedef struct _WDF_MEMORY_DESCRIPTOR_V2_0 *PWDF_MEMORY_DESCRIPTOR_V2_0; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V2_0 *PCWDF_MEMORY_DESCRIPTOR_V2_0; +typedef struct _WDF_OBJECT_ATTRIBUTES_V2_0 *PWDF_OBJECT_ATTRIBUTES_V2_0; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V2_0 *PCWDF_OBJECT_ATTRIBUTES_V2_0; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V2_0 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V2_0; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V2_0 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V2_0; +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V2_0 *PWDF_CUSTOM_TYPE_CONTEXT_V2_0; +typedef const struct _WDF_CUSTOM_TYPE_CONTEXT_V2_0 *PCWDF_CUSTOM_TYPE_CONTEXT_V2_0; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V2_0 *PWDF_PDO_EVENT_CALLBACKS_V2_0; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V2_0 *PCWDF_PDO_EVENT_CALLBACKS_V2_0; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V2_0 *PWDF_QUERY_INTERFACE_CONFIG_V2_0; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V2_0 *PCWDF_QUERY_INTERFACE_CONFIG_V2_0; +typedef struct _WDF_REQUEST_PARAMETERS_V2_0 *PWDF_REQUEST_PARAMETERS_V2_0; +typedef const struct _WDF_REQUEST_PARAMETERS_V2_0 *PCWDF_REQUEST_PARAMETERS_V2_0; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V2_0 *PWDF_REQUEST_COMPLETION_PARAMS_V2_0; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V2_0 *PCWDF_REQUEST_COMPLETION_PARAMS_V2_0; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V2_0 *PWDF_REQUEST_REUSE_PARAMS_V2_0; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V2_0 *PCWDF_REQUEST_REUSE_PARAMS_V2_0; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V2_0 *PWDF_REQUEST_SEND_OPTIONS_V2_0; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V2_0 *PCWDF_REQUEST_SEND_OPTIONS_V2_0; +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V2_0 *PWDF_REQUEST_FORWARD_OPTIONS_V2_0; +typedef const struct _WDF_REQUEST_FORWARD_OPTIONS_V2_0 *PCWDF_REQUEST_FORWARD_OPTIONS_V2_0; +typedef struct _WDF_TIMER_CONFIG_V2_0 *PWDF_TIMER_CONFIG_V2_0; +typedef const struct _WDF_TIMER_CONFIG_V2_0 *PCWDF_TIMER_CONFIG_V2_0; +typedef struct _WDFOBJECT_TRIAGE_INFO_V2_0 *PWDFOBJECT_TRIAGE_INFO_V2_0; +typedef const struct _WDFOBJECT_TRIAGE_INFO_V2_0 *PCWDFOBJECT_TRIAGE_INFO_V2_0; +typedef struct _WDFCONTEXT_TRIAGE_INFO_V2_0 *PWDFCONTEXT_TRIAGE_INFO_V2_0; +typedef const struct _WDFCONTEXT_TRIAGE_INFO_V2_0 *PCWDFCONTEXT_TRIAGE_INFO_V2_0; +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V2_0 *PWDFCONTEXTTYPE_TRIAGE_INFO_V2_0; +typedef const struct _WDFCONTEXTTYPE_TRIAGE_INFO_V2_0 *PCWDFCONTEXTTYPE_TRIAGE_INFO_V2_0; +typedef struct _WDFQUEUE_TRIAGE_INFO_V2_0 *PWDFQUEUE_TRIAGE_INFO_V2_0; +typedef const struct _WDFQUEUE_TRIAGE_INFO_V2_0 *PCWDFQUEUE_TRIAGE_INFO_V2_0; +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V2_0 *PWDFFWDPROGRESS_TRIAGE_INFO_V2_0; +typedef const struct _WDFFWDPROGRESS_TRIAGE_INFO_V2_0 *PCWDFFWDPROGRESS_TRIAGE_INFO_V2_0; +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V2_0 *PWDFIRPQUEUE_TRIAGE_INFO_V2_0; +typedef const struct _WDFIRPQUEUE_TRIAGE_INFO_V2_0 *PCWDFIRPQUEUE_TRIAGE_INFO_V2_0; +typedef struct _WDFREQUEST_TRIAGE_INFO_V2_0 *PWDFREQUEST_TRIAGE_INFO_V2_0; +typedef const struct _WDFREQUEST_TRIAGE_INFO_V2_0 *PCWDFREQUEST_TRIAGE_INFO_V2_0; +typedef struct _WDFDEVICE_TRIAGE_INFO_V2_0 *PWDFDEVICE_TRIAGE_INFO_V2_0; +typedef const struct _WDFDEVICE_TRIAGE_INFO_V2_0 *PCWDFDEVICE_TRIAGE_INFO_V2_0; +typedef struct _WDFIRP_TRIAGE_INFO_V2_0 *PWDFIRP_TRIAGE_INFO_V2_0; +typedef const struct _WDFIRP_TRIAGE_INFO_V2_0 *PCWDFIRP_TRIAGE_INFO_V2_0; +typedef struct _WDF_TRIAGE_INFO_V2_0 *PWDF_TRIAGE_INFO_V2_0; +typedef const struct _WDF_TRIAGE_INFO_V2_0 *PCWDF_TRIAGE_INFO_V2_0; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V2_0 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V2_0; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V2_0 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V2_0; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V2_0 *PWDF_USB_CONTINUOUS_READER_CONFIG_V2_0; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V2_0 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V2_0; +typedef struct _WDF_USB_DEVICE_INFORMATION_V2_0 *PWDF_USB_DEVICE_INFORMATION_V2_0; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V2_0 *PCWDF_USB_DEVICE_INFORMATION_V2_0; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V2_0 *PWDF_USB_INTERFACE_SETTING_PAIR_V2_0; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V2_0 *PCWDF_USB_INTERFACE_SETTING_PAIR_V2_0; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0; +typedef struct _WDF_USB_PIPE_INFORMATION_V2_0 *PWDF_USB_PIPE_INFORMATION_V2_0; +typedef const struct _WDF_USB_PIPE_INFORMATION_V2_0 *PCWDF_USB_PIPE_INFORMATION_V2_0; +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V2_0 *PWDF_USB_DEVICE_CREATE_CONFIG_V2_0; +typedef const struct _WDF_USB_DEVICE_CREATE_CONFIG_V2_0 *PCWDF_USB_DEVICE_CREATE_CONFIG_V2_0; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V2_0 *PWDF_WMI_PROVIDER_CONFIG_V2_0; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V2_0 *PCWDF_WMI_PROVIDER_CONFIG_V2_0; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V2_0 *PWDF_WMI_INSTANCE_CONFIG_V2_0; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V2_0 *PCWDF_WMI_INSTANCE_CONFIG_V2_0; +typedef struct _WDF_WORKITEM_CONFIG_V2_0 *PWDF_WORKITEM_CONFIG_V2_0; +typedef const struct _WDF_WORKITEM_CONFIG_V2_0 *PCWDF_WORKITEM_CONFIG_V2_0; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_0 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_0; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_0; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V2_0 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V2_0, *PWDF_QUEUE_FATAL_ERROR_DATA_V2_0; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_0 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_0 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V2_0, *PWDF_CHILD_RETRIEVE_INFO_V2_0; + +typedef struct _WDF_CHILD_LIST_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V2_0, *PWDF_CHILD_LIST_CONFIG_V2_0; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V2_0, *PWDF_CHILD_LIST_ITERATOR_V2_0; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfcx.h +// +typedef struct _WDFCX_FILEOBJECT_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDFCX_DEVICE_FILE_CREATE EvtCxDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDFCX_FILEOBJECT_CONFIG_V2_0, *PWDFCX_FILEOBJECT_CONFIG_V2_0; + +// End of versioning of structures for wdfcx.h + +// +// Versioning of structures for wdfcxbase.h +// +typedef struct _WDF_CLASS_VERSION_V2_0 { + WDF_MAJOR_VERSION Major; + + WDF_MINOR_VERSION Minor; + + WDF_BUILD_NUMBER Build; + +} WDF_CLASS_VERSION_V2_0; + +typedef struct _WDF_CLASS_BIND_INFO_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Name of the class to bind to + // + PWSTR ClassName; + + // + // Version information for the class + // + WDF_CLASS_VERSION_V2_0 Version; + + // + // Function export table from the class driver to resolve on bind + // + PFN_WDF_CLASS_EXPORT * FunctionTable; + + // + // Number of entries in FunctionTable + // + ULONG FunctionTableCount; + + // + // Optional field where the client specify additional information + // for the class driver to resolve + // + PVOID ClassBindInfo; + + // + // Optional bind callback. If set, WdfVersionBindClass will not + // be called and it will be up to ClientClassBind to call this function + // if required. + // + PFN_WDF_CLIENT_BIND_CLASS ClientBindClass; + + // + // Optional unbind callback. If set, WdfVersionUnbindClass will not be + // called and it will be up to ClientClassUnbind to call this function + // if required. + // + PFN_WDF_CLIENT_UNBIND_CLASS ClientUnbindClass; + + // + // Diagnostic cookie to use during debugging + // + PVOID ClassModule; + +} WDF_CLASS_BIND_INFO_V2_0, * PWDF_CLASS_BIND_INFO_V2_0; + +typedef struct _WDF_CLASS_LIBRARY_INFO_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Version of this class library + // + WDF_CLASS_VERSION_V2_0 Version; + + // + // Callback to be called by the loader to initialize the class library + // + PFN_WDF_CLASS_LIBRARY_INITIALIZE ClassLibraryInitialize; + + // + // Callback to be called by the loader to deinitialize the class library + // after succesful initialization (immediately before the class library will + // be unloaded). + // + PFN_WDF_CLASS_LIBRARY_DEINITIALIZE ClassLibraryDeinitialize; + + // + // Callback to be called by the loader when a client driver has request to + // be bound to this class library. + // + PFN_WDF_CLASS_LIBRARY_BIND_CLIENT ClassLibraryBindClient; + + // + // Callback to be called by the loader when a previously bound client driver + // is being unloaded. + // + PFN_WDF_CLASS_LIBRARY_UNBIND_CLIENT ClassLibraryUnbindClient; + +} WDF_CLASS_LIBRARY_INFO_V2_0, *PWDF_CLASS_LIBRARY_INFO_V2_0; + +// End of versioning of structures for wdfcxbase.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V2_0, *PWDF_FILEOBJECT_CONFIG_V2_0; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_0 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_0; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_0 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_0; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_0 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_0; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX EvtDeviceUsageNotificationEx; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V2_0, *PWDF_PNPPOWER_EVENT_CALLBACKS_V2_0; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V2_0, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V2_0; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + + // + // This field determines how the IdleTimeout field is used. + // + // If the value is DriverManagedIdleTimeout, then the idle timeout value + // is determined by the IdleTimeout field of this structure. + // + // If the value is SystemManagedIdleTimeout, then the timeout value is + // determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). The IdleTimeout field + // is ignored on these operating systems. On operating systems where the + // PoFx is not available, the behavior is same as DriverManagedIdleTimeout. + // + // If the value is SystemManagedIdleTimeoutWithHint, then the timeout value + // is determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). In addition, the value + // specified in the IdleTimeout field is provided as a hint to the PoFx in + // determining when the device should be allowed to enter a low-power state. + // Since it is only a hint, the actual duration after which the PoFx allows + // the device to enter a low-power state might be greater than or less than + // the IdleTimeout value. On operating systems where the PoFx is not + // available, the behavior is same as DriverManagedIdleTimeout. + // + WDF_POWER_POLICY_IDLE_TIMEOUT_TYPE IdleTimeoutType; + + // + // This field forces the device to avoid idling in the D3cold power state. + // WDF will ensure, with help from the bus drivers, that the device will + // idle in a D-state that can successfully generate a wake signal, if + // necessary. If the client specifies that DxState == PowerDeviceD3, this + // setting allows the client to distinguish betwen D3hot and D3cold. If + // the client sets DxState == PowerDeviceMaximum, then WDF will pick the + // deepest idle state identified by the bus driver. If that deepest state + // is D3cold, this field allows the client to override that and choose + // D3hot. + // + // If WdfTrue, device will not use D3cold in S0. + // If WdfFalse, device will use D3cold in S0 if the ACPI firmware indicates + // that the device can enter that state, if DxState above does not + // specify some other D-state and, if the device is armed for + // wake, that it can generate its wake signal from D3cold. + // If WdfUseDefault, this setting will be derived from the driver's INF, + // specifically the presence or absence of the following two lines in + // the DDInstall.HW section: + // Include=machine.inf + // Needs=PciD3ColdSupported + // + WDF_TRI_STATE ExcludeD3Cold; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_0; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_0; + +typedef struct _WDF_DEVICE_STATE_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V2_0, *PWDF_DEVICE_STATE_V2_0; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V2_0, *PWDF_DEVICE_PNP_CAPABILITIES_V2_0; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V2_0, *PWDF_DEVICE_POWER_CAPABILITIES_V2_0; + +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REMOVE_LOCK_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REMOVE_LOCK_OPTIONS_V2_0, *PWDF_REMOVE_LOCK_OPTIONS_V2_0; + +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V2_0 { + // + // Size of the structure, in bytes. + // + ULONG Size; + + // + // Client driver's callback function that is invoked after KMDF has + // registered with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE EvtDeviceWdmPostPoFxRegisterDevice; + + // + // Client driver's callback function that is invoked before KMDF + // unregisters with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE EvtDeviceWdmPrePoFxUnregisterDevice; + + // + // Pointer to a PO_FX_COMPONENT structure that describes the only component + // in the single-component device. This field can be NULL if the client + // driver wants KMDF to use the default specification for this component + // (i.e. support for F0 only). + // + PPO_FX_COMPONENT Component; + + // + // Client driver's PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_STATE_CALLBACK callback function. + // This field can be NULL if the client driver does not wish to specify + // this callback. + // + PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback; + + // + // Client driver's PO_FX_POWER_CONTROL_CALLBACK callback function. This + // field can be NULL if the client driver does not wish to specify this + // callback. + // + PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + + // + // Context value that is passed in to the ComponentIdleStateCallback and + // PowerControlCallback callback functions. + // + PVOID PoFxDeviceContext; + +} WDF_POWER_FRAMEWORK_SETTINGS_V2_0, *PWDF_POWER_FRAMEWORK_SETTINGS_V2_0; + +typedef struct _WDF_IO_TYPE_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // + // Identifies the method that the driver will use to access data buffers + // that it receives for read and write requests. + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for read and write requests. Note that UMDF + // driver provides just a preference, and not a guarantee.Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE ReadWriteIoType; + + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for IOCTL requests. Note that UMDF + // driver provides just a preference, and not a guarantee. Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE DeviceControlIoType; + + // + // + // Optional, Provides the smallest buffer size (in bytes) for which + // UMDF will use direct access for the buffers. For example, set + // DirectTransferThreshold to "12288" to indicate that UMDF should use buffered + // access for all buffers that are smaller than 12 kilobytes, and direct + // access for buffers equal to or greater than that. Typically, you + // do not need to provide this value because UMDF uses a value that provides + // the best performance. Note that there are other requirements that must be + // met in order to get direct access of buffers. See Docs for details. + // + ULONG DirectTransferThreshold; + +} WDF_IO_TYPE_CONFIG_V2_0, *PWDF_IO_TYPE_CONFIG_V2_0; + +typedef struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0 { + _In_ ULONG Size; + + // + // A pointer to a GUID that identifies the device interface class. + // + _In_ const GUID * InterfaceClassGUID; + + // + // A pointer to a UNICODE_STRING structure that describes a reference + // string for the device interface. This parameter is optional and can + // be NULL. + _In_opt_ PCUNICODE_STRING ReferenceString; + + // + // A pointer to a DEVPROPKEY structure that specifies the device + // property key. + // + _In_ const DEVPROPKEY * PropertyKey; + + // + // A locale identifier. Set this parameter either to a language-specific + // LCID value or to LOCALE_NEUTRAL. The LOCALE_NEUTRAL LCID specifies + // that the property is language-neutral (that is, not specific to any + // language). Do not set this parameter to LOCALE_SYSTEM_DEFAULT or + // LOCALE_USER_DEFAULT. For more information about language-specific + // LCID values, see LCID Structure. + // + _In_ LCID Lcid; + + // + // Set this parameter to PLUGPLAY_PROPERTY_PERSISTENT if the property + // value set by this routine should persist across computer restarts. + // Otherwise, set Flags to zero. Ignored for Query DDIs. + // + _In_ ULONG Flags; + +} WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0, *PWDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_0; + +typedef struct _WDF_DEVICE_PROPERTY_DATA_V2_0 { + // + // Size of this structure + // + _In_ ULONG Size; + + // + // A pointer to a DEVPROPKEY structure that specifies the device + // property key. + // + _In_ const DEVPROPKEY * PropertyKey; + + // + // A locale identifier. Set this parameter either to a language-specific + // LCID value or to LOCALE_NEUTRAL. The LOCALE_NEUTRAL LCID specifies + // that the property is language-neutral (that is, not specific to any + // language). Do not set this parameter to LOCALE_SYSTEM_DEFAULT or + // LOCALE_USER_DEFAULT. For more information about language-specific + // LCID values, see LCID Structure. + // + _In_ LCID Lcid; + + // + // Set this parameter to PLUGPLAY_PROPERTY_PERSISTENT if the property + // value set by this routine should persist across computer restarts. + // Otherwise, set Flags to zero. Ignored for Query DDIs. + // + _In_ ULONG Flags; + +} WDF_DEVICE_PROPERTY_DATA_V2_0, *PWDF_DEVICE_PROPERTY_DATA_V2_0; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V2_0, *PWDF_DRIVER_CONFIG_V2_0; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_0; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V2_0, *PWDF_FDO_EVENT_CALLBACKS_V2_0; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V2_0 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V2_0, *PWDF_DRIVER_GLOBALS_V2_0; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfhwaccess.h +// +// End of versioning of structures for wdfhwaccess.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinternal.h +// +// End of versioning of structures for wdfinternal.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V2_0 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + + // + // TRUE: Interrupt is reported inactive on explicit power down + // instead of disconnecting it. + // FALSE: Interrupt is disconnected instead of reporting inactive + // on explicit power down. + // DEFAULT: Framework decides the right value. + // + WDF_TRI_STATE ReportInactiveOnPowerDown; + + // + // TRUE: Interrupt is used to wake the device from low-power states + // and when the device is armed for wake this interrupt should + // remain connected. + // FALSE: Interrupt is not used to wake the device from low-power states. + // This is the default. + // + BOOLEAN CanWakeDevice; + +} WDF_INTERRUPT_CONFIG_V2_0, *PWDF_INTERRUPT_CONFIG_V2_0; + +typedef struct _WDF_INTERRUPT_INFO_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + + DECLSPEC_ALIGN(8) USHORT Group; + +} WDF_INTERRUPT_INFO_V2_0, *PWDF_INTERRUPT_INFO_V2_0; + +// +// Interrupt Extended Policy Configuration Structure +// +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + WDF_INTERRUPT_POLICY Policy; + + WDF_INTERRUPT_PRIORITY Priority; + + GROUP_AFFINITY TargetProcessorSetAndGroup; + +} WDF_INTERRUPT_EXTENDED_POLICY_V2_0, *PWDF_INTERRUPT_EXTENDED_POLICY_V2_0; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V2_0 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + + WDFDRIVER Driver; + +} WDF_IO_QUEUE_CONFIG_V2_0, *PWDF_IO_QUEUE_CONFIG_V2_0; + +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0 { + ULONG Size; + + ULONG TotalForwardProgressRequests; + + // + // Specify the type of the policy here. + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY ForwardProgressReservedPolicy; + + // + // Structure which contains the policy specific fields + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY_SETTINGS ForwardProgressReservePolicySettings; + + // + // Callback for reserved request given at initialization time + // + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; + + // + // Callback for reserved request given at run time + // + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateRequestResources; + +} WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0, *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_0; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + // + // The requested access to the file or device, which can be summarized as + // read, write, both or neither zero). For more information about + // this member, see the dwDesiredAccess parameter of CreateFile in the + // Windows SDK. Note that ACCESS_MASK data type is a DWORD value. + // + // + ACCESS_MASK DesiredAccess; + + // + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // A zero value means exclusive access to the target. + // + // + // + // The type of sharing to allow for the file. For more information about + // this member, see the dwShareMode parameter of CreateFile in the + // Windows SDK. A value of 0 means exclusive access. + // + // + ULONG ShareAccess; + + // + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // Additional flags and attributes for the file. For more information about + // this member, see the dwFlagsAndAttributes parameter of CreateFile + // in the Windows SDK. + // + // + ULONG FileAttributes; + + // + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // The action to take if the file already exists. For more information + // about this member, see the dwCreationDisposition parameter of + // CreateFile in the Windows SDK. + // + // + ULONG CreateDisposition; + + // + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + // + // + // + PVOID EaBuffer; + + // + // + // + ULONG EaBufferLength; + + // + // + // + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + + // ========== WdfIoTargetOpenLocalTargetByFile begin ========== + // + // + // A UNICODE_STRING-formatted string that contains the + // name of the file to create a file object from. This parameter is + // optional, and is applicable only when Type parameter is + // WdfIoTargetOpenLocalTargetByFile. The driver can leave this member + // unchanged if the driver does not have to create the file object + // from a file name. If the driver must supply a name, the string that + // the driver passes must not contain any path separator characters + // ("/" or "\"). + // + UNICODE_STRING FileName; + +} WDF_IO_TARGET_OPEN_PARAMS_V2_0, *PWDF_IO_TARGET_OPEN_PARAMS_V2_0; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V2_0 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V2_0, *PWDFMEMORY_OFFSET_V2_0; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V2_0 { + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V2_0 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V2_0, *PWDF_MEMORY_DESCRIPTOR_V2_0; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V2_0 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V2_0 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V2_0, *PWDF_OBJECT_ATTRIBUTES_V2_0; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V2_0 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V2_0 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V2_0, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V2_0; + +// +// Core structure for supporting custom types, see macros below. +// +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V2_0 { + ULONG Size; + + ULONG_PTR Data; + +} WDF_CUSTOM_TYPE_CONTEXT_V2_0, *PWDF_CUSTOM_TYPE_CONTEXT_V2_0; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V2_0 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + + // + // Called when reporting the PDO missing to PnP manager in response to + // IRP_MN_QUERY_DEVICE_RELATIONS for Bus Relations. + // + PFN_WDF_DEVICE_REPORTED_MISSING EvtDeviceReportedMissing; + +} WDF_PDO_EVENT_CALLBACKS_V2_0, *PWDF_PDO_EVENT_CALLBACKS_V2_0; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V2_0 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V2_0, *PWDF_QUERY_INTERFACE_CONFIG_V2_0; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V2_0 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V2_0, *PWDF_REQUEST_PARAMETERS_V2_0; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V2_0 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V2_0, *PWDF_REQUEST_COMPLETION_PARAMS_V2_0; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V2_0, *PWDF_REQUEST_REUSE_PARAMS_V2_0; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V2_0, *PWDF_REQUEST_SEND_OPTIONS_V2_0; + +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_FORWARD_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REQUEST_FORWARD_OPTIONS_V2_0, *PWDF_REQUEST_FORWARD_OPTIONS_V2_0; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfroletypes.h +// +// End of versioning of structures for wdfroletypes.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V2_0 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + + // + // If this is TRUE, high resolution timers will be used. The default + // value is FALSE + // + DECLSPEC_ALIGN(8) BOOLEAN UseHighResolutionTimer; + +} WDF_TIMER_CONFIG_V2_0, *PWDF_TIMER_CONFIG_V2_0; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftriage.h +// +typedef struct _WDFOBJECT_TRIAGE_INFO_V2_0 { + // value + ULONG RawObjectSize; + + ULONG ObjectType; + + ULONG TotalObjectSize; + + ULONG ChildListHead; + + ULONG ChildEntry; + + ULONG Globals; + + ULONG ParentObject; + +} WDFOBJECT_TRIAGE_INFO_V2_0, *PWDFOBJECT_TRIAGE_INFO_V2_0; + +typedef struct _WDFCONTEXT_TRIAGE_INFO_V2_0 { + // value + ULONG HeaderSize; + + ULONG NextHeader; + + ULONG Object; + + ULONG TypeInfoPtr; + + ULONG Context; + +} WDFCONTEXT_TRIAGE_INFO_V2_0, *PWDFCONTEXT_TRIAGE_INFO_V2_0; + +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V2_0 { + // value + ULONG TypeInfoSize; + + ULONG ContextSize; + + ULONG ContextName; + +} WDFCONTEXTTYPE_TRIAGE_INFO_V2_0, *PWDFCONTEXTTYPE_TRIAGE_INFO_V2_0; + +typedef struct _WDFQUEUE_TRIAGE_INFO_V2_0 { + // value + ULONG QueueSize; + + ULONG IrpQueue1; + + ULONG IrpQueue2; + + ULONG RequestList1; + + ULONG RequestList2; + + ULONG FwdProgressContext; + + ULONG PkgIo; + +} WDFQUEUE_TRIAGE_INFO_V2_0, *PWDFQUEUE_TRIAGE_INFO_V2_0; + +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V2_0 { + ULONG ReservedRequestList; + + ULONG ReservedRequestInUseList; + + ULONG PendedIrpList; + +} WDFFWDPROGRESS_TRIAGE_INFO_V2_0, *PWDFFWDPROGRESS_TRIAGE_INFO_V2_0; + +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V2_0 { + // value + ULONG IrpQueueSize; + + ULONG IrpListHeader; + + ULONG IrpListEntry; + + ULONG IrpContext; + +} WDFIRPQUEUE_TRIAGE_INFO_V2_0, *PWDFIRPQUEUE_TRIAGE_INFO_V2_0; + +typedef struct _WDFREQUEST_TRIAGE_INFO_V2_0 { + // value + ULONG RequestSize; + + ULONG CsqContext; + + // WDF irp wrapper, see below. + ULONG FxIrp; + + ULONG ListEntryQueueOwned; + + ULONG ListEntryQueueOwned2; + + ULONG RequestListEntry; + + ULONG FwdProgressList; + +} WDFREQUEST_TRIAGE_INFO_V2_0, *PWDFREQUEST_TRIAGE_INFO_V2_0; + +typedef struct _WDFDEVICE_TRIAGE_INFO_V2_0 { + // value + ULONG DeviceInitSize; + + ULONG DeviceDriver; + +} WDFDEVICE_TRIAGE_INFO_V2_0, *PWDFDEVICE_TRIAGE_INFO_V2_0; + +typedef struct _WDFIRP_TRIAGE_INFO_V2_0 { + // value + ULONG FxIrpSize; + + ULONG IrpPtr; + +} WDFIRP_TRIAGE_INFO_V2_0, *PWDFIRP_TRIAGE_INFO_V2_0; + +typedef struct _WDF_TRIAGE_INFO_V2_0 { + // + // Version. + // + ULONG WdfMajorVersion; + + ULONG WdfMinorVersion; + + ULONG TriageInfoMajorVersion; + + ULONG TriageInfoMinorVersion; + + // + // Reserved pointer. + // + PVOID Reserved; + + // + // WDF objects triage info. + // + PWDFOBJECT_TRIAGE_INFO_V2_0 WdfObjectTriageInfo; + + PWDFCONTEXT_TRIAGE_INFO_V2_0 WdfContextTriageInfo; + + PWDFCONTEXTTYPE_TRIAGE_INFO_V2_0 WdfContextTypeTriageInfo; + + PWDFQUEUE_TRIAGE_INFO_V2_0 WdfQueueTriageInfo; + + PWDFFWDPROGRESS_TRIAGE_INFO_V2_0 WdfFwdProgressTriageInfo; + + PWDFIRPQUEUE_TRIAGE_INFO_V2_0 WdfIrpQueueTriageInfo; + + PWDFREQUEST_TRIAGE_INFO_V2_0 WdfRequestTriageInfo; + + PWDFDEVICE_TRIAGE_INFO_V2_0 WdfDeviceTriageInfo; + + PWDFIRP_TRIAGE_INFO_V2_0 WdfIrpTriageInfo; + +} WDF_TRIAGE_INFO_V2_0, *PWDF_TRIAGE_INFO_V2_0; + +// End of versioning of structures for wdftriage.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V2_0 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V2_0, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V2_0; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V2_0 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V2_0 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V2_0, *PWDF_USB_CONTINUOUS_READER_CONFIG_V2_0; + +typedef struct _WDF_USB_DEVICE_INFORMATION_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V2_0, *PWDF_USB_DEVICE_INFORMATION_V2_0; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V2_0 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V2_0, *PWDF_USB_INTERFACE_SETTING_PAIR_V2_0; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V2_0 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_0; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_0; + +typedef struct _WDF_USB_PIPE_INFORMATION_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V2_0, *PWDF_USB_PIPE_INFORMATION_V2_0; + +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD Client Contraction of the Wdf Client + // + ULONG USBDClientContractVersion; + +} WDF_USB_DEVICE_CREATE_CONFIG_V2_0, *PWDF_USB_DEVICE_CREATE_CONFIG_V2_0; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V2_0 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V2_0, *PWDF_WMI_PROVIDER_CONFIG_V2_0; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V2_0 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V2_0 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V2_0, *PWDF_WMI_INSTANCE_CONFIG_V2_0; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V2_0 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V2_0, *PWDF_WORKITEM_CONFIG_V2_0; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V2_0_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/wdf215.h b/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/wdf215.h new file mode 100644 index 00000000000..95401f52acb --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/inc/private/wdf215.h @@ -0,0 +1,2989 @@ +#ifndef _WDF_V2_15_TYPES_H_ +#define _WDF_V2_15_TYPES_H_ + + +typedef enum _WDFFUNCENUM_V2_15 { + WdfFunctionTableNumEntries_V2_15 = 257, +} WDFFUNCENUM_V2_15; + +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_15 *PWDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_15; +typedef const struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_15 *PCWDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_15; +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15 *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15; +typedef const struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15 *PCWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15; +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V2_15 *PWDF_QUEUE_FATAL_ERROR_DATA_V2_15; +typedef const struct _WDF_QUEUE_FATAL_ERROR_DATA_V2_15 *PCWDF_QUEUE_FATAL_ERROR_DATA_V2_15; +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15 *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15; +typedef const struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15 *PCWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15; +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15 *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15; +typedef const struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15 *PCWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15; +typedef struct _WDF_CHILD_RETRIEVE_INFO_V2_15 *PWDF_CHILD_RETRIEVE_INFO_V2_15; +typedef const struct _WDF_CHILD_RETRIEVE_INFO_V2_15 *PCWDF_CHILD_RETRIEVE_INFO_V2_15; +typedef struct _WDF_CHILD_LIST_CONFIG_V2_15 *PWDF_CHILD_LIST_CONFIG_V2_15; +typedef const struct _WDF_CHILD_LIST_CONFIG_V2_15 *PCWDF_CHILD_LIST_CONFIG_V2_15; +typedef struct _WDF_CHILD_LIST_ITERATOR_V2_15 *PWDF_CHILD_LIST_ITERATOR_V2_15; +typedef const struct _WDF_CHILD_LIST_ITERATOR_V2_15 *PCWDF_CHILD_LIST_ITERATOR_V2_15; +typedef struct _WDF_COMMON_BUFFER_CONFIG_V2_15 *PWDF_COMMON_BUFFER_CONFIG_V2_15; +typedef const struct _WDF_COMMON_BUFFER_CONFIG_V2_15 *PCWDF_COMMON_BUFFER_CONFIG_V2_15; +typedef struct _WDFCX_FILEOBJECT_CONFIG_V2_15 *PWDFCX_FILEOBJECT_CONFIG_V2_15; +typedef const struct _WDFCX_FILEOBJECT_CONFIG_V2_15 *PCWDFCX_FILEOBJECT_CONFIG_V2_15; +typedef struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V2_15 *PWDF_CLASS_EXTENSION_DESCRIPTOR_V2_15; +typedef const struct _WDF_CLASS_EXTENSION_DESCRIPTOR_V2_15 *PCWDF_CLASS_EXTENSION_DESCRIPTOR_V2_15; +typedef struct _WDF_CLASS_VERSION_V2_15 *PWDF_CLASS_VERSION_V2_15; +typedef const struct _WDF_CLASS_VERSION_V2_15 *PCWDF_CLASS_VERSION_V2_15; +typedef struct _WDF_CLASS_BIND_INFO_V2_15 *PWDF_CLASS_BIND_INFO_V2_15; +typedef const struct _WDF_CLASS_BIND_INFO_V2_15 *PCWDF_CLASS_BIND_INFO_V2_15; +typedef struct _WDF_CLASS_LIBRARY_INFO_V2_15 *PWDF_CLASS_LIBRARY_INFO_V2_15; +typedef const struct _WDF_CLASS_LIBRARY_INFO_V2_15 *PCWDF_CLASS_LIBRARY_INFO_V2_15; +typedef struct _WDF_FILEOBJECT_CONFIG_V2_15 *PWDF_FILEOBJECT_CONFIG_V2_15; +typedef const struct _WDF_FILEOBJECT_CONFIG_V2_15 *PCWDF_FILEOBJECT_CONFIG_V2_15; +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_15 *PWDF_DEVICE_PNP_NOTIFICATION_DATA_V2_15; +typedef const struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_15 *PCWDF_DEVICE_PNP_NOTIFICATION_DATA_V2_15; +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_15 *PWDF_DEVICE_POWER_NOTIFICATION_DATA_V2_15; +typedef const struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_15 *PCWDF_DEVICE_POWER_NOTIFICATION_DATA_V2_15; +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_15 *PWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_15; +typedef const struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_15 *PCWDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_15; +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V2_15 *PWDF_PNPPOWER_EVENT_CALLBACKS_V2_15; +typedef const struct _WDF_PNPPOWER_EVENT_CALLBACKS_V2_15 *PCWDF_PNPPOWER_EVENT_CALLBACKS_V2_15; +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V2_15 *PWDF_POWER_POLICY_EVENT_CALLBACKS_V2_15; +typedef const struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V2_15 *PCWDF_POWER_POLICY_EVENT_CALLBACKS_V2_15; +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15 *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15; +typedef const struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15 *PCWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15; +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15 *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15; +typedef const struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15 *PCWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15; +typedef struct _WDF_DEVICE_STATE_V2_15 *PWDF_DEVICE_STATE_V2_15; +typedef const struct _WDF_DEVICE_STATE_V2_15 *PCWDF_DEVICE_STATE_V2_15; +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V2_15 *PWDF_DEVICE_PNP_CAPABILITIES_V2_15; +typedef const struct _WDF_DEVICE_PNP_CAPABILITIES_V2_15 *PCWDF_DEVICE_PNP_CAPABILITIES_V2_15; +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V2_15 *PWDF_DEVICE_POWER_CAPABILITIES_V2_15; +typedef const struct _WDF_DEVICE_POWER_CAPABILITIES_V2_15 *PCWDF_DEVICE_POWER_CAPABILITIES_V2_15; +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V2_15 *PWDF_REMOVE_LOCK_OPTIONS_V2_15; +typedef const struct _WDF_REMOVE_LOCK_OPTIONS_V2_15 *PCWDF_REMOVE_LOCK_OPTIONS_V2_15; +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V2_15 *PWDF_POWER_FRAMEWORK_SETTINGS_V2_15; +typedef const struct _WDF_POWER_FRAMEWORK_SETTINGS_V2_15 *PCWDF_POWER_FRAMEWORK_SETTINGS_V2_15; +typedef struct _WDF_IO_TYPE_CONFIG_V2_15 *PWDF_IO_TYPE_CONFIG_V2_15; +typedef const struct _WDF_IO_TYPE_CONFIG_V2_15 *PCWDF_IO_TYPE_CONFIG_V2_15; +typedef struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15 *PWDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15; +typedef const struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15 *PCWDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15; +typedef struct _WDF_DEVICE_PROPERTY_DATA_V2_15 *PWDF_DEVICE_PROPERTY_DATA_V2_15; +typedef const struct _WDF_DEVICE_PROPERTY_DATA_V2_15 *PCWDF_DEVICE_PROPERTY_DATA_V2_15; +typedef struct _WDF_DMA_ENABLER_CONFIG_V2_15 *PWDF_DMA_ENABLER_CONFIG_V2_15; +typedef const struct _WDF_DMA_ENABLER_CONFIG_V2_15 *PCWDF_DMA_ENABLER_CONFIG_V2_15; +typedef struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V2_15 *PWDF_DMA_SYSTEM_PROFILE_CONFIG_V2_15; +typedef const struct _WDF_DMA_SYSTEM_PROFILE_CONFIG_V2_15 *PCWDF_DMA_SYSTEM_PROFILE_CONFIG_V2_15; +typedef struct _WDF_DPC_CONFIG_V2_15 *PWDF_DPC_CONFIG_V2_15; +typedef const struct _WDF_DPC_CONFIG_V2_15 *PCWDF_DPC_CONFIG_V2_15; +typedef struct _WDF_DRIVER_CONFIG_V2_15 *PWDF_DRIVER_CONFIG_V2_15; +typedef const struct _WDF_DRIVER_CONFIG_V2_15 *PCWDF_DRIVER_CONFIG_V2_15; +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15 *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15; +typedef const struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15 *PCWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15; +typedef struct _WDF_FDO_EVENT_CALLBACKS_V2_15 *PWDF_FDO_EVENT_CALLBACKS_V2_15; +typedef const struct _WDF_FDO_EVENT_CALLBACKS_V2_15 *PCWDF_FDO_EVENT_CALLBACKS_V2_15; +typedef struct _WDF_DRIVER_GLOBALS_V2_15 *PWDF_DRIVER_GLOBALS_V2_15; +typedef const struct _WDF_DRIVER_GLOBALS_V2_15 *PCWDF_DRIVER_GLOBALS_V2_15; +typedef struct _WDF_INTERRUPT_CONFIG_V2_15 *PWDF_INTERRUPT_CONFIG_V2_15; +typedef const struct _WDF_INTERRUPT_CONFIG_V2_15 *PCWDF_INTERRUPT_CONFIG_V2_15; +typedef struct _WDF_INTERRUPT_INFO_V2_15 *PWDF_INTERRUPT_INFO_V2_15; +typedef const struct _WDF_INTERRUPT_INFO_V2_15 *PCWDF_INTERRUPT_INFO_V2_15; +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V2_15 *PWDF_INTERRUPT_EXTENDED_POLICY_V2_15; +typedef const struct _WDF_INTERRUPT_EXTENDED_POLICY_V2_15 *PCWDF_INTERRUPT_EXTENDED_POLICY_V2_15; +typedef struct _WDF_IO_QUEUE_CONFIG_V2_15 *PWDF_IO_QUEUE_CONFIG_V2_15; +typedef const struct _WDF_IO_QUEUE_CONFIG_V2_15 *PCWDF_IO_QUEUE_CONFIG_V2_15; +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15 *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15; +typedef const struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15 *PCWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15; +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V2_15 *PWDF_IO_TARGET_OPEN_PARAMS_V2_15; +typedef const struct _WDF_IO_TARGET_OPEN_PARAMS_V2_15 *PCWDF_IO_TARGET_OPEN_PARAMS_V2_15; +typedef struct _WDFMEMORY_OFFSET_V2_15 *PWDFMEMORY_OFFSET_V2_15; +typedef const struct _WDFMEMORY_OFFSET_V2_15 *PCWDFMEMORY_OFFSET_V2_15; +typedef struct _WDF_MEMORY_DESCRIPTOR_V2_15 *PWDF_MEMORY_DESCRIPTOR_V2_15; +typedef const struct _WDF_MEMORY_DESCRIPTOR_V2_15 *PCWDF_MEMORY_DESCRIPTOR_V2_15; +typedef struct _WDF_OBJECT_ATTRIBUTES_V2_15 *PWDF_OBJECT_ATTRIBUTES_V2_15; +typedef const struct _WDF_OBJECT_ATTRIBUTES_V2_15 *PCWDF_OBJECT_ATTRIBUTES_V2_15; +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V2_15 *PWDF_OBJECT_CONTEXT_TYPE_INFO_V2_15; +typedef const struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V2_15 *PCWDF_OBJECT_CONTEXT_TYPE_INFO_V2_15; +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V2_15 *PWDF_CUSTOM_TYPE_CONTEXT_V2_15; +typedef const struct _WDF_CUSTOM_TYPE_CONTEXT_V2_15 *PCWDF_CUSTOM_TYPE_CONTEXT_V2_15; +typedef struct _WDF_PDO_EVENT_CALLBACKS_V2_15 *PWDF_PDO_EVENT_CALLBACKS_V2_15; +typedef const struct _WDF_PDO_EVENT_CALLBACKS_V2_15 *PCWDF_PDO_EVENT_CALLBACKS_V2_15; +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V2_15 *PWDF_QUERY_INTERFACE_CONFIG_V2_15; +typedef const struct _WDF_QUERY_INTERFACE_CONFIG_V2_15 *PCWDF_QUERY_INTERFACE_CONFIG_V2_15; +typedef struct _WDF_REQUEST_PARAMETERS_V2_15 *PWDF_REQUEST_PARAMETERS_V2_15; +typedef const struct _WDF_REQUEST_PARAMETERS_V2_15 *PCWDF_REQUEST_PARAMETERS_V2_15; +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V2_15 *PWDF_REQUEST_COMPLETION_PARAMS_V2_15; +typedef const struct _WDF_REQUEST_COMPLETION_PARAMS_V2_15 *PCWDF_REQUEST_COMPLETION_PARAMS_V2_15; +typedef struct _WDF_REQUEST_REUSE_PARAMS_V2_15 *PWDF_REQUEST_REUSE_PARAMS_V2_15; +typedef const struct _WDF_REQUEST_REUSE_PARAMS_V2_15 *PCWDF_REQUEST_REUSE_PARAMS_V2_15; +typedef struct _WDF_REQUEST_SEND_OPTIONS_V2_15 *PWDF_REQUEST_SEND_OPTIONS_V2_15; +typedef const struct _WDF_REQUEST_SEND_OPTIONS_V2_15 *PCWDF_REQUEST_SEND_OPTIONS_V2_15; +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V2_15 *PWDF_REQUEST_FORWARD_OPTIONS_V2_15; +typedef const struct _WDF_REQUEST_FORWARD_OPTIONS_V2_15 *PCWDF_REQUEST_FORWARD_OPTIONS_V2_15; +typedef struct _WDF_TIMER_CONFIG_V2_15 *PWDF_TIMER_CONFIG_V2_15; +typedef const struct _WDF_TIMER_CONFIG_V2_15 *PCWDF_TIMER_CONFIG_V2_15; +typedef struct _WDFOBJECT_TRIAGE_INFO_V2_15 *PWDFOBJECT_TRIAGE_INFO_V2_15; +typedef const struct _WDFOBJECT_TRIAGE_INFO_V2_15 *PCWDFOBJECT_TRIAGE_INFO_V2_15; +typedef struct _WDFCONTEXT_TRIAGE_INFO_V2_15 *PWDFCONTEXT_TRIAGE_INFO_V2_15; +typedef const struct _WDFCONTEXT_TRIAGE_INFO_V2_15 *PCWDFCONTEXT_TRIAGE_INFO_V2_15; +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V2_15 *PWDFCONTEXTTYPE_TRIAGE_INFO_V2_15; +typedef const struct _WDFCONTEXTTYPE_TRIAGE_INFO_V2_15 *PCWDFCONTEXTTYPE_TRIAGE_INFO_V2_15; +typedef struct _WDFQUEUE_TRIAGE_INFO_V2_15 *PWDFQUEUE_TRIAGE_INFO_V2_15; +typedef const struct _WDFQUEUE_TRIAGE_INFO_V2_15 *PCWDFQUEUE_TRIAGE_INFO_V2_15; +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V2_15 *PWDFFWDPROGRESS_TRIAGE_INFO_V2_15; +typedef const struct _WDFFWDPROGRESS_TRIAGE_INFO_V2_15 *PCWDFFWDPROGRESS_TRIAGE_INFO_V2_15; +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V2_15 *PWDFIRPQUEUE_TRIAGE_INFO_V2_15; +typedef const struct _WDFIRPQUEUE_TRIAGE_INFO_V2_15 *PCWDFIRPQUEUE_TRIAGE_INFO_V2_15; +typedef struct _WDFREQUEST_TRIAGE_INFO_V2_15 *PWDFREQUEST_TRIAGE_INFO_V2_15; +typedef const struct _WDFREQUEST_TRIAGE_INFO_V2_15 *PCWDFREQUEST_TRIAGE_INFO_V2_15; +typedef struct _WDFDEVICE_TRIAGE_INFO_V2_15 *PWDFDEVICE_TRIAGE_INFO_V2_15; +typedef const struct _WDFDEVICE_TRIAGE_INFO_V2_15 *PCWDFDEVICE_TRIAGE_INFO_V2_15; +typedef struct _WDFIRP_TRIAGE_INFO_V2_15 *PWDFIRP_TRIAGE_INFO_V2_15; +typedef const struct _WDFIRP_TRIAGE_INFO_V2_15 *PCWDFIRP_TRIAGE_INFO_V2_15; +typedef struct _WDF_TRIAGE_INFO_V2_15 *PWDF_TRIAGE_INFO_V2_15; +typedef const struct _WDF_TRIAGE_INFO_V2_15 *PCWDF_TRIAGE_INFO_V2_15; +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V2_15 *PWDF_USB_REQUEST_COMPLETION_PARAMS_V2_15; +typedef const struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V2_15 *PCWDF_USB_REQUEST_COMPLETION_PARAMS_V2_15; +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V2_15 *PWDF_USB_CONTINUOUS_READER_CONFIG_V2_15; +typedef const struct _WDF_USB_CONTINUOUS_READER_CONFIG_V2_15 *PCWDF_USB_CONTINUOUS_READER_CONFIG_V2_15; +typedef struct _WDF_USB_DEVICE_INFORMATION_V2_15 *PWDF_USB_DEVICE_INFORMATION_V2_15; +typedef const struct _WDF_USB_DEVICE_INFORMATION_V2_15 *PCWDF_USB_DEVICE_INFORMATION_V2_15; +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V2_15 *PWDF_USB_INTERFACE_SETTING_PAIR_V2_15; +typedef const struct _WDF_USB_INTERFACE_SETTING_PAIR_V2_15 *PCWDF_USB_INTERFACE_SETTING_PAIR_V2_15; +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15 *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15; +typedef const struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15 *PCWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15; +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15 *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15; +typedef const struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15 *PCWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15; +typedef struct _WDF_USB_PIPE_INFORMATION_V2_15 *PWDF_USB_PIPE_INFORMATION_V2_15; +typedef const struct _WDF_USB_PIPE_INFORMATION_V2_15 *PCWDF_USB_PIPE_INFORMATION_V2_15; +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V2_15 *PWDF_USB_DEVICE_CREATE_CONFIG_V2_15; +typedef const struct _WDF_USB_DEVICE_CREATE_CONFIG_V2_15 *PCWDF_USB_DEVICE_CREATE_CONFIG_V2_15; +typedef struct _WDF_WMI_PROVIDER_CONFIG_V2_15 *PWDF_WMI_PROVIDER_CONFIG_V2_15; +typedef const struct _WDF_WMI_PROVIDER_CONFIG_V2_15 *PCWDF_WMI_PROVIDER_CONFIG_V2_15; +typedef struct _WDF_WMI_INSTANCE_CONFIG_V2_15 *PWDF_WMI_INSTANCE_CONFIG_V2_15; +typedef const struct _WDF_WMI_INSTANCE_CONFIG_V2_15 *PCWDF_WMI_INSTANCE_CONFIG_V2_15; +typedef struct _WDF_WORKITEM_CONFIG_V2_15 *PWDF_WORKITEM_CONFIG_V2_15; +typedef const struct _WDF_WORKITEM_CONFIG_V2_15 *PCWDF_WORKITEM_CONFIG_V2_15; + +// +// Versioning of structures for wdf.h +// +// End of versioning of structures for wdf.h + +// +// Versioning of structures for wdfassert.h +// +// End of versioning of structures for wdfassert.h + +// +// Versioning of structures for wdfbugcodes.h +// +typedef struct _WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_15 { + // + // Current power state associated with the timed out device + // + WDF_DEVICE_POWER_STATE PowerState; + + // + // Current power policy state associated with the timed out device + // + WDF_DEVICE_POWER_POLICY_STATE PowerPolicyState; + + // + // The device object for the timed out device + // + PDEVICE_OBJECT DeviceObject; + + // + // The handle for the timed out device + // + WDFDEVICE Device; + + // + // The thread which is stuck + // + PKTHREAD TimedOutThread; + +} WDF_POWER_ROUTINE_TIMED_OUT_DATA_V2_15; + +typedef struct _WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15 { + WDFREQUEST Request; + + PIRP Irp; + + ULONG OutputBufferLength; + + ULONG_PTR Information; + + UCHAR MajorFunction; + +} WDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15, *PWDF_REQUEST_FATAL_ERROR_INFORMATION_LENGTH_MISMATCH_DATA_V2_15; + +typedef struct _WDF_QUEUE_FATAL_ERROR_DATA_V2_15 { + WDFQUEUE Queue; + + WDFREQUEST Request; + + NTSTATUS Status; + +} WDF_QUEUE_FATAL_ERROR_DATA_V2_15, *PWDF_QUEUE_FATAL_ERROR_DATA_V2_15; + +// End of versioning of structures for wdfbugcodes.h + +// +// Versioning of structures for wdfchildlist.h +// +typedef struct _WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::IdentificationDescriptionSize + // Used as a sanity check. + // + ULONG IdentificationDescriptionSize; + +} WDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15, *PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15; + +typedef struct _WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15 { + // + // Size in bytes of the entire description, including this header. + // + // Same value as WDF_CHILD_LIST_CONFIG::AddressDescriptionSize + // Used as a sanity check. + // + ULONG AddressDescriptionSize; + +} WDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15, *PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15; + +typedef struct _WDF_CHILD_RETRIEVE_INFO_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Must be a valid pointer when passed in, copied into upon success + // + PWDF_CHILD_IDENTIFICATION_DESCRIPTION_HEADER_V2_15 IdentificationDescription; + + // + // Optional pointer when passed in, copied into upon success + // + PWDF_CHILD_ADDRESS_DESCRIPTION_HEADER_V2_15 AddressDescription; + + // + // Status of the returned device + // + WDF_CHILD_LIST_RETRIEVE_DEVICE_STATUS Status; + + // + // If provided, will be used for searching through the list of devices + // instead of the default list ID compare function + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + +} WDF_CHILD_RETRIEVE_INFO_V2_15, *PWDF_CHILD_RETRIEVE_INFO_V2_15; + +typedef struct _WDF_CHILD_LIST_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The size in bytes of an identificaiton description to be used with the + // created WDFCHILDLIST handle + // + ULONG IdentificationDescriptionSize; + + // + // Optional size in bytes of an address description to be used with the + // created WDFCHILDLIST handle. + // + ULONG AddressDescriptionSize; + + // + // Required callback to be invoked when a description on the device list + // needs to be converted into a real WDFDEVICE handle. + // + PFN_WDF_CHILD_LIST_CREATE_DEVICE EvtChildListCreateDevice; + + // + // Optional callback to be invoked when the device list needs to be + // rescanned. This function will be called after the device has entered D0 + // and been fully initialized but before I/O has started. + // + PFN_WDF_CHILD_LIST_SCAN_FOR_CHILDREN EvtChildListScanForChildren; + + // + // Optional callback to be invoked when an identification description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COPY EvtChildListIdentificationDescriptionCopy; + + // + // Optional callback to be invoked when an identification description needs + // to be duplicated. As opposed to EvtChildListIdentificationDescriptionCopy, + // EvtChildListIdentificationDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_DUPLICATE EvtChildListIdentificationDescriptionDuplicate; + + // + // Optional callback to be invoked when an identification description needs + // to be cleaned up. This function should *NOT* free the description passed + // to it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_CLEANUP EvtChildListIdentificationDescriptionCleanup; + + // + // Optional callback to be invoked when an identification description needs + // to be compared with another identificaiton description. + // + // If left NULL, RtlCompareMemory will be used to compare the two + // descriptions. + // + PFN_WDF_CHILD_LIST_IDENTIFICATION_DESCRIPTION_COMPARE EvtChildListIdentificationDescriptionCompare; + + // + // Optional callback to be invoked when an address description needs + // to be copied from one location to another. + // + // If left NULL, RtlCopyMemory will be used to copy the description. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_COPY EvtChildListAddressDescriptionCopy; + + // + // Optional callback to be invoked when an address description needs to be + // duplicated. As opposed to EvtChildListAddressDescriptionCopy, + // EvtChildListAddressDescriptionDuplicate can fail. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_DUPLICATE EvtChildListAddressDescriptionDuplicate; + + // + // Optional callback to be invoked when an address description needs to be + // cleaned up. This function should *NOT* free the description passed to + // it, just free any associated resources. + // + PFN_WDF_CHILD_LIST_ADDRESS_DESCRIPTION_CLEANUP EvtChildListAddressDescriptionCleanup; + + // + // If provided, will be called when the child's stack requests that the + // child be reenumerated. Returning TRUE allows for the reenumeration to + // proceed. FALSE will no reenumerate the stack. + // + PFN_WDF_CHILD_LIST_DEVICE_REENUMERATED EvtChildListDeviceReenumerated; + +} WDF_CHILD_LIST_CONFIG_V2_15, *PWDF_CHILD_LIST_CONFIG_V2_15; + +typedef struct _WDF_CHILD_LIST_ITERATOR_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // What type of devices to return, see WDF_RETRIEVE_CHILD_FLAGS for + // flag values + // + // + ULONG Flags; + + // + // For internal use, treat this field as opaque + // + PVOID Reserved[4]; + +} WDF_CHILD_LIST_ITERATOR_V2_15, *PWDF_CHILD_LIST_ITERATOR_V2_15; + +// End of versioning of structures for wdfchildlist.h + +// +// Versioning of structures for wdfcollection.h +// +// End of versioning of structures for wdfcollection.h + +// +// Versioning of structures for wdfCommonBuffer.h +// +// End of versioning of structures for wdfCommonBuffer.h + +// +// Versioning of structures for wdfcontrol.h +// +// End of versioning of structures for wdfcontrol.h + +// +// Versioning of structures for wdfcore.h +// +// End of versioning of structures for wdfcore.h + +// +// Versioning of structures for wdfcx.h +// +typedef struct _WDFCX_FILEOBJECT_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDFCX_DEVICE_FILE_CREATE EvtCxDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDFCX_FILEOBJECT_CONFIG_V2_15, *PWDFCX_FILEOBJECT_CONFIG_V2_15; + +// End of versioning of structures for wdfcx.h + +// +// Versioning of structures for wdfcxbase.h +// +typedef struct _WDF_CLASS_VERSION_V2_15 { + WDF_MAJOR_VERSION Major; + + WDF_MINOR_VERSION Minor; + + WDF_BUILD_NUMBER Build; + +} WDF_CLASS_VERSION_V2_15; + +typedef struct _WDF_CLASS_BIND_INFO_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Name of the class to bind to + // + PWSTR ClassName; + + // + // Version information for the class + // + WDF_CLASS_VERSION_V2_15 Version; + + // + // Function export table from the class driver to resolve on bind + // + PFN_WDF_CLASS_EXPORT * FunctionTable; + + // + // Number of entries in FunctionTable + // + ULONG FunctionTableCount; + + // + // Optional field where the client specify additional information + // for the class driver to resolve + // + PVOID ClassBindInfo; + + // + // Optional bind callback. If set, WdfVersionBindClass will not + // be called and it will be up to ClientClassBind to call this function + // if required. + // + PFN_WDF_CLIENT_BIND_CLASS ClientBindClass; + + // + // Optional unbind callback. If set, WdfVersionUnbindClass will not be + // called and it will be up to ClientClassUnbind to call this function + // if required. + // + PFN_WDF_CLIENT_UNBIND_CLASS ClientUnbindClass; + + // + // Diagnostic cookie to use during debugging + // + PVOID ClassModule; + +} WDF_CLASS_BIND_INFO_V2_15, * PWDF_CLASS_BIND_INFO_V2_15; + +typedef struct _WDF_CLASS_LIBRARY_INFO_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Version of this class library + // + WDF_CLASS_VERSION_V2_15 Version; + + // + // Callback to be called by the loader to initialize the class library + // + PFN_WDF_CLASS_LIBRARY_INITIALIZE ClassLibraryInitialize; + + // + // Callback to be called by the loader to deinitialize the class library + // after succesful initialization (immediately before the class library will + // be unloaded). + // + PFN_WDF_CLASS_LIBRARY_DEINITIALIZE ClassLibraryDeinitialize; + + // + // Callback to be called by the loader when a client driver has request to + // be bound to this class library. + // + PFN_WDF_CLASS_LIBRARY_BIND_CLIENT ClassLibraryBindClient; + + // + // Callback to be called by the loader when a previously bound client driver + // is being unloaded. + // + PFN_WDF_CLASS_LIBRARY_UNBIND_CLIENT ClassLibraryUnbindClient; + +} WDF_CLASS_LIBRARY_INFO_V2_15, *PWDF_CLASS_LIBRARY_INFO_V2_15; + +// End of versioning of structures for wdfcxbase.h + +// +// Versioning of structures for wdfDevice.h +// +typedef struct _WDF_FILEOBJECT_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callback for create requests + // + PFN_WDF_DEVICE_FILE_CREATE EvtDeviceFileCreate; + + // + // Event callback for close requests + // + PFN_WDF_FILE_CLOSE EvtFileClose; + + // + // Event callback for cleanup requests + // + PFN_WDF_FILE_CLEANUP EvtFileCleanup; + + // + // If WdfTrue, create/cleanup/close file object related requests will be + // sent down the stack. + // + // If WdfFalse, create/cleanup/close will be completed at this location in + // the device stack. + // + // If WdfDefault, behavior depends on device type + // FDO, PDO, Control: use the WdfFalse behavior + // Filter: use the WdfTrue behavior + // + WDF_TRI_STATE AutoForwardCleanupClose; + + // + // Specify whether framework should create WDFFILEOBJECT and also + // whether it can FsContexts fields in the WDM fileobject to store + // WDFFILEOBJECT so that it can avoid table look up and improve perf. + // + WDF_FILEOBJECT_CLASS FileObjectClass; + +} WDF_FILEOBJECT_CONFIG_V2_15, *PWDF_FILEOBJECT_CONFIG_V2_15; + +typedef struct _WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_15 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exited + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_PNP_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_PNP_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_PNP_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_PNP_NOTIFICATION_DATA_V2_15; + +typedef struct _WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_15 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_NOTIFICATION_DATA_V2_15; + +typedef struct _WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_15 { + // + // Type of data + // + WDF_STATE_NOTIFICATION_TYPE Type; + + union { + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The new state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } EnterState; + + struct { + // + // The current state + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + } PostProcessState; + + struct { + // + // The current state that is about to be exitted + // + WDF_DEVICE_POWER_POLICY_STATE CurrentState; + + // + // The state that is about to be entered + // + WDF_DEVICE_POWER_POLICY_STATE NewState; + + } LeaveState; + + } Data; + +} WDF_DEVICE_POWER_POLICY_NOTIFICATION_DATA_V2_15; + +typedef struct _WDF_PNPPOWER_EVENT_CALLBACKS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_D0_ENTRY EvtDeviceD0Entry; + + PFN_WDF_DEVICE_D0_ENTRY_POST_INTERRUPTS_ENABLED EvtDeviceD0EntryPostInterruptsEnabled; + + PFN_WDF_DEVICE_D0_EXIT EvtDeviceD0Exit; + + PFN_WDF_DEVICE_D0_EXIT_PRE_INTERRUPTS_DISABLED EvtDeviceD0ExitPreInterruptsDisabled; + + PFN_WDF_DEVICE_PREPARE_HARDWARE EvtDevicePrepareHardware; + + PFN_WDF_DEVICE_RELEASE_HARDWARE EvtDeviceReleaseHardware; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_CLEANUP EvtDeviceSelfManagedIoCleanup; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_FLUSH EvtDeviceSelfManagedIoFlush; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_INIT EvtDeviceSelfManagedIoInit; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_SUSPEND EvtDeviceSelfManagedIoSuspend; + + PFN_WDF_DEVICE_SELF_MANAGED_IO_RESTART EvtDeviceSelfManagedIoRestart; + + PFN_WDF_DEVICE_SURPRISE_REMOVAL EvtDeviceSurpriseRemoval; + + PFN_WDF_DEVICE_QUERY_REMOVE EvtDeviceQueryRemove; + + PFN_WDF_DEVICE_QUERY_STOP EvtDeviceQueryStop; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION EvtDeviceUsageNotification; + + PFN_WDF_DEVICE_RELATIONS_QUERY EvtDeviceRelationsQuery; + + PFN_WDF_DEVICE_USAGE_NOTIFICATION_EX EvtDeviceUsageNotificationEx; + +} WDF_PNPPOWER_EVENT_CALLBACKS_V2_15, *PWDF_PNPPOWER_EVENT_CALLBACKS_V2_15; + +typedef struct _WDF_POWER_POLICY_EVENT_CALLBACKS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_S0 EvtDeviceArmWakeFromS0; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_S0 EvtDeviceDisarmWakeFromS0; + + PFN_WDF_DEVICE_WAKE_FROM_S0_TRIGGERED EvtDeviceWakeFromS0Triggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX EvtDeviceArmWakeFromSx; + + PFN_WDF_DEVICE_DISARM_WAKE_FROM_SX EvtDeviceDisarmWakeFromSx; + + PFN_WDF_DEVICE_WAKE_FROM_SX_TRIGGERED EvtDeviceWakeFromSxTriggered; + + PFN_WDF_DEVICE_ARM_WAKE_FROM_SX_WITH_REASON EvtDeviceArmWakeFromSxWithReason; + +} WDF_POWER_POLICY_EVENT_CALLBACKS_V2_15, *PWDF_POWER_POLICY_EVENT_CALLBACKS_V2_15; + +typedef struct _WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates whether the device can wake itself up while the machine is in + // S0. + // + WDF_POWER_POLICY_S0_IDLE_CAPABILITIES IdleCaps; + + // + // The low power state in which the device will be placed when it is idled + // out while the machine is in S0. + // + DEVICE_POWER_STATE DxState; + + // + // Amount of time the device must be idle before idling out. Timeout is in + // milliseconds. + // + ULONG IdleTimeout; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_S0_IDLE_USER_CONTROL UserControlOfIdleSettings; + + // + // If WdfTrue, idling out while the machine is in S0 will be enabled. + // + // If WdfFalse, idling out will be disabled. + // + // If WdfUseDefault, the idling out will be enabled. If + // UserControlOfIdleSettings is set to IdleAllowUserControl, the user's + // settings will override the default. + // + WDF_TRI_STATE Enabled; + + // + // This field is applicable only when IdleCaps == IdleCannotWakeFromS0 + // If WdfTrue,device is powered up on System Wake even if device is idle + // If WdfFalse, device is not powered up on system wake if it is idle + // If WdfUseDefault, the behavior is same as WdfFalse + // + WDF_TRI_STATE PowerUpIdleDeviceOnSystemWake; + + // + // This field determines how the IdleTimeout field is used. + // + // If the value is DriverManagedIdleTimeout, then the idle timeout value + // is determined by the IdleTimeout field of this structure. + // + // If the value is SystemManagedIdleTimeout, then the timeout value is + // determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). The IdleTimeout field + // is ignored on these operating systems. On operating systems where the + // PoFx is not available, the behavior is same as DriverManagedIdleTimeout. + // + // If the value is SystemManagedIdleTimeoutWithHint, then the timeout value + // is determined by the power framework (PoFx) on operating systems where + // the PoFx is available (i.e. Windows 8 and later). In addition, the value + // specified in the IdleTimeout field is provided as a hint to the PoFx in + // determining when the device should be allowed to enter a low-power state. + // Since it is only a hint, the actual duration after which the PoFx allows + // the device to enter a low-power state might be greater than or less than + // the IdleTimeout value. On operating systems where the PoFx is not + // available, the behavior is same as DriverManagedIdleTimeout. + // + WDF_POWER_POLICY_IDLE_TIMEOUT_TYPE IdleTimeoutType; + + // + // This field forces the device to avoid idling in the D3cold power state. + // WDF will ensure, with help from the bus drivers, that the device will + // idle in a D-state that can successfully generate a wake signal, if + // necessary. If the client specifies that DxState == PowerDeviceD3, this + // setting allows the client to distinguish betwen D3hot and D3cold. If + // the client sets DxState == PowerDeviceMaximum, then WDF will pick the + // deepest idle state identified by the bus driver. If that deepest state + // is D3cold, this field allows the client to override that and choose + // D3hot. + // + // If WdfTrue, device will not use D3cold in S0. + // If WdfFalse, device will use D3cold in S0 if the ACPI firmware indicates + // that the device can enter that state, if DxState above does not + // specify some other D-state and, if the device is armed for + // wake, that it can generate its wake signal from D3cold. + // If WdfUseDefault, this setting will be derived from the driver's INF, + // specifically the presence or absence of the following two lines in + // the DDInstall.HW section: + // Include=machine.inf + // Needs=PciD3ColdSupported + // + WDF_TRI_STATE ExcludeD3Cold; + +} WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15, *PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_V2_15; + +typedef struct _WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The low power state in which the device will be placed when it is armed + // for wake from Sx. + // + DEVICE_POWER_STATE DxState; + + // + // Inidcates whether a user can control the idle policy of the device. + // By default, a user is allowed to change the policy. + // + WDF_POWER_POLICY_SX_WAKE_USER_CONTROL UserControlOfWakeSettings; + + // + // If WdfTrue, arming the device for wake while the machine is in Sx is + // enabled. + // + // If WdfFalse, arming the device for wake while the machine is in Sx is + // disabled. + // + // If WdfUseDefault, arming will be enabled. If UserControlOfWakeSettings + // is set to WakeAllowUserControl, the user's settings will override the + // default. + // + WDF_TRI_STATE Enabled; + + // + // If set to TRUE, arming the parent device can depend on whether there + // is atleast one child device armed for wake. + // + // If set to FALSE, arming of the parent device will be independent of + // whether any of the child devices are armed for wake. + // + BOOLEAN ArmForWakeIfChildrenAreArmedForWake; + + // + // Indicates that whenever the parent device completes the wake irp + // successfully, the status needs to be also propagated to the child + // devices. This helps in tracking which devices were responsible for + // waking the system. + // + BOOLEAN IndicateChildWakeOnParentWake; + +} WDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15, *PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS_V2_15; + +typedef struct _WDF_DEVICE_STATE_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // If set to WdfTrue, the device will be disabled + // + WDF_TRI_STATE Disabled; + + // + // If set to WdfTrue, the device will not be displayed in device manager. + // Once hidden, the device cannot be unhidden. + // + WDF_TRI_STATE DontDisplayInUI; + + // + // If set to WdfTrue, the device is reporting itself as failed. If set + // in conjuction with ResourcesChanged to WdfTrue, the device will receive + // a PnP stop and then a new PnP start device. + // + WDF_TRI_STATE Failed; + + // + // If set to WdfTrue, the device cannot be subsequently disabled. + // + WDF_TRI_STATE NotDisableable; + + + + + // + // + // If set to WdfTrue, the device stack will be torn down. + // + WDF_TRI_STATE Removed; + + // + // If set to WdfTrue, the device will be sent another PnP start. If the + // Failed field is set to WdfTrue as well, a PnP stop will be sent before + // the start. + // + WDF_TRI_STATE ResourcesChanged; + +} WDF_DEVICE_STATE_V2_15, *PWDF_DEVICE_STATE_V2_15; + +typedef struct _WDF_DEVICE_PNP_CAPABILITIES_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // NOTE: To mark a PDO as raw, call WdfPdoInitAssignRawDevice + // + // + WDF_TRI_STATE LockSupported; + + WDF_TRI_STATE EjectSupported; + + WDF_TRI_STATE Removable; + + WDF_TRI_STATE DockDevice; + + WDF_TRI_STATE UniqueID; + + WDF_TRI_STATE SilentInstall; + + WDF_TRI_STATE SurpriseRemovalOK; + + WDF_TRI_STATE HardwareDisabled; + + WDF_TRI_STATE NoDisplayInUI; + + // + // Default values of -1 indicate not to set this value + // + ULONG Address; + + ULONG UINumber; + +} WDF_DEVICE_PNP_CAPABILITIES_V2_15, *PWDF_DEVICE_PNP_CAPABILITIES_V2_15; + +typedef struct _WDF_DEVICE_POWER_CAPABILITIES_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_TRI_STATE DeviceD1; + + WDF_TRI_STATE DeviceD2; + + WDF_TRI_STATE WakeFromD0; + + WDF_TRI_STATE WakeFromD1; + + WDF_TRI_STATE WakeFromD2; + + WDF_TRI_STATE WakeFromD3; + + // + // Default value PowerDeviceMaximum indicates not to set this value + // + DEVICE_POWER_STATE DeviceState[PowerSystemMaximum]; + + // + // Default value PowerDeviceMaximum, PowerSystemMaximum indicates not to + // set this value. + // + DEVICE_POWER_STATE DeviceWake; + + SYSTEM_POWER_STATE SystemWake; + + // + // Default values of -1 indicate not to set this value + // + ULONG D1Latency; + + ULONG D2Latency; + + ULONG D3Latency; + + // + // Ideal Dx state for the device to be put into when the machine moves into + // Sx and the device is not armed for wake. By default, the default will be + // placed into D3. If IdealDxStateForSx is lighter then + // DeviceState[Sx], then DeviceState[Sx] will be used as the Dx state. + // + DEVICE_POWER_STATE IdealDxStateForSx; + +} WDF_DEVICE_POWER_CAPABILITIES_V2_15, *PWDF_DEVICE_POWER_CAPABILITIES_V2_15; + +typedef struct _WDF_REMOVE_LOCK_OPTIONS_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REMOVE_LOCK_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REMOVE_LOCK_OPTIONS_V2_15, *PWDF_REMOVE_LOCK_OPTIONS_V2_15; + +typedef struct _WDF_POWER_FRAMEWORK_SETTINGS_V2_15 { + // + // Size of the structure, in bytes. + // + ULONG Size; + + // + // Client driver's callback function that is invoked after KMDF has + // registered with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_POST_PO_FX_REGISTER_DEVICE EvtDeviceWdmPostPoFxRegisterDevice; + + // + // Client driver's callback function that is invoked before KMDF + // unregisters with the power framework. This field can be NULL if the + // client driver does not wish to specify this callback. + // + PFN_WDFDEVICE_WDM_PRE_PO_FX_UNREGISTER_DEVICE EvtDeviceWdmPrePoFxUnregisterDevice; + + // + // Pointer to a PO_FX_COMPONENT structure that describes the only component + // in the single-component device. This field can be NULL if the client + // driver wants KMDF to use the default specification for this component + // (i.e. support for F0 only). + // + PPO_FX_COMPONENT Component; + + // + // Client driver's PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK ComponentActiveConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK callback + // function. This field can be NULL if the client driver does not wish to + // specify this callback. + // + PPO_FX_COMPONENT_IDLE_CONDITION_CALLBACK ComponentIdleConditionCallback; + + // + // Client driver's PO_FX_COMPONENT_IDLE_STATE_CALLBACK callback function. + // This field can be NULL if the client driver does not wish to specify + // this callback. + // + PPO_FX_COMPONENT_IDLE_STATE_CALLBACK ComponentIdleStateCallback; + + // + // Client driver's PO_FX_POWER_CONTROL_CALLBACK callback function. This + // field can be NULL if the client driver does not wish to specify this + // callback. + // + PPO_FX_POWER_CONTROL_CALLBACK PowerControlCallback; + + // + // Context value that is passed in to the ComponentIdleStateCallback and + // PowerControlCallback callback functions. + // + PVOID PoFxDeviceContext; + +} WDF_POWER_FRAMEWORK_SETTINGS_V2_15, *PWDF_POWER_FRAMEWORK_SETTINGS_V2_15; + +typedef struct _WDF_IO_TYPE_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // + // Identifies the method that the driver will use to access data buffers + // that it receives for read and write requests. + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for read and write requests. Note that UMDF + // driver provides just a preference, and not a guarantee.Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE ReadWriteIoType; + + // + // + // Identifies the method that the driver will "prefer" to use to access data + // buffers that it receives for IOCTL requests. Note that UMDF + // driver provides just a preference, and not a guarantee. Therefore, + // even if a driver specified direct access method, UMDF might use the + // buffered access method for one or more of the device's requests to + // improve performance. For example, UMDF uses buffered access for small + // buffers, if it can copy the data to the driver's buffer faster than it + // can map the buffers for direct access. + // + WDF_DEVICE_IO_TYPE DeviceControlIoType; + + // + // + // Optional, Provides the smallest buffer size (in bytes) for which + // UMDF will use direct access for the buffers. For example, set + // DirectTransferThreshold to "12288" to indicate that UMDF should use buffered + // access for all buffers that are smaller than 12 kilobytes, and direct + // access for buffers equal to or greater than that. Typically, you + // do not need to provide this value because UMDF uses a value that provides + // the best performance. Note that there are other requirements that must be + // met in order to get direct access of buffers. See Docs for details. + // + ULONG DirectTransferThreshold; + +} WDF_IO_TYPE_CONFIG_V2_15, *PWDF_IO_TYPE_CONFIG_V2_15; + +typedef struct _WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15 { + _In_ ULONG Size; + + // + // A pointer to a GUID that identifies the device interface class. + // + _In_ const GUID * InterfaceClassGUID; + + // + // A pointer to a UNICODE_STRING structure that describes a reference + // string for the device interface. This parameter is optional and can + // be NULL. + _In_opt_ PCUNICODE_STRING ReferenceString; + + // + // A pointer to a DEVPROPKEY structure that specifies the device + // property key. + // + _In_ const DEVPROPKEY * PropertyKey; + + // + // A locale identifier. Set this parameter either to a language-specific + // LCID value or to LOCALE_NEUTRAL. The LOCALE_NEUTRAL LCID specifies + // that the property is language-neutral (that is, not specific to any + // language). Do not set this parameter to LOCALE_SYSTEM_DEFAULT or + // LOCALE_USER_DEFAULT. For more information about language-specific + // LCID values, see LCID Structure. + // + _In_ LCID Lcid; + + // + // Set this parameter to PLUGPLAY_PROPERTY_PERSISTENT if the property + // value set by this routine should persist across computer restarts. + // Otherwise, set Flags to zero. Ignored for Query DDIs. + // + _In_ ULONG Flags; + +} WDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15, *PWDF_DEVICE_INTERFACE_PROPERTY_DATA_V2_15; + +typedef struct _WDF_DEVICE_PROPERTY_DATA_V2_15 { + // + // Size of this structure + // + _In_ ULONG Size; + + // + // A pointer to a DEVPROPKEY structure that specifies the device + // property key. + // + _In_ const DEVPROPKEY * PropertyKey; + + // + // A locale identifier. Set this parameter either to a language-specific + // LCID value or to LOCALE_NEUTRAL. The LOCALE_NEUTRAL LCID specifies + // that the property is language-neutral (that is, not specific to any + // language). Do not set this parameter to LOCALE_SYSTEM_DEFAULT or + // LOCALE_USER_DEFAULT. For more information about language-specific + // LCID values, see LCID Structure. + // + _In_ LCID Lcid; + + // + // Set this parameter to PLUGPLAY_PROPERTY_PERSISTENT if the property + // value set by this routine should persist across computer restarts. + // Otherwise, set Flags to zero. Ignored for Query DDIs. + // + _In_ ULONG Flags; + +} WDF_DEVICE_PROPERTY_DATA_V2_15, *PWDF_DEVICE_PROPERTY_DATA_V2_15; + +// End of versioning of structures for wdfDevice.h + +// +// Versioning of structures for wdfDevicePri.h +// +// End of versioning of structures for wdfDevicePri.h + +// +// Versioning of structures for wdfDmaEnabler.h +// +// End of versioning of structures for wdfDmaEnabler.h + +// +// Versioning of structures for wdfDmaTransaction.h +// +// End of versioning of structures for wdfDmaTransaction.h + +// +// Versioning of structures for wdfdpc.h +// +// End of versioning of structures for wdfdpc.h + +// +// Versioning of structures for wdfdriver.h +// +typedef struct _WDF_DRIVER_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Event callbacks + // + PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd; + + PFN_WDF_DRIVER_UNLOAD EvtDriverUnload; + + // + // Combination of WDF_DRIVER_INIT_FLAGS values + // + ULONG DriverInitFlags; + + // + // Pool tag to use for all allocations made by the framework on behalf of + // the client driver. + // + ULONG DriverPoolTag; + +} WDF_DRIVER_CONFIG_V2_15, *PWDF_DRIVER_CONFIG_V2_15; + +typedef struct _WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Major Version requested + // + ULONG MajorVersion; + + // + // Minor Version requested + // + ULONG MinorVersion; + +} WDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15, *PWDF_DRIVER_VERSION_AVAILABLE_PARAMS_V2_15; + +// End of versioning of structures for wdfdriver.h + +// +// Versioning of structures for wdffdo.h +// +typedef struct _WDF_FDO_EVENT_CALLBACKS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterAddResourceRequirements; + + PFN_WDF_DEVICE_FILTER_RESOURCE_REQUIREMENTS EvtDeviceFilterRemoveResourceRequirements; + + PFN_WDF_DEVICE_REMOVE_ADDED_RESOURCES EvtDeviceRemoveAddedResources; + +} WDF_FDO_EVENT_CALLBACKS_V2_15, *PWDF_FDO_EVENT_CALLBACKS_V2_15; + +// End of versioning of structures for wdffdo.h + +// +// Versioning of structures for wdffileobject.h +// +// End of versioning of structures for wdffileobject.h + +// +// Versioning of structures for wdfGlobals.h +// +typedef struct _WDF_DRIVER_GLOBALS_V2_15 { + // backpointer to the handle for this driver + WDFDRIVER Driver; + + // Flags indicated by the driver during create + ULONG DriverFlags; + + // Tag generated by WDF for the driver. Tag used by allocations made on + // behalf of the driver by WDF. + ULONG DriverTag; + + CHAR DriverName[WDF_DRIVER_GLOBALS_NAME_LEN]; + + // If TRUE, the stub code will capture DriverObject->DriverUnload and insert + // itself first in the unload chain. If FALSE, DriverUnload is left alone + // (but WDF will not be notified of unload and there will be no auto cleanup). + BOOLEAN DisplaceDriverUnload; + +} WDF_DRIVER_GLOBALS_V2_15, *PWDF_DRIVER_GLOBALS_V2_15; + +// End of versioning of structures for wdfGlobals.h + +// +// Versioning of structures for wdfhid.h +// +// End of versioning of structures for wdfhid.h + +// +// Versioning of structures for wdfhwaccess.h +// +// End of versioning of structures for wdfhwaccess.h + +// +// Versioning of structures for wdfinstaller.h +// +// End of versioning of structures for wdfinstaller.h + +// +// Versioning of structures for wdfinternal.h +// +// End of versioning of structures for wdfinternal.h + +// +// Versioning of structures for wdfinterrupt.h +// +// +// Interrupt Configuration Structure +// +typedef struct _WDF_INTERRUPT_CONFIG_V2_15 { + ULONG Size; + + // + // If this interrupt is to be synchronized with other interrupt(s) assigned + // to the same WDFDEVICE, create a WDFSPINLOCK and assign it to each of the + // WDFINTERRUPTs config. + // + WDFSPINLOCK SpinLock; + + WDF_TRI_STATE ShareVector; + + BOOLEAN FloatingSave; + + // + // DIRQL handling: automatic serialization of the DpcForIsr/WaitItemForIsr. + // Passive-level handling: automatic serialization of all callbacks. + // + BOOLEAN AutomaticSerialization; + + // + // Event Callbacks + // + PFN_WDF_INTERRUPT_ISR EvtInterruptIsr; + + PFN_WDF_INTERRUPT_DPC EvtInterruptDpc; + + PFN_WDF_INTERRUPT_ENABLE EvtInterruptEnable; + + PFN_WDF_INTERRUPT_DISABLE EvtInterruptDisable; + + PFN_WDF_INTERRUPT_WORKITEM EvtInterruptWorkItem; + + // + // These fields are only used when interrupt is created in + // EvtDevicePrepareHardware callback. + // + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptRaw; + + PCM_PARTIAL_RESOURCE_DESCRIPTOR InterruptTranslated; + + // + // Optional passive lock for handling interrupts at passive-level. + // + WDFWAITLOCK WaitLock; + + // + // TRUE: handle interrupt at passive-level. + // FALSE: handle interrupt at DIRQL level. This is the default. + // + BOOLEAN PassiveHandling; + + // + // TRUE: Interrupt is reported inactive on explicit power down + // instead of disconnecting it. + // FALSE: Interrupt is disconnected instead of reporting inactive + // on explicit power down. + // DEFAULT: Framework decides the right value. + // + WDF_TRI_STATE ReportInactiveOnPowerDown; + + // + // TRUE: Interrupt is used to wake the device from low-power states + // and when the device is armed for wake this interrupt should + // remain connected. + // FALSE: Interrupt is not used to wake the device from low-power states. + // This is the default. + // + BOOLEAN CanWakeDevice; + +} WDF_INTERRUPT_CONFIG_V2_15, *PWDF_INTERRUPT_CONFIG_V2_15; + +typedef struct _WDF_INTERRUPT_INFO_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + ULONG64 Reserved1; + + KAFFINITY TargetProcessorSet; + + ULONG Reserved2; + + ULONG MessageNumber; + + ULONG Vector; + + KIRQL Irql; + + KINTERRUPT_MODE Mode; + + WDF_INTERRUPT_POLARITY Polarity; + + BOOLEAN MessageSignaled; + + // CM_SHARE_DISPOSITION + UCHAR ShareDisposition; + + DECLSPEC_ALIGN(8) USHORT Group; + +} WDF_INTERRUPT_INFO_V2_15, *PWDF_INTERRUPT_INFO_V2_15; + +// +// Interrupt Extended Policy Configuration Structure +// +typedef struct _WDF_INTERRUPT_EXTENDED_POLICY_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + WDF_INTERRUPT_POLICY Policy; + + WDF_INTERRUPT_PRIORITY Priority; + + GROUP_AFFINITY TargetProcessorSetAndGroup; + +} WDF_INTERRUPT_EXTENDED_POLICY_V2_15, *PWDF_INTERRUPT_EXTENDED_POLICY_V2_15; + +// End of versioning of structures for wdfinterrupt.h + +// +// Versioning of structures for wdfio.h +// +// +// This is the structure used to configure an IoQueue and +// register callback events to it. +// +// +typedef struct _WDF_IO_QUEUE_CONFIG_V2_15 { + ULONG Size; + + WDF_IO_QUEUE_DISPATCH_TYPE DispatchType; + + WDF_TRI_STATE PowerManaged; + + BOOLEAN AllowZeroLengthRequests; + + BOOLEAN DefaultQueue; + + PFN_WDF_IO_QUEUE_IO_DEFAULT EvtIoDefault; + + PFN_WDF_IO_QUEUE_IO_READ EvtIoRead; + + PFN_WDF_IO_QUEUE_IO_WRITE EvtIoWrite; + + PFN_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl; + + PFN_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL EvtIoInternalDeviceControl; + + PFN_WDF_IO_QUEUE_IO_STOP EvtIoStop; + + PFN_WDF_IO_QUEUE_IO_RESUME EvtIoResume; + + PFN_WDF_IO_QUEUE_IO_CANCELED_ON_QUEUE EvtIoCanceledOnQueue; + + union { + struct { + ULONG NumberOfPresentedRequests; + + } Parallel; + + } Settings; + + WDFDRIVER Driver; + +} WDF_IO_QUEUE_CONFIG_V2_15, *PWDF_IO_QUEUE_CONFIG_V2_15; + +typedef struct _WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15 { + ULONG Size; + + ULONG TotalForwardProgressRequests; + + // + // Specify the type of the policy here. + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY ForwardProgressReservedPolicy; + + // + // Structure which contains the policy specific fields + // + WDF_IO_FORWARD_PROGRESS_RESERVED_POLICY_SETTINGS ForwardProgressReservePolicySettings; + + // + // Callback for reserved request given at initialization time + // + PFN_WDF_IO_ALLOCATE_RESOURCES_FOR_RESERVED_REQUEST EvtIoAllocateResourcesForReservedRequest; + + // + // Callback for reserved request given at run time + // + PFN_WDF_IO_ALLOCATE_REQUEST_RESOURCES EvtIoAllocateRequestResources; + +} WDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15, *PWDF_IO_QUEUE_FORWARD_PROGRESS_POLICY_V2_15; + +// End of versioning of structures for wdfio.h + +// +// Versioning of structures for wdfIoTarget.h +// +typedef struct _WDF_IO_TARGET_OPEN_PARAMS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Indicates which fields of this structure are going to be used in + // creating the WDFIOTARGET. + // + WDF_IO_TARGET_OPEN_TYPE Type; + + // + // Notification when the target is being queried for removal. + // If !NT_SUCCESS is returned, the query will fail and the target will + // remain opened. + // + PFN_WDF_IO_TARGET_QUERY_REMOVE EvtIoTargetQueryRemove; + + // + // The previous query remove has been canceled and the target can now be + // reopened. + // + PFN_WDF_IO_TARGET_REMOVE_CANCELED EvtIoTargetRemoveCanceled; + + // + // The query remove has succeeded and the target is now removed from the + // system. + // + PFN_WDF_IO_TARGET_REMOVE_COMPLETE EvtIoTargetRemoveComplete; + + // + // ========== WdfIoTargetOpenUseExistingDevice begin ========== + // + // The device object to send requests to + // + PDEVICE_OBJECT TargetDeviceObject; + + // + // File object representing the TargetDeviceObject. The PFILE_OBJECT will + // be passed as a parameter in all requests sent to the resulting + // WDFIOTARGET. + // + PFILE_OBJECT TargetFileObject; + + // ========== WdfIoTargetOpenUseExistingDevice end ========== + // + // ========== WdfIoTargetOpenByName begin ========== + // + // Name of the device to open. + // + UNICODE_STRING TargetDeviceName; + + // + // The access desired on the device being opened up, ie WDM FILE_XXX_ACCESS + // such as FILE_ANY_ACCESS, FILE_SPECIAL_ACCESS, FILE_READ_ACCESS, or + // FILE_WRITE_ACCESS or you can use values such as GENERIC_READ, + // GENERIC_WRITE, or GENERIC_ALL. + // + // + // The requested access to the file or device, which can be summarized as + // read, write, both or neither zero). For more information about + // this member, see the dwDesiredAccess parameter of CreateFile in the + // Windows SDK. Note that ACCESS_MASK data type is a DWORD value. + // + // + ACCESS_MASK DesiredAccess; + + // + // + // Share access desired on the target being opened, ie WDM FILE_SHARE_XXX + // values such as FILE_SHARE_READ, FILE_SHARE_WRITE, FILE_SHARE_DELETE. + // A zero value means exclusive access to the target. + // + // + // + // The type of sharing to allow for the file. For more information about + // this member, see the dwShareMode parameter of CreateFile in the + // Windows SDK. A value of 0 means exclusive access. + // + // + ULONG ShareAccess; + + // + // + // File attributes, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // Additional flags and attributes for the file. For more information about + // this member, see the dwFlagsAndAttributes parameter of CreateFile + // in the Windows SDK. + // + // + ULONG FileAttributes; + + // + // + // Create disposition, see ZwCreateFile in the DDK for a list of valid + // values and their meaning. + // + // + // The action to take if the file already exists. For more information + // about this member, see the dwCreationDisposition parameter of + // CreateFile in the Windows SDK. + // + // + ULONG CreateDisposition; + + // + // + // Options for opening the device, see CreateOptions for ZwCreateFile in the + // DDK for a list of valid values and their meaning. + // + ULONG CreateOptions; + + // + // + // + PVOID EaBuffer; + + // + // + // + ULONG EaBufferLength; + + // + // + // + PLONGLONG AllocationSize; + + // ========== WdfIoTargetOpenByName end ========== + // + // + // + // + // On return for a create by name, this will contain one of the following + // values: FILE_CREATED, FILE_OPENED, FILE_OVERWRITTEN, FILE_SUPERSEDED, + // FILE_EXISTS, FILE_DOES_NOT_EXIST + // + ULONG FileInformation; + + // ========== WdfIoTargetOpenLocalTargetByFile begin ========== + // + // + // A UNICODE_STRING-formatted string that contains the + // name of the file to create a file object from. This parameter is + // optional, and is applicable only when Type parameter is + // WdfIoTargetOpenLocalTargetByFile. The driver can leave this member + // unchanged if the driver does not have to create the file object + // from a file name. If the driver must supply a name, the string that + // the driver passes must not contain any path separator characters + // ("/" or "\"). + // + UNICODE_STRING FileName; + +} WDF_IO_TARGET_OPEN_PARAMS_V2_15, *PWDF_IO_TARGET_OPEN_PARAMS_V2_15; + +// End of versioning of structures for wdfIoTarget.h + +// +// Versioning of structures for wdfIoTargetPri.h +// +// End of versioning of structures for wdfIoTargetPri.h + +// +// Versioning of structures for wdfMemory.h +// +typedef struct _WDFMEMORY_OFFSET_V2_15 { + // + // Offset into the WDFMEMORY that the operation should start at. + // + size_t BufferOffset; + + // + // Number of bytes that the operation should access. If 0, the entire + // length of the WDFMEMORY buffer will be used in the operation or ignored + // depending on the API. + // + size_t BufferLength; + +} WDFMEMORY_OFFSET_V2_15, *PWDFMEMORY_OFFSET_V2_15; + +typedef struct _WDF_MEMORY_DESCRIPTOR_V2_15 { + WDF_MEMORY_DESCRIPTOR_TYPE Type; + + union { + struct { + PVOID Buffer; + + ULONG Length; + + } BufferType; + + struct { + PMDL Mdl; + + ULONG BufferLength; + + } MdlType; + + struct { + WDFMEMORY Memory; + + PWDFMEMORY_OFFSET_V2_15 Offsets; + + } HandleType; + + } u; + +} WDF_MEMORY_DESCRIPTOR_V2_15, *PWDF_MEMORY_DESCRIPTOR_V2_15; + +// End of versioning of structures for wdfMemory.h + +// +// Versioning of structures for wdfMiniport.h +// +// End of versioning of structures for wdfMiniport.h + +// +// Versioning of structures for wdfObject.h +// +typedef struct _WDF_OBJECT_ATTRIBUTES_V2_15 { + // + // Size in bytes of this structure + // + ULONG Size; + + // + // Function to call when the object is deleted + // + PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback; + + // + // Function to call when the objects memory is destroyed when the + // the last reference count goes to zero + // + PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback; + + // + // Execution level constraints for Object + // + WDF_EXECUTION_LEVEL ExecutionLevel; + + // + // Synchronization level constraint for Object + // + WDF_SYNCHRONIZATION_SCOPE SynchronizationScope; + + // + // Optional Parent Object + // + WDFOBJECT ParentObject; + + // + // Overrides the size of the context allocated as specified by + // ContextTypeInfo->ContextSize + // + size_t ContextSizeOverride; + + // + // Pointer to the type information to be associated with the object + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V2_15 ContextTypeInfo; + +} WDF_OBJECT_ATTRIBUTES_V2_15, *PWDF_OBJECT_ATTRIBUTES_V2_15; + +// +// Since C does not have strong type checking we must invent our own +// +typedef struct _WDF_OBJECT_CONTEXT_TYPE_INFO_V2_15 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // String representation of the context's type name, i.e. "DEVICE_CONTEXT" + // + PCHAR ContextName; + + // + // The size of the context in bytes. This will be the size of the context + // associated with the handle unless + // WDF_OBJECT_ATTRIBUTES::ContextSizeOverride is specified. + // + size_t ContextSize; + + // + // If NULL, this structure is the unique type identifier for the context + // type. If != NULL, the UniqueType pointer value is the unique type id + // for the context type. + // + PCWDF_OBJECT_CONTEXT_TYPE_INFO_V2_15 UniqueType; + + // + // Function pointer to retrieve the context type information structure + // pointer from the provider of the context type. This function is invoked + // by the client driver's entry point by the KMDF stub after all class + // drivers are loaded and before DriverEntry is invoked. + // + PFN_GET_UNIQUE_CONTEXT_TYPE EvtDriverGetUniqueContextType; + +} WDF_OBJECT_CONTEXT_TYPE_INFO_V2_15, *PWDF_OBJECT_CONTEXT_TYPE_INFO_V2_15; + +// +// Core structure for supporting custom types, see macros below. +// +typedef struct _WDF_CUSTOM_TYPE_CONTEXT_V2_15 { + ULONG Size; + + ULONG_PTR Data; + +} WDF_CUSTOM_TYPE_CONTEXT_V2_15, *PWDF_CUSTOM_TYPE_CONTEXT_V2_15; + +// End of versioning of structures for wdfObject.h + +// +// Versioning of structures for wdfpdo.h +// +typedef struct _WDF_PDO_EVENT_CALLBACKS_V2_15 { + // + // The size of this structure in bytes + // + ULONG Size; + + // + // Called in response to IRP_MN_QUERY_RESOURCES + // + PFN_WDF_DEVICE_RESOURCES_QUERY EvtDeviceResourcesQuery; + + // + // Called in response to IRP_MN_QUERY_RESOURCE_REQUIREMENTS + // + PFN_WDF_DEVICE_RESOURCE_REQUIREMENTS_QUERY EvtDeviceResourceRequirementsQuery; + + // + // Called in response to IRP_MN_EJECT + // + PFN_WDF_DEVICE_EJECT EvtDeviceEject; + + // + // Called in response to IRP_MN_SET_LOCK + // + PFN_WDF_DEVICE_SET_LOCK EvtDeviceSetLock; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic arming shoulding occur here. + // + PFN_WDF_DEVICE_ENABLE_WAKE_AT_BUS EvtDeviceEnableWakeAtBus; + + // + // Called in response to the power policy owner sending a wait wake to the + // PDO. Bus generic disarming shoulding occur here. + // + PFN_WDF_DEVICE_DISABLE_WAKE_AT_BUS EvtDeviceDisableWakeAtBus; + + // + // Called when reporting the PDO missing to PnP manager in response to + // IRP_MN_QUERY_DEVICE_RELATIONS for Bus Relations. + // + PFN_WDF_DEVICE_REPORTED_MISSING EvtDeviceReportedMissing; + +} WDF_PDO_EVENT_CALLBACKS_V2_15, *PWDF_PDO_EVENT_CALLBACKS_V2_15; + +// End of versioning of structures for wdfpdo.h + +// +// Versioning of structures for wdfpool.h +// +// End of versioning of structures for wdfpool.h + +// +// Versioning of structures for wdfqueryinterface.h +// +typedef struct _WDF_QUERY_INTERFACE_CONFIG_V2_15 { + // + // Size of this structure in bytes. + // + ULONG Size; + + // + // Interface to be returned to the caller. Optional if BehaviorType is set + // to WdfQueryInterfaceTypePassThrough or ImportInterface is set to TRUE. + // + PINTERFACE Interface; + + // + // The GUID identifying the interface + // + CONST GUID * InterfaceType; + + // + // Valid only for PDOs. The framework will allocate a new request and + // forward it down the parent's device stack. + // + BOOLEAN SendQueryToParentStack; + + // + // Driver supplied callback which is called after some basic interface + // validation has been performed (size, version, and guid checking). This + // is an optional parameter and may be NULL unless ImportInterface is + // specified. + // + // If the callback returns !NT_SUCCESS, this error will be returned to the + // caller and the query interface will fail. + // + // In this callback, the caller is free to modify the ExposedInterface in + // any manner of its choosing. For instance, the callback may change any + // field in the interface. The callback may also alloate a dynamic context + // to be associated with the interface; the InterfaceReference and + // InterfaceDereference functions may also be overridden. + // + // If ImportInterface is set to TRUE, then this is a required field and the + // callback must initialize the interface (the framework will leave the + // ExposedInterface buffer exactly as it received it) since the framework + // has no way of knowing which fields to fill in and which to leave alone. + // + PFN_WDF_DEVICE_PROCESS_QUERY_INTERFACE_REQUEST EvtDeviceProcessQueryInterfaceRequest; + + // + // If TRUE, the interface provided by the caller contains data that the + // driver is interested in. By setting to this field to TRUE, the + // EvtDeviceProcessQueryInterfaceRequest callback must initialize the + // ExposedInterface. + // + // If FALSE, the entire ExposedInterface is initialized through a memory + // copy before the EvtDeviceProcessQueryInterfaceRequest is called. + // + BOOLEAN ImportInterface; + +} WDF_QUERY_INTERFACE_CONFIG_V2_15, *PWDF_QUERY_INTERFACE_CONFIG_V2_15; + +// End of versioning of structures for wdfqueryinterface.h + +// +// Versioning of structures for wdfregistry.h +// +// End of versioning of structures for wdfregistry.h + +// +// Versioning of structures for wdfrequest.h +// +// +// This parameters structure allows general access to a requests parameters +// +typedef struct _WDF_REQUEST_PARAMETERS_V2_15 { + USHORT Size; + + UCHAR MinorFunction; + + WDF_REQUEST_TYPE Type; + + // + // The following user parameters are based on the service that is being + // invoked. Drivers and file systems can determine which set to use based + // on the above major and minor function codes. + // + union { + // + // System service parameters for: Create + // + // + struct { + PIO_SECURITY_CONTEXT SecurityContext; + + ULONG Options; + + USHORT POINTER_ALIGNMENT FileAttributes; + + USHORT ShareAccess; + + ULONG POINTER_ALIGNMENT EaLength; + + } Create; + + // + // System service parameters for: Read + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Read; + + // + // System service parameters for: Write + // + // + struct { + size_t Length; + + ULONG POINTER_ALIGNMENT Key; + + LONGLONG DeviceOffset; + + } Write; + + // + // System service parameters for: Device Control + // + // Note that the user's output buffer is stored in the UserBuffer field + // and the user's input buffer is stored in the SystemBuffer field. + // + // + struct { + size_t OutputBufferLength; + + size_t POINTER_ALIGNMENT InputBufferLength; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Type3InputBuffer; + + } DeviceIoControl; + + struct { + PVOID Arg1; + + PVOID Arg2; + + ULONG POINTER_ALIGNMENT IoControlCode; + + PVOID Arg4; + + } Others; + + } Parameters; + +} WDF_REQUEST_PARAMETERS_V2_15, *PWDF_REQUEST_PARAMETERS_V2_15; + +typedef struct _WDF_REQUEST_COMPLETION_PARAMS_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + WDF_REQUEST_TYPE Type; + + IO_STATUS_BLOCK IoStatus; + + union { + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Write; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } Read; + + struct { + ULONG IoControlCode; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + } Input; + + struct { + WDFMEMORY Buffer; + + size_t Offset; + + size_t Length; + + } Output; + + } Ioctl; + + struct { + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument1; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument2; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument3; + + union { + PVOID Ptr; + + ULONG_PTR Value; + + } Argument4; + + } Others; + + struct { + PWDF_USB_REQUEST_COMPLETION_PARAMS_V2_15 Completion; + + } Usb; + + } Parameters; + +} WDF_REQUEST_COMPLETION_PARAMS_V2_15, *PWDF_REQUEST_COMPLETION_PARAMS_V2_15; + +typedef struct _WDF_REQUEST_REUSE_PARAMS_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // Bit field combination of WDF_REQUEST_REUSE_Xxx values + // + ULONG Flags; + + // + // The new status of the request. + // + NTSTATUS Status; + + // + // New PIRP to be contained in the WDFREQUEST. Setting a new PIRP value + // is only valid for WDFREQUESTs created by WdfRequestCreateFromIrp where + // RequestFreesIrp == FALSE. No other WDFREQUESTs (presented by the + // I/O queue for instance) may have their IRPs changed. + // + PIRP NewIrp; + +} WDF_REQUEST_REUSE_PARAMS_V2_15, *PWDF_REQUEST_REUSE_PARAMS_V2_15; + +typedef struct _WDF_REQUEST_SEND_OPTIONS_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_SEND_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + + // + // Valid when WDF_REQUEST_SEND_OPTION_TIMEOUT is set + // + LONGLONG Timeout; + +} WDF_REQUEST_SEND_OPTIONS_V2_15, *PWDF_REQUEST_SEND_OPTIONS_V2_15; + +typedef struct _WDF_REQUEST_FORWARD_OPTIONS_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Bit field combination of values from the WDF_REQUEST_FORWARD_OPTIONS_FLAGS + // enumeration + // + ULONG Flags; + +} WDF_REQUEST_FORWARD_OPTIONS_V2_15, *PWDF_REQUEST_FORWARD_OPTIONS_V2_15; + +// End of versioning of structures for wdfrequest.h + +// +// Versioning of structures for wdfresource.h +// +// End of versioning of structures for wdfresource.h + +// +// Versioning of structures for wdfroletypes.h +// +// End of versioning of structures for wdfroletypes.h + +// +// Versioning of structures for wdfstring.h +// +// End of versioning of structures for wdfstring.h + +// +// Versioning of structures for wdfsync.h +// +// End of versioning of structures for wdfsync.h + +// +// Versioning of structures for wdftimer.h +// +typedef struct _WDF_TIMER_CONFIG_V2_15 { + ULONG Size; + + PFN_WDF_TIMER EvtTimerFunc; + + ULONG Period; + + // + // If this is TRUE, the Timer will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the Timer DPC (DISPATCH_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + + // + // Optional tolerance for the timer in milliseconds. + // + ULONG TolerableDelay; + + // + // If this is TRUE, high resolution timers will be used. The default + // value is FALSE + // + DECLSPEC_ALIGN(8) BOOLEAN UseHighResolutionTimer; + +} WDF_TIMER_CONFIG_V2_15, *PWDF_TIMER_CONFIG_V2_15; + +// End of versioning of structures for wdftimer.h + +// +// Versioning of structures for wdftriage.h +// +typedef struct _WDFOBJECT_TRIAGE_INFO_V2_15 { + // value + ULONG RawObjectSize; + + ULONG ObjectType; + + ULONG TotalObjectSize; + + ULONG ChildListHead; + + ULONG ChildEntry; + + ULONG Globals; + + ULONG ParentObject; + +} WDFOBJECT_TRIAGE_INFO_V2_15, *PWDFOBJECT_TRIAGE_INFO_V2_15; + +typedef struct _WDFCONTEXT_TRIAGE_INFO_V2_15 { + // value + ULONG HeaderSize; + + ULONG NextHeader; + + ULONG Object; + + ULONG TypeInfoPtr; + + ULONG Context; + +} WDFCONTEXT_TRIAGE_INFO_V2_15, *PWDFCONTEXT_TRIAGE_INFO_V2_15; + +typedef struct _WDFCONTEXTTYPE_TRIAGE_INFO_V2_15 { + // value + ULONG TypeInfoSize; + + ULONG ContextSize; + + ULONG ContextName; + +} WDFCONTEXTTYPE_TRIAGE_INFO_V2_15, *PWDFCONTEXTTYPE_TRIAGE_INFO_V2_15; + +typedef struct _WDFQUEUE_TRIAGE_INFO_V2_15 { + // value + ULONG QueueSize; + + ULONG IrpQueue1; + + ULONG IrpQueue2; + + ULONG RequestList1; + + ULONG RequestList2; + + ULONG FwdProgressContext; + + ULONG PkgIo; + +} WDFQUEUE_TRIAGE_INFO_V2_15, *PWDFQUEUE_TRIAGE_INFO_V2_15; + +typedef struct _WDFFWDPROGRESS_TRIAGE_INFO_V2_15 { + ULONG ReservedRequestList; + + ULONG ReservedRequestInUseList; + + ULONG PendedIrpList; + +} WDFFWDPROGRESS_TRIAGE_INFO_V2_15, *PWDFFWDPROGRESS_TRIAGE_INFO_V2_15; + +typedef struct _WDFIRPQUEUE_TRIAGE_INFO_V2_15 { + // value + ULONG IrpQueueSize; + + ULONG IrpListHeader; + + ULONG IrpListEntry; + + ULONG IrpContext; + +} WDFIRPQUEUE_TRIAGE_INFO_V2_15, *PWDFIRPQUEUE_TRIAGE_INFO_V2_15; + +typedef struct _WDFREQUEST_TRIAGE_INFO_V2_15 { + // value + ULONG RequestSize; + + ULONG CsqContext; + + // WDF irp wrapper, see below. + ULONG FxIrp; + + ULONG ListEntryQueueOwned; + + ULONG ListEntryQueueOwned2; + + ULONG RequestListEntry; + + ULONG FwdProgressList; + +} WDFREQUEST_TRIAGE_INFO_V2_15, *PWDFREQUEST_TRIAGE_INFO_V2_15; + +typedef struct _WDFDEVICE_TRIAGE_INFO_V2_15 { + // value + ULONG DeviceInitSize; + + ULONG DeviceDriver; + +} WDFDEVICE_TRIAGE_INFO_V2_15, *PWDFDEVICE_TRIAGE_INFO_V2_15; + +typedef struct _WDFIRP_TRIAGE_INFO_V2_15 { + // value + ULONG FxIrpSize; + + ULONG IrpPtr; + +} WDFIRP_TRIAGE_INFO_V2_15, *PWDFIRP_TRIAGE_INFO_V2_15; + +typedef struct _WDF_TRIAGE_INFO_V2_15 { + // + // Version. + // + ULONG WdfMajorVersion; + + ULONG WdfMinorVersion; + + ULONG TriageInfoMajorVersion; + + ULONG TriageInfoMinorVersion; + + // + // Reserved pointer. + // + PVOID Reserved; + + // + // WDF objects triage info. + // + PWDFOBJECT_TRIAGE_INFO_V2_15 WdfObjectTriageInfo; + + PWDFCONTEXT_TRIAGE_INFO_V2_15 WdfContextTriageInfo; + + PWDFCONTEXTTYPE_TRIAGE_INFO_V2_15 WdfContextTypeTriageInfo; + + PWDFQUEUE_TRIAGE_INFO_V2_15 WdfQueueTriageInfo; + + PWDFFWDPROGRESS_TRIAGE_INFO_V2_15 WdfFwdProgressTriageInfo; + + PWDFIRPQUEUE_TRIAGE_INFO_V2_15 WdfIrpQueueTriageInfo; + + PWDFREQUEST_TRIAGE_INFO_V2_15 WdfRequestTriageInfo; + + PWDFDEVICE_TRIAGE_INFO_V2_15 WdfDeviceTriageInfo; + + PWDFIRP_TRIAGE_INFO_V2_15 WdfIrpTriageInfo; + +} WDF_TRIAGE_INFO_V2_15, *PWDF_TRIAGE_INFO_V2_15; + +// End of versioning of structures for wdftriage.h + +// +// Versioning of structures for wdftypes.h +// +// End of versioning of structures for wdftypes.h + +// +// Versioning of structures for wdfUsb.h +// +typedef struct _WDF_USB_REQUEST_COMPLETION_PARAMS_V2_15 { + USBD_STATUS UsbdStatus; + + WDF_USB_REQUEST_TYPE Type; + + union { + struct { + WDFMEMORY Buffer; + + USHORT LangID; + + UCHAR StringIndex; + + // + // If STATUS_BUFFER_OVERFLOW is returned, this field will contain the + // number of bytes required to retrieve the entire string. + // + UCHAR RequiredSize; + + } DeviceString; + + struct { + WDFMEMORY Buffer; + + WDF_USB_CONTROL_SETUP_PACKET SetupPacket; + + ULONG Length; + + } DeviceControlTransfer; + + struct { + WDFMEMORY Buffer; + + } DeviceUrb; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeWrite; + + struct { + WDFMEMORY Buffer; + + size_t Length; + + size_t Offset; + + } PipeRead; + + struct { + WDFMEMORY Buffer; + + } PipeUrb; + + } Parameters; + +} WDF_USB_REQUEST_COMPLETION_PARAMS_V2_15, *PWDF_USB_REQUEST_COMPLETION_PARAMS_V2_15; + +typedef struct _WDF_USB_CONTINUOUS_READER_CONFIG_V2_15 { + // + // Size of the string in bytes + // + ULONG Size; + + // + // Number of bytes to send ask for from the usb device. + // + size_t TransferLength; + + // + // Number of bytes to allocate before the requested transfer length + // + size_t HeaderLength; + + // + // Number of bytes to allocate after the requested transfer length + // + size_t TrailerLength; + + // + // Number of reads to send to the device at once. If zero is specified, the + // default will be used. + // + UCHAR NumPendingReads; + + // + // Optional attributes to apply to each WDFMEMORY allocated for each read + // + PWDF_OBJECT_ATTRIBUTES_V2_15 BufferAttributes; + + // + // Event callback invoked when a read is completed + // + PFN_WDF_USB_READER_COMPLETION_ROUTINE EvtUsbTargetPipeReadComplete; + + // + // Context to be passed to EvtUsbTargetPipeReadComplete + // + WDFCONTEXT EvtUsbTargetPipeReadCompleteContext; + + // + // Event callback invoked when a reader fails. If TRUE is returned, the + // readers are restarted. + // + PFN_WDF_USB_READERS_FAILED EvtUsbTargetPipeReadersFailed; + +} WDF_USB_CONTINUOUS_READER_CONFIG_V2_15, *PWDF_USB_CONTINUOUS_READER_CONFIG_V2_15; + +typedef struct _WDF_USB_DEVICE_INFORMATION_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD version information + // + USBD_VERSION_INFORMATION UsbdVersionInformation; + + // + // Usb controller port capabilities + // + ULONG HcdPortCapabilities; + + // + // Bitfield of WDF_USB_DEVICE_TRAITS values + // + ULONG Traits; + +} WDF_USB_DEVICE_INFORMATION_V2_15, *PWDF_USB_DEVICE_INFORMATION_V2_15; + +typedef struct _WDF_USB_INTERFACE_SETTING_PAIR_V2_15 { + // + // Interface to select + // + WDFUSBINTERFACE UsbInterface; + + // + // Setting to select on UsbInterface + // + UCHAR SettingIndex; + +} WDF_USB_INTERFACE_SETTING_PAIR_V2_15, *PWDF_USB_INTERFACE_SETTING_PAIR_V2_15; + +typedef struct _WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Type of select config, one of WdfUsbTargetDeviceSelectConfigType values + // + WdfUsbTargetDeviceSelectConfigType Type; + + union { + struct { + // + // Configuration descriptor to use + // + PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor; + + // + // Array of interface descriptors pointers. + // + PUSB_INTERFACE_DESCRIPTOR * InterfaceDescriptors; + + // + // Number of elements in the InterfaceDescrtiptors pointer array. + // + ULONG NumInterfaceDescriptors; + + } Descriptor; + + struct { + // + // Preallocated select config URB formatted by the caller. + // Will be used, as supplied without modification, as the select + // config request. + // + PURB Urb; + + } Urb; + + struct { + // + // Number of pipes configured on the single after. This value is + // returned to the caller after a succssful call. + // + UCHAR NumberConfiguredPipes; + + // + // The interface which was configred. This value is returned to the + // caller after a successful call. + // + WDFUSBINTERFACE ConfiguredUsbInterface; + + } SingleInterface; + + struct { + // + // Number of interface pairs in the Pairs array + // + UCHAR NumberInterfaces; + + // + // Array of interface + settings + // + PWDF_USB_INTERFACE_SETTING_PAIR_V2_15 Pairs; + + // + // Number of interfaces which were configured after a successful call + // + UCHAR NumberOfConfiguredInterfaces; + + } MultiInterface; + + } Types; + +} WDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15, *PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS_V2_15; + +typedef struct _WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15 { + // + // Size of this data structure in bytes + // + ULONG Size; + + // + // Type of select interface as indicated by one of the + // WdfUsbTargetDeviceSelectSettingType values. + // + WdfUsbTargetDeviceSelectSettingType Type; + + union { + struct { + // + // Interface descriptor that will be used in the interface selection + // + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor; + + } Descriptor; + + struct { + // + // The setting index of the WDFUSBINTERFACE to use + // + UCHAR SettingIndex; + + } Interface; + + struct { + // + // Preformatted select interface URB which will be used in the + // select interface request. + // + PURB Urb; + + } Urb; + + } Types; + +} WDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15, *PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS_V2_15; + +typedef struct _WDF_USB_PIPE_INFORMATION_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Maximum packet size this device is capable of + // + ULONG MaximumPacketSize; + + // + // Raw endpoint address of the device as described by its descriptor + // + UCHAR EndpointAddress; + + // + // Polling interval + // + UCHAR Interval; + + // + // Which alternate setting this structure is relevant for + // + UCHAR SettingIndex; + + // + // The type of the pipe + WDF_USB_PIPE_TYPE PipeType; + + // + // Maximum size of one transfer which should be sent to the host controller + // + ULONG MaximumTransferSize; + +} WDF_USB_PIPE_INFORMATION_V2_15, *PWDF_USB_PIPE_INFORMATION_V2_15; + +typedef struct _WDF_USB_DEVICE_CREATE_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // USBD Client Contraction of the Wdf Client + // + ULONG USBDClientContractVersion; + +} WDF_USB_DEVICE_CREATE_CONFIG_V2_15, *PWDF_USB_DEVICE_CREATE_CONFIG_V2_15; + +// End of versioning of structures for wdfUsb.h + +// +// Versioning of structures for wdfverifier.h +// +// End of versioning of structures for wdfverifier.h + +// +// Versioning of structures for wdfWMI.h +// +typedef struct _WDF_WMI_PROVIDER_CONFIG_V2_15 { + // + // Size of this structure in bytes + // + ULONG Size; + + // + // The GUID being registered + // + GUID Guid; + + // + // Combination of values from the enum WDF_WMI_PROVIDER_FLAGS + // + ULONG Flags; + + // + // Minimum expected buffer size for query and set instance requests. + // Ignored if WdfWmiProviderEventOnly is set in Flags. + // + ULONG MinInstanceBufferSize; + + // + // Callback when caller is opening a provider which ha been marked as + // expensive or when a caller is interested in events. + // + PFN_WDF_WMI_PROVIDER_FUNCTION_CONTROL EvtWmiProviderFunctionControl; + +} WDF_WMI_PROVIDER_CONFIG_V2_15, *PWDF_WMI_PROVIDER_CONFIG_V2_15; + +typedef struct _WDF_WMI_INSTANCE_CONFIG_V2_15 { + // + // Size of the structure in bytes + // + ULONG Size; + + // + // Optional parameter. If NULL, ProviderConfig must be set to a valid pointer + // value. If specified, indicates the provider to create an instance for. + // + WDFWMIPROVIDER Provider; + + // + // Optional parameter. If NULL, Provider must be set to a valid handle + // value. If specifeid, indicates the configuration for a provider to be + // created and for this instance to be associated with. + // + PWDF_WMI_PROVIDER_CONFIG_V2_15 ProviderConfig; + + // + // If the Provider is configured as read only and this field is set to TRUE, + // the EvtWmiInstanceQueryInstance is ignored and WDF will blindly copy the + // context associated with this instance (using RtlCopyMemory, with no locks + // held) into the query buffer. + // + BOOLEAN UseContextForQuery; + + // + // If TRUE, the instance will be registered as well as created. + // + BOOLEAN Register; + + // + // Callback when caller wants to query the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_QUERY_INSTANCE EvtWmiInstanceQueryInstance; + + // + // Callback when caller wants to set the entire data item's buffer. + // + PFN_WDF_WMI_INSTANCE_SET_INSTANCE EvtWmiInstanceSetInstance; + + // + // Callback when caller wants to set a single field in the data item's buffer + // + PFN_WDF_WMI_INSTANCE_SET_ITEM EvtWmiInstanceSetItem; + + // + // Callback when caller wants to execute a method on the data item. + // + PFN_WDF_WMI_INSTANCE_EXECUTE_METHOD EvtWmiInstanceExecuteMethod; + +} WDF_WMI_INSTANCE_CONFIG_V2_15, *PWDF_WMI_INSTANCE_CONFIG_V2_15; + +// End of versioning of structures for wdfWMI.h + +// +// Versioning of structures for wdfworkitem.h +// +typedef struct _WDF_WORKITEM_CONFIG_V2_15 { + ULONG Size; + + PFN_WDF_WORKITEM EvtWorkItemFunc; + + // + // If this is TRUE, the workitem will automatically serialize + // with the event callback handlers of its Parent Object. + // + // Parent Object's callback constraints should be compatible + // with the work item (PASSIVE_LEVEL), or the request will fail. + // + BOOLEAN AutomaticSerialization; + +} WDF_WORKITEM_CONFIG_V2_15, *PWDF_WORKITEM_CONFIG_V2_15; + +// End of versioning of structures for wdfworkitem.h + + +#endif // _WDF_V2_15_TYPES_H_ diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.cpp b/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.cpp new file mode 100644 index 00000000000..45ee960d7b4 --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.cpp @@ -0,0 +1,508 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#include +#include +#include + +extern "C" { +#include "mx.h" +} +#include "fxmin.hpp" +#include + +#include +#include "wdf20.h" +#include "wdf215.h" + +// +// This will cause inclusion of VfWdfFunctions table implementation from header +// +#define VF_FX_DYNAMICS_GENERATE_TABLE 1 + + + + + +#include "..\version\FxDynamics.h" +#include "..\version\vffxdynamics.h" +#include "FxLibraryCommon.h" + +#include "FxTelemetry.hpp" + +extern "C" { +// +// Global triage Info for dbgeng and 0x9F work +// +static WDFOBJECT_TRIAGE_INFO _WdfObjectTriageInfo = {0}; +static WDFCONTEXT_TRIAGE_INFO _WdfContextTriageInfo = {0}; +static WDFCONTEXTTYPE_TRIAGE_INFO _WdfContextTypeTriageInfo = {0}; +static WDFQUEUE_TRIAGE_INFO _WdfQueueTriageInfo = {0}; +static WDFIRPQUEUE_TRIAGE_INFO _WdfIrpQueueTriageInfo = {0}; +static WDFREQUEST_TRIAGE_INFO _WdfRequestTriageInfo = {0}; +static WDFDEVICE_TRIAGE_INFO _WdfDeviceTriageInfo = {0}; +static WDFIRP_TRIAGE_INFO _WdfIrpTriageInfo = {0}; +static WDFFWDPROGRESS_TRIAGE_INFO _WdfFwdProgressTriageInfo = {0}; + +WDF_TRIAGE_INFO g_WdfTriageInfo = { + // + // UMDF Version. + // + __WUDF_MAJOR_VERSION, + __WUDF_MINOR_VERSION, + + // + // Table Version. + // + WDF_01_TRIAGE_INFO_MAJOR_VERSION, + WDF_01_TRIAGE_INFO_MINOR_VERSION, + + // + // Reserved ptr (set to NULL). + // + NULL, + + // + // WDF objects triage info. + // + &_WdfObjectTriageInfo, + &_WdfContextTriageInfo, + &_WdfContextTypeTriageInfo, + &_WdfQueueTriageInfo, + &_WdfFwdProgressTriageInfo, + &_WdfIrpQueueTriageInfo, + &_WdfRequestTriageInfo, + &_WdfDeviceTriageInfo, + &_WdfIrpTriageInfo, +}; +} // extern "C" + +VOID +GetTriageInfo( + VOID + ) +{ + // Object + _WdfObjectTriageInfo.RawObjectSize = sizeof(FxObject); + _WdfObjectTriageInfo.ObjectType = FIELD_OFFSET(FxObject, m_Type); + _WdfObjectTriageInfo.TotalObjectSize = FIELD_OFFSET(FxObject, m_ObjectSize); + _WdfObjectTriageInfo.ChildListHead = FIELD_OFFSET(FxObject, m_ChildListHead); + _WdfObjectTriageInfo.ChildEntry = FIELD_OFFSET(FxObject, m_ChildEntry); + _WdfObjectTriageInfo.Globals = FIELD_OFFSET(FxObject, m_Globals); + _WdfObjectTriageInfo.ParentObject = FIELD_OFFSET(FxObject, m_ParentObject); + + // Context Triage Info + _WdfContextTriageInfo.HeaderSize = sizeof(FxContextHeader); + _WdfContextTriageInfo.NextHeader = FIELD_OFFSET(FxContextHeader, NextHeader); + _WdfContextTriageInfo.Object = FIELD_OFFSET(FxContextHeader, Object); + _WdfContextTriageInfo.TypeInfoPtr = FIELD_OFFSET(FxContextHeader, ContextTypeInfo); + _WdfContextTriageInfo.Context = FIELD_OFFSET(FxContextHeader, Context); + + // Context type Triage info + _WdfContextTypeTriageInfo.TypeInfoSize = sizeof(WDF_OBJECT_CONTEXT_TYPE_INFO); + _WdfContextTypeTriageInfo.ContextSize = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextSize); + _WdfContextTypeTriageInfo.ContextName = FIELD_OFFSET(WDF_OBJECT_CONTEXT_TYPE_INFO, ContextName); + + // WdfRequest Queue + _WdfQueueTriageInfo.QueueSize = sizeof(FxIoQueue); + _WdfQueueTriageInfo.IrpQueue1 = FIELD_OFFSET(FxIoQueue, m_Queue); + _WdfQueueTriageInfo.IrpQueue2 = FIELD_OFFSET(FxIoQueue, m_DriverCancelable); + _WdfQueueTriageInfo.RequestList1 = FIELD_OFFSET(FxIoQueue, m_Cancelled); + _WdfQueueTriageInfo.RequestList2 = FIELD_OFFSET(FxIoQueue, m_CanceledOnQueueList); + _WdfQueueTriageInfo.FwdProgressContext = FIELD_OFFSET(FxIoQueue, m_FwdProgContext); + _WdfQueueTriageInfo.PkgIo = FIELD_OFFSET(FxIoQueue, m_PkgIo); + + // Forward Progress + _WdfFwdProgressTriageInfo.ReservedRequestList = + FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestList); + _WdfFwdProgressTriageInfo.ReservedRequestInUseList = + FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_ReservedRequestInUseList); + _WdfFwdProgressTriageInfo.PendedIrpList = + FIELD_OFFSET(FXIO_FORWARD_PROGRESS_CONTEXT, m_PendedIrpList); + + // Irp Queue + _WdfIrpQueueTriageInfo.IrpQueueSize = sizeof(FxIrpQueue); + _WdfIrpQueueTriageInfo.IrpListHeader = FIELD_OFFSET(FxIrpQueue, m_Queue); + + + + + + + + + + _WdfIrpQueueTriageInfo.IrpListEntry = 0; + _WdfIrpQueueTriageInfo.IrpContext = 0; + + // WdfRequest + _WdfRequestTriageInfo.RequestSize = sizeof(FxRequest); + _WdfRequestTriageInfo.CsqContext = FIELD_OFFSET(FxRequest, m_CsqContext); + _WdfRequestTriageInfo.FxIrp = FIELD_OFFSET(FxRequest, m_Irp); + _WdfRequestTriageInfo.ListEntryQueueOwned = + FIELD_OFFSET(FxRequest, m_OwnerListEntry); + _WdfRequestTriageInfo.ListEntryQueueOwned2 = + FIELD_OFFSET(FxRequest, m_OwnerListEntry2); + _WdfRequestTriageInfo.RequestListEntry = + FIELD_OFFSET(FxRequest, m_ListEntry); + _WdfRequestTriageInfo.FwdProgressList = + FIELD_OFFSET(FxRequest, m_ForwardProgressList); + + // WdfDevice + _WdfDeviceTriageInfo.DeviceInitSize = sizeof(WDFDEVICE_INIT); + _WdfDeviceTriageInfo.DeviceDriver = FIELD_OFFSET(FxDevice, m_Driver); + + // FxIrp + _WdfIrpTriageInfo.FxIrpSize = sizeof(FxIrp); + _WdfIrpTriageInfo.IrpPtr = FIELD_OFFSET(FxIrp, m_Irp); +} + +NTSTATUS +FxLibraryCommonCommission( + VOID + ) +{ + NTSTATUS status; + + __Print((LITERAL(WDF_LIBRARY_COMMISSION) "\n")); + + // + // Commission this version's DLL globals. + // + status = FxLibraryGlobalsCommission(); + if (!NT_SUCCESS(status)) { + __Print(("FxLibraryGlobalsCommission failed %X\n", status)); + return status; + } + + // + // register for ETW tracing. + // + RegisterTelemetryProvider(); + + // + // Initialize internal WPP tracing. + // + status = FxTraceInitialize(); + if (NT_SUCCESS(status)) { + FxLibraryGlobals.InternalTracingInitialized = TRUE; + } + else { + __Print(("Failed to initialize tracing for WDF\n")); + + // + // Failure to initialize is not critical enough to fail driver load. + // + status = STATUS_SUCCESS; + } + + return status; +} + +NTSTATUS +FxLibraryCommonDecommission( + VOID + ) +{ + __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": enter\n")); + + // + // Uninitialize WPP tracing. + // + if (FxLibraryGlobals.InternalTracingInitialized) { + TraceUninitialize(); + FxLibraryGlobals.InternalTracingInitialized = FALSE; + } + + // + // Unregister telemetry provider. + // + UnregisterTelemetryProvider(); + + EventUnregisterMicrosoft_Windows_DriverFrameworks_UserMode_Performance(); + + // + // Decommission this version's DLL globals. + // + FxLibraryGlobalsDecommission(); + + // + // Note: This is the absolute last action from WDF library (dynamic or static). + // The image is likely to be deleted after returning. + // + __Print((LITERAL(WDF_LIBRARY_DECOMMISSION) ": exit\n")); + + return STATUS_SUCCESS; +} + + +NTSTATUS +FxLibraryCommonRegisterClient( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + PCLIENT_INFO ClientInfo + ) +{ + NTSTATUS status; + + status = STATUS_INVALID_PARAMETER; + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n")); + + ASSERT(Info != NULL && Info->FuncCount != 0); + ASSERT(WdfDriverGlobals != 0); + + if (Info == NULL || WdfDriverGlobals == NULL || Info->FuncTable == NULL) { + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": NULL parameter -- %s\n", + (Info == NULL) ? "PWDF_BIND_INFO" : + (WdfDriverGlobals == NULL) ? "PWDF_DRIVER_GLOBALS *" : + (Info->FuncTable == NULL) ? "PWDF_BIND_INFO->FuncTable" : + "unknown" )); + goto Done; + } + + *WdfDriverGlobals = NULL; + + ASSERT(Info->FuncCount <= WdfVersion.FuncCount); + + // + // WdfVersion.Count is initialized in FxDynamics.h and is never changed. + // Prefast is unable to make that determination. + // + __assume(WdfVersion.FuncCount == sizeof(WDFFUNCTIONS)/sizeof(PVOID)); + + if (Info->FuncCount > WdfVersion.FuncCount) { + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": version mismatch detected in function table count: client" + "has 0x%x, library has 0x%x\n", + Info->FuncCount, WdfVersion.FuncCount)); + goto Done; + } + + if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_15) { + + switch (Info->FuncCount) { + + case WdfFunctionTableNumEntries_V2_15: + case WdfFunctionTableNumEntries_V2_0: + break; + + default: + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": Function table count 0x%x doesn't match any previously " + "released framework version table size\n", + Info->FuncCount)); + goto Done; + } + } + else { + // + // Client version is same as framework version. Make + // sure table count is exact. + // + // Note that in order for build-to-build upgrade to work, the following + // check should be commented out during active development. + // + // DO CHANGE it to a real failure towards the tail end of release to + // prevent cases where a driver sneaks out into public after being built + // with a non-RTM version of WDF and has a function count less than the + // final count. An HCK test has been added to ensure such drivers are + // caught early. This check is an additional prevention. + // + if (Info->FuncCount != WdfFunctionTableNumEntries) { + __Print(("Framework function table size (%d) doesn't match " + "with client (%d). Rebuild the client driver.", + WdfFunctionTableNumEntries, Info->FuncCount)); + + ASSERT(FALSE); + goto Done; + } + } + + // + // Allocate an new FxDriverGlobals area for this driver. + // + *WdfDriverGlobals = FxAllocateDriverGlobals(); + + if (*WdfDriverGlobals) { + BOOLEAN isFunctinTableHookingOn = FALSE; + BOOLEAN isPerformanceAnalysisOn = FALSE; + PFX_DRIVER_GLOBALS fxDriverGlobals = NULL; + // + // Check the registry to see if Enhanced verifier is on for this driver. + // if registry read fails, options value remains unchanged. + // store enhanced verifier options in driver globals + // + fxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals); + GetEnhancedVerifierOptions(ClientInfo, &fxDriverGlobals->FxEnhancedVerifierOptions); + isFunctinTableHookingOn = IsFxVerifierFunctionTableHooking(fxDriverGlobals); + isPerformanceAnalysisOn = IsFxPerformanceAnalysis(fxDriverGlobals); + + // + // Set-up the function table. Enhanced verifier and Performance analysis is off by default. + // + if (isFunctinTableHookingOn == FALSE && isPerformanceAnalysisOn == FALSE) { + // + // Set-up the function table + // + // Starting in 2.15 we reference a copy of the DDI table in WDF01000, + // prior to that we copy the entire table to local memory. + // + if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_0) { + RtlCopyMemory( Info->FuncTable, + &WdfVersion.Functions, + Info->FuncCount * sizeof(PVOID) ); + } + else { + // + // FuncTable arrives with a ptr to &WdfFunctions, so we update + // what WdfFunctions points to + // + *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &WdfVersion.Functions; + } + } + else { + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": Enhanced Verification is ON \n")); + + if (Microsoft_Windows_DriverFrameworks_UserMode_PerformanceHandle == NULL) + { + EventRegisterMicrosoft_Windows_DriverFrameworks_UserMode_Performance(); + } + + // + // Enhanced verification is on. Return verifier function table + // + // Starting in 1.15 we reference a copy of the DDI table in WDF01000, + // prior to that we copy the entire table to local memory. + // + if (Info->FuncCount <= WdfFunctionTableNumEntries_V2_0) { + RtlCopyMemory( Info->FuncTable, + &VfWdfVersion.Functions, + Info->FuncCount * sizeof(PVOID) ); + } + else { + // + // FuncTable arrives with a ptr to &WdfFunctions, so we update + // what WdfFunctions points to. + // + *((WDFFUNC**) Info->FuncTable) = (WDFFUNC*) &VfWdfVersion.Functions; + } + } + + status = STATUS_SUCCESS; + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": WdfFunctions %p\n", Info->FuncTable)); + } + +Done: + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": exit: status %X\n", status)); + + if (!NT_SUCCESS(status)) { + FX_VERIFY(DRIVER(BadArgument, TODO), + TRAPMSG("Version mismatch detected in function table count. Recompile" + " driver with correct headers")); + } + + return status; +} + +NTSTATUS +FxLibraryCommonUnregisterClient( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS WdfDriverGlobals + ) +{ + NTSTATUS status; + + __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) ": enter\n")); + + ASSERT(Info != NULL); + ASSERT(WdfDriverGlobals != NULL); + + if (Info != NULL && WdfDriverGlobals != NULL) { + PFX_DRIVER_GLOBALS pFxDriverGlobals; + + status = STATUS_SUCCESS; + + pFxDriverGlobals = GetFxDriverGlobals(WdfDriverGlobals); + + // + // Destroy this FxDriver instance, if its still indicated. + // + if (pFxDriverGlobals->Driver != NULL) { + // + // Association support, we are a root with no parent + // + pFxDriverGlobals->Driver->DeleteObject(); + + FxDestroy(pFxDriverGlobals); + } + + // + // Stop IFR logging + // + FxIFRStop(pFxDriverGlobals); + + // + // This will free the client's FxDriverGlobals area + // + FxFreeDriverGlobals(WdfDriverGlobals); + } + else { + status = STATUS_UNSUCCESSFUL; + } + + __Print((LITERAL(WDF_LIBRARY_UNREGISTER_CLIENT) + ": exit: status %X\n", status)); + + return status; +} + +VOID +GetEnhancedVerifierOptions( + PCLIENT_INFO ClientInfo, + PULONG Options + ) +{ + NTSTATUS status; + ULONG value; + FxAutoRegKey hWdf; + DECLARE_CONST_UNICODE_STRING(valueName, WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME); + + *Options = 0; + if (ClientInfo == NULL || + ClientInfo->Size != sizeof(CLIENT_INFO) || + ClientInfo->RegistryPath == NULL || + ClientInfo->RegistryPath->Length == 0 || + ClientInfo->RegistryPath->Buffer == NULL || + Options == NULL) { + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) + ": Invalid ClientInfo received from wudfldr \n")); + return; + } + + status = FxRegKey::_OpenKey(NULL, + ClientInfo->RegistryPath, + &hWdf.m_Key, + KEY_READ); + if (!NT_SUCCESS(status)) { + return; + } + + status = FxRegKey::_QueryULong( + hWdf.m_Key, &valueName, &value); + + // + // Examine key values and set Options only on success. + // + if (NT_SUCCESS(status)) { + if (value) { + *Options = value; + } + } +} diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.h b/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.h new file mode 100644 index 00000000000..32994b5d7eb --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/librarycommon/fxlibrarycommon.h @@ -0,0 +1,71 @@ +// +// Copyright (C) Microsoft. All rights reserved. +// +#ifndef __FX_LIBRARY_COMMON_H__ +#define __FX_LIBRARY_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +extern ULONG WdfLdrDbgPrintOn; +extern PCHAR WdfLdrType; + +extern WDFVERSION WdfVersion; + +extern RTL_OSVERSIONINFOW gOsVersion; + +#define _LIT_(a) # a +#define LITERAL(a) _LIT_(a) + + + + +#define __Print(_x_) \ +{ \ + if (WdfLdrDbgPrintOn) { \ + } \ +} + +#define WDF_ENHANCED_VERIFIER_OPTIONS_VALUE_NAME L"EnhancedVerifierOptions" + +typedef +NTSTATUS +(*PFN_RTL_GET_VERSION)( + OUT PRTL_OSVERSIONINFOW VersionInformation + ); + +NTSTATUS +FxLibraryCommonCommission( + VOID + ); + +NTSTATUS +FxLibraryCommonDecommission( + VOID + ); + +NTSTATUS +FxLibraryCommonRegisterClient( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + PCLIENT_INFO ClientInfo + ); + +NTSTATUS +FxLibraryCommonUnregisterClient( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS WdfDriverGlobals + ); + +VOID +GetEnhancedVerifierOptions( + PCLIENT_INFO ClientInfo, + PULONG Options + ); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __FX_LIBRARY_COMMON_H__ diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/version/framework.cpp b/sdk/lib/drivers/wdf/umdf/fxlib/version/framework.cpp new file mode 100644 index 00000000000..34e785693f3 --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/version/framework.cpp @@ -0,0 +1,133 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + framework.cpp + +Abstract: + +Environment: + + User mode only + +Revision History: + + +--*/ + +#include +#include +#include + +#include "fxmin.hpp" +#include "FxFrameworkStubUm.h" + +extern "C" { +#include "FxDynamics.h" +#include "..\librarycommon\FxLibraryCommon.h" +extern WDF_LIBRARY_INFO WdfLibraryInfo; + +#if !(NO_UMDF_VERSION_EXPORT) +__declspec(dllexport) + +__declspec(selectany) + +UMDF_VERSION_DATA Microsoft_WDF_UMDF_Version = {__WUDF_MAJOR_VERSION, + + __WUDF_MINOR_VERSION, + + __WUDF_SERVICE_VERSION}; + +#endif + +// +// Pointer to the platform interface supplied by the host +// +IUMDFPlatform *g_IUMDFPlatform = NULL; +IWudfHost2 *g_IWudfHost2 = NULL; + + +// *********************************************************************************** +// DLL Entry Point +BOOL +WINAPI DllMain( + __in HINSTANCE hInstance, + __in DWORD dwReason, + __in LPVOID lpReserved + ) +{ + UNREFERENCED_PARAMETER(lpReserved); + + hInstance; + + if (DLL_PROCESS_ATTACH == dwReason) + { + DisableThreadLibraryCalls(hInstance); + } + else if (DLL_PROCESS_DETACH == dwReason) + { + DO_NOTHING(); + } + + return TRUE; +} + +__control_entrypoint(DllExport) +NTSTATUS +FxFrameworkEntryUm( + __in PWUDF_LOADER_FX_INTERFACE LoaderInterface, + __in PVOID Context + ) +{ + NTSTATUS status; + + // + // Basic validation. + // + if (LoaderInterface == NULL || + LoaderInterface->Size < sizeof(WUDF_LOADER_FX_INTERFACE) || + LoaderInterface->pUMDFPlatform == NULL) { + status = STATUS_INVALID_PARAMETER; + __Print(("Failed to validate loader interface parameters, " + "status 0x%x\n", status)); + goto Done; + } + + // + // Store platform interface. + // + g_IUMDFPlatform = LoaderInterface->pUMDFPlatform; + + // + // Get the IWudfHost * from LoaderInterface. + // + FX_VERIFY(INTERNAL, CHECK_NOT_NULL(LoaderInterface->pIWudfHost)); + HRESULT hrQI = LoaderInterface->pIWudfHost->QueryInterface( + IID_IWudfHost2, + (PVOID*)&g_IWudfHost2 + ); + + FX_VERIFY(INTERNAL, CHECK_QI(hrQI, g_IWudfHost2)); + g_IWudfHost2->Release(); + + // + // Do first time init of this v2.x framework module. + // In framework v1.x this is done as a side effect of invoking the + // IUMDFramework->Initialize method. + // + status = LoaderInterface->RegisterLibrary(Context, &WdfLibraryInfo); + if (!NT_SUCCESS(status)) { + __Print(("RegisterLibrary failed, status 0x%x\n", status)); + goto Done; + } + + status = STATUS_SUCCESS; + +Done: + + return status; +} + +} diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/version/fxdynamics.h b/sdk/lib/drivers/wdf/umdf/fxlib/version/fxdynamics.h new file mode 100644 index 00000000000..ad27977e717 --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/version/fxdynamics.h @@ -0,0 +1,4188 @@ +/*++ + +Copyright (c) Microsoft. All rights reserved. + +Module Name: FxDynamics.h + +Abstract: + Generated header for WDF APIs + +Environment: + User mode only + + Warning: manual changes to this file will be lost. +--*/ + +#ifndef _FXDYNAMICS_H_ +#define _FXDYNAMICS_H_ + + +typedef struct _WDFFUNCTIONS { + + PFN_WDFCOLLECTIONCREATE pfnWdfCollectionCreate; + PFN_WDFCOLLECTIONGETCOUNT pfnWdfCollectionGetCount; + PFN_WDFCOLLECTIONADD pfnWdfCollectionAdd; + PFN_WDFCOLLECTIONREMOVE pfnWdfCollectionRemove; + PFN_WDFCOLLECTIONREMOVEITEM pfnWdfCollectionRemoveItem; + PFN_WDFCOLLECTIONGETITEM pfnWdfCollectionGetItem; + PFN_WDFCOLLECTIONGETFIRSTITEM pfnWdfCollectionGetFirstItem; + PFN_WDFCOLLECTIONGETLASTITEM pfnWdfCollectionGetLastItem; + PFN_WDFCXDEVICEINITALLOCATE pfnWdfCxDeviceInitAllocate; + PFN_WDFCXDEVICEINITSETREQUESTATTRIBUTES pfnWdfCxDeviceInitSetRequestAttributes; + PFN_WDFCXDEVICEINITSETFILEOBJECTCONFIG pfnWdfCxDeviceInitSetFileObjectConfig; + PFN_WDFCXVERIFIERKEBUGCHECK pfnWdfCxVerifierKeBugCheck; + PFN_WDFDEVICEGETDEVICESTATE pfnWdfDeviceGetDeviceState; + PFN_WDFDEVICESETDEVICESTATE pfnWdfDeviceSetDeviceState; + PFN_WDFDEVICEGETDRIVER pfnWdfDeviceGetDriver; + PFN_WDFDEVICEGETIOTARGET pfnWdfDeviceGetIoTarget; + PFN_WDFDEVICEASSIGNS0IDLESETTINGS pfnWdfDeviceAssignS0IdleSettings; + PFN_WDFDEVICEASSIGNSXWAKESETTINGS pfnWdfDeviceAssignSxWakeSettings; + PFN_WDFDEVICEOPENREGISTRYKEY pfnWdfDeviceOpenRegistryKey; + PFN_WDFDEVICEINITSETPNPPOWEREVENTCALLBACKS pfnWdfDeviceInitSetPnpPowerEventCallbacks; + PFN_WDFDEVICEINITSETPOWERPOLICYEVENTCALLBACKS pfnWdfDeviceInitSetPowerPolicyEventCallbacks; + PFN_WDFDEVICEINITSETPOWERPOLICYOWNERSHIP pfnWdfDeviceInitSetPowerPolicyOwnership; + PFN_WDFDEVICEINITSETIOTYPE pfnWdfDeviceInitSetIoType; + PFN_WDFDEVICEINITSETFILEOBJECTCONFIG pfnWdfDeviceInitSetFileObjectConfig; + PFN_WDFDEVICEINITSETREQUESTATTRIBUTES pfnWdfDeviceInitSetRequestAttributes; + PFN_WDFDEVICECREATE pfnWdfDeviceCreate; + PFN_WDFDEVICESETSTATICSTOPREMOVE pfnWdfDeviceSetStaticStopRemove; + PFN_WDFDEVICECREATEDEVICEINTERFACE pfnWdfDeviceCreateDeviceInterface; + PFN_WDFDEVICESETDEVICEINTERFACESTATE pfnWdfDeviceSetDeviceInterfaceState; + PFN_WDFDEVICERETRIEVEDEVICEINTERFACESTRING pfnWdfDeviceRetrieveDeviceInterfaceString; + PFN_WDFDEVICECREATESYMBOLICLINK pfnWdfDeviceCreateSymbolicLink; + PFN_WDFDEVICEQUERYPROPERTY pfnWdfDeviceQueryProperty; + PFN_WDFDEVICEALLOCANDQUERYPROPERTY pfnWdfDeviceAllocAndQueryProperty; + PFN_WDFDEVICESETPNPCAPABILITIES pfnWdfDeviceSetPnpCapabilities; + PFN_WDFDEVICESETPOWERCAPABILITIES pfnWdfDeviceSetPowerCapabilities; + PFN_WDFDEVICESETFAILED pfnWdfDeviceSetFailed; + PFN_WDFDEVICESTOPIDLENOTRACK pfnWdfDeviceStopIdleNoTrack; + PFN_WDFDEVICERESUMEIDLENOTRACK pfnWdfDeviceResumeIdleNoTrack; + PFN_WDFDEVICEGETFILEOBJECT pfnWdfDeviceGetFileObject; + PFN_WDFDEVICEGETDEFAULTQUEUE pfnWdfDeviceGetDefaultQueue; + PFN_WDFDEVICECONFIGUREREQUESTDISPATCHING pfnWdfDeviceConfigureRequestDispatching; + PFN_WDFDEVICEGETSYSTEMPOWERACTION pfnWdfDeviceGetSystemPowerAction; + PFN_WDFDEVICEINITSETRELEASEHARDWAREORDERONFAILURE pfnWdfDeviceInitSetReleaseHardwareOrderOnFailure; + PFN_WDFDEVICEINITSETIOTYPEEX pfnWdfDeviceInitSetIoTypeEx; + PFN_WDFDEVICEPOSTEVENT pfnWdfDevicePostEvent; + PFN_WDFDEVICEMAPIOSPACE pfnWdfDeviceMapIoSpace; + PFN_WDFDEVICEUNMAPIOSPACE pfnWdfDeviceUnmapIoSpace; + PFN_WDFDEVICEGETHARDWAREREGISTERMAPPEDADDRESS pfnWdfDeviceGetHardwareRegisterMappedAddress; + PFN_WDFDEVICEREADFROMHARDWARE pfnWdfDeviceReadFromHardware; + PFN_WDFDEVICEWRITETOHARDWARE pfnWdfDeviceWriteToHardware; + PFN_WDFDEVICEASSIGNINTERFACEPROPERTY pfnWdfDeviceAssignInterfaceProperty; + PFN_WDFDEVICEALLOCANDQUERYINTERFACEPROPERTY pfnWdfDeviceAllocAndQueryInterfaceProperty; + PFN_WDFDEVICEQUERYINTERFACEPROPERTY pfnWdfDeviceQueryInterfaceProperty; + PFN_WDFDEVICEGETDEVICESTACKIOTYPE pfnWdfDeviceGetDeviceStackIoType; + PFN_WDFDEVICEQUERYPROPERTYEX pfnWdfDeviceQueryPropertyEx; + PFN_WDFDEVICEALLOCANDQUERYPROPERTYEX pfnWdfDeviceAllocAndQueryPropertyEx; + PFN_WDFDEVICEASSIGNPROPERTY pfnWdfDeviceAssignProperty; + PFN_WDFDRIVERCREATE pfnWdfDriverCreate; + PFN_WDFDRIVERGETREGISTRYPATH pfnWdfDriverGetRegistryPath; + PFN_WDFDRIVEROPENPARAMETERSREGISTRYKEY pfnWdfDriverOpenParametersRegistryKey; + PFN_WDFDRIVERRETRIEVEVERSIONSTRING pfnWdfDriverRetrieveVersionString; + PFN_WDFDRIVERISVERSIONAVAILABLE pfnWdfDriverIsVersionAvailable; + PFN_WDFFDOINITOPENREGISTRYKEY pfnWdfFdoInitOpenRegistryKey; + PFN_WDFFDOINITQUERYPROPERTY pfnWdfFdoInitQueryProperty; + PFN_WDFFDOINITALLOCANDQUERYPROPERTY pfnWdfFdoInitAllocAndQueryProperty; + PFN_WDFFDOINITQUERYPROPERTYEX pfnWdfFdoInitQueryPropertyEx; + PFN_WDFFDOINITALLOCANDQUERYPROPERTYEX pfnWdfFdoInitAllocAndQueryPropertyEx; + PFN_WDFFDOINITSETFILTER pfnWdfFdoInitSetFilter; + PFN_WDFFILEOBJECTGETFILENAME pfnWdfFileObjectGetFileName; + PFN_WDFFILEOBJECTGETDEVICE pfnWdfFileObjectGetDevice; + PFN_WDFFILEOBJECTGETINITIATORPROCESSID pfnWdfFileObjectGetInitiatorProcessId; + PFN_WDFFILEOBJECTGETRELATEDFILEOBJECT pfnWdfFileObjectGetRelatedFileObject; + PFN_WDFINTERRUPTCREATE pfnWdfInterruptCreate; + PFN_WDFINTERRUPTQUEUEDPCFORISR pfnWdfInterruptQueueDpcForIsr; + PFN_WDFINTERRUPTQUEUEWORKITEMFORISR pfnWdfInterruptQueueWorkItemForIsr; + PFN_WDFINTERRUPTSYNCHRONIZE pfnWdfInterruptSynchronize; + PFN_WDFINTERRUPTACQUIRELOCK pfnWdfInterruptAcquireLock; + PFN_WDFINTERRUPTRELEASELOCK pfnWdfInterruptReleaseLock; + PFN_WDFINTERRUPTENABLE pfnWdfInterruptEnable; + PFN_WDFINTERRUPTDISABLE pfnWdfInterruptDisable; + PFN_WDFINTERRUPTGETINFO pfnWdfInterruptGetInfo; + PFN_WDFINTERRUPTSETPOLICY pfnWdfInterruptSetPolicy; + PFN_WDFINTERRUPTSETEXTENDEDPOLICY pfnWdfInterruptSetExtendedPolicy; + PFN_WDFINTERRUPTGETDEVICE pfnWdfInterruptGetDevice; + PFN_WDFINTERRUPTTRYTOACQUIRELOCK pfnWdfInterruptTryToAcquireLock; + PFN_WDFIOQUEUECREATE pfnWdfIoQueueCreate; + PFN_WDFIOQUEUEGETSTATE pfnWdfIoQueueGetState; + PFN_WDFIOQUEUESTART pfnWdfIoQueueStart; + PFN_WDFIOQUEUESTOP pfnWdfIoQueueStop; + PFN_WDFIOQUEUESTOPSYNCHRONOUSLY pfnWdfIoQueueStopSynchronously; + PFN_WDFIOQUEUEGETDEVICE pfnWdfIoQueueGetDevice; + PFN_WDFIOQUEUERETRIEVENEXTREQUEST pfnWdfIoQueueRetrieveNextRequest; + PFN_WDFIOQUEUERETRIEVEREQUESTBYFILEOBJECT pfnWdfIoQueueRetrieveRequestByFileObject; + PFN_WDFIOQUEUEFINDREQUEST pfnWdfIoQueueFindRequest; + PFN_WDFIOQUEUERETRIEVEFOUNDREQUEST pfnWdfIoQueueRetrieveFoundRequest; + PFN_WDFIOQUEUEDRAINSYNCHRONOUSLY pfnWdfIoQueueDrainSynchronously; + PFN_WDFIOQUEUEDRAIN pfnWdfIoQueueDrain; + PFN_WDFIOQUEUEPURGESYNCHRONOUSLY pfnWdfIoQueuePurgeSynchronously; + PFN_WDFIOQUEUEPURGE pfnWdfIoQueuePurge; + PFN_WDFIOQUEUEREADYNOTIFY pfnWdfIoQueueReadyNotify; + PFN_WDFIOQUEUESTOPANDPURGE pfnWdfIoQueueStopAndPurge; + PFN_WDFIOQUEUESTOPANDPURGESYNCHRONOUSLY pfnWdfIoQueueStopAndPurgeSynchronously; + PFN_WDFIOTARGETCREATE pfnWdfIoTargetCreate; + PFN_WDFIOTARGETOPEN pfnWdfIoTargetOpen; + PFN_WDFIOTARGETCLOSEFORQUERYREMOVE pfnWdfIoTargetCloseForQueryRemove; + PFN_WDFIOTARGETCLOSE pfnWdfIoTargetClose; + PFN_WDFIOTARGETSTART pfnWdfIoTargetStart; + PFN_WDFIOTARGETSTOP pfnWdfIoTargetStop; + PFN_WDFIOTARGETPURGE pfnWdfIoTargetPurge; + PFN_WDFIOTARGETGETSTATE pfnWdfIoTargetGetState; + PFN_WDFIOTARGETGETDEVICE pfnWdfIoTargetGetDevice; + PFN_WDFIOTARGETSENDREADSYNCHRONOUSLY pfnWdfIoTargetSendReadSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORREAD pfnWdfIoTargetFormatRequestForRead; + PFN_WDFIOTARGETSENDWRITESYNCHRONOUSLY pfnWdfIoTargetSendWriteSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORWRITE pfnWdfIoTargetFormatRequestForWrite; + PFN_WDFIOTARGETSENDIOCTLSYNCHRONOUSLY pfnWdfIoTargetSendIoctlSynchronously; + PFN_WDFIOTARGETFORMATREQUESTFORIOCTL pfnWdfIoTargetFormatRequestForIoctl; + PFN_WDFMEMORYCREATE pfnWdfMemoryCreate; + PFN_WDFMEMORYCREATEPREALLOCATED pfnWdfMemoryCreatePreallocated; + PFN_WDFMEMORYGETBUFFER pfnWdfMemoryGetBuffer; + PFN_WDFMEMORYASSIGNBUFFER pfnWdfMemoryAssignBuffer; + PFN_WDFMEMORYCOPYTOBUFFER pfnWdfMemoryCopyToBuffer; + PFN_WDFMEMORYCOPYFROMBUFFER pfnWdfMemoryCopyFromBuffer; + PFN_WDFOBJECTGETTYPEDCONTEXTWORKER pfnWdfObjectGetTypedContextWorker; + PFN_WDFOBJECTALLOCATECONTEXT pfnWdfObjectAllocateContext; + PFN_WDFOBJECTCONTEXTGETOBJECT pfnWdfObjectContextGetObject; + PFN_WDFOBJECTREFERENCEACTUAL pfnWdfObjectReferenceActual; + PFN_WDFOBJECTDEREFERENCEACTUAL pfnWdfObjectDereferenceActual; + PFN_WDFOBJECTCREATE pfnWdfObjectCreate; + PFN_WDFOBJECTDELETE pfnWdfObjectDelete; + PFN_WDFOBJECTQUERY pfnWdfObjectQuery; + PFN_WDFREGISTRYOPENKEY pfnWdfRegistryOpenKey; + PFN_WDFREGISTRYCREATEKEY pfnWdfRegistryCreateKey; + PFN_WDFREGISTRYCLOSE pfnWdfRegistryClose; + PFN_WDFREGISTRYREMOVEKEY pfnWdfRegistryRemoveKey; + PFN_WDFREGISTRYREMOVEVALUE pfnWdfRegistryRemoveValue; + PFN_WDFREGISTRYQUERYVALUE pfnWdfRegistryQueryValue; + PFN_WDFREGISTRYQUERYMEMORY pfnWdfRegistryQueryMemory; + PFN_WDFREGISTRYQUERYMULTISTRING pfnWdfRegistryQueryMultiString; + PFN_WDFREGISTRYQUERYUNICODESTRING pfnWdfRegistryQueryUnicodeString; + PFN_WDFREGISTRYQUERYSTRING pfnWdfRegistryQueryString; + PFN_WDFREGISTRYQUERYULONG pfnWdfRegistryQueryULong; + PFN_WDFREGISTRYASSIGNVALUE pfnWdfRegistryAssignValue; + PFN_WDFREGISTRYASSIGNMEMORY pfnWdfRegistryAssignMemory; + PFN_WDFREGISTRYASSIGNMULTISTRING pfnWdfRegistryAssignMultiString; + PFN_WDFREGISTRYASSIGNUNICODESTRING pfnWdfRegistryAssignUnicodeString; + PFN_WDFREGISTRYASSIGNSTRING pfnWdfRegistryAssignString; + PFN_WDFREGISTRYASSIGNULONG pfnWdfRegistryAssignULong; + PFN_WDFREQUESTCREATE pfnWdfRequestCreate; + PFN_WDFREQUESTREUSE pfnWdfRequestReuse; + PFN_WDFREQUESTCHANGETARGET pfnWdfRequestChangeTarget; + PFN_WDFREQUESTFORMATREQUESTUSINGCURRENTTYPE pfnWdfRequestFormatRequestUsingCurrentType; + PFN_WDFREQUESTSEND pfnWdfRequestSend; + PFN_WDFREQUESTGETSTATUS pfnWdfRequestGetStatus; + PFN_WDFREQUESTMARKCANCELABLE pfnWdfRequestMarkCancelable; + PFN_WDFREQUESTMARKCANCELABLEEX pfnWdfRequestMarkCancelableEx; + PFN_WDFREQUESTUNMARKCANCELABLE pfnWdfRequestUnmarkCancelable; + PFN_WDFREQUESTISCANCELED pfnWdfRequestIsCanceled; + PFN_WDFREQUESTCANCELSENTREQUEST pfnWdfRequestCancelSentRequest; + PFN_WDFREQUESTISFROM32BITPROCESS pfnWdfRequestIsFrom32BitProcess; + PFN_WDFREQUESTSETCOMPLETIONROUTINE pfnWdfRequestSetCompletionRoutine; + PFN_WDFREQUESTGETCOMPLETIONPARAMS pfnWdfRequestGetCompletionParams; + PFN_WDFREQUESTALLOCATETIMER pfnWdfRequestAllocateTimer; + PFN_WDFREQUESTCOMPLETE pfnWdfRequestComplete; + PFN_WDFREQUESTCOMPLETEWITHINFORMATION pfnWdfRequestCompleteWithInformation; + PFN_WDFREQUESTGETPARAMETERS pfnWdfRequestGetParameters; + PFN_WDFREQUESTRETRIEVEINPUTMEMORY pfnWdfRequestRetrieveInputMemory; + PFN_WDFREQUESTRETRIEVEOUTPUTMEMORY pfnWdfRequestRetrieveOutputMemory; + PFN_WDFREQUESTRETRIEVEINPUTBUFFER pfnWdfRequestRetrieveInputBuffer; + PFN_WDFREQUESTRETRIEVEOUTPUTBUFFER pfnWdfRequestRetrieveOutputBuffer; + PFN_WDFREQUESTSETINFORMATION pfnWdfRequestSetInformation; + PFN_WDFREQUESTGETINFORMATION pfnWdfRequestGetInformation; + PFN_WDFREQUESTGETFILEOBJECT pfnWdfRequestGetFileObject; + PFN_WDFREQUESTGETREQUESTORMODE pfnWdfRequestGetRequestorMode; + PFN_WDFREQUESTFORWARDTOIOQUEUE pfnWdfRequestForwardToIoQueue; + PFN_WDFREQUESTGETIOQUEUE pfnWdfRequestGetIoQueue; + PFN_WDFREQUESTREQUEUE pfnWdfRequestRequeue; + PFN_WDFREQUESTSTOPACKNOWLEDGE pfnWdfRequestStopAcknowledge; + PFN_WDFREQUESTIMPERSONATE pfnWdfRequestImpersonate; + PFN_WDFREQUESTGETREQUESTORPROCESSID pfnWdfRequestGetRequestorProcessId; + PFN_WDFREQUESTISFROMUSERMODEDRIVER pfnWdfRequestIsFromUserModeDriver; + PFN_WDFREQUESTSETUSERMODEDRIVERINITIATEDIO pfnWdfRequestSetUserModeDriverInitiatedIo; + PFN_WDFREQUESTGETUSERMODEDRIVERINITIATEDIO pfnWdfRequestGetUserModeDriverInitiatedIo; + PFN_WDFREQUESTSETACTIVITYID pfnWdfRequestSetActivityId; + PFN_WDFREQUESTRETRIEVEACTIVITYID pfnWdfRequestRetrieveActivityId; + PFN_WDFREQUESTGETEFFECTIVEIOTYPE pfnWdfRequestGetEffectiveIoType; + PFN_WDFCMRESOURCELISTGETCOUNT pfnWdfCmResourceListGetCount; + PFN_WDFCMRESOURCELISTGETDESCRIPTOR pfnWdfCmResourceListGetDescriptor; + PFN_WDFSTRINGCREATE pfnWdfStringCreate; + PFN_WDFSTRINGGETUNICODESTRING pfnWdfStringGetUnicodeString; + PFN_WDFOBJECTACQUIRELOCK pfnWdfObjectAcquireLock; + PFN_WDFOBJECTRELEASELOCK pfnWdfObjectReleaseLock; + PFN_WDFWAITLOCKCREATE pfnWdfWaitLockCreate; + PFN_WDFWAITLOCKACQUIRE pfnWdfWaitLockAcquire; + PFN_WDFWAITLOCKRELEASE pfnWdfWaitLockRelease; + PFN_WDFSPINLOCKCREATE pfnWdfSpinLockCreate; + PFN_WDFSPINLOCKACQUIRE pfnWdfSpinLockAcquire; + PFN_WDFSPINLOCKRELEASE pfnWdfSpinLockRelease; + PFN_WDFTIMERCREATE pfnWdfTimerCreate; + PFN_WDFTIMERSTART pfnWdfTimerStart; + PFN_WDFTIMERSTOP pfnWdfTimerStop; + PFN_WDFTIMERGETPARENTOBJECT pfnWdfTimerGetParentObject; + PFN_WDFUSBTARGETDEVICECREATE pfnWdfUsbTargetDeviceCreate; + PFN_WDFUSBTARGETDEVICECREATEWITHPARAMETERS pfnWdfUsbTargetDeviceCreateWithParameters; + PFN_WDFUSBTARGETDEVICERETRIEVEINFORMATION pfnWdfUsbTargetDeviceRetrieveInformation; + PFN_WDFUSBTARGETDEVICEGETDEVICEDESCRIPTOR pfnWdfUsbTargetDeviceGetDeviceDescriptor; + PFN_WDFUSBTARGETDEVICERETRIEVECONFIGDESCRIPTOR pfnWdfUsbTargetDeviceRetrieveConfigDescriptor; + PFN_WDFUSBTARGETDEVICEQUERYSTRING pfnWdfUsbTargetDeviceQueryString; + PFN_WDFUSBTARGETDEVICEALLOCANDQUERYSTRING pfnWdfUsbTargetDeviceAllocAndQueryString; + PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORSTRING pfnWdfUsbTargetDeviceFormatRequestForString; + PFN_WDFUSBTARGETDEVICEGETNUMINTERFACES pfnWdfUsbTargetDeviceGetNumInterfaces; + PFN_WDFUSBTARGETDEVICESELECTCONFIG pfnWdfUsbTargetDeviceSelectConfig; + PFN_WDFUSBTARGETDEVICESENDCONTROLTRANSFERSYNCHRONOUSLY pfnWdfUsbTargetDeviceSendControlTransferSynchronously; + PFN_WDFUSBTARGETDEVICEFORMATREQUESTFORCONTROLTRANSFER pfnWdfUsbTargetDeviceFormatRequestForControlTransfer; + PFN_WDFUSBTARGETDEVICERESETPORTSYNCHRONOUSLY pfnWdfUsbTargetDeviceResetPortSynchronously; + PFN_WDFUSBTARGETDEVICEQUERYUSBCAPABILITY pfnWdfUsbTargetDeviceQueryUsbCapability; + PFN_WDFUSBTARGETPIPEGETINFORMATION pfnWdfUsbTargetPipeGetInformation; + PFN_WDFUSBTARGETPIPEISINENDPOINT pfnWdfUsbTargetPipeIsInEndpoint; + PFN_WDFUSBTARGETPIPEISOUTENDPOINT pfnWdfUsbTargetPipeIsOutEndpoint; + PFN_WDFUSBTARGETPIPEGETTYPE pfnWdfUsbTargetPipeGetType; + PFN_WDFUSBTARGETPIPESETNOMAXIMUMPACKETSIZECHECK pfnWdfUsbTargetPipeSetNoMaximumPacketSizeCheck; + PFN_WDFUSBTARGETPIPEWRITESYNCHRONOUSLY pfnWdfUsbTargetPipeWriteSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORWRITE pfnWdfUsbTargetPipeFormatRequestForWrite; + PFN_WDFUSBTARGETPIPEREADSYNCHRONOUSLY pfnWdfUsbTargetPipeReadSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORREAD pfnWdfUsbTargetPipeFormatRequestForRead; + PFN_WDFUSBTARGETPIPECONFIGCONTINUOUSREADER pfnWdfUsbTargetPipeConfigContinuousReader; + PFN_WDFUSBTARGETPIPEABORTSYNCHRONOUSLY pfnWdfUsbTargetPipeAbortSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORABORT pfnWdfUsbTargetPipeFormatRequestForAbort; + PFN_WDFUSBTARGETPIPERESETSYNCHRONOUSLY pfnWdfUsbTargetPipeResetSynchronously; + PFN_WDFUSBTARGETPIPEFORMATREQUESTFORRESET pfnWdfUsbTargetPipeFormatRequestForReset; + PFN_WDFUSBINTERFACEGETINTERFACENUMBER pfnWdfUsbInterfaceGetInterfaceNumber; + PFN_WDFUSBINTERFACEGETNUMENDPOINTS pfnWdfUsbInterfaceGetNumEndpoints; + PFN_WDFUSBINTERFACEGETDESCRIPTOR pfnWdfUsbInterfaceGetDescriptor; + PFN_WDFUSBINTERFACEGETNUMSETTINGS pfnWdfUsbInterfaceGetNumSettings; + PFN_WDFUSBINTERFACESELECTSETTING pfnWdfUsbInterfaceSelectSetting; + PFN_WDFUSBINTERFACEGETENDPOINTINFORMATION pfnWdfUsbInterfaceGetEndpointInformation; + PFN_WDFUSBTARGETDEVICEGETINTERFACE pfnWdfUsbTargetDeviceGetInterface; + PFN_WDFUSBINTERFACEGETCONFIGUREDSETTINGINDEX pfnWdfUsbInterfaceGetConfiguredSettingIndex; + PFN_WDFUSBINTERFACEGETNUMCONFIGUREDPIPES pfnWdfUsbInterfaceGetNumConfiguredPipes; + PFN_WDFUSBINTERFACEGETCONFIGUREDPIPE pfnWdfUsbInterfaceGetConfiguredPipe; + PFN_WDFVERIFIERDBGBREAKPOINT pfnWdfVerifierDbgBreakPoint; + PFN_WDFVERIFIERKEBUGCHECK pfnWdfVerifierKeBugCheck; + PFN_WDFGETTRIAGEINFO pfnWdfGetTriageInfo; + PFN_WDFWORKITEMCREATE pfnWdfWorkItemCreate; + PFN_WDFWORKITEMENQUEUE pfnWdfWorkItemEnqueue; + PFN_WDFWORKITEMGETPARENTOBJECT pfnWdfWorkItemGetParentObject; + PFN_WDFWORKITEMFLUSH pfnWdfWorkItemFlush; + PFN_WDFREGISTRYWDMGETHANDLE pfnWdfRegistryWdmGetHandle; + PFN_WDFDEVICESTOPIDLEACTUAL pfnWdfDeviceStopIdleActual; + PFN_WDFDEVICERESUMEIDLEACTUAL pfnWdfDeviceResumeIdleActual; + PFN_WDFDEVICEINITENABLEHIDINTERFACE pfnWdfDeviceInitEnableHidInterface; + PFN_WDFDEVICEHIDNOTIFYPRESENCE pfnWdfDeviceHidNotifyPresence; + PFN_WDFDEVICEGETSELFIOTARGET pfnWdfDeviceGetSelfIoTarget; + PFN_WDFDEVICEINITALLOWSELFIOTARGET pfnWdfDeviceInitAllowSelfIoTarget; + PFN_WDFIOTARGETSELFASSIGNDEFAULTIOQUEUE pfnWdfIoTargetSelfAssignDefaultIoQueue; + PFN_WDFDEVICEOPENDEVICEMAPKEY pfnWdfDeviceOpenDevicemapKey; + PFN_WDFIOTARGETWDMGETTARGETFILEHANDLE pfnWdfIoTargetWdmGetTargetFileHandle; + PFN_WDFDEVICEWDMDISPATCHIRP pfnWdfDeviceWdmDispatchIrp; + PFN_WDFDEVICEWDMDISPATCHIRPTOIOQUEUE pfnWdfDeviceWdmDispatchIrpToIoQueue; + PFN_WDFDEVICECONFIGUREWDMIRPDISPATCHCALLBACK pfnWdfDeviceConfigureWdmIrpDispatchCallback; + +} WDFFUNCTIONS, *PWDFFUNCTIONS; + + +typedef struct _WDFVERSION { + + ULONG Size; + ULONG FuncCount; + WDFFUNCTIONS Functions; + +} WDFVERSION, *PWDFVERSION; + + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCollectionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + _Out_ + WDFCOLLECTION* Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfCollectionGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfCollectionAdd)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCollectionRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Item + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCollectionRemoveItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfCollectionGetItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfCollectionGetFirstItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfCollectionGetLastItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFCXDEVICE_INIT +WDFEXPORT(WdfCxDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +WDFAPI +VOID +WDFEXPORT(WdfCxVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFOBJECT Object, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceGetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + PWDF_DEVICE_STATE DeviceState + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_STATE DeviceState + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFCONTEXT DispatchContext + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFQUEUE Queue, + _In_ + ULONG Flags + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +WDFEXPORT(WdfDeviceGetDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +WDFEXPORT(WdfDeviceGetIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignS0IdleSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignSxWakeSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceOpenDevicemapKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsPowerPolicyOwner + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_IO_TYPE IoType + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT* DeviceInit, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + _Out_ + WDFDEVICE* Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetStaticStopRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN Stoppable + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceCreateDeviceInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + BOOLEAN IsInterfaceEnabled + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceCreateSymbolicLink)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING SymbolicLinkName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetPnpCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetPowerCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceSetFailed)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_FAILED_ACTION FailedAction + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceStopIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceResumeIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceStopIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceResumeIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +WDFEXPORT(WdfDeviceGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PFILE_OBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +WDFEXPORT(WdfDeviceGetDefaultQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceConfigureRequestDispatching)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFQUEUE Queue, + _In_ + _Strict_type_match_ + WDF_REQUEST_TYPE RequestType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDisptach, + _In_opt_ + WDFCONTEXT DriverContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +POWER_ACTION +WDFEXPORT(WdfDeviceGetSystemPowerAction)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDevicePostEvent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + REFGUID EventGuid, + _In_ + WDF_EVENT_TYPE WdfEventType, + _In_reads_bytes_(DataSizeCb) + BYTE* Data, + _In_ + ULONG DataSizeCb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceMapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PHYSICAL_ADDRESS PhysicalAddress, + _In_ + SIZE_T NumberOfBytes, + _In_ + MEMORY_CACHING_TYPE CacheType, + _Out_ + PVOID* PseudoBaseAddress + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceUnmapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress, + _In_ + SIZE_T NumberOfBytes + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PVOID +WDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +SIZE_T +WDFEXPORT(WdfDeviceReadFromHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _Out_writes_all_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceWriteToHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _In_ + SIZE_T Value, + _In_reads_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG BufferLength, + _In_reads_bytes_opt_(BufferLength) + PVOID PropertyBuffer + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + ULONG BufferLength, + _Out_writes_bytes_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceGetDeviceStackIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + WDF_DEVICE_IO_TYPE* ReadWriteIoType, + _Out_ + WDF_DEVICE_IO_TYPE* IoControlIoType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG Size, + _In_opt_ + PVOID Data + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +WDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PCUNICODE_STRING RegistryPath, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + _In_ + PWDF_DRIVER_CONFIG DriverConfig, + _Out_opt_ + WDFDRIVER* Driver + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWSTR +WDFEXPORT(WdfDriverGetRegistryPath)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverOpenParametersRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDriverRetrieveVersionString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfDriverIsVersionAvailable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfFdoInitSetFilter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PUNICODE_STRING +WDFEXPORT(WdfFileObjectGetFileName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfFileObjectGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfFileObjectGetInitiatorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDFFILEOBJECT +WDFEXPORT(WdfFileObjectGetRelatedFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfDeviceInitEnableHidInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfDeviceHidNotifyPresence)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN IsPresent + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfInterruptCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_INTERRUPT_CONFIG Configuration, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFINTERRUPT* Interrupt + ); + +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptQueueDpcForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptSynchronize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + _In_ + WDFCONTEXT Context + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +WDFEXPORT(WdfInterruptAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +WDFEXPORT(WdfInterruptReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptEnable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptDisable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptGetInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _Out_ + PWDF_INTERRUPT_INFO Info + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptSetPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + WDF_INTERRUPT_POLICY Policy, + _In_ + WDF_INTERRUPT_PRIORITY Priority, + _In_ + KAFFINITY TargetProcessorSet + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfInterruptSetExtendedPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ); + +WDFAPI +WDFDEVICE +WDFEXPORT(WdfInterruptGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_Post_satisfies_(return == 1 || return == 0) +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfInterruptTryToAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_IO_QUEUE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + _Out_opt_ + WDFQUEUE* Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_QUEUE_STATE +WDFEXPORT(WdfIoQueueGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_opt_ + PULONG QueueRequests, + _Out_opt_ + PULONG DriverRequests + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopComplete, + _When_(StopComplete != 0, _In_) + _When_(StopComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStopSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfIoQueueGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveNextRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFFILEOBJECT FileObject, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueFindRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + WDFREQUEST FoundRequest, + _In_opt_ + WDFFILEOBJECT FileObject, + _Inout_opt_ + PWDF_REQUEST_PARAMETERS Parameters, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFREQUEST FoundRequest, + _Out_ + WDFREQUEST* OutRequest + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueDrainSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueDrain)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + _When_(DrainComplete != 0, _In_) + _When_(DrainComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueuePurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueuePurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + _When_(PurgeComplete != 0, _In_) + _When_(PurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoQueueReadyNotify)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + PFN_WDF_IO_QUEUE_STATE QueueReady, + _In_opt_ + WDFCONTEXT Context + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStopAndPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + _When_(StopAndPurgeComplete != 0, _In_) + _When_(StopAndPurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + _Out_ + WDFIOTARGET* IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetOpen)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetCloseForQueryRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_When_(Action == 3, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1 || Action == 2, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_SENT_IO_ACTION Action + ); + +_When_(Action == 2, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +WDFEXPORT(WdfIoTargetPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_PURGE_IO_ACTION Action + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_TARGET_STATE +WDFEXPORT(WdfIoTargetGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +WDFEXPORT(WdfIoTargetGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +HANDLE +WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + ULONG PoolTag, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory, + _Outptr_opt_result_bytebuffer_(BufferSize) + PVOID* Buffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCreatePreallocated)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ __drv_aliasesMem + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +WDFEXPORT(WdfMemoryGetBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Out_opt_ + size_t* BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCopyToBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY SourceMemory, + _In_ + size_t SourceOffset, + _Out_writes_bytes_( NumBytesToCopyTo ) + PVOID Buffer, + _In_ + _When_(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfMemoryCopyFromBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY DestinationMemory, + _In_ + size_t DestinationOffset, + _In_ + PVOID Buffer, + _In_ + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ); + +WDFAPI +PVOID +FASTCALL +WDFEXPORT(WdfObjectGetTypedContextWorker)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ); + +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectAllocateContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PWDF_OBJECT_ATTRIBUTES ContextAttributes, + _Outptr_opt_ + PVOID* Context + ); + +WDFAPI +WDFOBJECT +FASTCALL +WDFEXPORT(WdfObjectContextGetObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PVOID ContextPointer + ); + +WDFAPI +VOID +WDFEXPORT(WdfObjectReferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +WDFAPI +VOID +WDFEXPORT(WdfObjectDereferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFOBJECT* Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectDelete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfObjectQuery)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object, + _In_ + CONST GUID* Guid, + _In_ + ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryOpenKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryCreateKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_ + ULONG CreateOptions, + _Out_opt_ + PULONG CreateDisposition, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRegistryClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +HANDLE +WDFEXPORT(WdfRegistryWdmGetHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryRemoveKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryRemoveValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueLength, + _Out_writes_bytes_opt_( ValueLength) + PVOID Value, + _Out_opt_ + PULONG ValueLengthQueried, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _Out_ + WDFMEMORY* Memory, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_opt_ + PUSHORT ValueByteLength, + _Inout_opt_ + PUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryQueryULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_ + PULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + ULONG ValueLength, + _In_reads_( ValueLength) + PVOID Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET MemoryOffsets + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFCOLLECTION StringsCollection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + PCUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRegistryAssignULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_opt_ + WDFIOTARGET IoTarget, + _Out_ + WDFREQUEST* Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestReuse)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestChangeTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS == 0, _Must_inspect_result_) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestSend)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET Target, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS Options + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestGetStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestMarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestMarkCancelableEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestUnmarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsCanceled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestCancelSentRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsFrom32BitProcess)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetCompletionRoutine)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_opt_ + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ __drv_aliasesMem + WDFCONTEXT CompletionContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestGetCompletionParams)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_COMPLETION_PARAMS Params + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestAllocateTimer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestComplete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestCompleteWithInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestGetParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_PARAMETERS Parameters + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveInputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveOutputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredSize, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG_PTR +WDFEXPORT(WdfRequestGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +WDFEXPORT(WdfRequestGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +KPROCESSOR_MODE +WDFEXPORT(WdfRequestGetRequestorMode)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestForwardToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE DestinationQueue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +WDFEXPORT(WdfRequestGetIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRequeue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestStopAcknowledge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN Requeue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestImpersonate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_ + PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate, + _In_opt_ + PVOID Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfRequestGetRequestorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestIsFromUserModeDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN IsUserModeDriverInitiated + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfRequestSetActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + LPGUID ActivityId + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfRequestRetrieveActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + LPGUID ActivityId + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDF_DEVICE_IO_TYPE +WDFEXPORT(WdfRequestGetEffectiveIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +WDFEXPORT(WdfCmResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PCM_PARTIAL_RESOURCE_DESCRIPTOR +WDFEXPORT(WdfCmResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfStringCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PCUNICODE_STRING UnicodeString, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringAttributes, + _Out_ + WDFSTRING* String + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfStringGetUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFSTRING String, + _Out_ + PUNICODE_STRING UnicodeString + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfObjectReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWaitLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LockAttributes, + _Out_ + WDFWAITLOCK* Lock + ); + +_When_(Timeout == NULL, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Timeout != NULL && *Timeout == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Timeout != NULL && *Timeout != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +_Always_(_When_(Timeout == NULL, _Acquires_lock_(Lock))) +_When_(Timeout != NULL && return == STATUS_SUCCESS, _Acquires_lock_(Lock)) +_When_(Timeout != NULL, _Must_inspect_result_) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWaitLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + WDFWAITLOCK Lock, + _In_opt_ + PLONGLONG Timeout + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWaitLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFWAITLOCK Lock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfSpinLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + _Out_ + WDFSPINLOCK* SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfSpinLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + _IRQL_saves_ + WDFSPINLOCK SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_min_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfSpinLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + _IRQL_restores_ + WDFSPINLOCK SpinLock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfTimerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_TIMER_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFTIMER* Timer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfTimerStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + LONGLONG DueTime + ); + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +BOOLEAN +WDFEXPORT(WdfTimerStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + BOOLEAN Wait + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfTimerGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_USB_DEVICE_CREATE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PWDF_USB_DEVICE_INFORMATION Information + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_writes_bytes_to_opt_(*ConfigDescriptorLength,*ConfigDescriptorLength) + PVOID ConfigDescriptor, + _Inout_ + PUSHORT ConfigDescriptorLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_writes_opt_(*NumCharacters) + PUSHORT String, + _Inout_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + _Out_ + WDFMEMORY* StringMemory, + _Out_opt_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET Offset, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +UCHAR +WDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipeAttributes, + _Inout_ + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesTransferred + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + WDFMEMORY TransferMemory, + _In_opt_ + PWDFMEMORY_OFFSET TransferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + CONST GUID* CapabilityType, + _In_ + ULONG CapabilityBufferLength, + _When_(CapabilityBufferLength == 0, _Out_opt_) + _When_(CapabilityBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(CapabilityBufferLength)) + _When_(CapabilityBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + _Out_opt_ + _When_(ResultLength != NULL,_Deref_out_range_(<=,CapabilityBufferLength)) + PULONG ResultLength + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbTargetPipeGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _Out_ + PWDF_USB_PIPE_INFORMATION PipeInformation + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +WDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_USB_PIPE_TYPE +WDFEXPORT(WdfUsbTargetPipeGetType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY WriteMemory, + _In_opt_ + PWDFMEMORY_OFFSET WriteOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY ReadMemory, + _In_opt_ + PWDFMEMORY_OFFSET ReadOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbInterfaceGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _Out_ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfUsbInterfaceSelectSetting)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + _In_ + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _In_ + UCHAR EndpointIndex, + _Out_ + PWDF_USB_PIPE_INFORMATION EndpointInfo + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBINTERFACE +WDFEXPORT(WdfUsbTargetDeviceGetInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + UCHAR InterfaceIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE Interface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +WDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBPIPE +WDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR PipeIndex, + _Out_opt_ + PWDF_USB_PIPE_INFORMATION PipeInfo + ); + +WDFAPI +VOID +WDFEXPORT(WdfVerifierDbgBreakPoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +WDFAPI +VOID +WDFEXPORT(WdfVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +WDFAPI +PVOID +WDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +WDFEXPORT(WdfWorkItemCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_WORKITEM_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFWORKITEM* WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWorkItemEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +WDFEXPORT(WdfWorkItemGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +WDFEXPORT(WdfWorkItemFlush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + + +#ifdef FX_DYNAMICS_GENERATE_TABLE + +WDFVERSION WdfVersion = { + sizeof(WDFVERSION), + sizeof(WDFFUNCTIONS)/sizeof(PVOID), + { + WDFEXPORT(WdfCollectionCreate), + WDFEXPORT(WdfCollectionGetCount), + WDFEXPORT(WdfCollectionAdd), + WDFEXPORT(WdfCollectionRemove), + WDFEXPORT(WdfCollectionRemoveItem), + WDFEXPORT(WdfCollectionGetItem), + WDFEXPORT(WdfCollectionGetFirstItem), + WDFEXPORT(WdfCollectionGetLastItem), + WDFEXPORT(WdfCxDeviceInitAllocate), + WDFEXPORT(WdfCxDeviceInitSetRequestAttributes), + WDFEXPORT(WdfCxDeviceInitSetFileObjectConfig), + WDFEXPORT(WdfCxVerifierKeBugCheck), + WDFEXPORT(WdfDeviceGetDeviceState), + WDFEXPORT(WdfDeviceSetDeviceState), + WDFEXPORT(WdfDeviceGetDriver), + WDFEXPORT(WdfDeviceGetIoTarget), + WDFEXPORT(WdfDeviceAssignS0IdleSettings), + WDFEXPORT(WdfDeviceAssignSxWakeSettings), + WDFEXPORT(WdfDeviceOpenRegistryKey), + WDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks), + WDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks), + WDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership), + WDFEXPORT(WdfDeviceInitSetIoType), + WDFEXPORT(WdfDeviceInitSetFileObjectConfig), + WDFEXPORT(WdfDeviceInitSetRequestAttributes), + WDFEXPORT(WdfDeviceCreate), + WDFEXPORT(WdfDeviceSetStaticStopRemove), + WDFEXPORT(WdfDeviceCreateDeviceInterface), + WDFEXPORT(WdfDeviceSetDeviceInterfaceState), + WDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString), + WDFEXPORT(WdfDeviceCreateSymbolicLink), + WDFEXPORT(WdfDeviceQueryProperty), + WDFEXPORT(WdfDeviceAllocAndQueryProperty), + WDFEXPORT(WdfDeviceSetPnpCapabilities), + WDFEXPORT(WdfDeviceSetPowerCapabilities), + WDFEXPORT(WdfDeviceSetFailed), + WDFEXPORT(WdfDeviceStopIdleNoTrack), + WDFEXPORT(WdfDeviceResumeIdleNoTrack), + WDFEXPORT(WdfDeviceGetFileObject), + WDFEXPORT(WdfDeviceGetDefaultQueue), + WDFEXPORT(WdfDeviceConfigureRequestDispatching), + WDFEXPORT(WdfDeviceGetSystemPowerAction), + WDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure), + WDFEXPORT(WdfDeviceInitSetIoTypeEx), + WDFEXPORT(WdfDevicePostEvent), + WDFEXPORT(WdfDeviceMapIoSpace), + WDFEXPORT(WdfDeviceUnmapIoSpace), + WDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress), + WDFEXPORT(WdfDeviceReadFromHardware), + WDFEXPORT(WdfDeviceWriteToHardware), + WDFEXPORT(WdfDeviceAssignInterfaceProperty), + WDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty), + WDFEXPORT(WdfDeviceQueryInterfaceProperty), + WDFEXPORT(WdfDeviceGetDeviceStackIoType), + WDFEXPORT(WdfDeviceQueryPropertyEx), + WDFEXPORT(WdfDeviceAllocAndQueryPropertyEx), + WDFEXPORT(WdfDeviceAssignProperty), + WDFEXPORT(WdfDriverCreate), + WDFEXPORT(WdfDriverGetRegistryPath), + WDFEXPORT(WdfDriverOpenParametersRegistryKey), + WDFEXPORT(WdfDriverRetrieveVersionString), + WDFEXPORT(WdfDriverIsVersionAvailable), + WDFEXPORT(WdfFdoInitOpenRegistryKey), + WDFEXPORT(WdfFdoInitQueryProperty), + WDFEXPORT(WdfFdoInitAllocAndQueryProperty), + WDFEXPORT(WdfFdoInitQueryPropertyEx), + WDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx), + WDFEXPORT(WdfFdoInitSetFilter), + WDFEXPORT(WdfFileObjectGetFileName), + WDFEXPORT(WdfFileObjectGetDevice), + WDFEXPORT(WdfFileObjectGetInitiatorProcessId), + WDFEXPORT(WdfFileObjectGetRelatedFileObject), + WDFEXPORT(WdfInterruptCreate), + WDFEXPORT(WdfInterruptQueueDpcForIsr), + WDFEXPORT(WdfInterruptQueueWorkItemForIsr), + WDFEXPORT(WdfInterruptSynchronize), + WDFEXPORT(WdfInterruptAcquireLock), + WDFEXPORT(WdfInterruptReleaseLock), + WDFEXPORT(WdfInterruptEnable), + WDFEXPORT(WdfInterruptDisable), + WDFEXPORT(WdfInterruptGetInfo), + WDFEXPORT(WdfInterruptSetPolicy), + WDFEXPORT(WdfInterruptSetExtendedPolicy), + WDFEXPORT(WdfInterruptGetDevice), + WDFEXPORT(WdfInterruptTryToAcquireLock), + WDFEXPORT(WdfIoQueueCreate), + WDFEXPORT(WdfIoQueueGetState), + WDFEXPORT(WdfIoQueueStart), + WDFEXPORT(WdfIoQueueStop), + WDFEXPORT(WdfIoQueueStopSynchronously), + WDFEXPORT(WdfIoQueueGetDevice), + WDFEXPORT(WdfIoQueueRetrieveNextRequest), + WDFEXPORT(WdfIoQueueRetrieveRequestByFileObject), + WDFEXPORT(WdfIoQueueFindRequest), + WDFEXPORT(WdfIoQueueRetrieveFoundRequest), + WDFEXPORT(WdfIoQueueDrainSynchronously), + WDFEXPORT(WdfIoQueueDrain), + WDFEXPORT(WdfIoQueuePurgeSynchronously), + WDFEXPORT(WdfIoQueuePurge), + WDFEXPORT(WdfIoQueueReadyNotify), + WDFEXPORT(WdfIoQueueStopAndPurge), + WDFEXPORT(WdfIoQueueStopAndPurgeSynchronously), + WDFEXPORT(WdfIoTargetCreate), + WDFEXPORT(WdfIoTargetOpen), + WDFEXPORT(WdfIoTargetCloseForQueryRemove), + WDFEXPORT(WdfIoTargetClose), + WDFEXPORT(WdfIoTargetStart), + WDFEXPORT(WdfIoTargetStop), + WDFEXPORT(WdfIoTargetPurge), + WDFEXPORT(WdfIoTargetGetState), + WDFEXPORT(WdfIoTargetGetDevice), + WDFEXPORT(WdfIoTargetSendReadSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForRead), + WDFEXPORT(WdfIoTargetSendWriteSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForWrite), + WDFEXPORT(WdfIoTargetSendIoctlSynchronously), + WDFEXPORT(WdfIoTargetFormatRequestForIoctl), + WDFEXPORT(WdfMemoryCreate), + WDFEXPORT(WdfMemoryCreatePreallocated), + WDFEXPORT(WdfMemoryGetBuffer), + WDFEXPORT(WdfMemoryAssignBuffer), + WDFEXPORT(WdfMemoryCopyToBuffer), + WDFEXPORT(WdfMemoryCopyFromBuffer), + WDFEXPORT(WdfObjectGetTypedContextWorker), + WDFEXPORT(WdfObjectAllocateContext), + WDFEXPORT(WdfObjectContextGetObject), + WDFEXPORT(WdfObjectReferenceActual), + WDFEXPORT(WdfObjectDereferenceActual), + WDFEXPORT(WdfObjectCreate), + WDFEXPORT(WdfObjectDelete), + WDFEXPORT(WdfObjectQuery), + WDFEXPORT(WdfRegistryOpenKey), + WDFEXPORT(WdfRegistryCreateKey), + WDFEXPORT(WdfRegistryClose), + WDFEXPORT(WdfRegistryRemoveKey), + WDFEXPORT(WdfRegistryRemoveValue), + WDFEXPORT(WdfRegistryQueryValue), + WDFEXPORT(WdfRegistryQueryMemory), + WDFEXPORT(WdfRegistryQueryMultiString), + WDFEXPORT(WdfRegistryQueryUnicodeString), + WDFEXPORT(WdfRegistryQueryString), + WDFEXPORT(WdfRegistryQueryULong), + WDFEXPORT(WdfRegistryAssignValue), + WDFEXPORT(WdfRegistryAssignMemory), + WDFEXPORT(WdfRegistryAssignMultiString), + WDFEXPORT(WdfRegistryAssignUnicodeString), + WDFEXPORT(WdfRegistryAssignString), + WDFEXPORT(WdfRegistryAssignULong), + WDFEXPORT(WdfRequestCreate), + WDFEXPORT(WdfRequestReuse), + WDFEXPORT(WdfRequestChangeTarget), + WDFEXPORT(WdfRequestFormatRequestUsingCurrentType), + WDFEXPORT(WdfRequestSend), + WDFEXPORT(WdfRequestGetStatus), + WDFEXPORT(WdfRequestMarkCancelable), + WDFEXPORT(WdfRequestMarkCancelableEx), + WDFEXPORT(WdfRequestUnmarkCancelable), + WDFEXPORT(WdfRequestIsCanceled), + WDFEXPORT(WdfRequestCancelSentRequest), + WDFEXPORT(WdfRequestIsFrom32BitProcess), + WDFEXPORT(WdfRequestSetCompletionRoutine), + WDFEXPORT(WdfRequestGetCompletionParams), + WDFEXPORT(WdfRequestAllocateTimer), + WDFEXPORT(WdfRequestComplete), + WDFEXPORT(WdfRequestCompleteWithInformation), + WDFEXPORT(WdfRequestGetParameters), + WDFEXPORT(WdfRequestRetrieveInputMemory), + WDFEXPORT(WdfRequestRetrieveOutputMemory), + WDFEXPORT(WdfRequestRetrieveInputBuffer), + WDFEXPORT(WdfRequestRetrieveOutputBuffer), + WDFEXPORT(WdfRequestSetInformation), + WDFEXPORT(WdfRequestGetInformation), + WDFEXPORT(WdfRequestGetFileObject), + WDFEXPORT(WdfRequestGetRequestorMode), + WDFEXPORT(WdfRequestForwardToIoQueue), + WDFEXPORT(WdfRequestGetIoQueue), + WDFEXPORT(WdfRequestRequeue), + WDFEXPORT(WdfRequestStopAcknowledge), + WDFEXPORT(WdfRequestImpersonate), + WDFEXPORT(WdfRequestGetRequestorProcessId), + WDFEXPORT(WdfRequestIsFromUserModeDriver), + WDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo), + WDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo), + WDFEXPORT(WdfRequestSetActivityId), + WDFEXPORT(WdfRequestRetrieveActivityId), + WDFEXPORT(WdfRequestGetEffectiveIoType), + WDFEXPORT(WdfCmResourceListGetCount), + WDFEXPORT(WdfCmResourceListGetDescriptor), + WDFEXPORT(WdfStringCreate), + WDFEXPORT(WdfStringGetUnicodeString), + WDFEXPORT(WdfObjectAcquireLock), + WDFEXPORT(WdfObjectReleaseLock), + WDFEXPORT(WdfWaitLockCreate), + WDFEXPORT(WdfWaitLockAcquire), + WDFEXPORT(WdfWaitLockRelease), + WDFEXPORT(WdfSpinLockCreate), + WDFEXPORT(WdfSpinLockAcquire), + WDFEXPORT(WdfSpinLockRelease), + WDFEXPORT(WdfTimerCreate), + WDFEXPORT(WdfTimerStart), + WDFEXPORT(WdfTimerStop), + WDFEXPORT(WdfTimerGetParentObject), + WDFEXPORT(WdfUsbTargetDeviceCreate), + WDFEXPORT(WdfUsbTargetDeviceCreateWithParameters), + WDFEXPORT(WdfUsbTargetDeviceRetrieveInformation), + WDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor), + WDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor), + WDFEXPORT(WdfUsbTargetDeviceQueryString), + WDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString), + WDFEXPORT(WdfUsbTargetDeviceFormatRequestForString), + WDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces), + WDFEXPORT(WdfUsbTargetDeviceSelectConfig), + WDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously), + WDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer), + WDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously), + WDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability), + WDFEXPORT(WdfUsbTargetPipeGetInformation), + WDFEXPORT(WdfUsbTargetPipeIsInEndpoint), + WDFEXPORT(WdfUsbTargetPipeIsOutEndpoint), + WDFEXPORT(WdfUsbTargetPipeGetType), + WDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck), + WDFEXPORT(WdfUsbTargetPipeWriteSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite), + WDFEXPORT(WdfUsbTargetPipeReadSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForRead), + WDFEXPORT(WdfUsbTargetPipeConfigContinuousReader), + WDFEXPORT(WdfUsbTargetPipeAbortSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort), + WDFEXPORT(WdfUsbTargetPipeResetSynchronously), + WDFEXPORT(WdfUsbTargetPipeFormatRequestForReset), + WDFEXPORT(WdfUsbInterfaceGetInterfaceNumber), + WDFEXPORT(WdfUsbInterfaceGetNumEndpoints), + WDFEXPORT(WdfUsbInterfaceGetDescriptor), + WDFEXPORT(WdfUsbInterfaceGetNumSettings), + WDFEXPORT(WdfUsbInterfaceSelectSetting), + WDFEXPORT(WdfUsbInterfaceGetEndpointInformation), + WDFEXPORT(WdfUsbTargetDeviceGetInterface), + WDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex), + WDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes), + WDFEXPORT(WdfUsbInterfaceGetConfiguredPipe), + WDFEXPORT(WdfVerifierDbgBreakPoint), + WDFEXPORT(WdfVerifierKeBugCheck), + WDFEXPORT(WdfGetTriageInfo), + WDFEXPORT(WdfWorkItemCreate), + WDFEXPORT(WdfWorkItemEnqueue), + WDFEXPORT(WdfWorkItemGetParentObject), + WDFEXPORT(WdfWorkItemFlush), + WDFEXPORT(WdfRegistryWdmGetHandle), + WDFEXPORT(WdfDeviceStopIdleActual), + WDFEXPORT(WdfDeviceResumeIdleActual), + WDFEXPORT(WdfDeviceInitEnableHidInterface), + WDFEXPORT(WdfDeviceHidNotifyPresence), + WDFEXPORT(WdfDeviceGetSelfIoTarget), + WDFEXPORT(WdfDeviceInitAllowSelfIoTarget), + WDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue), + WDFEXPORT(WdfDeviceOpenDevicemapKey), + WDFEXPORT(WdfIoTargetWdmGetTargetFileHandle), + WDFEXPORT(WdfDeviceWdmDispatchIrp), + WDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue), + WDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback), + } +}; + +#endif // FX_DYNAMICS_GENERATE_TABLE + +#endif // _FXDYNAMICS_H_ + diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/version/fxframeworkstubum.h b/sdk/lib/drivers/wdf/umdf/fxlib/version/fxframeworkstubum.h new file mode 100644 index 00000000000..17c720f4f50 --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/version/fxframeworkstubum.h @@ -0,0 +1,48 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + FxFrameworkStubUm.h + +Abstract: + + This is the internal flat-api stub version. + +--*/ + +// generic loader defines. +#include + +#pragma once + +#ifdef __cplusplus +extern "C"{ +#endif + +//------------------------------------------------------------------------ +// UMDF Loader interface for Flat-c framework stub. +//------------------------------------------------------------------------ +struct IWudfHost; +struct IUMDFPlatform; + +typedef +__checkReturn +NTSTATUS +(*PFN_WUDF_REGISTER_LIBRARY) ( + __in PVOID Context, + __in PWDF_LIBRARY_INFO LibraryInfo + ); + +typedef struct _WUDF_LOADER_FX_INTERFACE { + ULONG Size; + PFN_WUDF_REGISTER_LIBRARY RegisterLibrary; + IWudfHost * pIWudfHost; + IUMDFPlatform * pUMDFPlatform; +} WUDF_LOADER_FX_INTERFACE, *PWUDF_LOADER_FX_INTERFACE; + +#ifdef __cplusplus +} +#endif + diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/version/version.cpp b/sdk/lib/drivers/wdf/umdf/fxlib/version/version.cpp new file mode 100644 index 00000000000..e374ab4f6c0 --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/version/version.cpp @@ -0,0 +1,312 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + + Stub.cpp + +Abstract: + + This is the stub used by UMDF corresponding to the stub used by + KMDF. + + It includes definitions of WdfFunctions, WdfBindInfo and WdfDriverGlobals + + On the UMDF side we don't need the thunk for DriverEntry because + DriverEntry is invoked by UMDF host. + + For COM API UMDF framework will link the stub in + For flat-C API UMDF driver will need to link the stub in + (similar to the way KMDF drivers link the stub) + +Environment: + + User mode only + +Revision History: + +--*/ + +#define FX_DYNAMICS_GENERATE_TABLE 1 + +#include +extern "C" { +#include "mx.h" +} +#include "fxmin.hpp" +#include "fxldrUm.h" +#include "fxIFR.h" + +#include +#include + +extern const WDFFUNC *WdfFunctions; + +extern "C" { + +#include "FxDynamics.h" + +#include "..\librarycommon\FxLibraryCommon.h" + +#define KMDF_DEFAULT_NAME "Wdf" ## \ + LITERAL(__WDF_MAJOR_VERSION) ## \ + "000" //minor version + + + +//----------------------------------------------------------------------------- +// local prototype definitions +//----------------------------------------------------------------------------- + +ULONG WdfLdrDbgPrintOn = 0; + +PCHAR WdfLdrType = KMDF_DEFAULT_NAME; + +} // extern "C" + +#include "umdfstub.h" + +extern "C" +NTSTATUS +WDF_LIBRARY_COMMISSION( + VOID + ); + +extern "C" +NTSTATUS +WDF_LIBRARY_DECOMMISSION( + VOID + ); + +extern "C" +NTSTATUS +WDF_LIBRARY_REGISTER_CLIENT( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + PVOID * Context + ); + +extern "C" +NTSTATUS +WDF_LIBRARY_UNREGISTER_CLIENT( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS WdfDriverGlobals + ); + +extern "C" { + +WDF_LIBRARY_INFO WdfLibraryInfo = { + sizeof(WDF_LIBRARY_INFO), + (PFNLIBRARYCOMMISSION) WDF_LIBRARY_COMMISSION, + (PFNLIBRARYDECOMMISSION) WDF_LIBRARY_DECOMMISSION, + (PFNLIBRARYREGISTERCLIENT) WDF_LIBRARY_REGISTER_CLIENT, + (PFNLIBRARYUNREGISTERCLIENT) WDF_LIBRARY_UNREGISTER_CLIENT, + { __WUDF_MAJOR_VERSION, __WUDF_MINOR_VERSION, __WUDF_SERVICE_VERSION } +}; + +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +NTSTATUS +WDF_LIBRARY_COMMISSION( + VOID + ) +{ + return FxLibraryCommonCommission(); +} + +//----------------------------------------------------------------------------- +// +//----------------------------------------------------------------------------- +extern "C" +NTSTATUS +WDF_LIBRARY_DECOMMISSION( + VOID + ) +{ + return FxLibraryCommonDecommission(); +} + +#define EVTLOG_MESSAGE_SIZE 70 +#define RAW_DATA_SIZE 4 + +extern "C" +NTSTATUS +WDF_LIBRARY_REGISTER_CLIENT( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS * WdfDriverGlobals, + PVOID * Context + ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + PFX_DRIVER_GLOBALS pFxDriverGlobals; + WCHAR insertString[EVTLOG_MESSAGE_SIZE]; + ULONG rawData[RAW_DATA_SIZE]; + PCLIENT_INFO clientInfo = NULL; + + __Print((LITERAL(WDF_LIBRARY_REGISTER_CLIENT) ": enter\n")); + + clientInfo = (PCLIENT_INFO)*Context; + *Context = NULL; + + ASSERT(Info->Version.Major == WdfLibraryInfo.Version.Major); + + // + // NOTE: If the currently loaded library < drivers minor version fail the load + // instead of binding to a lower minor version. The reason for that if there + // is a newer API or new contract change made the driver shouldn't be using older + // API than it was compiled with. + // + + if (Info->Version.Minor > WdfLibraryInfo.Version.Minor) { + status = StringCchPrintfW(insertString, + RTL_NUMBER_OF(insertString), + L"Driver Version: %d.%d Umdf Lib. Version: %d.%d", + Info->Version.Major, + Info->Version.Minor, + WdfLibraryInfo.Version.Major, + WdfLibraryInfo.Version.Minor); + if (!NT_SUCCESS(status)) { + __Print(("ERROR: RtlStringCchPrintfW failed with Status 0x%x\n", status)); + return status; + } + rawData[0] = Info->Version.Major; + rawData[1] = Info->Version.Minor; + rawData[2] = WdfLibraryInfo.Version.Major; + rawData[3] = WdfLibraryInfo.Version.Minor; + + + + + + + + + + + + // + // this looks like the best status to return + // + return STATUS_OBJECT_TYPE_MISMATCH; + + } + + status = FxLibraryCommonRegisterClient(Info, WdfDriverGlobals, clientInfo); + + if (NT_SUCCESS(status)) { + // + // The context will be a pointer to FX_DRIVER_GLOBALS + // + *Context = GetFxDriverGlobals(*WdfDriverGlobals); + + // + // Set the WDF_BIND_INFO structure pointer in FxDriverGlobals + // + pFxDriverGlobals = GetFxDriverGlobals(*WdfDriverGlobals); + pFxDriverGlobals->WdfBindInfo = Info; + } + + return status; +} + +extern "C" +NTSTATUS +WDF_LIBRARY_UNREGISTER_CLIENT( + PWDF_BIND_INFO Info, + PWDF_DRIVER_GLOBALS WdfDriverGlobals + ) +{ + return FxLibraryCommonUnregisterClient(Info, WdfDriverGlobals); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +extern "C" { + +//----------------------------------------------------------------------------- +// These header files are referenced in order to make internal structures +// available in public symbols. Various WDFKD debug commands use these +// internal structures to provide information about WDF. +//----------------------------------------------------------------------------- + +#ifndef DECLARE_TYPE +#define DECLARE_TYPE(Name) Name* _DECL_##Name +#endif + +union { + + DECLARE_TYPE (WDF_IFR_HEADER); + DECLARE_TYPE (WDF_IFR_RECORD); + DECLARE_TYPE (WDF_IFR_OFFSET); + DECLARE_TYPE (WDF_BIND_INFO); + DECLARE_TYPE (WDF_OBJECT_CONTEXT_TYPE_INFO); + DECLARE_TYPE (WDF_POWER_ROUTINE_TIMED_OUT_DATA); + DECLARE_TYPE (WDF_BUGCHECK_CODES); + DECLARE_TYPE (WDF_REQUEST_FATAL_ERROR_CODES); + DECLARE_TYPE (FX_OBJECT_INFO); + DECLARE_TYPE (FX_POOL_HEADER); + DECLARE_TYPE (FX_POOL); + DECLARE_TYPE (FxObject); + DECLARE_TYPE (FxContextHeader); +// DECLARE_TYPE (FX_DUMP_DRIVER_INFO_ENTRY); // KMDF only + DECLARE_TYPE (FxTargetSubmitSyncParams); + +} uAllPublicTypes; + +} // extern "C" end + +//----------------------------------------------------------------------------- diff --git a/sdk/lib/drivers/wdf/umdf/fxlib/version/vffxdynamics.h b/sdk/lib/drivers/wdf/umdf/fxlib/version/vffxdynamics.h new file mode 100644 index 00000000000..8e568e21baf --- /dev/null +++ b/sdk/lib/drivers/wdf/umdf/fxlib/version/vffxdynamics.h @@ -0,0 +1,3911 @@ +/*++ + +Module Name: VfFxDynamics.h + +Abstract: + Generated header for WDF API Verifier hooks + +Environment: + user mode only + + Warning: manual changes to this file will be lost. +--*/ + +#ifndef _VFFXDYNAMICS_H_ +#define _VFFXDYNAMICS_H_ + + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES CollectionAttributes, + _Out_ + WDFCOLLECTION* Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCollectionGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfCollectionAdd)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + WDFOBJECT Item + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCollectionRemoveItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection, + _In_ + ULONG Index + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetFirstItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfCollectionGetLastItem)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWDFCXDEVICE_INIT +VFWDFEXPORT(WdfCxDeviceInitAllocate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFCXDEVICE_INIT CxDeviceInit, + _In_ + PWDFCX_FILEOBJECT_CONFIG CxFileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfCxVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFOBJECT Object, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceGetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + PWDF_DEVICE_STATE DeviceState + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_STATE DeviceState + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrp)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFCONTEXT DispatchContext + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PIRP Irp, + _In_ + WDFQUEUE Queue, + _In_ + ULONG Flags + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDRIVER +VFWDFEXPORT(WdfDeviceGetDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignS0IdleSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_IDLE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignSxWakeSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_POLICY_WAKE_SETTINGS Settings + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceOpenDevicemapKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_PNPPOWER_EVENT_CALLBACKS PnpPowerEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_POWER_POLICY_EVENT_CALLBACKS PowerPolicyEventCallbacks + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + BOOLEAN IsPowerPolicyOwner + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_DEVICE_IO_TYPE IoType + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_FILEOBJECT_CONFIG FileObjectConfig, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES FileObjectAttributes + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetRequestAttributes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _Inout_ + PWDFDEVICE_INIT* DeviceInit, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DeviceAttributes, + _Out_ + WDFDEVICE* Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetStaticStopRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN Stoppable + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateDeviceInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + BOOLEAN IsInterfaceEnabled + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + CONST GUID* InterfaceClassGUID, + _In_opt_ + PCUNICODE_STRING ReferenceString, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceCreateSymbolicLink)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PCUNICODE_STRING SymbolicLinkName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPnpCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PNP_CAPABILITIES PnpCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetPowerCapabilities)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_POWER_CAPABILITIES PowerCapabilities + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceSetFailed)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_FAILED_ACTION FailedAction + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0 + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleNoTrack)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_When_(WaitForD0 == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(WaitForD0 != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceStopIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN WaitForD0, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceResumeIdleActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfDeviceGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PFILE_OBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfDeviceGetDefaultQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureRequestDispatching)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDFQUEUE Queue, + _In_ + _Strict_type_match_ + WDF_REQUEST_TYPE RequestType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + WDFDRIVER Driver, + _In_ + UCHAR MajorFunction, + _In_ + PFN_WDFDEVICE_WDM_IRP_DISPATCH EvtDeviceWdmIrpDisptach, + _In_opt_ + WDFCONTEXT DriverContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +POWER_ACTION +VFWDFEXPORT(WdfDeviceGetSystemPowerAction)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + WDF_RELEASE_HARDWARE_ORDER_ON_FAILURE ReleaseHardwareOrderOnFailure + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitSetIoTypeEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_IO_TYPE_CONFIG IoTypeConfig + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDevicePostEvent)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + REFGUID EventGuid, + _In_ + WDF_EVENT_TYPE WdfEventType, + _In_reads_bytes_(DataSizeCb) + BYTE* Data, + _In_ + ULONG DataSizeCb + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceMapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PHYSICAL_ADDRESS PhysicalAddress, + _In_ + SIZE_T NumberOfBytes, + _In_ + MEMORY_CACHING_TYPE CacheType, + _Out_ + PVOID* PseudoBaseAddress + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceUnmapIoSpace)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress, + _In_ + SIZE_T NumberOfBytes + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PVOID PseudoBaseAddress + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +SIZE_T +VFWDFEXPORT(WdfDeviceReadFromHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _Out_writes_all_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceWriteToHardware)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + WDF_DEVICE_HWACCESS_TARGET_TYPE Type, + _In_ + WDF_DEVICE_HWACCESS_TARGET_SIZE Size, + _In_ + PVOID TargetAddress, + _In_ + SIZE_T Value, + _In_reads_opt_(Count) + PVOID Buffer, + _In_opt_ + ULONG Count + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG BufferLength, + _In_reads_bytes_opt_(BufferLength) + PVOID PropertyBuffer + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryInterfaceProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_INTERFACE_PROPERTY_DATA PropertyData, + _In_ + ULONG BufferLength, + _Out_writes_bytes_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceGetDeviceStackIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _Out_ + WDF_DEVICE_IO_TYPE* ReadWriteIoType, + _Out_ + WDF_DEVICE_IO_TYPE* IoControlIoType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG RequiredSize, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceAssignProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + DEVPROPTYPE Type, + _In_ + ULONG Size, + _In_opt_ + PVOID Data + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFIOTARGET +VFWDFEXPORT(WdfDeviceGetSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PDRIVER_OBJECT DriverObject, + _In_ + PCUNICODE_STRING RegistryPath, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES DriverAttributes, + _In_ + PWDF_DRIVER_CONFIG DriverConfig, + _Out_opt_ + WDFDRIVER* Driver + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PWSTR +VFWDFEXPORT(WdfDriverGetRegistryPath)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverOpenParametersRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDriverRetrieveVersionString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfDriverIsVersionAvailable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDRIVER Driver, + _In_ + PWDF_DRIVER_VERSION_AVAILABLE_PARAMS VersionAvailableParams + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitOpenRegistryKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + ULONG DeviceInstanceKeyType, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + ULONG BufferLength, + _Out_writes_bytes_all_opt_(BufferLength) + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + DEVICE_REGISTRY_PROPERTY DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + ULONG BufferLength, + _Out_ + PVOID PropertyBuffer, + _Out_ + PULONG ResultLength, + _Out_ + PDEVPROPTYPE Type + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit, + _In_ + PWDF_DEVICE_PROPERTY_DATA DeviceProperty, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PropertyMemoryAttributes, + _Out_ + WDFMEMORY* PropertyMemory, + _Out_ + PDEVPROPTYPE Type + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfFdoInitSetFilter)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +PUNICODE_STRING +VFWDFEXPORT(WdfFileObjectGetFileName)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfFileObjectGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfFileObjectGetInitiatorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfFileObjectGetRelatedFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFFILEOBJECT FileObject + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfDeviceInitEnableHidInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDFDEVICE_INIT DeviceInit + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfDeviceHidNotifyPresence)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + BOOLEAN IsPresent + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfInterruptCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_INTERRUPT_CONFIG Configuration, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFINTERRUPT* Interrupt + ); + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueDpcForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptSynchronize)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PFN_WDF_INTERRUPT_SYNCHRONIZE Callback, + _In_ + WDFCONTEXT Context + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL + 1) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptEnable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptDisable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptGetInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _Out_ + PWDF_INTERRUPT_INFO Info + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + WDF_INTERRUPT_POLICY Policy, + _In_ + WDF_INTERRUPT_PRIORITY Priority, + _In_ + KAFFINITY TargetProcessorSet + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfInterruptSetExtendedPolicy)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt, + _In_ + PWDF_INTERRUPT_EXTENDED_POLICY PolicyAndGroup + ); + +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfInterruptGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_Post_satisfies_(return == 1 || return == 0) +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfInterruptTryToAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _When_(return!=0, _Acquires_lock_(_Curr_)) + WDFINTERRUPT Interrupt + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_IO_QUEUE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES QueueAttributes, + _Out_opt_ + WDFQUEUE* Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_QUEUE_STATE +VFWDFEXPORT(WdfIoQueueGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_opt_ + PULONG QueueRequests, + _Out_opt_ + PULONG DriverRequests + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopComplete, + _When_(StopComplete != 0, _In_) + _When_(StopComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoQueueGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveNextRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFFILEOBJECT FileObject, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueFindRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + WDFREQUEST FoundRequest, + _In_opt_ + WDFFILEOBJECT FileObject, + _Inout_opt_ + PWDF_REQUEST_PARAMETERS Parameters, + _Out_ + WDFREQUEST* OutRequest + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_ + WDFREQUEST FoundRequest, + _Out_ + WDFREQUEST* OutRequest + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrainSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueDrain)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE DrainComplete, + _When_(DrainComplete != 0, _In_) + _When_(DrainComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueuePurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE PurgeComplete, + _When_(PurgeComplete != 0, _In_) + _When_(PurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoQueueReadyNotify)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _In_opt_ + PFN_WDF_IO_QUEUE_STATE QueueReady, + _In_opt_ + WDFCONTEXT Context + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue, + _When_(Context != 0, _In_) + _When_(Context == 0, _In_opt_) + PFN_WDF_IO_QUEUE_STATE StopAndPurgeComplete, + _When_(StopAndPurgeComplete != 0, _In_) + _When_(StopAndPurgeComplete == 0, _In_opt_) + WDFCONTEXT Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES IoTargetAttributes, + _Out_ + WDFIOTARGET* IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetOpen)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + PWDF_IO_TARGET_OPEN_PARAMS OpenParams + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetCloseForQueryRemove)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_When_(Action == 3, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1 || Action == 2, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_SENT_IO_ACTION Action + ); + +_When_(Action == 2, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Action == 0 || Action == 1, _IRQL_requires_max_(PASSIVE_LEVEL)) +WDFAPI +VOID +VFWDFEXPORT(WdfIoTargetPurge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + _Strict_type_match_ + WDF_IO_TARGET_PURGE_IO_ACTION Action + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_IO_TARGET_STATE +VFWDFEXPORT(WdfIoTargetGetState)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFDEVICE +VFWDFEXPORT(WdfIoTargetGetDevice)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PLONGLONG DeviceOffset, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + PLONGLONG DeviceOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_opt_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR InputBuffer, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR OutputBuffer, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_opt_ + PULONG_PTR BytesReturned + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFREQUEST Request, + _In_ + ULONG IoctlCode, + _In_opt_ + WDFMEMORY InputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET InputBufferOffset, + _In_opt_ + WDFMEMORY OutputBuffer, + _In_opt_ + PWDFMEMORY_OFFSET OutputBufferOffset + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFIOTARGET IoTarget, + _In_ + WDFQUEUE Queue + ); + +_Must_inspect_result_ +_When_(PoolType == 1 || PoolType == 257, _IRQL_requires_max_(APC_LEVEL)) +_When_(PoolType == 0 || PoolType == 256, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + ULONG PoolTag, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory, + _Outptr_opt_result_bytebuffer_(BufferSize) + PVOID* Buffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCreatePreallocated)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ __drv_aliasesMem + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize, + _Out_ + WDFMEMORY* Memory + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PVOID +VFWDFEXPORT(WdfMemoryGetBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Out_opt_ + size_t* BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryAssignBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY Memory, + _Pre_notnull_ _Pre_writable_byte_size_(BufferSize) + PVOID Buffer, + _In_ + _When_(BufferSize == 0, __drv_reportError(BufferSize cannot be zero)) + size_t BufferSize + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyToBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY SourceMemory, + _In_ + size_t SourceOffset, + _Out_writes_bytes_( NumBytesToCopyTo ) + PVOID Buffer, + _In_ + _When_(NumBytesToCopyTo == 0, __drv_reportError(NumBytesToCopyTo cannot be zero)) + size_t NumBytesToCopyTo + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfMemoryCopyFromBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFMEMORY DestinationMemory, + _In_ + size_t DestinationOffset, + _In_ + PVOID Buffer, + _In_ + _When_(NumBytesToCopyFrom == 0, __drv_reportError(NumBytesToCopyFrom cannot be zero)) + size_t NumBytesToCopyFrom + ); + +WDFAPI +PVOID +FASTCALL +VFWDFEXPORT(WdfObjectGetTypedContextWorker)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PCWDF_OBJECT_CONTEXT_TYPE_INFO TypeInfo + ); + +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectAllocateContext)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_ + PWDF_OBJECT_ATTRIBUTES ContextAttributes, + _Outptr_opt_ + PVOID* Context + ); + +WDFAPI +WDFOBJECT +FASTCALL +VFWDFEXPORT(WdfObjectContextGetObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PVOID ContextPointer + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDereferenceActual)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Handle, + _In_opt_ + PVOID Tag, + _In_ + LONG Line, + _In_z_ + PCHAR File + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFOBJECT* Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectDelete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfObjectQuery)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFOBJECT Object, + _In_ + CONST GUID* Guid, + _In_ + ULONG QueryBufferLength, + _Out_writes_bytes_(QueryBufferLength) + PVOID QueryBuffer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryOpenKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryCreateKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + WDFKEY ParentKey, + _In_ + PCUNICODE_STRING KeyName, + _In_ + ACCESS_MASK DesiredAccess, + _In_ + ULONG CreateOptions, + _Out_opt_ + PULONG CreateDisposition, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES KeyAttributes, + _Out_ + WDFKEY* Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRegistryClose)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +HANDLE +VFWDFEXPORT(WdfRegistryWdmGetHandle)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveKey)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryRemoveValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueLength, + _Out_writes_bytes_opt_( ValueLength) + PVOID Value, + _Out_opt_ + PULONG ValueLengthQueried, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + _Strict_type_match_ + POOL_TYPE PoolType, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES MemoryAttributes, + _Out_ + WDFMEMORY* Memory, + _Out_opt_ + PULONG ValueType + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringsAttributes, + _In_ + WDFCOLLECTION Collection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_opt_ + PUSHORT ValueByteLength, + _Inout_opt_ + PUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryQueryULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _Out_ + PULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignValue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + ULONG ValueLength, + _In_reads_( ValueLength) + PVOID Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG ValueType, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET MemoryOffsets + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignMultiString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFCOLLECTION StringsCollection + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + PCUNICODE_STRING Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + WDFSTRING String + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRegistryAssignULong)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFKEY Key, + _In_ + PCUNICODE_STRING ValueName, + _In_ + ULONG Value + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES RequestAttributes, + _In_opt_ + WDFIOTARGET IoTarget, + _Out_ + WDFREQUEST* Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestReuse)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PWDF_REQUEST_REUSE_PARAMS ReuseParams + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestChangeTarget)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET IoTarget + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_When_(Options->Flags & WDF_REQUEST_SEND_OPTION_SYNCHRONOUS == 0, _Must_inspect_result_) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestSend)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFIOTARGET Target, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS Options + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestGetStatus)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestMarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestMarkCancelableEx)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + PFN_WDF_REQUEST_CANCEL EvtRequestCancel + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestUnmarkCancelable)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsCanceled)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestCancelSentRequest)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(APC_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsFrom32BitProcess)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetCompletionRoutine)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_opt_ + PFN_WDF_REQUEST_COMPLETION_ROUTINE CompletionRoutine, + _In_opt_ __drv_aliasesMem + WDFCONTEXT CompletionContext + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetCompletionParams)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_COMPLETION_PARAMS Params + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestAllocateTimer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestComplete)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestCompleteWithInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + NTSTATUS Status, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestGetParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + PWDF_REQUEST_PARAMETERS Parameters + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputMemory)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + WDFMEMORY* Memory + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveInputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredLength, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveOutputBuffer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + size_t MinimumRequiredSize, + _Outptr_result_bytebuffer_(*Length) + PVOID* Buffer, + _Out_opt_ + size_t* Length + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + ULONG_PTR Information + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG_PTR +VFWDFEXPORT(WdfRequestGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFFILEOBJECT +VFWDFEXPORT(WdfRequestGetFileObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +KPROCESSOR_MODE +VFWDFEXPORT(WdfRequestGetRequestorMode)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestForwardToIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + WDFQUEUE DestinationQueue + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFQUEUE +VFWDFEXPORT(WdfRequestGetIoQueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRequeue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestStopAcknowledge)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN Requeue + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestImpersonate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, + _In_ + PFN_WDF_REQUEST_IMPERSONATE EvtRequestImpersonate, + _In_opt_ + PVOID Context + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfRequestGetRequestorProcessId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestIsFromUserModeDriver)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + BOOLEAN IsUserModeDriverInitiated + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfRequestSetActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _In_ + LPGUID ActivityId + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfRequestRetrieveActivityId)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request, + _Out_ + LPGUID ActivityId + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +WDF_DEVICE_IO_TYPE +VFWDFEXPORT(WdfRequestGetEffectiveIoType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +ULONG +VFWDFEXPORT(WdfCmResourceListGetCount)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +PCM_PARTIAL_RESOURCE_DESCRIPTOR +VFWDFEXPORT(WdfCmResourceListGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFCMRESLIST List, + _In_ + ULONG Index + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfStringCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PCUNICODE_STRING UnicodeString, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringAttributes, + _Out_ + WDFSTRING* String + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfStringGetUnicodeString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFSTRING String, + _Out_ + PUNICODE_STRING UnicodeString + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectAcquireLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + WDFOBJECT Object + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfObjectReleaseLock)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFOBJECT Object + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES LockAttributes, + _Out_ + WDFWAITLOCK* Lock + ); + +_When_(Timeout == NULL, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Timeout != NULL && *Timeout == 0, _IRQL_requires_max_(DISPATCH_LEVEL)) +_When_(Timeout != NULL && *Timeout != 0, _IRQL_requires_max_(PASSIVE_LEVEL)) +_Always_(_When_(Timeout == NULL, _Acquires_lock_(Lock))) +_When_(Timeout != NULL && return == STATUS_SUCCESS, _Acquires_lock_(Lock)) +_When_(Timeout != NULL, _Must_inspect_result_) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWaitLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + WDFWAITLOCK Lock, + _In_opt_ + PLONGLONG Timeout + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWaitLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + WDFWAITLOCK Lock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfSpinLockCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES SpinLockAttributes, + _Out_ + WDFSPINLOCK* SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_raises_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockAcquire)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_not_held_(_Curr_) + _Acquires_lock_(_Curr_) + _IRQL_saves_ + WDFSPINLOCK SpinLock + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +_IRQL_requires_min_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfSpinLockRelease)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + _Requires_lock_held_(_Curr_) + _Releases_lock_(_Curr_) + _IRQL_restores_ + WDFSPINLOCK SpinLock + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfTimerCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_TIMER_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFTIMER* Timer + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStart)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + LONGLONG DueTime + ); + +_When_(Wait == __true, _IRQL_requires_max_(PASSIVE_LEVEL)) +_When_(Wait == __false, _IRQL_requires_max_(DISPATCH_LEVEL)) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfTimerStop)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer, + _In_ + BOOLEAN Wait + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfTimerGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFTIMER Timer + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFDEVICE Device, + _In_ + PWDF_USB_DEVICE_CREATE_CONFIG Config, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFUSBDEVICE* UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PWDF_USB_DEVICE_INFORMATION Information + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_ + PUSB_DEVICE_DESCRIPTOR UsbDeviceDescriptor + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _Out_writes_bytes_to_opt_(*ConfigDescriptorLength,*ConfigDescriptorLength) + PVOID ConfigDescriptor, + _Inout_ + PUSHORT ConfigDescriptorLength + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _Out_writes_opt_(*NumCharacters) + PUSHORT String, + _Inout_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES StringMemoryAttributes, + _Out_ + WDFMEMORY* StringMemory, + _Out_opt_ + PUSHORT NumCharacters, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + WDFMEMORY Memory, + _In_opt_ + PWDFMEMORY_OFFSET Offset, + _In_ + UCHAR StringIndex, + _In_opt_ + USHORT LangID + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +UCHAR +VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipeAttributes, + _Inout_ + PWDF_USB_DEVICE_SELECT_CONFIG_PARAMS Params + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesTransferred + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + WDFREQUEST Request, + _In_ + PWDF_USB_CONTROL_SETUP_PACKET SetupPacket, + _In_opt_ + WDFMEMORY TransferMemory, + _In_opt_ + PWDFMEMORY_OFFSET TransferOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + CONST GUID* CapabilityType, + _In_ + ULONG CapabilityBufferLength, + _When_(CapabilityBufferLength == 0, _Out_opt_) + _When_(CapabilityBufferLength != 0 && ResultLength == NULL, _Out_writes_bytes_(CapabilityBufferLength)) + _When_(CapabilityBufferLength != 0 && ResultLength != NULL, _Out_writes_bytes_to_opt_(CapabilityBufferLength, *ResultLength)) + PVOID CapabilityBuffer, + _Out_opt_ + _When_(ResultLength != NULL,_Deref_out_range_(<=,CapabilityBufferLength)) + PULONG ResultLength + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeGetInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _Out_ + PWDF_USB_PIPE_INFORMATION PipeInformation + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BOOLEAN +VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDF_USB_PIPE_TYPE +VFWDFEXPORT(WdfUsbTargetPipeGetType)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesWritten + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY WriteMemory, + _In_opt_ + PWDFMEMORY_OFFSET WriteOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions, + _In_opt_ + PWDF_MEMORY_DESCRIPTOR MemoryDescriptor, + _Out_opt_ + PULONG BytesRead + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request, + _In_opt_ + WDFMEMORY ReadMemory, + _In_opt_ + PWDFMEMORY_OFFSET ReadOffset + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + PWDF_USB_CONTINUOUS_READER_CONFIG Config + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_opt_ + WDFREQUEST Request, + _In_opt_ + PWDF_REQUEST_SEND_OPTIONS RequestOptions + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBPIPE Pipe, + _In_ + WDFREQUEST Request + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetDescriptor)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _Out_ + PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumSettings)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_Must_inspect_result_ +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfUsbInterfaceSelectSetting)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_opt_ + PWDF_OBJECT_ATTRIBUTES PipesAttributes, + _In_ + PWDF_USB_INTERFACE_SELECT_SETTING_PARAMS Params + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR SettingIndex, + _In_ + UCHAR EndpointIndex, + _Out_ + PWDF_USB_PIPE_INFORMATION EndpointInfo + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBINTERFACE +VFWDFEXPORT(WdfUsbTargetDeviceGetInterface)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBDEVICE UsbDevice, + _In_ + UCHAR InterfaceIndex + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE Interface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +BYTE +VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFUSBPIPE +VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFUSBINTERFACE UsbInterface, + _In_ + UCHAR PipeIndex, + _Out_opt_ + PWDF_USB_PIPE_INFORMATION PipeInfo + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierDbgBreakPoint)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +WDFAPI +VOID +VFWDFEXPORT(WdfVerifierKeBugCheck)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + ULONG BugCheckCode, + _In_ + ULONG_PTR BugCheckParameter1, + _In_ + ULONG_PTR BugCheckParameter2, + _In_ + ULONG_PTR BugCheckParameter3, + _In_ + ULONG_PTR BugCheckParameter4 + ); + +WDFAPI +PVOID +VFWDFEXPORT(WdfGetTriageInfo)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals + ); + +_Must_inspect_result_ +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +NTSTATUS +VFWDFEXPORT(WdfWorkItemCreate)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + PWDF_WORKITEM_CONFIG Config, + _In_ + PWDF_OBJECT_ATTRIBUTES Attributes, + _Out_ + WDFWORKITEM* WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemEnqueue)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(DISPATCH_LEVEL) +WDFAPI +WDFOBJECT +VFWDFEXPORT(WdfWorkItemGetParentObject)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + +_IRQL_requires_max_(PASSIVE_LEVEL) +WDFAPI +VOID +VFWDFEXPORT(WdfWorkItemFlush)( + _In_ + PWDF_DRIVER_GLOBALS DriverGlobals, + _In_ + WDFWORKITEM WorkItem + ); + + +#ifdef VF_FX_DYNAMICS_GENERATE_TABLE + +WDFVERSION VfWdfVersion = { + sizeof(WDFVERSION), + sizeof(WDFFUNCTIONS)/sizeof(PVOID), + { + VFWDFEXPORT(WdfCollectionCreate), + VFWDFEXPORT(WdfCollectionGetCount), + VFWDFEXPORT(WdfCollectionAdd), + VFWDFEXPORT(WdfCollectionRemove), + VFWDFEXPORT(WdfCollectionRemoveItem), + VFWDFEXPORT(WdfCollectionGetItem), + VFWDFEXPORT(WdfCollectionGetFirstItem), + VFWDFEXPORT(WdfCollectionGetLastItem), + VFWDFEXPORT(WdfCxDeviceInitAllocate), + VFWDFEXPORT(WdfCxDeviceInitSetRequestAttributes), + VFWDFEXPORT(WdfCxDeviceInitSetFileObjectConfig), + VFWDFEXPORT(WdfCxVerifierKeBugCheck), + VFWDFEXPORT(WdfDeviceGetDeviceState), + VFWDFEXPORT(WdfDeviceSetDeviceState), + VFWDFEXPORT(WdfDeviceGetDriver), + VFWDFEXPORT(WdfDeviceGetIoTarget), + VFWDFEXPORT(WdfDeviceAssignS0IdleSettings), + VFWDFEXPORT(WdfDeviceAssignSxWakeSettings), + VFWDFEXPORT(WdfDeviceOpenRegistryKey), + VFWDFEXPORT(WdfDeviceInitSetPnpPowerEventCallbacks), + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyEventCallbacks), + VFWDFEXPORT(WdfDeviceInitSetPowerPolicyOwnership), + VFWDFEXPORT(WdfDeviceInitSetIoType), + VFWDFEXPORT(WdfDeviceInitSetFileObjectConfig), + VFWDFEXPORT(WdfDeviceInitSetRequestAttributes), + VFWDFEXPORT(WdfDeviceCreate), + VFWDFEXPORT(WdfDeviceSetStaticStopRemove), + VFWDFEXPORT(WdfDeviceCreateDeviceInterface), + VFWDFEXPORT(WdfDeviceSetDeviceInterfaceState), + VFWDFEXPORT(WdfDeviceRetrieveDeviceInterfaceString), + VFWDFEXPORT(WdfDeviceCreateSymbolicLink), + VFWDFEXPORT(WdfDeviceQueryProperty), + VFWDFEXPORT(WdfDeviceAllocAndQueryProperty), + VFWDFEXPORT(WdfDeviceSetPnpCapabilities), + VFWDFEXPORT(WdfDeviceSetPowerCapabilities), + VFWDFEXPORT(WdfDeviceSetFailed), + VFWDFEXPORT(WdfDeviceStopIdleNoTrack), + VFWDFEXPORT(WdfDeviceResumeIdleNoTrack), + VFWDFEXPORT(WdfDeviceGetFileObject), + VFWDFEXPORT(WdfDeviceGetDefaultQueue), + VFWDFEXPORT(WdfDeviceConfigureRequestDispatching), + VFWDFEXPORT(WdfDeviceGetSystemPowerAction), + VFWDFEXPORT(WdfDeviceInitSetReleaseHardwareOrderOnFailure), + VFWDFEXPORT(WdfDeviceInitSetIoTypeEx), + VFWDFEXPORT(WdfDevicePostEvent), + VFWDFEXPORT(WdfDeviceMapIoSpace), + VFWDFEXPORT(WdfDeviceUnmapIoSpace), + VFWDFEXPORT(WdfDeviceGetHardwareRegisterMappedAddress), + VFWDFEXPORT(WdfDeviceReadFromHardware), + VFWDFEXPORT(WdfDeviceWriteToHardware), + VFWDFEXPORT(WdfDeviceAssignInterfaceProperty), + VFWDFEXPORT(WdfDeviceAllocAndQueryInterfaceProperty), + VFWDFEXPORT(WdfDeviceQueryInterfaceProperty), + VFWDFEXPORT(WdfDeviceGetDeviceStackIoType), + VFWDFEXPORT(WdfDeviceQueryPropertyEx), + VFWDFEXPORT(WdfDeviceAllocAndQueryPropertyEx), + VFWDFEXPORT(WdfDeviceAssignProperty), + VFWDFEXPORT(WdfDriverCreate), + VFWDFEXPORT(WdfDriverGetRegistryPath), + VFWDFEXPORT(WdfDriverOpenParametersRegistryKey), + VFWDFEXPORT(WdfDriverRetrieveVersionString), + VFWDFEXPORT(WdfDriverIsVersionAvailable), + VFWDFEXPORT(WdfFdoInitOpenRegistryKey), + VFWDFEXPORT(WdfFdoInitQueryProperty), + VFWDFEXPORT(WdfFdoInitAllocAndQueryProperty), + VFWDFEXPORT(WdfFdoInitQueryPropertyEx), + VFWDFEXPORT(WdfFdoInitAllocAndQueryPropertyEx), + VFWDFEXPORT(WdfFdoInitSetFilter), + VFWDFEXPORT(WdfFileObjectGetFileName), + VFWDFEXPORT(WdfFileObjectGetDevice), + VFWDFEXPORT(WdfFileObjectGetInitiatorProcessId), + VFWDFEXPORT(WdfFileObjectGetRelatedFileObject), + VFWDFEXPORT(WdfInterruptCreate), + VFWDFEXPORT(WdfInterruptQueueDpcForIsr), + VFWDFEXPORT(WdfInterruptQueueWorkItemForIsr), + VFWDFEXPORT(WdfInterruptSynchronize), + VFWDFEXPORT(WdfInterruptAcquireLock), + VFWDFEXPORT(WdfInterruptReleaseLock), + VFWDFEXPORT(WdfInterruptEnable), + VFWDFEXPORT(WdfInterruptDisable), + VFWDFEXPORT(WdfInterruptGetInfo), + VFWDFEXPORT(WdfInterruptSetPolicy), + VFWDFEXPORT(WdfInterruptSetExtendedPolicy), + VFWDFEXPORT(WdfInterruptGetDevice), + VFWDFEXPORT(WdfInterruptTryToAcquireLock), + VFWDFEXPORT(WdfIoQueueCreate), + VFWDFEXPORT(WdfIoQueueGetState), + VFWDFEXPORT(WdfIoQueueStart), + VFWDFEXPORT(WdfIoQueueStop), + VFWDFEXPORT(WdfIoQueueStopSynchronously), + VFWDFEXPORT(WdfIoQueueGetDevice), + VFWDFEXPORT(WdfIoQueueRetrieveNextRequest), + VFWDFEXPORT(WdfIoQueueRetrieveRequestByFileObject), + VFWDFEXPORT(WdfIoQueueFindRequest), + VFWDFEXPORT(WdfIoQueueRetrieveFoundRequest), + VFWDFEXPORT(WdfIoQueueDrainSynchronously), + VFWDFEXPORT(WdfIoQueueDrain), + VFWDFEXPORT(WdfIoQueuePurgeSynchronously), + VFWDFEXPORT(WdfIoQueuePurge), + VFWDFEXPORT(WdfIoQueueReadyNotify), + VFWDFEXPORT(WdfIoQueueStopAndPurge), + VFWDFEXPORT(WdfIoQueueStopAndPurgeSynchronously), + VFWDFEXPORT(WdfIoTargetCreate), + VFWDFEXPORT(WdfIoTargetOpen), + VFWDFEXPORT(WdfIoTargetCloseForQueryRemove), + VFWDFEXPORT(WdfIoTargetClose), + VFWDFEXPORT(WdfIoTargetStart), + VFWDFEXPORT(WdfIoTargetStop), + VFWDFEXPORT(WdfIoTargetPurge), + VFWDFEXPORT(WdfIoTargetGetState), + VFWDFEXPORT(WdfIoTargetGetDevice), + VFWDFEXPORT(WdfIoTargetSendReadSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForRead), + VFWDFEXPORT(WdfIoTargetSendWriteSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForWrite), + VFWDFEXPORT(WdfIoTargetSendIoctlSynchronously), + VFWDFEXPORT(WdfIoTargetFormatRequestForIoctl), + VFWDFEXPORT(WdfMemoryCreate), + VFWDFEXPORT(WdfMemoryCreatePreallocated), + VFWDFEXPORT(WdfMemoryGetBuffer), + VFWDFEXPORT(WdfMemoryAssignBuffer), + VFWDFEXPORT(WdfMemoryCopyToBuffer), + VFWDFEXPORT(WdfMemoryCopyFromBuffer), + VFWDFEXPORT(WdfObjectGetTypedContextWorker), + VFWDFEXPORT(WdfObjectAllocateContext), + VFWDFEXPORT(WdfObjectContextGetObject), + VFWDFEXPORT(WdfObjectReferenceActual), + VFWDFEXPORT(WdfObjectDereferenceActual), + VFWDFEXPORT(WdfObjectCreate), + VFWDFEXPORT(WdfObjectDelete), + VFWDFEXPORT(WdfObjectQuery), + VFWDFEXPORT(WdfRegistryOpenKey), + VFWDFEXPORT(WdfRegistryCreateKey), + VFWDFEXPORT(WdfRegistryClose), + VFWDFEXPORT(WdfRegistryRemoveKey), + VFWDFEXPORT(WdfRegistryRemoveValue), + VFWDFEXPORT(WdfRegistryQueryValue), + VFWDFEXPORT(WdfRegistryQueryMemory), + VFWDFEXPORT(WdfRegistryQueryMultiString), + VFWDFEXPORT(WdfRegistryQueryUnicodeString), + VFWDFEXPORT(WdfRegistryQueryString), + VFWDFEXPORT(WdfRegistryQueryULong), + VFWDFEXPORT(WdfRegistryAssignValue), + VFWDFEXPORT(WdfRegistryAssignMemory), + VFWDFEXPORT(WdfRegistryAssignMultiString), + VFWDFEXPORT(WdfRegistryAssignUnicodeString), + VFWDFEXPORT(WdfRegistryAssignString), + VFWDFEXPORT(WdfRegistryAssignULong), + VFWDFEXPORT(WdfRequestCreate), + VFWDFEXPORT(WdfRequestReuse), + VFWDFEXPORT(WdfRequestChangeTarget), + VFWDFEXPORT(WdfRequestFormatRequestUsingCurrentType), + VFWDFEXPORT(WdfRequestSend), + VFWDFEXPORT(WdfRequestGetStatus), + VFWDFEXPORT(WdfRequestMarkCancelable), + VFWDFEXPORT(WdfRequestMarkCancelableEx), + VFWDFEXPORT(WdfRequestUnmarkCancelable), + VFWDFEXPORT(WdfRequestIsCanceled), + VFWDFEXPORT(WdfRequestCancelSentRequest), + VFWDFEXPORT(WdfRequestIsFrom32BitProcess), + VFWDFEXPORT(WdfRequestSetCompletionRoutine), + VFWDFEXPORT(WdfRequestGetCompletionParams), + VFWDFEXPORT(WdfRequestAllocateTimer), + VFWDFEXPORT(WdfRequestComplete), + VFWDFEXPORT(WdfRequestCompleteWithInformation), + VFWDFEXPORT(WdfRequestGetParameters), + VFWDFEXPORT(WdfRequestRetrieveInputMemory), + VFWDFEXPORT(WdfRequestRetrieveOutputMemory), + VFWDFEXPORT(WdfRequestRetrieveInputBuffer), + VFWDFEXPORT(WdfRequestRetrieveOutputBuffer), + VFWDFEXPORT(WdfRequestSetInformation), + VFWDFEXPORT(WdfRequestGetInformation), + VFWDFEXPORT(WdfRequestGetFileObject), + VFWDFEXPORT(WdfRequestGetRequestorMode), + VFWDFEXPORT(WdfRequestForwardToIoQueue), + VFWDFEXPORT(WdfRequestGetIoQueue), + VFWDFEXPORT(WdfRequestRequeue), + VFWDFEXPORT(WdfRequestStopAcknowledge), + VFWDFEXPORT(WdfRequestImpersonate), + VFWDFEXPORT(WdfRequestGetRequestorProcessId), + VFWDFEXPORT(WdfRequestIsFromUserModeDriver), + VFWDFEXPORT(WdfRequestSetUserModeDriverInitiatedIo), + VFWDFEXPORT(WdfRequestGetUserModeDriverInitiatedIo), + VFWDFEXPORT(WdfRequestSetActivityId), + VFWDFEXPORT(WdfRequestRetrieveActivityId), + VFWDFEXPORT(WdfRequestGetEffectiveIoType), + VFWDFEXPORT(WdfCmResourceListGetCount), + VFWDFEXPORT(WdfCmResourceListGetDescriptor), + VFWDFEXPORT(WdfStringCreate), + VFWDFEXPORT(WdfStringGetUnicodeString), + VFWDFEXPORT(WdfObjectAcquireLock), + VFWDFEXPORT(WdfObjectReleaseLock), + VFWDFEXPORT(WdfWaitLockCreate), + VFWDFEXPORT(WdfWaitLockAcquire), + VFWDFEXPORT(WdfWaitLockRelease), + VFWDFEXPORT(WdfSpinLockCreate), + VFWDFEXPORT(WdfSpinLockAcquire), + VFWDFEXPORT(WdfSpinLockRelease), + VFWDFEXPORT(WdfTimerCreate), + VFWDFEXPORT(WdfTimerStart), + VFWDFEXPORT(WdfTimerStop), + VFWDFEXPORT(WdfTimerGetParentObject), + VFWDFEXPORT(WdfUsbTargetDeviceCreate), + VFWDFEXPORT(WdfUsbTargetDeviceCreateWithParameters), + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveInformation), + VFWDFEXPORT(WdfUsbTargetDeviceGetDeviceDescriptor), + VFWDFEXPORT(WdfUsbTargetDeviceRetrieveConfigDescriptor), + VFWDFEXPORT(WdfUsbTargetDeviceQueryString), + VFWDFEXPORT(WdfUsbTargetDeviceAllocAndQueryString), + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForString), + VFWDFEXPORT(WdfUsbTargetDeviceGetNumInterfaces), + VFWDFEXPORT(WdfUsbTargetDeviceSelectConfig), + VFWDFEXPORT(WdfUsbTargetDeviceSendControlTransferSynchronously), + VFWDFEXPORT(WdfUsbTargetDeviceFormatRequestForControlTransfer), + VFWDFEXPORT(WdfUsbTargetDeviceResetPortSynchronously), + VFWDFEXPORT(WdfUsbTargetDeviceQueryUsbCapability), + VFWDFEXPORT(WdfUsbTargetPipeGetInformation), + VFWDFEXPORT(WdfUsbTargetPipeIsInEndpoint), + VFWDFEXPORT(WdfUsbTargetPipeIsOutEndpoint), + VFWDFEXPORT(WdfUsbTargetPipeGetType), + VFWDFEXPORT(WdfUsbTargetPipeSetNoMaximumPacketSizeCheck), + VFWDFEXPORT(WdfUsbTargetPipeWriteSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForWrite), + VFWDFEXPORT(WdfUsbTargetPipeReadSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForRead), + VFWDFEXPORT(WdfUsbTargetPipeConfigContinuousReader), + VFWDFEXPORT(WdfUsbTargetPipeAbortSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForAbort), + VFWDFEXPORT(WdfUsbTargetPipeResetSynchronously), + VFWDFEXPORT(WdfUsbTargetPipeFormatRequestForReset), + VFWDFEXPORT(WdfUsbInterfaceGetInterfaceNumber), + VFWDFEXPORT(WdfUsbInterfaceGetNumEndpoints), + VFWDFEXPORT(WdfUsbInterfaceGetDescriptor), + VFWDFEXPORT(WdfUsbInterfaceGetNumSettings), + VFWDFEXPORT(WdfUsbInterfaceSelectSetting), + VFWDFEXPORT(WdfUsbInterfaceGetEndpointInformation), + VFWDFEXPORT(WdfUsbTargetDeviceGetInterface), + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredSettingIndex), + VFWDFEXPORT(WdfUsbInterfaceGetNumConfiguredPipes), + VFWDFEXPORT(WdfUsbInterfaceGetConfiguredPipe), + VFWDFEXPORT(WdfVerifierDbgBreakPoint), + VFWDFEXPORT(WdfVerifierKeBugCheck), + VFWDFEXPORT(WdfGetTriageInfo), + VFWDFEXPORT(WdfWorkItemCreate), + VFWDFEXPORT(WdfWorkItemEnqueue), + VFWDFEXPORT(WdfWorkItemGetParentObject), + VFWDFEXPORT(WdfWorkItemFlush), + VFWDFEXPORT(WdfRegistryWdmGetHandle), + VFWDFEXPORT(WdfDeviceStopIdleActual), + VFWDFEXPORT(WdfDeviceResumeIdleActual), + VFWDFEXPORT(WdfDeviceInitEnableHidInterface), + VFWDFEXPORT(WdfDeviceHidNotifyPresence), + VFWDFEXPORT(WdfDeviceGetSelfIoTarget), + VFWDFEXPORT(WdfDeviceInitAllowSelfIoTarget), + VFWDFEXPORT(WdfIoTargetSelfAssignDefaultIoQueue), + VFWDFEXPORT(WdfDeviceOpenDevicemapKey), + VFWDFEXPORT(WdfIoTargetWdmGetTargetFileHandle), + VFWDFEXPORT(WdfDeviceWdmDispatchIrp), + VFWDFEXPORT(WdfDeviceWdmDispatchIrpToIoQueue), + VFWDFEXPORT(WdfDeviceConfigureWdmIrpDispatchCallback), + } +}; + +#endif // VF_FX_DYNAMICS_GENERATE_TABLE + +#endif // _VFFXDYNAMICS_H_ +