NTSTATUS SingleCompWdmEvtDeviceWdmPostPoFxRegisterDevice( _In_ WDFDEVICE Device, _In_ POHANDLE PoHandle ) /*++ Routine Description: KMDF calls this routine after it has registered with the Power Framework and supplies the registration handle that driver can use directly. Arguments: Device - Handle to the framework device object PoHandle - Handle of registration with Power Framework. Return Value: An NTSTATUS value representing success or failure of the function. --*/ { FDO_DATA *fdoContext = NULL; PAGED_CODE(); // // Get the device context // fdoContext = FdoGetContext(Device); // // Save the POHANDLE // fdoContext->PoHandle = PoHandle; // // Set latency and residency hints so that the power framework chooses lower // powered F-states when we are idle. // The values used here are for illustration purposes only. The driver // should use values that are appropriate for its device. // PoFxSetComponentLatency( PoHandle, 0, // Component (WDF_ABS_TIMEOUT_IN_MS(DEEPEST_FSTATE_LATENCY_IN_MS) + 1) ); PoFxSetComponentResidency( PoHandle, 0, // Component (WDF_ABS_TIMEOUT_IN_SEC(DEEPEST_FSTATE_RESIDENCY_IN_SEC) + 1) ); return STATUS_SUCCESS; }
VOID SingleCompWdmEvtDeviceWdmPrePoFxUnregisterDevice( _In_ WDFDEVICE Device, _In_ POHANDLE PoHandle ) /*++ Routine Description: KMDF calls this routine when it is about to unregister with the Power Framework. After returning from this routine driver must not use the supplied registration handle anymore. Arguments: Device - Handle to the framework device object PoHandle - Handle of registration with Power Framework. Return Value: An NTSTATUS value representing success or failure of the function. --*/ { FDO_DATA *fdoContext = NULL; PAGED_CODE(); UNREFERENCED_PARAMETER(PoHandle); // // Get the device context // fdoContext = FdoGetContext(Device); // // Reset the POHANDLE // fdoContext->PoHandle = NULL; return; }
VOID SingleCompEvtIoDeviceControl( _In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, _In_ size_t OutputBufferLength, _In_ size_t InputBufferLength, _In_ ULONG IoControlCode ) /*++ Routine Description: Callback invoked by WDFQUEUE for a Device Io Control request. Arguments: Queue - Device I/O control queue Request - Device I/O control request OutputBufferLength - Output buffer length for the I/O control InputBufferLength - Input buffer length for the I/O control IoControlCode - I/O control code --*/ { NTSTATUS status; PPOWERFX_READ_COMPONENT_OUTPUT outputBuffer = NULL; WDFDEVICE device = NULL; ULONG componentData; ULONG_PTR information = 0; FDO_DATA *fdoContext = NULL; // // When we complete the request, make sure we don't get the I/O manager to // copy any more data to the client address space than what we write to the // output buffer. The only data that we write to the output buffer is the // component data and the C_ASSERT below ensures that the output buffer does // not have room to contain anything other than that. // C_ASSERT(sizeof(componentData) == sizeof(*outputBuffer)); UNREFERENCED_PARAMETER(OutputBufferLength); UNREFERENCED_PARAMETER(InputBufferLength); // // This is a power-managed queue. So our queue stop/start logic should have // ensured that we are in the active condition when a request is dispatched // from this queue. // device = WdfIoQueueGetDevice(Queue); fdoContext = FdoGetContext(device); if (FALSE == fdoContext->IsActive) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - IOCTL %d was dispatched from WDFQUEUE %p when the " "component was not in an active condition.", IOCTL_POWERFX_READ_COMPONENT, Queue); WdfVerifierDbgBreakPoint(); } // // Validate Ioctl code // if (IOCTL_POWERFX_READ_COMPONENT != IoControlCode) { status = STATUS_NOT_SUPPORTED; Trace(TRACE_LEVEL_ERROR, "%!FUNC! -Unsupported IoControlCode. Expected: %d. Actual: %d." " %!status!.", IOCTL_POWERFX_READ_COMPONENT, IoControlCode, status); goto exit; } // // Get the output buffer // status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*outputBuffer), (PVOID*) &outputBuffer, NULL // Length ); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfRequestRetrieveOutputBuffer failed with %!status!.", status); goto exit; } // // Read the data from the component // componentData = HwSimReadComponent(device); outputBuffer->ComponentData = componentData; information = sizeof(*outputBuffer); status = STATUS_SUCCESS; exit: // // Complete the request // WdfRequestCompleteWithInformation(Request, status, information); return; }
NTSTATUS SingleCompEvtDeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by UMDF in response to AddDevice call from the PnP manager. Arguments: Driver - Handle to the UMDF driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: An NTSTATUS value representing success or failure of the function. --*/ { NTSTATUS status; WDFDEVICE device; WDFQUEUE queue; WDF_IO_QUEUE_CONFIG queueConfig; FDO_DATA *fdoContext = NULL; WDF_OBJECT_ATTRIBUTES objectAttributes; WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; UNREFERENCED_PARAMETER(Driver); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, FDO_DATA); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDeviceD0Entry = SingleCompEvtDeviceD0Entry; pnpCallbacks.EvtDeviceD0Exit = SingleCompEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); status = WdfDeviceCreate(&DeviceInit, &objectAttributes, &device); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceCreate failed with %!status!.", status); goto exit; } fdoContext = FdoGetContext(device); // // Our initial state is active // fdoContext->IsActive = TRUE; // // Create a power-managed queue for IOCTL requests. // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoDeviceControl = SingleCompEvtIoDeviceControl; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests or // forward them to other drivers. This driver completes the requests // directly in the queue's handlers. If the EvtIoStop callback is not // implemented, the framework waits for all driver-owned requests to be // done before moving in the Dx/sleep states or before removing the // device, which is the correct behavior for this type of driver. // If the requests were taking an indeterminate amount of time to complete, // or if the driver forwarded the requests to a lower driver/another stack, // the queue should have an EvtIoStop/EvtIoResume. // __analysis_assume(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &queue); __analysis_assume(queueConfig.EvtIoStop == 0); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfIoQueueCreate for IoDeviceControl failed with %!status!.", status); goto exit; } status = WdfDeviceConfigureRequestDispatching(device, queue, WdfRequestTypeDeviceControl); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceConfigureRequestDispatching for " "WdfRequestTypeDeviceControl failed with %!status!.", status); goto exit; } status = AssignS0IdleSettings(device); if (!NT_SUCCESS(status)) { goto exit; } // // Create a device interface so that applications can open a handle to this // device. // status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_POWERFX, NULL /* ReferenceString */); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceCreateDeviceInterface failed with %!status!.", status); goto exit; } // // Initialize the hardware simulator // status = HwSimInitialize(device); if (FALSE == NT_SUCCESS(status)) { goto exit; } exit: return status; }
VOID SingleCompWdmIdleStateCallback( _In_ PVOID Context, _In_ ULONG Component, _In_ ULONG State ) /*++ Routine Description: This callback is invoked by Power Framework to notify driver about any F-state transition. Arguments: Context - Context supplied to Power Framework. KMDF supplies WDFDEVICE as the context while registering with Power Framework. Hence Context contains the KMDF device object. Component - Component for which F state transition is requested. Since we have only one component this value is always 0. Return Value: BOOLEAN indicating whether Fx transition has completed. --*/ { WDFDEVICE device = NULL; FDO_DATA *fdoContext = NULL; BOOLEAN transitionComplete = TRUE; // // We have only component 0 // if (0 != Component) { Trace(TRACE_LEVEL_ERROR,"%!FUNC! - Unexpected component %d",Component); ASSERT(FALSE); } // // Get the device // device = (WDFDEVICE) Context; // // Get the device context // fdoContext = FdoGetContext(device); // // Note the new F-state // switch (State) { case 0: { transitionComplete = F0Entry(device); } break; // // PEP may make us go to any of the F-states directly, hence we execute // F0Exit code for all of the Fx states. // // Transition to any Fx state happens from F0 (and not another // Fx state) // default: { ASSERT(State < FSTATE_COUNT); transitionComplete = F0Exit(device, State); } break; } if (transitionComplete) { PoFxCompleteIdleState(fdoContext->PoHandle, 0 /* Component */); } }
NTSTATUS SingleCompEvtDeviceAdd( _In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit ) /*++ Routine Description: EvtDeviceAdd is called by the KMDF in response to AddDevice call from the PnP manager. Arguments: Driver - Handle to the KMDF driver object created in DriverEntry DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. Return Value: An NTSTATUS value representing success or failure of the function. --*/ { NTSTATUS status; WDFDEVICE device; WDF_IO_QUEUE_CONFIG queueConfig; FDO_DATA *fdoContext = NULL; ULONG queueIndex = 0; WDF_OBJECT_ATTRIBUTES objectAttributes; WDF_PNPPOWER_EVENT_CALLBACKS pnpCallbacks; PAGED_CODE(); UNREFERENCED_PARAMETER(Driver); WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&objectAttributes, FDO_DATA); WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpCallbacks); pnpCallbacks.EvtDeviceD0Entry = SingleCompEvtDeviceD0Entry; pnpCallbacks.EvtDeviceD0Exit = SingleCompEvtDeviceD0Exit; WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpCallbacks); status = WdfDeviceCreate(&DeviceInit, &objectAttributes, &device); if (!NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceCreate failed with %!status!.", status); goto exit; } fdoContext = FdoGetContext(device); // // Our initial state is active // fdoContext->IsActive = TRUE; // // Create three power-managed queues, one each for read, write and IOCTL // requests. The handles to these power-managed queues are stored in an // array in the device object context space. When the component becomes idle // we need to stop our power-managed queues. When the component becomes // active we need to start them. In those situations, we go through this // array of power-managed queues and stop or start each queue as // appropriate. Handles to non-power-managed queues should not be stored in // this array. // WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoDeviceControl = SingleCompEvtIoDeviceControl; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests or // forward them to other drivers. This driver completes the requests // directly in the queue's handlers. If the EvtIoStop callback is not // implemented, the framework waits for all driver-owned requests to be // done before moving in the Dx/sleep states or before removing the // device, which is the correct behavior for this type of driver. // If the requests were taking an indeterminate amount of time to complete, // or if the driver forwarded the requests to a lower driver/another stack, // the queue should have an EvtIoStop/EvtIoResume. // __analysis_assume(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &(fdoContext->Queues[queueIndex])); __analysis_assume(queueConfig.EvtIoStop == 0); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfIoQueueCreate for IoDeviceControl failed with %!status!.", status); goto exit; } status = WdfDeviceConfigureRequestDispatching(device, fdoContext->Queues[queueIndex], WdfRequestTypeDeviceControl); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceConfigureRequestDispatching for " "WdfRequestTypeDeviceControl failed with %!status!.", status); goto exit; } ++queueIndex; WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoRead = SingleCompEvtIoRead; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests or // forward them to other drivers. This driver completes the requests // directly in the queue's handlers. If the EvtIoStop callback is not // implemented, the framework waits for all driver-owned requests to be // done before moving in the Dx/sleep states or before removing the // device, which is the correct behavior for this type of driver. // If the requests were taking an indeterminate amount of time to complete, // or if the driver forwarded the requests to a lower driver/another stack, // the queue should have an EvtIoStop/EvtIoResume. // __analysis_assume(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &(fdoContext->Queues[queueIndex])); __analysis_assume(queueConfig.EvtIoStop == 0); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfIoQueueCreate for IoRead failed with %!status!.", status); goto exit; } status = WdfDeviceConfigureRequestDispatching(device, fdoContext->Queues[queueIndex], WdfRequestTypeRead); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceConfigureRequestDispatching for " "WdfRequestTypeRead failed with %!status!.", status); goto exit; } ++queueIndex; WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); queueConfig.EvtIoWrite = SingleCompEvtIoWrite; // // By default, Static Driver Verifier (SDV) displays a warning if it // doesn't find the EvtIoStop callback on a power-managed queue. // The 'assume' below causes SDV to suppress this warning. If the driver // has not explicitly set PowerManaged to WdfFalse, the framework creates // power-managed queues when the device is not a filter driver. Normally // the EvtIoStop is required for power-managed queues, but for this driver // it is not needed b/c the driver doesn't hold on to the requests or // forward them to other drivers. This driver completes the requests // directly in the queue's handlers. If the EvtIoStop callback is not // implemented, the framework waits for all driver-owned requests to be // done before moving in the Dx/sleep states or before removing the // device, which is the correct behavior for this type of driver. // If the requests were taking an indeterminate amount of time to complete, // or if the driver forwarded the requests to a lower driver/another stack, // the queue should have an EvtIoStop/EvtIoResume. // __analysis_assume(queueConfig.EvtIoStop != 0); status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, &(fdoContext->Queues[queueIndex])); __analysis_assume(queueConfig.EvtIoStop == 0); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfIoQueueCreate for IoWrite failed with %!status!.", status); goto exit; } status = WdfDeviceConfigureRequestDispatching(device, fdoContext->Queues[queueIndex], WdfRequestTypeWrite); if (FALSE == NT_SUCCESS (status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceConfigureRequestDispatching for " "WdfRequestTypeWrite failed with %!status!.", status); goto exit; } ++queueIndex; ASSERT(queueIndex == QUEUE_COUNT); status = AssignS0IdleSettings(device); if (!NT_SUCCESS(status)) { goto exit; } // // If you need to talk to hardware to figure out what F-states are // applicable this can be done in EvtSelfManagedIoInit // (but no later than that). EvtSelfManagedIoInit gets invoked after // EvtPrepareHardware so you'd have chance to initialize your hardware. // status = AssignPowerFrameworkSettings(device); if (!NT_SUCCESS(status)) { goto exit; } // // Create a device interface so that applications can open a handle to this // device. // status = WdfDeviceCreateDeviceInterface(device, &GUID_DEVINTERFACE_POWERFX, NULL /* ReferenceString */); if (FALSE == NT_SUCCESS(status)) { Trace(TRACE_LEVEL_ERROR, "%!FUNC! - WdfDeviceCreateDeviceInterface failed with %!status!.", status); goto exit; } // // Initialize the hardware simulator // status = HwSimInitialize(device); if (FALSE == NT_SUCCESS(status)) { goto exit; } exit: return status; }
VOID SingleCompWdmIdleConditionCallback( _In_ PVOID Context, _In_ ULONG Component ) /*++ Routine Description: This callback is invoked by Power Framework to notify driver that one of its components has become idle. Arguments: Context - Context that we supplied when calling WdfDeviceWdmAssignPowerFrameworkSettings. Component - Component that have become idle. Since we have only one component this value is always 0. Return Value: None --*/ { WDFDEVICE device; FDO_DATA *fdoContext = NULL; UCHAR i = 0; // // We have only component 0 // if (0 != Component) { Trace(TRACE_LEVEL_ERROR,"%!FUNC! - Unexpected component %d",Component); ASSERT(FALSE); } // // Get the device // device = (WDFDEVICE) Context; // // Get the device context // fdoContext = FdoGetContext(device); // // Initialize the count of queues to be stopped. // // Until we complete this idle transition there cannot be other idle // transitions, which is only where we use this count. Thus nothing races // with it. // // If you have other code that stops/starts queues, it may be simpler // to queue a work-item from this callback which stops all the queues // synchronously. Synchronous queue stop cannot be done from here since // this callback may be called at DISPATCH_LEVEL. // fdoContext->QueueStopCount = QUEUE_COUNT; // // Stop power-managed queues // for (i = 0; i < QUEUE_COUNT; i++) { #pragma warning(suppress: 6387) // passing NULL Context parameter is safe in this instance WdfIoQueueStop(fdoContext->Queues[i], SingleCompEvtQueueStopComplete, NULL /* Context */); } // // The idle transition will complete asynchronously. We'll call // PoFxCompleteIdleCondition to complete it when all the queues have been // stopped. // // IMPORTANT NOTE // ============== // Given that the idle transition does not complete until all the power- // managed queues have been stopped, it is extremely important for the // driver to ensure that stopping of power-managed queues is reasonably // quick. If the driver fails to ensure this, the power framework can remain // stuck in the idle transition for a long time, which could hamper its // ability to put the component in a low-power F-state. This could // negatively impact any power savings that can be gained via component // power management. // // In order to ensure that idle transitions can complete quickly, the driver // should quickly process any requests that are dispatched to it via a // power-managed queue. If the driver forwards a request (that was received // via a power-managed queue) to an I/O target that might keep the request // pending for a long time, then the driver should cancel the request when // the component idle condition callback is invoked. This is because the // power-managed queue cannot be stopped while the request is pending in the // I/O target. // return; }
VOID SingleCompWdmActiveConditionCallback( _In_ PVOID Context, _In_ ULONG Component ) /*++ Routine Description: This callback is invoked by Power Framework to notify driver that one of its components has become active. Arguments: Context - Context that we supplied when calling WdfDeviceWdmAssignPowerFrameworkSettings. Component - Component that have become active. Since we have only one component this value is always 0. Return Value: None --*/ { WDFDEVICE device; FDO_DATA *fdoContext = NULL; UCHAR i = 0; // // We have only component 0 // if (0 != Component) { Trace(TRACE_LEVEL_ERROR,"%!FUNC! - Unexpected component %d",Component); ASSERT(FALSE); } // // Get the device // device = (WDFDEVICE) Context; // // Get the device context // fdoContext = FdoGetContext(device); // // Mark ourselves as active // fdoContext->IsActive = TRUE; // // Start power-managed queues // for (i = 0; i < QUEUE_COUNT; i++) { WdfIoQueueStart(fdoContext->Queues[i]); } return; }