Sample Code
Windows Driver Samples/ KMDF Power Framework (PoFx) Sample/ C++/ Driver/ MultiComp/ lib/ init.c/
/*++ Copyright (c) Microsoft Corporation. All rights reserved. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. Module Name: init.c Abstract: This module contains routines that are used to initialize the power framework helper library Environment: Kernel mode --*/ #include "WdfPoFxPriv.h" #include "init.tmh" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, GetDeviceInitSettings) #pragma alloc_text(PAGE, PfhInitializerCreate) #pragma alloc_text(PAGE, CopyAndUpdateMinorFunctionsArray) #pragma alloc_text(PAGE, PfhAssignWdmPowerIrpPreProcessCallback) #pragma alloc_text(PAGE, PfhInterceptWdfPnpPowerEventCallbacks) #pragma alloc_text(PAGE, PfhSetPoHandleAvailabilityCallbacks) #pragma alloc_text(PAGE, CopyMinorFunctionsArray) #pragma alloc_text(PAGE, PfhInitializeDeviceSettings) #pragma alloc_text(PAGE, PfhInitializePowerFrameworkSettings) #endif PHELPER_DEVICE_INIT GetDeviceInitSettings( _In_ WDFOBJECT Initializer ) /*++ Routine description: This routine gets a pointer to the location in the initializer object's context space where we store the driver layer's device object settings. Arguments: Initializer - Handle to the initializer object that is being used to initialize our device object settings. Return value: Pointer to a HELPER_DEVICE_INIT structure where the driver layer's device object settings are stored. --*/ { PHELPER_INIT initContext = NULL; PAGED_CODE(); initContext = HelperGetInitContext(Initializer); if ((initContext->InitType != HelperInitTypeNone) && (initContext->InitType != HelperInitTypeDevice)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Cannot get device initialization settings for " "initializer object %p because it is currently being used to " "initialize a different object.", Initializer); WdfVerifierDbgBreakPoint(); return NULL; } if (initContext->InitType == HelperInitTypeNone) { initContext->InitType = HelperInitTypeDevice; } return &(initContext->u.DeviceInit); } PHELPER_QUEUE_INIT GetQueueInitSettings( _In_ WDFOBJECT Initializer ) /*++ Routine description: This routine gets a pointer to the location in the initializer object's context space where we store the driver layer's queue object settings. Arguments: Initializer - Handle to the initializer object that is being used to initialize our queue object settings. Return value: Pointer to a HELPER_QUEUE_INIT structure where the driver layer's queue object settings are stored. --*/ { PHELPER_INIT initContext = NULL; initContext = HelperGetInitContext(Initializer); if ((initContext->InitType != HelperInitTypeNone) && (initContext->InitType != HelperInitTypeQueue)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Cannot get queue initialization settings for " "initializer object %p because it is currently being used to " "initialize a different object.", Initializer); WdfVerifierDbgBreakPoint(); return NULL; } if (initContext->InitType == HelperInitTypeNone) { initContext->InitType = HelperInitTypeQueue; } return &(initContext->u.QueueInit); } BOOLEAN IsDeviceInitialized( _In_ WDFDEVICE Device ) /*++ Routine description: This routine determines whether we have initialized our settings for the given device object. Arguments: Device - Handle to the KMDF device object Return value: TRUE if we have initialized our settings for the device object, FALSE otherwise. --*/ { PPOFX_DEVICE_CONTEXT devCtx; devCtx = HelperGetDeviceContext(Device); return (NULL != devCtx); } BOOLEAN ArePowerFrameworkSettingsAvailable( _In_ WDFDEVICE Device ) /*++ Routine description: This routine determines whether the driver layer has provided us with its power framework settings for the given device object. Arguments: Device - Handle to the KMDF device object Return value: TRUE if we the driver layer has provided us with its power framework settings for the device object, FALSE otherwise. --*/ { PPOFX_DEVICE_CONTEXT devCtx; devCtx = HelperGetDeviceContext(Device); return ((NULL != devCtx) && (NULL != devCtx->PoFxDeviceInfo)); } BOOLEAN IsQueueInitialized( _In_ WDFQUEUE Queue ) /*++ Routine description: This routine determines whether we have initialized our settings for the given queue object. Arguments: Queue - Handle to the KMDF queue object Return value: TRUE if we have initialized our settings for the queue object, FALSE otherwise. --*/ { PPOFX_QUEUE_CONTEXT qCtx; qCtx = HelperGetQueueContext(Queue); return (NULL != qCtx); } VOID ResetInitializer( _In_ WDFOBJECT Initializer ) /*++ Routine description: This routine prepares the given initializer object for initializing a new KMDF object. Arguments: Initializer - Handle to the initializer object Return value: None --*/ { PHELPER_INIT initContext = NULL; // // We want to make sure that when the initializer context is zeroed, the // default S0-idle power management configuration for the device is // PfhS0IdleNotSupported. // C_ASSERT(0 == PfhS0IdleNotSupported); // // Reset the initializer context // initContext = HelperGetInitContext(Initializer); RtlZeroMemory(initContext, sizeof(*initContext)); initContext->InitType = HelperInitTypeNone; return; } _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS PfhInitializerCreate( _Out_ WDFOBJECT * Initializer ) // See comments in WdfPoFx.h { NTSTATUS status; WDFOBJECT initializer = NULL; WDF_OBJECT_ATTRIBUTES objectAttributes; PAGED_CODE(); // // Create an initializer object // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, HELPER_INIT); status = WdfObjectCreate(&objectAttributes, &initializer); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfObjectCreate failed with %!status!.", status); goto exit; } // // Initialize context // ResetInitializer(initializer); *Initializer = initializer; status = STATUS_SUCCESS; exit: return status; } NTSTATUS CopyAndUpdateMinorFunctionsArray( _In_ WDFOBJECT Initializer, _In_reads_opt_(NumMinorFunctions) PUCHAR MinorFunctions, _In_ ULONG NumMinorFunctions, _Out_ WDFMEMORY * MinorFunctionsMemory, _Outptr_result_buffer_(*UpdatedNumMinorFunctions) PUCHAR *UpdatedMinorFunctions, _Out_ PULONG UpdatedNumMinorFunctions ) /*++ Routine description: This routine takes an array of power IRP minor functions and makes a copy of it. If the input array does not include IRP_MN_SET_POWER as one of the minor functions, the copy of the array made by this routine is expanded to include IRP_MN_SET_POWER too. This enables us to register a WDM pre-process callback for IRP_MN_SET_POWER, regardless of whether the driver layer is interested in that minor function. Arguments: Initializer - Handle to the initializer object MinorFunctions - Caller-initialized array of minor functions that the driver layer is interested in for the IRP_MJ_POWER major function. NumMinorFunctions - The number of minor functions in the MinorFunctions array MinorFunctionsMemory - Pointer to a location that receives a handle to the memory object created by this routine to store a copy of the minor functions UpdatedMinorFunctions - Pointer to a location that receives an array of minor functions that the driver layer is interested in, plus IRP_MN_SET_POWER if it was not present in the original array UpdatedNumMinorFunctions - Pointer to a location that receives the number of minor functions in the UpdatedMinorFunctions array Return value: An NTSTATUS value representing success or failure of the function. --*/ { NTSTATUS status; BOOLEAN driverLayerPreprocessesSetPower = FALSE; UCHAR setPowerMinorFunction; ULONG i; ULONG driverLayerMinorFunctions = 0; ULONG extraMinorFunctions = 0; ULONG totalMinorFunctions = 0; ULONG totalMinorFunctionsSize = 0; ULONG memorySize = 0; WDF_OBJECT_ATTRIBUTES objectAttributes; WDFMEMORY memory = NULL; PPOFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO memoryBuffer = NULL; ULONG minorFunctionsOffset; ULONG minorFunctionsSize; ULONG extraMinorFunctionOffset; PAGED_CODE(); // // Check if the driver layer needs to preprocess IRP_MN_SET_POWER // if ((NULL != MinorFunctions) && (0 != NumMinorFunctions)) { driverLayerMinorFunctions = NumMinorFunctions; for (i=0; i < NumMinorFunctions; i++) { if (IRP_MN_SET_POWER == MinorFunctions[i]) { driverLayerPreprocessesSetPower = TRUE; break; } } } // // If the driver layer does not preprocess IRP_MN_SET_POWER, then we need to // update the minor functions array with an extra entry for IRP_MN_SET_POWER // extraMinorFunctions = driverLayerPreprocessesSetPower ? 0 : 1; // // Allocate memory to store a copy of the minor functions array // status = RtlULongAdd(driverLayerMinorFunctions, extraMinorFunctions, &totalMinorFunctions); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute total minor functions count for " "power IRP preprocessing. RtlUlongAdd failed with %!status!.", status); goto exit; } ASSERT(totalMinorFunctions > 0); status = RtlULongMult(sizeof(MinorFunctions[0]), totalMinorFunctions, &totalMinorFunctionsSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute buffer size needed to store the " "functions array. RtlULongMult failed with %!status!.", status); goto exit; } status = RtlULongAdd(sizeof(POFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO), totalMinorFunctionsSize, &memorySize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute buffer size needed to store the " "minor functions array and count. RtlUlongAdd failed with " "%!status!.", status); goto exit; } if (0 == memorySize) { status = STATUS_INVALID_BUFFER_SIZE; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to set memorySize. Failed with %!status!.", status); goto exit; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.ParentObject = Initializer; // auto-delete when parent // deleted #pragma prefast(suppress:28160, "memorySize > 0") status = WdfMemoryCreate(&objectAttributes, NonPagedPool, 0, // PoolTag memorySize, &memory, (PVOID*) &memoryBuffer); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to allocate memory to store the minor functions" " array and count. WdfMemoryCreate failed with %!status!.", status); goto exit; } // // We'll remember only the minor functions that the driver layer is // interested in. If we add IRP_MN_SET_POWER to that list, we won't need to // remember that beyond initialization time. // memoryBuffer->NumMinorFunctions = driverLayerMinorFunctions; // // Copy the minor functions array // minorFunctionsOffset = FIELD_OFFSET(POFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO, MinorFunctions); minorFunctionsSize = driverLayerMinorFunctions * sizeof(MinorFunctions[0]); // already performed // intsafe math above // won't overflow if (driverLayerMinorFunctions > 0) { if (0 == minorFunctionsSize) { status = STATUS_INVALID_BUFFER_SIZE; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to set minorFunctionsSize. Failed with %!status!.", status); goto exit; } #pragma prefast(suppress:28160, "minorFunctionsSize > 0") status = WdfMemoryCopyFromBuffer(memory, minorFunctionsOffset, memoryBuffer->MinorFunctions, minorFunctionsSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to copy driver layer's minor functions " "array. WdfMemoryCopyFromBuffer failed with %!status!.", status); goto exit; } } if (extraMinorFunctions > 0) { ASSERT(extraMinorFunctions == 1); // // Add an extra minor function for IRP_MN_SET_POWER since it was not in // the driver layer's list. // NOTE: This minor function is added at the end and is not reflected in // memoryBuffer.NumMinorFunctions. // extraMinorFunctionOffset = minorFunctionsOffset + minorFunctionsSize;// already performed intsafe // math above so this won't // overflow setPowerMinorFunction = IRP_MN_SET_POWER; status = WdfMemoryCopyFromBuffer(memory, extraMinorFunctionOffset, &setPowerMinorFunction, sizeof(setPowerMinorFunction)); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to add an extra minor function " "(IRP_MN_SET_POWER) to the minor functions array. " "WdfMemoryCopyFromBuffer failed with %!status!.", status); goto exit; } } *MinorFunctionsMemory = memory; *UpdatedMinorFunctions = memoryBuffer->MinorFunctions; *UpdatedNumMinorFunctions = totalMinorFunctions;// Do not use memoryBuffer.NumMinorFunctions // here because it does not include the extra // minor function that we might have added. // // If we added an extra minor function, it is present in the buffer but not // reflected in memoryBuffer.NumMinorFunctions // ASSERT((memoryBuffer->NumMinorFunctions + extraMinorFunctions) == totalMinorFunctions); status = STATUS_SUCCESS; exit: if (FALSE == NT_SUCCESS(status)) { if (NULL != memory) { WdfObjectDelete(memory); } } return status; } _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS PfhAssignWdmPowerIrpPreProcessCallback( _In_ WDFOBJECT Initializer, _In_ PWDFDEVICE_INIT DeviceInit, _In_opt_ PFN_WDFDEVICE_WDM_IRP_PREPROCESS EvtDeviceWdmPowerIrpPreprocess, _In_reads_opt_(NumMinorFunctions) PUCHAR MinorFunctions, _In_ ULONG NumMinorFunctions ) // See comments in WdfPoFx.h { NTSTATUS status; WDFMEMORY minorFunctionsMemory = NULL; ULONG numMinorFunctions = 0; PUCHAR minorFunctions = NULL; PHELPER_DEVICE_INIT deviceInitSettings = NULL; PAGED_CODE(); deviceInitSettings = GetDeviceInitSettings(Initializer); if (deviceInitSettings->PowerIrpPreprocessCallbackAssigned) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhAssignWdmPowerIrpPreProcessCallback has already" " been called on initialier %p. It should not be called again " "before the initializer has been used to initialize a KMDF device" " object. %!status!.", Initializer, status); WdfVerifierDbgBreakPoint(); goto exit; } // // Copy the minor functions array and, if needed, update it to include // IRP_MN_SET_POWER. // status = CopyAndUpdateMinorFunctionsArray(Initializer, MinorFunctions, NumMinorFunctions, &minorFunctionsMemory, &minorFunctions, &numMinorFunctions); if (FALSE == NT_SUCCESS(status)) { goto exit; } // // Assign the WDM preprocess callback // status = WdfDeviceInitAssignWdmIrpPreprocessCallback( DeviceInit, _PfhEvtWdmPowerIrpPreprocess, IRP_MJ_POWER, minorFunctions, numMinorFunctions ); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceInitAssignWdmIrpPreprocessCallback failed " "with %!status!.", status); goto exit; } deviceInitSettings->PowerIrpPreprocessMinorFunctions = minorFunctionsMemory; deviceInitSettings->EvtDeviceWdmPowerIrpPreprocess = EvtDeviceWdmPowerIrpPreprocess; deviceInitSettings->PowerIrpPreprocessCallbackAssigned = TRUE; status = STATUS_SUCCESS; exit: if (FALSE == NT_SUCCESS(status)) { if (NULL != minorFunctionsMemory) { WdfObjectDelete(minorFunctionsMemory); } } return status; } _IRQL_requires_max_(PASSIVE_LEVEL) VOID PfhInterceptWdfPnpPowerEventCallbacks( _In_ WDFOBJECT Initializer, _Inout_ PWDF_PNPPOWER_EVENT_CALLBACKS DriverLayerPnpPowerCallbacks ) // See comments in WdfPoFx.h { PHELPER_DEVICE_INIT deviceInitSettings = NULL; PAGED_CODE(); deviceInitSettings = GetDeviceInitSettings(Initializer); if (deviceInitSettings->PnpPowerEventCallbacksIntercepted) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInterceptWdfPnpPowerEventCallbacks has already been" " called on initialier %p. It should not be called again before " "the initializer has been used to initialize a KMDF device " "object.", Initializer); WdfVerifierDbgBreakPoint(); } // // Save the driver layer's callbacks that we are going to replace // deviceInitSettings->EvtDeviceSelfManagedIoInit = DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoInit; deviceInitSettings->EvtDeviceSelfManagedIoFlush = DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoFlush; deviceInitSettings->EvtDeviceSelfManagedIoRestart = DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoRestart; deviceInitSettings->EvtDeviceD0Entry = DriverLayerPnpPowerCallbacks->EvtDeviceD0Entry; // // Replace the driver layer's callbacks with our own // DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoInit = _PfhEvtSelfManagedIoInit; DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoFlush = _PfhEvtSelfManagedIoFlush; DriverLayerPnpPowerCallbacks->EvtDeviceSelfManagedIoRestart = _PfhEvtSelfManagedIoRestart; DriverLayerPnpPowerCallbacks->EvtDeviceD0Entry = _PfhEvtD0Entry; deviceInitSettings->PnpPowerEventCallbacksIntercepted = TRUE; return; } _IRQL_requires_max_(PASSIVE_LEVEL) VOID PfhSetPoHandleAvailabilityCallbacks( _In_ WDFOBJECT Initializer, _In_ PPFH_CALLBACK_POHANDLE_AVAILABLE PfhCallbackPoHandleAvailable, _In_ PPFH_CALLBACK_POHANDLE_UNAVAILABLE PfhCallbackPoHandleUnavailable ) // See comments in WdfPoFx.h { PHELPER_DEVICE_INIT deviceInitSettings = NULL; PAGED_CODE(); deviceInitSettings = GetDeviceInitSettings(Initializer); if (deviceInitSettings->PoHandleAvailabilityCallbacksSet) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhSetPoHandleAvailabilityCallbacks has already been " "called on initialier %p. It should not be called again before " "the initializer has been used to initialize a KMDF device " "object.", Initializer); WdfVerifierDbgBreakPoint(); } // // Save the driver layer's callbacks // deviceInitSettings->PfhCallbackPoHandleAvailable = PfhCallbackPoHandleAvailable; deviceInitSettings->PfhCallbackPoHandleUnavailable = PfhCallbackPoHandleUnavailable; deviceInitSettings->PoHandleAvailabilityCallbacksSet = TRUE; return; } NTSTATUS CopyMinorFunctionsArray( _In_ WDFDEVICE Device, _In_ WDFMEMORY SourceMemory, _Out_ WDFMEMORY * DestinationMemory ) /*++ Routine description: This routine creates a new memory object to store the array of power IRP minor functions that the driver layer is interested in. The array is currently stored in a memory object that we had created as a child of the initializer object that was being used to initialize the device object. Now that the initialization of the device object is about to complete, we need to make a copy of the contents of that memory object. Once the device object initialization is complete, the driver layer is free to delete the initializer object, which will result in the original memory object also getting delete. That is why we copy the contents to a new memory object. Arguments: Device - Handle to the KMDF device object SourceMemory - Handle to the memory object that contains the array of power IRP minor functions that the driver layer is interested in DestinationMemory - Pointer to a location that receives a handle to a new memory object created by this routine. The new memory object contains a copy of the a Return value: An NTSTATUS value representing success or failure of the function. --*/ { NTSTATUS status; PPOFX_DRIVER_LAYER_POWER_IRP_PREPROCESS_INFO powerIrpPreprocessInfo = NULL; size_t powerIrpPreprocessInfoSize; WDF_OBJECT_ATTRIBUTES objectAttributes; WDFMEMORY memory = NULL; PAGED_CODE(); // // Get the source memory buffer // powerIrpPreprocessInfo = WdfMemoryGetBuffer(SourceMemory, &powerIrpPreprocessInfoSize); if (0 == powerIrpPreprocessInfoSize) { status = STATUS_INVALID_BUFFER_SIZE; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to get powerIrpPreprocessInfoSize. Failed with %!status!.", status); goto exit; } // // Create a new memory object to hold a copy of the buffer // WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.ParentObject = Device; // auto-delete when parent deleted status = WdfMemoryCreate(&objectAttributes, NonPagedPool, 0, // PoolTag powerIrpPreprocessInfoSize, &memory, NULL // Buffer ); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to allocate memory for the driver layer's minor" " functions array. WdfMemoryCreate failed with %!status!.", status); goto exit; } // // Copy the buffer into the new memory object // status = WdfMemoryCopyFromBuffer(memory, 0, // DestinationOffset powerIrpPreprocessInfo, powerIrpPreprocessInfoSize); if (FALSE == NT_SUCCESS(status)) { goto exit; } *DestinationMemory = memory; status = STATUS_SUCCESS; exit: return status; } _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS PfhInitializeDeviceSettings( _In_ WDFDEVICE Device, _In_ WDFOBJECT Initializer ) // See comments in WdfPoFx.h { NTSTATUS status; WDF_OBJECT_ATTRIBUTES objectAttributes; PPOFX_DEVICE_CONTEXT devCtx; PHELPER_DEVICE_INIT deviceInitSettings = NULL; WDFMEMORY memory = NULL; PAGED_CODE(); deviceInitSettings = GetDeviceInitSettings(Initializer); if (IsDeviceInitialized(Device)) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInitializeDeviceSettings has already been called " "for WDFDEVICE %p. It should not be called again. %!status!.", Device, status); WdfVerifierDbgBreakPoint(); goto exit; } if (FALSE == deviceInitSettings->PowerIrpPreprocessCallbackAssigned) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhAssignWdmPowerIrpPreProcessCallback has not yet " "been called for WDFDEVICE %p. %!status!.", Device, status); WdfVerifierDbgBreakPoint(); goto exit; } if (FALSE == deviceInitSettings->PnpPowerEventCallbacksIntercepted) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInterceptWdfPnpPowerEventCallbacks has not yet been" " called for WDFDEVICE %p. %!status!.", Device, status); WdfVerifierDbgBreakPoint(); goto exit; } // // Allocate our context for this device // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, POFX_DEVICE_CONTEXT); status = WdfObjectAllocateContext((WDFOBJECT) Device, &objectAttributes, (PVOID*) &devCtx); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfObjectAllocateContext failed with %!status!", status); goto exit; } // // Copy the device init settings // devCtx->DeviceInitSettings = *deviceInitSettings; // // Copy the minor functions array into a new memory object that is a child // of the device object. The array is currently in a memory object that is // a child of the initializer object. The initializer object can be deleted // by the driver layer any time after initialization is complete, so we need // to make a copy now. // status = CopyMinorFunctionsArray( Device, devCtx->DeviceInitSettings.PowerIrpPreprocessMinorFunctions, &memory ); if (FALSE == NT_SUCCESS(status)) { goto exit; } // // Perform initialization specific to S0-idle support (if enabled) // INITIALIZE_DEVICE_SETTINGS_FOR_S0_IDLE(Device, devCtx); // // In our device context, replace the pointer to the initializer's memory // object with a pointer to the new memory object that we just created. // devCtx->DeviceInitSettings.PowerIrpPreprocessMinorFunctions = memory; // // For convenient access, also save the memory object's buffer in our device // context. // devCtx->DriverLayerPowerIrpPreprocessInfo = WdfMemoryGetBuffer( memory, NULL // BufferSize ); // // By default, we do not need to call PoFxReportDevicePoweredOn from our // EvtDeviceD0Entry callback. We only need to call it in the // EvtDeviceD0Entry callback that is invoked right after we receive an S0 // IRP. // devCtx->ShouldReportDevicePoweredOn = FALSE; // // The initializer can now be used to initialize some other object // ResetInitializer(Initializer); status = STATUS_SUCCESS; exit: return status; } _IRQL_requires_max_(PASSIVE_LEVEL) NTSTATUS PfhInitializePowerFrameworkSettings( _In_ WDFDEVICE Device, _In_ PPO_FX_DEVICE PoFxDeviceInfo ) // See comments in WdfPoFx.h { NTSTATUS status; WDF_OBJECT_ATTRIBUTES objectAttributes; PPOFX_DEVICE_CONTEXT devCtx; ULONG i; ULONG pofxExtraComponentsSize; ULONG pofxDeviceInfoSize; WDFMEMORY memory = NULL; ULONG idleStatesSize; PVOID idleStates = NULL; PPO_FX_DEVICE poFxDeviceInfo = NULL; PPOFX_COMPONENT_INFO componentInfo = NULL; ULONG componentInfoSize; PAGED_CODE(); if (FALSE == IsDeviceInitialized(Device)) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInitializeDeviceSettings has not yet been called " "for WDFDEVICE %p. %!status!.", Device, status); WdfVerifierDbgBreakPoint(); goto exit; } if (ArePowerFrameworkSettingsAvailable(Device)) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInitializePowerFrameworkSettings has already been " "called for WDFDEVICE %p. It should not be called again. " "%!status!.", Device, status); WdfVerifierDbgBreakPoint(); goto exit; } // // Get the device context // devCtx = HelperGetDeviceContext(Device); // // Allocate memory to store power framework settings // status = RtlULongMult(sizeof(PO_FX_COMPONENT), (PoFxDeviceInfo->ComponentCount - 1), &pofxExtraComponentsSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute buffer size needed for extra " "components. RtlULongMult failed with %!status!.", status); goto exit; } status = RtlULongAdd(sizeof(PO_FX_DEVICE), pofxExtraComponentsSize, &pofxDeviceInfoSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute buffer size needed for power " "framework settings. RtlUlongAdd failed with %!status!.", status); goto exit; } if (0 == pofxDeviceInfoSize) { status = STATUS_INVALID_BUFFER_SIZE; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to set pofxDeviceInfoSize. Failed with %!status!.", status); goto exit; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.ParentObject = Device; // auto-delete when parent deleted status = WdfMemoryCreate(&objectAttributes, NonPagedPool, 0, // PoolTag pofxDeviceInfoSize, &memory, (PVOID*) &poFxDeviceInfo); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to allocate memory for power framework " "settings. WdfMemoryCreate failed with %!status!.", status); goto exit; } devCtx->PoFxDeviceInfo = poFxDeviceInfo; // // Copy power framework settings // status = WdfMemoryCopyFromBuffer(memory, 0, // DestinationOffset PoFxDeviceInfo, pofxDeviceInfoSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to copy power framework settings. " "WdfMemoryCopyFromBuffer failed with %!status!.", status); goto exit; } // // Save the driver layer's callbacks and replace them with our own // devCtx->DriverLayerPoFxCallbacks.ComponentIdleStateCallback = devCtx->PoFxDeviceInfo->ComponentIdleStateCallback; devCtx->DriverLayerPoFxCallbacks.ComponentActiveConditionCallback = devCtx->PoFxDeviceInfo->ComponentActiveConditionCallback; devCtx->DriverLayerPoFxCallbacks.ComponentIdleConditionCallback = devCtx->PoFxDeviceInfo->ComponentIdleConditionCallback; devCtx->DriverLayerPoFxCallbacks.DevicePowerRequiredCallback = devCtx->PoFxDeviceInfo->DevicePowerRequiredCallback; devCtx->DriverLayerPoFxCallbacks.DevicePowerNotRequiredCallback = devCtx->PoFxDeviceInfo->DevicePowerNotRequiredCallback; devCtx->PoFxDeviceInfo->ComponentIdleStateCallback = _PfhComponentIdleStateCallback; devCtx->PoFxDeviceInfo->ComponentActiveConditionCallback = _PfhComponentActiveConditionCallback; devCtx->PoFxDeviceInfo->ComponentIdleConditionCallback = _PfhComponentIdleConditionCallback; devCtx->PoFxDeviceInfo->DevicePowerRequiredCallback = _PfhDevicePowerRequiredCallback; devCtx->PoFxDeviceInfo->DevicePowerNotRequiredCallback = _PfhDevicePowerNotRequiredCallback; // // Save the driver layer's context and replace it with our own // devCtx->DriverLayerPoFxContext = devCtx->PoFxDeviceInfo->DeviceContext; devCtx->PoFxDeviceInfo->DeviceContext = (PVOID) Device; // // Store the idle states for each component // for (i=0; i < devCtx->PoFxDeviceInfo->ComponentCount; i++) { status = RtlULongMult(sizeof(PO_FX_COMPONENT_IDLE_STATE), PoFxDeviceInfo->Components[i].IdleStateCount, &idleStatesSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute buffer size needed for idle " "states for component %d. RtlUlongMult failed with " "%!status!.", i, status); goto exit; } if (0 == idleStatesSize) { status = STATUS_INVALID_BUFFER_SIZE; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to set idleStatesSize. Failed with %!status!.", status); goto exit; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.ParentObject = Device;//auto-delete when parent deleted status = WdfMemoryCreate(&objectAttributes, NonPagedPool, 0, // PoolTag idleStatesSize, &memory, &idleStates); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to allocate memory for idle states for " "component %d. WdfMemoryCreate failed with %!status!.", i, status); goto exit; } status = WdfMemoryCopyFromBuffer( memory, 0, // DestinationOffset devCtx->PoFxDeviceInfo->Components[i].IdleStates, idleStatesSize ); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to copy idle states for component %d. " "WdfMemoryCopyFromBuffer failed with %!status!.", i, status); goto exit; } devCtx->PoFxDeviceInfo->Components[i].IdleStates = idleStates; } // // Allocate memory to store our private, per-component information // status = RtlULongMult(sizeof(POFX_COMPONENT_INFO), devCtx->PoFxDeviceInfo->ComponentCount, &componentInfoSize); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to compute buffer size needed for storing " "private, per-component information. RtlULongMult failed with " "%!status!.", status); goto exit; } if (0 == componentInfoSize) { status = STATUS_INVALID_BUFFER_SIZE; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to set componentInfoSize. Failed with %!status!.", status); goto exit; } WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes); objectAttributes.ParentObject = Device; // auto-delete when parent deleted status = WdfMemoryCreate(&objectAttributes, NonPagedPool, 0, // PoolTag componentInfoSize, &memory, (PVOID*) &componentInfo); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Unable to allocate memory for storing private, per-" "component information. WdfMemoryCreate failed with %!status!.", status); goto exit; } RtlZeroMemory(componentInfo, componentInfoSize); devCtx->ComponentInfo = componentInfo; status = STATUS_SUCCESS; exit: return status; } _IRQL_requires_max_(DISPATCH_LEVEL) VOID PfhInterceptComponentQueueConfig( _In_ WDFOBJECT Initializer, _Inout_ PWDF_IO_QUEUE_CONFIG DriverLayerQueueConfig ) // See comments in WdfPoFx.h { PHELPER_QUEUE_INIT queueInitSettings = NULL; queueInitSettings = GetQueueInitSettings(Initializer); if (queueInitSettings->ComponentQueueConfigIntercepted) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInterceptComponentQueueConfig has already been " "called on initialier %p. It should not be called again before " "the initializer has been used to initialize a KMDF queue " "object.", Initializer); WdfVerifierDbgBreakPoint(); } // // Save the driver layer's callbacks that we are going to replace // queueInitSettings->EvtIoCanceledOnQueue = DriverLayerQueueConfig->EvtIoCanceledOnQueue; // // Replace the driver layer's callbacks with our own // DriverLayerQueueConfig->EvtIoCanceledOnQueue = _PfhEvtRequestCanceledOnComponentQueue; queueInitSettings->ComponentQueueConfigIntercepted = TRUE; return; } _IRQL_requires_max_(DISPATCH_LEVEL) VOID PfhSetComponentForComponentQueue( _In_ WDFOBJECT Initializer, _In_ ULONG Component ) // See comments in WdfPoFx.h { PHELPER_QUEUE_INIT queueInitSettings = NULL; queueInitSettings = GetQueueInitSettings(Initializer); if (queueInitSettings->ComponentSet) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhSetComponentForComponentQueue has already been " "called on initialier %p. It should not be called again before " "the initializer has been used to initialize a KMDF queue " "object.", Initializer); WdfVerifierDbgBreakPoint(); } queueInitSettings->Component = Component; queueInitSettings->ComponentSet = TRUE; return; } _IRQL_requires_max_(DISPATCH_LEVEL) NTSTATUS PfhInitializeComponentQueueSettings( _In_ WDFQUEUE Queue, _In_ WDFOBJECT Initializer ) // See comments in WdfPoFx.h { NTSTATUS status; WDFDEVICE device = NULL; ULONG component; WDF_OBJECT_ATTRIBUTES objectAttributes; PPOFX_DEVICE_CONTEXT devCtx; PPOFX_QUEUE_CONTEXT qCtx; PHELPER_QUEUE_INIT queueInitSettings = NULL; queueInitSettings = GetQueueInitSettings(Initializer); if (IsQueueInitialized(Queue)) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInitializeComponentQueueSettings has already been " "called for WDFQUEUE %p. It should not be called again. " "%!status!.", Queue, status); WdfVerifierDbgBreakPoint(); goto exit; } device = WdfIoQueueGetDevice(Queue); if (FALSE == ArePowerFrameworkSettingsAvailable(device)) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInitializePowerFrameworkSettings has not yet been " "called for WDFDEVICE %p. %!status!.", device, status); WdfVerifierDbgBreakPoint(); goto exit; } if (FALSE == queueInitSettings->ComponentQueueConfigIntercepted) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhInterceptComponentQueueConfig has not yet been " "called for WDFQUEUE %p. %!status!.", Queue, status); WdfVerifierDbgBreakPoint(); goto exit; } if (FALSE == queueInitSettings->ComponentSet) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - PfhSetComponentForComponentQueue has not yet been " "called for WDFQUEUE %p. %!status!.", Queue, status); WdfVerifierDbgBreakPoint(); goto exit; } // // Get the device context // devCtx = HelperGetDeviceContext(device); // // Validate the component number // component = queueInitSettings->Component; if (component >= devCtx->PoFxDeviceInfo->ComponentCount) { status = STATUS_INVALID_PARAMETER; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Component number %d is invalid. Component count is %d." " %!status!.", component, devCtx->PoFxDeviceInfo->ComponentCount, status); WdfVerifierDbgBreakPoint(); goto exit; } // // Allocate our context for this queue // WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, POFX_QUEUE_CONTEXT); status = WdfObjectAllocateContext((WDFOBJECT) Queue, &objectAttributes, (PVOID*) &qCtx); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfObjectAllocateContext failed with %!status!", status); goto exit; } if (NULL != devCtx->ComponentInfo[component].Queue) { status = STATUS_INVALID_DEVICE_REQUEST; Trace(TRACE_LEVEL_ERROR, "%!FUNC! - Component %d has already been associated with WDFQUEUE" " %p. Associating a component with more than one queue is not " "supported. %!status!.", component, devCtx->ComponentInfo[component].Queue, status); WdfVerifierDbgBreakPoint(); goto exit; } // // Copy the queue init settings // qCtx->QueueInitSettings = *queueInitSettings; // // The initializer can now be used to initialize some other object // ResetInitializer(Initializer); // // Save the queue handle in our private component information // devCtx->ComponentInfo[component].Queue = Queue; status = STATUS_SUCCESS; exit: return status; }
Our Services
-
What our customers say about us?
Read our customer testimonials to find out why our clients keep returning for their projects.
View Testimonials