summaryrefslogtreecommitdiff
path: root/powerlimit/plclient
diff options
context:
space:
mode:
authorJakob Lichtenberg (170957) <[email protected]>2024-06-28 11:39:18 -0700
committerJakob Lichtenberg (170957) <[email protected]>2024-06-28 11:39:18 -0700
commit1971c7bfc27f90764155ef96df64db4b4cfb93df (patch)
tree9193a001a463219d073ce9ea5f1e3408a0ba3d56 /powerlimit/plclient
parent3c4d58d08b74cf2925ec632ed1fe81e0d81df8a1 (diff)
parentb3af8c8f9bd508f54075da2f2516b31d05cd52c8 (diff)
Merge branch 'main' into user/jakobl/nuget_packagereference_instead_of_packages_configuser/jakobl/nuget_packagereference_instead_of_packages_config
Diffstat (limited to 'powerlimit/plclient')
-rw-r--r--powerlimit/plclient/README.md17
-rw-r--r--powerlimit/plclient/plclient.asl10
-rw-r--r--powerlimit/plclient/plclient.c451
-rw-r--r--powerlimit/plclient/plclient.h95
-rw-r--r--powerlimit/plclient/plclient.inf83
-rw-r--r--powerlimit/plclient/plclient.rc11
-rw-r--r--powerlimit/plclient/plclient.sln35
-rw-r--r--powerlimit/plclient/plclient.vcxproj123
-rw-r--r--powerlimit/plclient/plclient.vcxproj.filters47
-rw-r--r--powerlimit/plclient/powerlimitclient_drvinterface.h58
-rw-r--r--powerlimit/plclient/wdf.c477
11 files changed, 1407 insertions, 0 deletions
diff --git a/powerlimit/plclient/README.md b/powerlimit/plclient/README.md
new file mode 100644
index 00000000..8ee71011
--- /dev/null
+++ b/powerlimit/plclient/README.md
@@ -0,0 +1,17 @@
+---
+page_type: sample
+description: "Demonstrates a simulated power limit device."
+languages:
+- cpp
+products:
+- windows
+- windows-wdk
+---
+
+# plclient - Simulated Power Limit Client Driver
+
+This sample is a driver for a simulated power limit client device.
+
+## Universal Windows Driver Compliant
+
+The plclient sample provides the source code for a power limit device that supports power limit management by the operating system.
diff --git a/powerlimit/plclient/plclient.asl b/powerlimit/plclient/plclient.asl
new file mode 100644
index 00000000..ce0458df
--- /dev/null
+++ b/powerlimit/plclient/plclient.asl
@@ -0,0 +1,10 @@
+DefinitionBlock ("ACPITABL.DAT", "SSDT", 0x02, "MSFT", "simulatr", 0x1) {
+ Device (\_SB.SOC0) {
+ Name (_HID, "PLCL0001")
+ Name (_UID, 1)
+ }
+ Device (\_SB.GPU1) {
+ Name (_HID, "PLCL0001")
+ Name (_UID, 2)
+ }
+} \ No newline at end of file
diff --git a/powerlimit/plclient/plclient.c b/powerlimit/plclient/plclient.c
new file mode 100644
index 00000000..41676590
--- /dev/null
+++ b/powerlimit/plclient/plclient.c
@@ -0,0 +1,451 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ plclient.c
+
+Abstract:
+
+ This module implements power limit related operations for the simulated power
+ limit client driver.
+
+--*/
+
+//-------------------------------------------------------------------- Includes
+
+#include "plclient.h"
+
+//--------------------------------------------------------------------- Pragmas
+
+#pragma alloc_text(PAGE, InitPowerLimitValues)
+#pragma alloc_text(PAGE, CleanupPowerLimitValues)
+#pragma alloc_text(PAGE, PLCQueryAttributes)
+#pragma alloc_text(PAGE, PLCSetLimits)
+#pragma alloc_text(PAGE, PLCQueryLimitValues)
+
+//------------------------------------------------------------------- Functions
+
+_Use_decl_annotations_
+NTSTATUS
+InitPowerLimitValues (
+ PFDO_DATA DevExt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes simulated limit values and attributes for the supplied
+ device extension.
+
+Parameters Description:
+
+ DevExt - Supplies a pointer to the device extension to be udpated.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ ULONG DomainId;
+ ULONG Index;
+ PPOWER_LIMIT_ATTRIBUTES LimitAttributes;
+ ULONG LimitCount;
+ PPOWER_LIMIT_VALUE LimitValues;
+ NTSTATUS Status;
+ ULONG Type;
+
+ PAGED_CODE();
+
+ LimitAttributes = NULL;
+ LimitValues = NULL;
+ LimitCount = PLCLIENT_DEFAULT_DOMAIN_COUNT * PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN;
+ LimitAttributes = ExAllocatePool2(POOL_FLAG_PAGED,
+ LimitCount * sizeof(POWER_LIMIT_ATTRIBUTES),
+ PLCLIENT_TAG);
+
+ LimitValues = ExAllocatePool2(POOL_FLAG_PAGED,
+ LimitCount * sizeof(POWER_LIMIT_VALUE),
+ PLCLIENT_TAG);
+
+ if ((LimitAttributes == NULL) || (LimitValues == NULL)) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto InitPowerLimitValuesEnd;
+ }
+
+ for (DomainId = 0; DomainId < PLCLIENT_DEFAULT_DOMAIN_COUNT; DomainId += 1) {
+ for (Type = 0; Type < PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN; Type += 1) {
+ Index = (PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN * DomainId) + Type;
+
+ //
+ // Set init attributes.
+ //
+
+ LimitAttributes[Index].Type = Type;
+ LimitAttributes[Index].DomainId = DomainId;
+ LimitAttributes[Index].MaxValue = PLCLIENT_DEFAULT_MAX_VALUE;
+ LimitAttributes[Index].MinValue = PLCLIENT_DEFAULT_MIN_VALUE;
+ LimitAttributes[Index].DefaultACValue = POWER_LIMIT_VALUE_NO_CONTROL;
+ LimitAttributes[Index].DefaultDCValue = POWER_LIMIT_VALUE_NO_CONTROL;
+
+ if (Type == PowerLimitContinuous) {
+ LimitAttributes[Index].MinTimeParameter = PLCLIENT_DEFAULT_MIN_VALUE;
+ LimitAttributes[Index].MaxTimeParameter = PLCLIENT_DEFAULT_MAX_VALUE;
+ LimitAttributes[Index].Flags.SupportTimeParameter = 1;
+ }
+
+ //
+ // Set init values.
+ //
+
+ LimitValues[Index].Type = Type;
+ LimitValues[Index].DomainId = DomainId;
+ LimitValues[Index].TargetValue = POWER_LIMIT_VALUE_NO_CONTROL;
+ LimitValues[Index].TimeParameter = POWER_LIMIT_VALUE_NO_CONTROL;
+ }
+ }
+
+ DevExt->LimitCount = LimitCount;
+ DevExt->LimitAttributes = LimitAttributes;
+ DevExt->LimitValues = LimitValues;
+ LimitAttributes = NULL;
+ LimitValues = NULL;
+ Status = STATUS_SUCCESS;
+
+InitPowerLimitValuesEnd:
+ if (LimitAttributes != NULL) {
+ ExFreePoolWithTag(LimitAttributes, PLCLIENT_TAG);
+ LimitAttributes = NULL;
+ }
+
+ if (LimitValues != NULL) {
+ ExFreePoolWithTag(LimitValues, PLCLIENT_TAG);
+ LimitValues = NULL;
+ }
+
+ return Status;
+}
+
+_Use_decl_annotations_
+VOID
+CleanupPowerLimitValues (
+ PFDO_DATA DevExt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cleans up simulated limit values and attributes for the supplied
+ device extension.
+
+Parameters Description:
+
+ DevExt - Supplies a pointer to the device extension to be udpated.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ PAGED_CODE();
+
+ if (DevExt == NULL) {
+ goto CleanupPowerLimitValuesEnd;
+ }
+
+ if (DevExt->LimitAttributes != NULL) {
+ ExFreePoolWithTag(DevExt->LimitAttributes, PLCLIENT_TAG);
+ DevExt->LimitAttributes = NULL;
+ }
+
+ if (DevExt->LimitValues != NULL) {
+ ExFreePoolWithTag(DevExt->LimitValues, PLCLIENT_TAG);
+ DevExt->LimitValues = NULL;
+ }
+
+ DevExt->LimitCount = 0;
+
+CleanupPowerLimitValuesEnd:
+ return;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+PLCQueryAttributes (
+ PVOID Context,
+ ULONG BufferCount,
+ PVOID Buffer,
+ PULONG AttributeCount
+ )
+
+/*++
+
+Routine Description:
+
+ This is the callback function which returns power limit attributes.
+
+Parameters Description:
+
+ Context - Supplies a pointer to the device handle.
+
+ BufferCount - Supplies count of Buffer entries.
+
+ Buffer - Supplies a pointer to the buffer to store power limit attributes.
+
+ AttributeCount - Supplies a pointer to save the number of attributes.
+
+Return Value:
+
+ Returns STATUS_BUFFER_TOO_SMALL if the supplied buffer is not big enough, otherwise
+ other NTSTATUS values.
+
+--*/
+
+{
+
+ PFDO_DATA DevExt;
+ WDFDEVICE DeviceHandle;
+ BOOLEAN ReleaseLock;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ ReleaseLock = FALSE;
+ if (Context == NULL) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto QueryAttributesEnd;
+ }
+
+ DeviceHandle = (WDFDEVICE)Context;
+ DevExt = GetDeviceExtension(DeviceHandle);
+ AcquireGlobalMutex();
+ ReleaseLock = TRUE;
+ if (BufferCount < DevExt->LimitCount) {
+ if (AttributeCount != NULL) {
+ *AttributeCount = DevExt->LimitCount;
+ }
+
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto QueryAttributesEnd;
+ }
+
+ RtlCopyMemory(Buffer,
+ DevExt->LimitAttributes,
+ sizeof(POWER_LIMIT_ATTRIBUTES) * DevExt->LimitCount);
+
+ Status = STATUS_SUCCESS;
+
+QueryAttributesEnd:
+ if (ReleaseLock != FALSE) {
+ ReleaseGlobalMutex();
+ }
+
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+PLCSetLimits (
+ PVOID Context,
+ ULONG ValueCount,
+ PVOID Values
+ )
+
+/*++
+
+Routine Description:
+
+ This is the callback function which takes requests to set power limit values.
+
+Parameters Description:
+
+ Context - Supplies a pointer to the device handle.
+
+ ValueCount - Supplies count of Value entries.
+
+ Values - Supplies a pointer to the buffer contains values to be updated.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ PPOWER_LIMIT_ATTRIBUTES Attributes;
+ PFDO_DATA DevExt;
+ WDFDEVICE DeviceHandle;
+ ULONG Index;
+ BOOLEAN ReleaseLock;
+ NTSTATUS Status;
+ BOOLEAN Valid;
+ PPOWER_LIMIT_VALUE ValueBuffer;
+ ULONG ValueIndex;
+
+ PAGED_CODE();
+
+ ReleaseLock = FALSE;
+ if ((Context == NULL) || (ValueCount == 0) || (Values == NULL)) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto SetLimitsEnd;
+ }
+
+ ValueBuffer = (PPOWER_LIMIT_VALUE)Values;
+ DeviceHandle = (WDFDEVICE)Context;
+ DevExt = GetDeviceExtension(DeviceHandle);
+ AcquireGlobalMutex();
+ ReleaseLock = TRUE;
+
+ //
+ // Sanity check on proposed values before update.
+ //
+
+ if (DevExt->LimitCount < ValueCount) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto SetLimitsEnd;
+ }
+
+ //
+ // N.B. On a production driver, those values should be used as power limit targets
+ // for the hardware.
+ //
+
+ for (Index = 0; Index < ValueCount; Index += 1) {
+ Valid = FALSE;
+ for (ValueIndex = 0; ValueIndex < DevExt->LimitCount; ValueIndex += 1) {
+ if ((ValueBuffer[Index].Type != DevExt->LimitAttributes[ValueIndex].Type) ||
+ (ValueBuffer[Index].DomainId != DevExt->LimitAttributes[ValueIndex].DomainId)) {
+
+ continue;
+ }
+
+ Attributes = &DevExt->LimitAttributes[ValueIndex];
+ if ((ValueBuffer[Index].TargetValue == POWER_LIMIT_VALUE_NO_CONTROL) ||
+ ((ValueBuffer[Index].TargetValue >= Attributes->MinValue) &&
+ (ValueBuffer[Index].TargetValue <= Attributes->MaxValue))) {
+
+ Valid = TRUE;
+ }
+
+ if (ValueBuffer[Index].TimeParameter != POWER_LIMIT_VALUE_NO_CONTROL) {
+ if ((Attributes->Flags.SupportTimeParameter != 0) &&
+ (ValueBuffer[Index].TimeParameter >= Attributes->MinTimeParameter) &&
+ (ValueBuffer[Index].TimeParameter <= Attributes->MaxTimeParameter)) {
+
+ Valid = TRUE;
+ }
+ }
+
+ break;
+ }
+
+ //
+ // N.B. Bail out if this proposed value is not valid.
+ //
+
+ if (Valid == FALSE) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto SetLimitsEnd;
+ }
+ }
+
+ for (Index = 0; Index < ValueCount; Index += 1) {
+ for (ValueIndex = 0; ValueIndex < DevExt->LimitCount; ValueIndex += 1) {
+ if ((ValueBuffer[Index].Type != DevExt->LimitValues[ValueIndex].Type) ||
+ (ValueBuffer[Index].DomainId != DevExt->LimitValues[ValueIndex].DomainId)) {
+
+ continue;
+ }
+
+ DevExt->LimitValues[ValueIndex].TargetValue = ValueBuffer[Index].TargetValue;
+ DevExt->LimitValues[ValueIndex].TimeParameter = ValueBuffer[Index].TimeParameter;
+ break;
+ }
+ }
+
+ Status = STATUS_SUCCESS;
+
+SetLimitsEnd:
+ if (ReleaseLock != FALSE) {
+ ReleaseGlobalMutex();
+ }
+
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+PLCQueryLimitValues (
+ PVOID Context,
+ ULONG ValueCount,
+ PVOID Values
+ )
+
+/*++
+
+Routine Description:
+
+ This is the callback function which returns power limit values.
+
+Parameters Description:
+
+ Context - Supplies a pointer to the device handle.
+
+ ValueCount - Supplies count of Value entries.
+
+ Values - Supplies a pointer to the buffer to store power limit values.
+
+Return Value:
+
+ Returns STATUS_BUFFER_TOO_SMALL if the supplied buffer is not big enough, otherwise
+ other NTSTATUS values.
+
+--*/
+
+{
+
+ PFDO_DATA DevExt;
+ WDFDEVICE DeviceHandle;
+ BOOLEAN ReleaseLock;
+ NTSTATUS Status;
+
+ PAGED_CODE();
+
+ ReleaseLock = FALSE;
+ if ((Context == NULL) || (ValueCount == 0) || (Values == NULL)){
+ Status = STATUS_INVALID_PARAMETER;
+ goto QueryLimitsEnd;
+ }
+
+ DeviceHandle = (WDFDEVICE)Context;
+ DevExt = GetDeviceExtension(DeviceHandle);
+ AcquireGlobalMutex();
+ ReleaseLock = TRUE;
+ if (ValueCount < DevExt->LimitCount) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto QueryLimitsEnd;
+ }
+
+ RtlCopyMemory(Values,
+ DevExt->LimitValues,
+ sizeof(POWER_LIMIT_VALUE) * DevExt->LimitCount);
+
+ Status = STATUS_SUCCESS;
+
+QueryLimitsEnd:
+ if (ReleaseLock != FALSE) {
+ ReleaseGlobalMutex();
+ }
+
+ return Status;
+}
diff --git a/powerlimit/plclient/plclient.h b/powerlimit/plclient/plclient.h
new file mode 100644
index 00000000..6e9a7f3f
--- /dev/null
+++ b/powerlimit/plclient/plclient.h
@@ -0,0 +1,95 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ plclient.h
+
+Abstract:
+
+ This is the header file for the simulated power limit client driver.
+
+--*/
+
+#pragma once
+
+//-------------------------------------------------------------------- Includes
+
+#include <ntddk.h>
+#include <wdf.h>
+#include <ntstrsafe.h>
+#include <initguid.h>
+#include <wdmguid.h>
+#include <poclass.h>
+#include <limits.h>
+#include "powerlimitclient_drvinterface.h"
+
+//----------------------------------------------------------------------- Types
+
+typedef struct {
+ ULONG LimitCount;
+ PPOWER_LIMIT_ATTRIBUTES LimitAttributes;
+ PPOWER_LIMIT_VALUE LimitValues;
+} FDO_DATA, *PFDO_DATA;
+
+WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FDO_DATA, GetDeviceExtension);
+
+//----------------------------------------------------------------------- Debug
+
+#define DebugPrint(l, m, ...) DbgPrintEx(DPFLTR_POWER_ID, l, "[plclient]: "m, __VA_ARGS__)
+#define DebugEnter() DebugPrint(PLCLIENT_PRINT_TRACE, "Entering %s", __FUNCTION__)
+#define DebugExit() DebugPrint(PLCLIENT_PRINT_TRACE, "Leaving " __FUNCTION__ "\n")
+#define DebugExitStatus(_status_) DebugPrint(PLCLIENT_PRINT_TRACE, "Leaving " __FUNCTION__ ": Status=0x%08x\n", _status_)
+
+#define PLCLIENT_PRINT_ERROR DPFLTR_ERROR_LEVEL
+#define PLCLIENT_PRINT_TRACE DPFLTR_TRACE_LEVEL
+#define PLCLIENT_PRINT_INFO DPFLTR_INFO_LEVEL
+
+#define PLCLIENT_TAG 'PLCL'
+
+//--------------------------------------------------------------------- Globals
+
+extern WDFWAITLOCK GlobalMutex;
+
+//------------------------------------------------------------------ Prototypes
+
+FORCEINLINE
+VOID
+AcquireGlobalMutex (
+ VOID
+ )
+{
+
+ WdfWaitLockAcquire(GlobalMutex, 0);
+ return;
+}
+
+FORCEINLINE
+VOID
+ReleaseGlobalMutex (
+ VOID
+ )
+{
+
+ WdfWaitLockRelease(GlobalMutex);
+ return;
+}
+
+//
+// plclient.c
+//
+
+QUERY_POWER_LIMIT_ATTRIBUTES PLCQueryAttributes;
+SET_POWER_LIMIT PLCSetLimits;
+QUERY_POWER_LIMIT PLCQueryLimitValues;
+
+NTSTATUS
+InitPowerLimitValues (
+ _Inout_ PFDO_DATA DevExt
+ );
+
+VOID
+CleanupPowerLimitValues (
+ _Inout_opt_ PFDO_DATA DevExt
+ );
diff --git a/powerlimit/plclient/plclient.inf b/powerlimit/plclient/plclient.inf
new file mode 100644
index 00000000..136b6761
--- /dev/null
+++ b/powerlimit/plclient/plclient.inf
@@ -0,0 +1,83 @@
+;/*++
+;
+;Copyright (c) Microsoft Corporation All rights Reserved
+;
+;Module Name:
+;
+; plclient.inf
+;
+;Abstract:
+;
+; INF file for installing simulate power limit client driver.
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=System
+ClassGuid={4D36E97D-E325-11CE-BFC1-08002BE10318}
+Provider=%ProviderString%
+DriverVer=08/29/2023, 1.00.0000
+CatalogFile=plclient.cat
+PnpLockdown=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+[SourceDisksNames]
+1 = %DiskId1%,,,""
+
+[SourceDisksFiles]
+plclient.sys = 1,,
+
+;********************************************
+; Simulated Power Limit Client Install Section
+;********************************************
+
+[Manufacturer]
+%StdMfg%=Standard,NTamd64
+%StdMfg%=Standard,NTarm64
+
+[Standard.NTamd64]
+%PlCl.DeviceDesc% = PlCl_Device, ACPI\PLCL0001
+%PlCl.DeviceDesc% = PlCl_Device, root\PLCL0001
+
+[Standard.NTarm64]
+%PlCl.DeviceDesc% = PlCl_Device, ACPI\PLCL0001
+%PlCl.DeviceDesc% = PlCl_Device, root\PLCL0001
+
+[PlCl_Device.NT]
+CopyFiles=PlCl_Device_Drivers
+
+[PlCl_Device.NT.HW]
+AddReg=PlCl_Device.NT.AddReg
+
+[PlCl_Device.NT.AddReg]
+HKR,,DeviceCharacteristics,0x10001,0x0100 ; Use same security checks on relative opens
+HKR,,Security,,"D:P(A;;GA;;;BA)(A;;GA;;;SY)" ; Allow generic-all access to Built-in administrators and Local system
+
+[PlCl_Device_Drivers]
+plclient.sys
+
+;-------------- Service installation
+
+[PlCl_Device.NT.Services]
+AddService = plclient,%SPSVCINST_ASSOCSERVICE%,PlCl_Service_Inst
+
+; -------------- plclient driver install sections
+
+[PlCl_Service_Inst]
+DisplayName = %PlCl.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\plclient.sys
+LoadOrderGroup = Extended Base
+
+[Strings]
+SPSVCINST_ASSOCSERVICE= 0x00000002
+ProviderString = "TODO-Set-Provider"
+StdMfg = "(Standard system devices)"
+DiskId1 = "Simulate Power Limit Client Installation Disk #1"
+PlCl.DeviceDesc = "Simulate Power Limit Client Device"
+PlCl.SVCDESC = "Simulate Power Limit Client Driver"
diff --git a/powerlimit/plclient/plclient.rc b/powerlimit/plclient/plclient.rc
new file mode 100644
index 00000000..326c61c2
--- /dev/null
+++ b/powerlimit/plclient/plclient.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+#define VER_FILEDESCRIPTION_STR "Simulate Power Limit Client Driver"
+#define VER_INTERNALNAME_STR "plclient.sys"
+#define VER_ORIGINALFILENAME_STR "plclient.sys"
+
+#include "common.ver"
diff --git a/powerlimit/plclient/plclient.sln b/powerlimit/plclient/plclient.sln
new file mode 100644
index 00000000..0401b799
--- /dev/null
+++ b/powerlimit/plclient/plclient.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34701.34
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plclient", "plclient.vcxproj", "{D6B30052-9124-44DB-A421-4DEE110B91E2}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM64 = Debug|ARM64
+ Debug|x64 = Debug|x64
+ Release|ARM64 = Release|ARM64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|ARM64.Build.0 = Debug|ARM64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|ARM64.Deploy.0 = Debug|ARM64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|x64.ActiveCfg = Debug|x64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|x64.Build.0 = Debug|x64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Debug|x64.Deploy.0 = Debug|x64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|ARM64.ActiveCfg = Release|ARM64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|ARM64.Build.0 = Release|ARM64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|ARM64.Deploy.0 = Release|ARM64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|x64.ActiveCfg = Release|x64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|x64.Build.0 = Release|x64
+ {D6B30052-9124-44DB-A421-4DEE110B91E2}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {810BCAEA-5B6F-43EC-AF83-6B849DF63425}
+ EndGlobalSection
+EndGlobal
diff --git a/powerlimit/plclient/plclient.vcxproj b/powerlimit/plclient/plclient.vcxproj
new file mode 100644
index 00000000..b1ecc40d
--- /dev/null
+++ b/powerlimit/plclient/plclient.vcxproj
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{D6B30052-9124-44DB-A421-4DEE110B91E2}</ProjectGuid>
+ <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
+ <Configuration>Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">x64</Platform>
+ <RootNamespace>plclient</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <DriverSign>
+ <FileDigestAlgorithm>sha256</FileDigestAlgorithm>
+ </DriverSign>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <Inf Include="plclient.inf" />
+ </ItemGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="plclient.h" />
+ <ClInclude Include="powerlimitclient_drvinterface.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="plclient.c" />
+ <ClCompile Include="wdf.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="plclient.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/powerlimit/plclient/plclient.vcxproj.filters b/powerlimit/plclient/plclient.vcxproj.filters
new file mode 100644
index 00000000..391468bc
--- /dev/null
+++ b/powerlimit/plclient/plclient.vcxproj.filters
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Driver Files">
+ <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="plclient.inf">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="plclient.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="powerlimitclient_drvinterface.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="plclient.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="wdf.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="plclient.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/powerlimit/plclient/powerlimitclient_drvinterface.h b/powerlimit/plclient/powerlimitclient_drvinterface.h
new file mode 100644
index 00000000..d4c71bda
--- /dev/null
+++ b/powerlimit/plclient/powerlimitclient_drvinterface.h
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ powerlimitclient_drvinterface.h
+
+Abstract:
+
+ This module contains the interfaces used to communicate with the simulate
+ power limit client driver stack.
+
+--*/
+
+//--------------------------------------------------------------------- Pragmas
+
+#pragma once
+
+//--------------------------------------------------------------------- Defines
+
+//
+// IOCTLs to control the client driver
+//
+
+#define POWERLIMITCLIENT_IOCTL(_index_) \
+ CTL_CODE(FILE_DEVICE_UNKNOWN, _index_, METHOD_BUFFERED, FILE_WRITE_DATA)
+
+//
+// IOCTL_POWERLIMIT_CLIENT_QUERY_LIMIT_COUNT
+// - Output: ULONG, number of supported power limit parameters.
+//
+
+#define IOCTL_POWERLIMIT_CLIENT_QUERY_LIMIT_COUNT POWERLIMITCLIENT_IOCTL(0x800)
+
+//
+// IOCTL_POWERLIMIT_CLIENT_QUERY_ATTRIBUTES
+// - Output: POWER_LIMIT_ATTRIBUTES[], attributes of supported power limit parameters.
+//
+
+#define IOCTL_POWERLIMIT_CLIENT_QUERY_ATTRIBUTES POWERLIMITCLIENT_IOCTL(0x801)
+
+//
+// IOCTL_POWERLIMIT_CLIENT_QUERY_LIMITS
+// - Output: POWER_LIMIT_VALUE[], values of supported power limit parameters.
+//
+
+#define IOCTL_POWERLIMIT_CLIENT_QUERY_LIMITS POWERLIMITCLIENT_IOCTL(0x802)
+
+//
+// Each domain supports PowerLimitContinuous/Burst/BurstTimeParameter.
+//
+
+#define PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN 3UL
+#define PLCLIENT_DEFAULT_DOMAIN_COUNT 2UL
+#define PLCLIENT_DEFAULT_LIMIT_COUNT PLCLIENT_DEFAULT_LIMIT_COUNT_PER_DOMAIN * PLCLIENT_DEFAULT_DOMAIN_COUNT
+#define PLCLIENT_DEFAULT_MAX_VALUE 50000UL
+#define PLCLIENT_DEFAULT_MIN_VALUE 1000UL
diff --git a/powerlimit/plclient/wdf.c b/powerlimit/plclient/wdf.c
new file mode 100644
index 00000000..f5d0eb9b
--- /dev/null
+++ b/powerlimit/plclient/wdf.c
@@ -0,0 +1,477 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ wdf.c
+
+Abstract:
+
+ The module implements WDF boilerplate for the simulate power limit client.
+
+--*/
+
+//-------------------------------------------------------------------- Includes
+
+#include "plclient.h"
+
+//--------------------------------------------------------------------- Globals
+
+WDFWAITLOCK GlobalMutex;
+
+//------------------------------------------------------------------ Prototypes
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd;
+EVT_WDF_DRIVER_UNLOAD EvtDriverUnload;
+EVT_WDF_OBJECT_CONTEXT_DESTROY EvtDeviceDestroy;
+EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL EvtIoDeviceControl;
+
+//--------------------------------------------------------------------- Pragmas
+
+#pragma alloc_text(INIT, DriverEntry)
+#pragma alloc_text(PAGE, EvtDriverDeviceAdd)
+#pragma alloc_text(PAGE, EvtDriverUnload)
+#pragma alloc_text(PAGE, EvtIoDeviceControl)
+#pragma alloc_text(PAGE, EvtDeviceDestroy)
+
+//------------------------------------------------------------------- Functions
+
+_Use_decl_annotations_
+NTSTATUS
+DriverEntry (
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+
+/*++
+
+Routine Description:
+
+ DriverEntry initializes the driver and is the first routine called by the
+ system after the driver is loaded. DriverEntry configures and creates a WDF
+ driver object.
+
+Parameters Description:
+
+ DriverObject - Supplies a pointer to the driver object.
+
+ RegistryPath - Supplies a pointer to a unicode string representing the path
+ to the driver-specific key in the registry.
+
+Return Value:
+
+ NTSTATUS.
+
+--*/
+
+{
+
+ WDF_DRIVER_CONFIG DriverConfig;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ //
+ // Initiialize the DriverConfig data that controls the attributes that are
+ // global to this driver.
+ //
+
+ DebugEnter();
+ WDF_DRIVER_CONFIG_INIT(&DriverConfig, EvtDriverDeviceAdd);
+ DriverConfig.EvtDriverUnload = EvtDriverUnload;
+
+ //
+ // Create the driver object
+ //
+
+ Status = WdfDriverCreate(DriverObject,
+ RegistryPath,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &DriverConfig,
+ WDF_NO_HANDLE);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLCLIENT_PRINT_ERROR,
+ "WdfDriverCreate() Failed. Status 0x%x\n",
+ Status);
+
+ goto DriverEntryEnd;
+ }
+
+ //
+ // Initialize global mutex.
+ //
+
+ Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &GlobalMutex);
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLCLIENT_PRINT_ERROR,
+ "WdfWaitLockCreate() Failed! 0x%x\n",
+ Status);
+
+ goto DriverEntryEnd;
+ }
+
+DriverEntryEnd:
+ DebugExitStatus(Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+EvtDriverDeviceAdd (
+ WDFDRIVER Driver,
+ PWDFDEVICE_INIT DeviceInit
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the framework in response to AddDevice call from
+ the PnP manager. A WDF device object is created and initialized to represent
+ a new instance of the power limit client device.
+
+Arguments:
+
+ Driver - Supplies a handle to the WDF Driver object.
+
+ DeviceInit - Supplies a pointer to a framework-allocated WDFDEVICE_INIT structure.
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+
+ PFDO_DATA DevExt;
+ WDF_OBJECT_ATTRIBUTES DeviceAttributes;
+ WDFDEVICE DeviceHandle;
+ POWER_LIMIT_INTERFACE PowerLimitInterface;
+ WDFQUEUE Queue;
+ WDF_IO_QUEUE_CONFIG QueueConfig;
+ WDF_QUERY_INTERFACE_CONFIG QueryInterfaceConfig;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ DevExt = NULL;
+
+ DebugEnter();
+
+ //
+ // Initialize attributes and a context area for the device object.
+ //
+
+ WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&DeviceAttributes, FDO_DATA);
+ DeviceAttributes.EvtDestroyCallback = &EvtDeviceDestroy;
+
+ //
+ // Create a framework device object. This call will in turn create
+ // a WDM device object, attach to the lower stack, and set the
+ // appropriate flags and attributes.
+ //
+
+ Status = WdfDeviceCreate(&DeviceInit, &DeviceAttributes, &DeviceHandle);
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLCLIENT_PRINT_ERROR,
+ "WdfDeviceCreate() Failed. 0x%x\n",
+ Status);
+
+ goto DriverDeviceAddEnd;
+ }
+
+ //
+ // Configure a default queue for IO requests. This queue processes requests
+ // to read the simulated state.
+ //
+ // N.B. Those IOCTLs supplies another approach to validate device driver
+ // interface, which are not needed by production code.
+ //
+
+ WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&QueueConfig,
+ WdfIoQueueDispatchSequential);
+
+ QueueConfig.EvtIoDeviceControl = EvtIoDeviceControl;
+ Status = WdfIoQueueCreate(DeviceHandle,
+ &QueueConfig,
+ WDF_NO_OBJECT_ATTRIBUTES,
+ &Queue);
+
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLCLIENT_PRINT_ERROR,
+ "WdfIoQueueCreate() Failed. 0x%x\n",
+ Status);
+
+ goto DriverDeviceAddEnd;
+ }
+
+ //
+ // Initialize the device extension.
+ //
+
+ DevExt = GetDeviceExtension(DeviceHandle);
+ Status = InitPowerLimitValues(DevExt);
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLCLIENT_PRINT_ERROR,
+ "InitPowerLimitValues() Failed. 0x%x\n",
+ Status);
+
+ goto DriverDeviceAddEnd;
+ }
+
+ //
+ // Create a device interface for this device to advertise the simulated
+ // power limit client IO interface.
+ //
+
+ Status = WdfDeviceCreateDeviceInterface(
+ DeviceHandle,
+ &GUID_DEVINTERFACE_POWER_LIMIT,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DriverDeviceAddEnd;
+ }
+
+ //
+ // Create a driver interface for this device to advertise the power limit
+ // interface.
+ //
+
+ RtlZeroMemory(&PowerLimitInterface, sizeof(PowerLimitInterface));
+ PowerLimitInterface.Version = 1;
+ PowerLimitInterface.Size = sizeof(PowerLimitInterface);
+ PowerLimitInterface.Context = DeviceHandle;
+ PowerLimitInterface.InterfaceReference = WdfDeviceInterfaceReferenceNoOp;
+ PowerLimitInterface.InterfaceDereference = WdfDeviceInterfaceDereferenceNoOp;
+ PowerLimitInterface.DomainCount = PLCLIENT_DEFAULT_DOMAIN_COUNT;
+ PowerLimitInterface.QueryAttributes = PLCQueryAttributes;
+ PowerLimitInterface.SetPowerLimit = PLCSetLimits;
+ PowerLimitInterface.QueryPowerLimit = PLCQueryLimitValues;
+ WDF_QUERY_INTERFACE_CONFIG_INIT(&QueryInterfaceConfig,
+ (PINTERFACE)&PowerLimitInterface,
+ &GUID_POWER_LIMIT_INTERFACE,
+ NULL);
+
+ Status = WdfDeviceAddQueryInterface(DeviceHandle, &QueryInterfaceConfig);
+ if (!NT_SUCCESS(Status)) {
+ DebugPrint(PLCLIENT_PRINT_ERROR,
+ "WdfDeviceAddQueryInterface() Failed. 0x%x\n",
+ Status);
+
+ goto DriverDeviceAddEnd;
+ }
+
+DriverDeviceAddEnd:
+ if (!NT_SUCCESS(Status)) {
+ CleanupPowerLimitValues(DevExt);
+ }
+
+ DebugExitStatus(Status);
+ return Status;
+}
+
+_Use_decl_annotations_
+VOID
+EvtDeviceDestroy (
+ WDFOBJECT Object
+ )
+
+/*++
+
+Routine Description:
+
+ This routine destroys the device's data.
+
+Arguments:
+
+ Object - Supplies the WDF reference to the device that is being removed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PFDO_DATA DevExt;
+
+ PAGED_CODE();
+
+ DebugEnter();
+ DevExt = GetDeviceExtension(Object);
+ CleanupPowerLimitValues(DevExt);
+ DebugExit();
+ return;
+}
+
+_Use_decl_annotations_
+VOID
+EvtIoDeviceControl (
+ WDFQUEUE Queue,
+ WDFREQUEST Request,
+ size_t OutputBufferLength,
+ size_t InputBufferLength,
+ ULONG IoControlCode
+ )
+
+/*++
+
+Routine Description:
+
+ Handles requests to read the simulated device state.
+
+Arguments:
+
+ Queue - Supplies a handle to the framework queue object that is associated
+ with the I/O request.
+
+ Request - Supplies a handle to a framework request object. This one
+ represents the IRP_MJ_DEVICE_CONTROL IRP received by the framework.
+
+ OutputBufferLength - Supplies the length, in bytes, of the request's output
+ buffer, if an output buffer is available.
+
+ InputBufferLength - Supplies the length, in bytes, of the request's input
+ buffer, if an input buffer is available.
+
+ IoControlCode - Supplies the Driver-defined or system-defined I/O control
+ code (IOCTL) that is associated with the request.
+
+Return Value:
+
+ VOID
+
+--*/
+
+{
+
+ ULONG BytesReturned;
+ WDFDEVICE Device;
+ PFDO_DATA DevExt;
+ PVOID OutputBuffer;
+ NTSTATUS Status;
+
+ UNREFERENCED_PARAMETER(InputBufferLength);
+
+ PAGED_CODE();
+
+ Device = WdfIoQueueGetDevice(Queue);
+ DevExt = GetDeviceExtension(Device);
+ DebugPrint(PLCLIENT_PRINT_TRACE,
+ "EvtIoDeviceControl: 0x%08x\n",
+ IoControlCode);
+
+ BytesReturned = 0;
+ OutputBuffer = NULL;
+ if (OutputBufferLength > 0) {
+ Status = WdfRequestRetrieveOutputBuffer(Request,
+ OutputBufferLength,
+ &OutputBuffer,
+ NULL);
+
+ if (!NT_SUCCESS(Status)) {
+ goto DeviceIoControlEnd;
+ }
+ }
+
+ Status = STATUS_NOT_SUPPORTED;
+ switch(IoControlCode) {
+ case IOCTL_POWERLIMIT_CLIENT_QUERY_LIMIT_COUNT:
+ if (OutputBufferLength == sizeof(ULONG)) {
+ AcquireGlobalMutex();
+ *((PULONG)OutputBuffer) = DevExt->LimitCount;
+ BytesReturned = sizeof(ULONG);
+ ReleaseGlobalMutex();
+ Status = STATUS_SUCCESS;
+
+ } else {
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ break;
+
+ case IOCTL_POWERLIMIT_CLIENT_QUERY_ATTRIBUTES:
+ if (OutputBufferLength == sizeof(POWER_LIMIT_ATTRIBUTES) * DevExt->LimitCount) {
+ AcquireGlobalMutex();
+ RtlCopyMemory(OutputBuffer, DevExt->LimitAttributes, OutputBufferLength);
+ ReleaseGlobalMutex();
+ BytesReturned = (ULONG)OutputBufferLength;
+ Status = STATUS_SUCCESS;
+
+ } else {
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ break;
+
+ case IOCTL_POWERLIMIT_CLIENT_QUERY_LIMITS:
+ if (OutputBufferLength == sizeof(POWER_LIMIT_VALUE) * DevExt->LimitCount) {
+ AcquireGlobalMutex();
+ RtlCopyMemory(OutputBuffer, DevExt->LimitValues, OutputBufferLength);
+ ReleaseGlobalMutex();
+ BytesReturned = (ULONG)OutputBufferLength;
+ Status = STATUS_SUCCESS;
+
+ } else {
+ Status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+DeviceIoControlEnd:
+ WdfRequestCompleteWithInformation(Request, Status, BytesReturned);
+ DebugExitStatus(Status);
+ return;
+}
+
+_Use_decl_annotations_
+VOID
+EvtDriverUnload (
+ WDFDRIVER Driver
+ )
+
+/*++
+
+Routine Description:
+
+ EvtDriverUnload is called when the driver is being unloaded to clean up
+ driver state.
+
+Arguments:
+
+ Driver - Supplies a handle to the WDF Driver object.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Driver);
+
+ PAGED_CODE();
+
+ DebugEnter();
+
+ //
+ // N.B. Does nothing since we don't have anything to clean up, just print
+ // some debug info.
+ //
+
+ DebugExit();
+ return;
+}