summaryrefslogtreecommitdiff
path: root/powerlimit/plclient/wdf.c
diff options
context:
space:
mode:
Diffstat (limited to 'powerlimit/plclient/wdf.c')
-rw-r--r--powerlimit/plclient/wdf.c477
1 files changed, 477 insertions, 0 deletions
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;
+}