diff options
Diffstat (limited to 'powerlimit/plclient/wdf.c')
| -rw-r--r-- | powerlimit/plclient/wdf.c | 477 |
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; +} |
