diff options
| author | Rajib Dutta <[email protected]> | 2018-08-20 13:13:49 -0700 |
|---|---|---|
| committer | Rajib Dutta <[email protected]> | 2018-08-20 13:13:49 -0700 |
| commit | 534de83ddd9f5ab13af2325d11e9414d72066722 (patch) | |
| tree | 3c4d814bf2d637fd823e75a80915ee9aefb463c4 | |
| parent | 2af3e666d01a60568c2875b4ccbd56b122ad714f (diff) | |
UcmUcsiCx Sample ACPI Client Driver.
18 files changed, 3363 insertions, 0 deletions
diff --git a/usb/UcmUcsiAcpiSample/README.md b/usb/UcmUcsiAcpiSample/README.md new file mode 100644 index 00000000..cb2c7d02 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/README.md @@ -0,0 +1,51 @@ +<!--- + name: UcmUcsiCx Client Driver + platform: KMDF + language: cpp + category: USB + description: Demonstrates how to create a Windows UCSI client UCSI class extension driver (UcmUcsiCx). + samplefwlink: +---> + +# UcmUcsiCx ACPI Client Driver + +This is a sample driver that shows how to create a Windows USB Type-C port controller driver using the USB Connector Manager class extension driver (UcmCx). The sample is a driver for an embedded controller which is compliant with the [USB Type-C Connector System Software Interface (UCSI)](http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html). + + +## Note on UCM UCSI + +Microsoft already provides an inbox UCSI Class extension (UcmUcsiCx.sys) and ACPI client driver (UcmUcsiAcpiClient.sys) . This UcmUcsi ACPI sample driver is not to a very large extent identical to and functionally replaceable with UcmUcsiAcpiClient.sys. Microsoft recommends that you use this sample to bring up your UcmUcsiCx Client driver that is interfaced over a non ACPI transport. + +This sample demonstrates the following: +- Preparing connector collection with UcmUcsiCx +- Initializing Platform Policy Manager (or PPM) object with UcmUcsiCx +- Handling IOCTLs from UcmUcsiCx to send or get UCSI block +- Delivering PPM notifications to UcmUcsiCx + +## Customizing the sample for your UCSI transport +This sample is specific to ACPI based UCSI systems. You may choose to structure your driver in a similar way for your own hardware. Understand the requirements and specification of your own system prior to writing a new UcmUcsiCx client driver. In addition to making the logic and functionality suit your specific UCSI transport, you will need to modify the .inf such that it matches your device's information. + +### UcmUcsiCx structure + +In this sample, UCMUCSI-specific interactions are split apart from most of the UCSI-specific operations. + +#### UcmUcsiCx Interactions +The following files contain methods that interface with UcmUcsiCx. + +- Ppm.cpp + - Contains bulk of interactions with UcmUcsiCx. Ppm::CreateAndInitialize which is called in the context of PrepareHardware PnP callback, creates connector collection with UcmUcsiCx by calling DDI UcmUcsiConnectorCollectionCreate and UcmUcsiConnectorCollectionAddConnector. The collection serves as a parameter to initialize PPM object with the class extension when the DDI UcmUcsiPpmCreate is called. Ppm::PpmNotificationCallback function calls DDI on the event of a PPM notification. Ppm::EvtIoDeviceControl contains the logic of handling IOCTLs from UcmUcsiCx. +- Fdo.cpp + - FDO callbacks, functions, and types, most of which do not interface with UcmUcsiCx. However, the method Fdo::CreateAndInitialize calls to UcmUcsiCx DDIs UcmUcsiDeviceInitInitialize and UcmUcsiDeviceInitialize. + +#### UCSI and WDF Interactions +The remainder of the files perform operations for UCSI and WDF, non-specific to UCM. + +- Acpi.cpp + - ACPI method evaluation helper routines. +- Driver.cpp + - Entry point to the driver. Initializes the driver with WDF. +- Ppm.cpp + - Type-C Platform Policy Manager. Main interface to talk to the UCSI-compliant hardware (via ACPI transport in this case). + +## When to write a UcmUcsiCx client driver +UcmUcsiCx is intended to abstract UCSI protocol from UCSI based driver support. If you have a system that implements PPM logic in an Embedded controller which is connected to the system over a non ACPI transport - e.g. USB, PCI, I2C or UART, it is advised that you write a UcmUcsiCx client driver that implements the necessary transport. Ideally, you would just need to replace Acpi class and implement your way to talk to the PPM. Please note, UcmUcsiCx client is the power policy owner. The class extension does handle S0 idling if you chose to enable it in the client driver. diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample.sln b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample.sln new file mode 100644 index 00000000..7f93d805 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UcmUcsiAcpiSample", "UcmUcsiAcpiSample\UcmUcsiAcpiSample.vcxproj", "{89486440-A6FB-4E95-9EE9-957B646F28DD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|ARM = Release|ARM + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|ARM.ActiveCfg = Debug|ARM + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|ARM.Build.0 = Debug|ARM + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|ARM.Deploy.0 = Debug|ARM + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|ARM64.Build.0 = Debug|ARM64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|x64.ActiveCfg = Debug|x64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|x64.Build.0 = Debug|x64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|x64.Deploy.0 = Debug|x64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|x86.ActiveCfg = Debug|Win32 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|x86.Build.0 = Debug|Win32 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Debug|x86.Deploy.0 = Debug|Win32 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|ARM.ActiveCfg = Release|ARM + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|ARM.Build.0 = Release|ARM + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|ARM.Deploy.0 = Release|ARM + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|ARM64.ActiveCfg = Release|ARM64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|ARM64.Build.0 = Release|ARM64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|ARM64.Deploy.0 = Release|ARM64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|x64.ActiveCfg = Release|x64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|x64.Build.0 = Release|x64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|x64.Deploy.0 = Release|x64 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|x86.ActiveCfg = Release|Win32 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|x86.Build.0 = Release|Win32 + {89486440-A6FB-4E95-9EE9-957B646F28DD}.Release|x86.Deploy.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {65421185-9FFE-48A0-BAC9-067A8EB1C481} + EndGlobalSection +EndGlobal diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Acpi.cpp b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Acpi.cpp new file mode 100644 index 00000000..bca0e2f2 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Acpi.cpp @@ -0,0 +1,841 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Acpi.cpp + +Abstract: + + UCSI Acpi transport functions. + +Environment: + + Kernel-mode. + +--*/ + +#include "Pch.h" +#include "Acpi.tmh" + + +namespace UcmUcsiAcpiClient +{ + +// +// ACPI _DSM method GUID value as described in the document "BIOS Implemetation of UCSI" at +// https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/bios-implementation-of-ucsi.pdf +// {6F8398C2-7CA4-11E4-AD36-631042B5008F} +// +DEFINE_GUID(GUID_UCSI_DSM, +0x6f8398c2, 0x7ca4, 0x11e4, 0xad, 0x36, 0x63, 0x10, 0x42, 0xb5, 0x00, 0x8f); + +const ULONG UCSI_DSM_REVISION = 0; +const ULONG UCSI_DSM_FUNCTION_SUPPORTED_FUNCTIONS_INDEX = 0x0; +const ULONG UCSI_DSM_FUNCTION_SEND_DATA_INDEX = 0x1; +const ULONG UCSI_DSM_FUNCTION_RECEIVE_DATA_INDEX = 0x2; +const ULONG UCSI_DSM_FUNCTION_USB_DEVICE_CONTROLLER_STATUS_INDEX = 0x3; + +// +// There is no formal requirement of timeout for _DMS method. 3 second timeout +// was inherited from the previous driver ucmucsi.sys. +// +const ULONG UCSI_DSM_EXECUTION_TIMEOUT_IN_MS = 3000; + +PAGED_CODE_SEG +NTSTATUS +Acpi::Initialize( + WDFDEVICE Device + ) +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + m_OwningDevice = Device; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Device; + + status = WdfWaitLockCreate(&attributes, &m_CallbackLock); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[WDFDEVICE: 0x%p] WdfWaitLockCreate failed - %!STATUS!", + Device, status); + goto Exit; + } + + status = STATUS_SUCCESS; + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::PrepareHardware( + PCONFIG Config + ) +{ + NTSTATUS status; + PVOID mappedMemory; + UCSI_VERSION version; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + // + // Map the shared memory to the virtual space so that the driver can access it. + // + mappedMemory = MmMapIoSpaceEx(Config->DataBlockAddress, + Config->DataBlockLength, + PAGE_NOCACHE | PAGE_READWRITE); + +#pragma prefast(suppress: __WARNING_REDUNDANT_POINTER_TEST, "API indicates failure by returning NULL") + if (mappedMemory == nullptr) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TRACE_ERROR(TRACE_FLAG_PPM, "[Device: 0x%p] MmMapIoSpaceEx failed", m_OwningDevice); + goto Exit; + } + + m_UcsiDataBlock = (PUCSI_DATA_BLOCK) mappedMemory; + m_MappedMemoryLength = Config->DataBlockLength; + + version = m_UcsiDataBlock->UcsiVersion; + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] UCSI version Major: %hx Minor: %hx SubMinor: %hx", + m_OwningDevice, version.MajorVersion, version.MinorVersion, version.SubMinorVersion); + + // + // Query ACPI interface so that we can register notifications with ACPI. + // + if (m_InterfaceQueried != false) + { + status = STATUS_INVALID_DEVICE_STATE; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI interface already queried", m_OwningDevice); + goto Exit; + } + + status = WdfFdoQueryForInterface(m_OwningDevice, + &GUID_ACPI_INTERFACE_STANDARD2, + (PINTERFACE) &m_AcpiInterface, + sizeof(ACPI_INTERFACE_STANDARD2), + 1, + NULL); + + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfFdoQueryForInterface for ACPI_INTERFACE_STANDARD2 failed - %!STATUS!", + m_OwningDevice, status); + goto Exit; + } + + m_InterfaceQueried = true; + TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI prepare hardware completed", m_OwningDevice); + +Exit: + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +VOID +Acpi::ReleaseHardware() +{ + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + if (m_UcsiDataBlock != nullptr) + { + MmUnmapIoSpace(m_UcsiDataBlock, m_MappedMemoryLength); + m_UcsiDataBlock = nullptr; + m_MappedMemoryLength = 0; + } + + if (m_InterfaceQueried == false) + { + goto Exit; + } + + m_AcpiInterface.InterfaceDereference(m_AcpiInterface.Context); + RtlZeroMemory(&m_AcpiInterface, sizeof(m_AcpiInterface)); + + m_InterfaceQueried = false; + + TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI release hardware completed", m_OwningDevice); + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::EnumChildren( + WDFMEMORY* EnumChildrenOutput + ) +{ + NTSTATUS status; + WDFMEMORY inputMem; + PACPI_ENUM_CHILDREN_INPUT_BUFFER inputBuf; + size_t inputBufSize; + WDF_MEMORY_DESCRIPTOR inputMemDesc; + WDFMEMORY outputMem; + PACPI_ENUM_CHILDREN_OUTPUT_BUFFER outputBuf; + size_t outputBufSize; + WDF_MEMORY_DESCRIPTOR outputMemDesc; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + inputMem = WDF_NO_HANDLE; + outputMem = WDF_NO_HANDLE; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = m_OwningDevice; + + inputBufSize = sizeof(*inputBuf); + status = WdfMemoryCreate(&attributes, + NonPagedPoolNx, + 0, + inputBufSize, + &inputMem, + (PVOID*) &inputBuf); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfMemoryCreate for %Iu bytes failed", + m_OwningDevice, inputBufSize); + goto Exit; + } + + RtlZeroMemory(inputBuf, inputBufSize); + inputBuf->Signature = ACPI_ENUM_CHILDREN_INPUT_BUFFER_SIGNATURE; + inputBuf->Flags = ENUM_CHILDREN_IMMEDIATE_ONLY; + + WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputMemDesc, inputMem, nullptr); + + outputBufSize = sizeof(*outputBuf); + + do + { + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = m_OwningDevice; + + status = WdfMemoryCreate(&attributes, + NonPagedPoolNx, + 0, + outputBufSize, + &outputMem, + (PVOID*) &outputBuf); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfMemoryCreate for %Iu bytes failed", + m_OwningDevice, outputBufSize); + goto Exit; + } + + WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&outputMemDesc, outputMem, nullptr); + + status = WdfIoTargetSendIoctlSynchronously(WdfDeviceGetIoTarget(m_OwningDevice), + NULL, + IOCTL_ACPI_ENUM_CHILDREN, + &inputMemDesc, + &outputMemDesc, + nullptr, + nullptr); + + if (NT_SUCCESS(status)) + { + if (outputBuf->Signature != ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Invalid data in ACPI_ENUM_CHILDREN_OUTPUT_BUFFER", m_OwningDevice); + goto Exit; + } + + // There must be atleast one, because this device is included in the list. + if (outputBuf->NumberOfChildren < 1) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] No child devices in ACPI_ENUM_CHILDREN_OUTPUT_BUFFER", m_OwningDevice); + goto Exit; + } + + break; + } + + if (status != STATUS_BUFFER_OVERFLOW) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] IOCTL_ACPI_ENUM_CHILDREN failed - %!STATUS!", m_OwningDevice, status); + goto Exit; + } + + if (outputBuf->Signature != ACPI_ENUM_CHILDREN_OUTPUT_BUFFER_SIGNATURE) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Invalid data in ACPI_ENUM_CHILDREN_OUTPUT_BUFFER", m_OwningDevice); + goto Exit; + } + + // NOTE: The NumberOfChildren returned by ACPI actually contains the required size + // when the status returned is STATUS_BUFFER_OVERFLOW + outputBufSize = outputBuf->NumberOfChildren; + WdfObjectDelete(outputMem); + outputMem = WDF_NO_HANDLE; + +#pragma warning(suppress:4127) + } while (true); + + *EnumChildrenOutput = outputMem; + +Exit: + + if (inputMem != WDF_NO_HANDLE) + { + WdfObjectDelete(inputMem); + } + + if (!NT_SUCCESS(status) && (outputMem != WDF_NO_HANDLE)) + { + WdfObjectDelete(outputMem); + } + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::EvaluatePld( + LPCSTR DeviceName, + PACPI_PLD_BUFFER PldBuffer + ) +{ + NTSTATUS status; + WDF_MEMORY_DESCRIPTOR inputMemDesc; + ACPI_EVAL_INPUT_BUFFER_EX inputBuffer; + size_t inputBufferSize; + WDFMEMORY outputMemory; + WDF_MEMORY_DESCRIPTOR outputMemDesc; + PACPI_EVAL_OUTPUT_BUFFER outputBuffer; + size_t outputBufferSize; + size_t outputArgumentBufferSize; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + // @@BEGIN_NOTPUBLICCODE + // TODO: Refactor so that _DSM evaluation and _PLD evaluation use a common helper routine. + // + // TODO: _PLD evaluation of multiple connectors can be optimized to reduce number of memory + // allocations. Right now, output memory will be allocated for each request. We can + // reuse a single allocation for all evaluations. + // + // TODO: When refactoring code, must keep in mind that it would be efficient to allow the + // caller to specify a good initial output buffer size, which would depend on the method + // being evaluated. Caller may have a good estimate of the buffer size required. Otherwise + // we'll end up making two calls (one to figure out the size, another for actual + // evaluation) everytime. + // @@END_NOTPUBLICCODE + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + outputMemory = WDF_NO_HANDLE; + + inputBufferSize = sizeof(inputBuffer); + RtlZeroMemory(&inputBuffer, inputBufferSize); + + inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE_EX; + + status = RtlStringCchPrintfA(inputBuffer.MethodName, + sizeof(inputBuffer.MethodName), + "%s._PLD", + DeviceName); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] RtlStringCchPrintfA for creating method name failed - %!STATUS!", m_OwningDevice, status); + goto Exit; + } + + // @@BEGIN_NOTPUBLICCODE + // TODO: Pick an intelligent initial size for the buffer, and then do try-and-try-again. + // @@END_NOTPUBLICCODE + + outputArgumentBufferSize = 1024; + outputBufferSize = + FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + + outputArgumentBufferSize; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = m_OwningDevice; + + status = WdfMemoryCreate(&attributes, + NonPagedPoolNx, + 0, + outputBufferSize, + &outputMemory, + (PVOID*) &outputBuffer); + + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfMemoryCreate failed for %Iu bytes - %!STATUS!", m_OwningDevice, outputBufferSize, status); + goto Exit; + } + + RtlZeroMemory(outputBuffer, outputBufferSize); + + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&inputMemDesc, &inputBuffer, (ULONG) inputBufferSize); + WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&outputMemDesc, outputMemory, NULL); + + status = WdfIoTargetSendInternalIoctlSynchronously( + WdfDeviceGetIoTarget(m_OwningDevice), + NULL, + IOCTL_ACPI_EVAL_METHOD_EX, + &inputMemDesc, + &outputMemDesc, + NULL, + NULL); + + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] IOCTL_ACPI_EVAL_METHOD_EX for %s failed - %!STATUS!", m_OwningDevice, inputBuffer.MethodName, status); + goto Exit; + } + + if (outputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI_EVAL_OUTPUT_BUFFER signature is incorrect", m_OwningDevice); + goto Exit; + } + + if (outputBuffer->Count < 1) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _PLD for %s didn't return anything", m_OwningDevice, inputBuffer.MethodName); + goto Exit; + } + + if (outputBuffer->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _PLD for %s returned an unexpected argument of type %d", m_OwningDevice, inputBuffer.MethodName, outputBuffer->Argument[0].Type); + goto Exit; + } + + if (outputBuffer->Argument[0].DataLength < sizeof(*PldBuffer)) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Unexpected _PLD buffer size for %s. Expected %Iu bytes, got %Iu bytes", m_OwningDevice, inputBuffer.MethodName, sizeof(*PldBuffer), outputBuffer->Argument[0].DataLength); + goto Exit; + } + + *PldBuffer = *((PACPI_PLD_BUFFER) outputBuffer->Argument[0].Data); + +Exit: + if (outputMemory != WDF_NO_HANDLE) + { + WdfObjectDelete(outputMemory); + } + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::CheckIfUsbDeviceControllerIsEnabled( + bool& IsUsbDeviceControllerEnabled + ) +{ + NTSTATUS status; + PACPI_EVAL_OUTPUT_BUFFER output; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + output = nullptr; + + status = EvaluateUcsiDsm(UCSI_DSM_FUNCTION_SUPPORTED_FUNCTIONS_INDEX, &output); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _DSM query for supported functions failed - %!STATUS!", m_OwningDevice, status); + goto Exit; + } + + if (output->Count != 1) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _DSM query for supported functions returned unexpected number of arguments %lu", m_OwningDevice, output->Count); + goto Exit; + } + + NT_ASSERT_ASSUME(output->Length == sizeof(ACPI_EVAL_OUTPUT_BUFFER)); + + if (output->Argument[0].Type != ACPI_METHOD_ARGUMENT_BUFFER) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _DSM query for supported functions returned an unexpected argument of type %d", m_OwningDevice, output->Argument[0].Type); + goto Exit; + } + + if (!TEST_BIT(output->Argument[0].Data[0], UCSI_DSM_FUNCTION_USB_DEVICE_CONTROLLER_STATUS_INDEX)) + { + // + // The function to query whether the device controller is enabled is not supported. Assume + // that the controller is enabled. + // + + TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] _DSM to query if USB device controller is enabled is not supported. Assuming that device controller is supported", + m_OwningDevice); + + status = STATUS_SUCCESS; + IsUsbDeviceControllerEnabled = true; + goto Exit; + } + + delete[] output; + output = nullptr; + + status = EvaluateUcsiDsm(UCSI_DSM_FUNCTION_USB_DEVICE_CONTROLLER_STATUS_INDEX, &output); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _DSM query for USB device controller status failed - %!STATUS!", m_OwningDevice, status); + goto Exit; + } + + if (output->Count != 1) + { + status = STATUS_ACPI_INVALID_DATA; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] _DSM query for USB device controller status returned unexpected number of arguments %lu", m_OwningDevice, output->Count); + goto Exit; + } + + NT_ASSERT_ASSUME(output->Length == sizeof(ACPI_EVAL_OUTPUT_BUFFER)); + + IsUsbDeviceControllerEnabled = (output->Argument[0].Argument) ? true : false; + status = STATUS_SUCCESS; + +Exit: + + if (output) + { + delete[] output; + output = nullptr; + } + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::EvaluateUcsiDsm( + ULONG FunctionIndex, + PACPI_EVAL_OUTPUT_BUFFER* Output + ) +{ + NTSTATUS status; + WDFMEMORY inputMemory; + WDF_MEMORY_DESCRIPTOR inputMemDesc; + PACPI_EVAL_INPUT_BUFFER_COMPLEX inputBuffer; + size_t inputBufferSize; + size_t inputArgumentBufferSize; + PACPI_METHOD_ARGUMENT argument; + WDF_MEMORY_DESCRIPTOR outputMemDesc; + PACPI_EVAL_OUTPUT_BUFFER outputBuffer; + size_t outputBufferSize; + size_t outputArgumentBufferSize; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_REQUEST_SEND_OPTIONS sendOptions; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + inputMemory = WDF_NO_HANDLE; + outputBuffer = nullptr; + + inputArgumentBufferSize = + ACPI_METHOD_ARGUMENT_LENGTH(sizeof(GUID)) + + ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + + ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)) + + ACPI_METHOD_ARGUMENT_LENGTH(0); + + inputBufferSize = + FIELD_OFFSET(ACPI_EVAL_INPUT_BUFFER_COMPLEX, Argument) + + inputArgumentBufferSize; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = m_OwningDevice; + + status = WdfMemoryCreate(&attributes, + NonPagedPoolNx, + 0, + inputBufferSize, + &inputMemory, + (PVOID*) &inputBuffer); + + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] WdfMemoryCreate failed for %Iu bytes - %!STATUS!", + m_OwningDevice, inputBufferSize, status); + goto Exit; + } + + RtlZeroMemory(inputBuffer, inputBufferSize); + + inputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_COMPLEX_SIGNATURE; + inputBuffer->Size = (ULONG) inputArgumentBufferSize; + inputBuffer->ArgumentCount = 4; + inputBuffer->MethodNameAsUlong = (ULONG) 'MSD_'; + + argument = &(inputBuffer->Argument[0]); + ACPI_METHOD_SET_ARGUMENT_BUFFER(argument, + &GUID_UCSI_DSM, + sizeof(GUID_UCSI_DSM)); + + argument = ACPI_METHOD_NEXT_ARGUMENT(argument); + ACPI_METHOD_SET_ARGUMENT_INTEGER(argument, UCSI_DSM_REVISION); + + argument = ACPI_METHOD_NEXT_ARGUMENT(argument); + ACPI_METHOD_SET_ARGUMENT_INTEGER(argument, FunctionIndex); + + argument = ACPI_METHOD_NEXT_ARGUMENT(argument); + argument->Type = ACPI_METHOD_ARGUMENT_PACKAGE_EX; + argument->DataLength = 0; + + // @@BEGIN_NOTPUBLICCODE + // TODO: Try-and-try-again approach so that it can fetch any size output buffer. + // @@END_NOTPUBLICCODE + + outputArgumentBufferSize = ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG)); + outputBufferSize = + FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) + + outputArgumentBufferSize; + + outputBuffer = reinterpret_cast<PACPI_EVAL_OUTPUT_BUFFER>(new BYTE[outputBufferSize]); + + if (outputBuffer == nullptr) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Memory allocation failed for %Iu bytes", m_OwningDevice, outputBufferSize); + goto Exit; + } + + RtlZeroMemory(outputBuffer, outputBufferSize); + + WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&inputMemDesc, inputMemory, NULL); + WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(&outputMemDesc, outputBuffer, (ULONG) outputBufferSize); + + WDF_REQUEST_SEND_OPTIONS_INIT(&sendOptions, WDF_REQUEST_SEND_OPTION_SYNCHRONOUS); + WDF_REQUEST_SEND_OPTIONS_SET_TIMEOUT(&sendOptions, + WDF_REL_TIMEOUT_IN_MS(UCSI_DSM_EXECUTION_TIMEOUT_IN_MS)); + + status = WdfIoTargetSendInternalIoctlSynchronously( + WdfDeviceGetIoTarget(m_OwningDevice), + NULL, + IOCTL_ACPI_EVAL_METHOD, + &inputMemDesc, + &outputMemDesc, + &sendOptions, + NULL); + + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] IOCTL_ACPI_EVAL_METHOD for _DSM failed - %!STATUS!", m_OwningDevice, status); + goto Exit; + } + + if (outputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI_EVAL_OUTPUT_BUFFER signature is incorrect", m_OwningDevice); + status = STATUS_ACPI_INVALID_DATA; + goto Exit; + } + +Exit: + + if (inputMemory != WDF_NO_HANDLE) + { + WdfObjectDelete(inputMemory); + } + + if (!NT_SUCCESS(status) || (Output == nullptr)) + { + if (outputBuffer) + { + delete[] outputBuffer; + outputBuffer = nullptr; + } + } + else + { + *Output = outputBuffer; + } + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::SendData( + const PUCSI_DATA_BLOCK DataBlock + ) +{ + NTSTATUS status; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + m_UcsiDataBlock->Control = DataBlock->Control; + + status = EvaluateUcsiDsm(UCSI_DSM_FUNCTION_SEND_DATA_INDEX, + nullptr); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::ReceiveData ( + PUCSI_DATA_BLOCK DataBlockOut + ) +{ + NTSTATUS status; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + status = EvaluateUcsiDsm(UCSI_DSM_FUNCTION_RECEIVE_DATA_INDEX, + nullptr); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + // Right now there is no use case of copying the whole block. Just copying + // CCI as of now since all the caller would want to know is whether the last + // command has been completed. + DataBlockOut->CCI = m_UcsiDataBlock->CCI; + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +VOID +Acpi::NotificationCallback( + PVOID Context, + ULONG NotifyValue + ) +{ + PAGED_CODE(); + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + // + // Get the Acpi object from the Context passed by the notification callback. + // + Acpi *acpi = reinterpret_cast<Acpi*>(Context); + + acpi->AcquireCallbackLock(); + if (acpi->m_CallbackContext.m_CallbackFunction) + { + acpi->InvokeCallback(NotifyValue); + } + acpi->ReleaseCallbackLock(); + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); +} + +PAGED_CODE_SEG +NTSTATUS +Acpi::RegisterNotificationCallbackInternal( + _In_ PACPI_NOTIFICATION_CALLBACK_CONTEXT CallbackContext + ) +{ + NTSTATUS status; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + status = m_AcpiInterface.RegisterForDeviceNotifications(m_AcpiInterface.Context, + Acpi::NotificationCallback, this); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Registering for ACPI notifications failed - %!STATUS!", + m_OwningDevice, status); + goto Exit; + } + + AcquireCallbackLock(); + + m_CallbackContext.m_PpmObject = CallbackContext->m_PpmObject; + m_CallbackContext.m_CallbackFunction = CallbackContext->m_CallbackFunction; + + ReleaseCallbackLock(); + + status = STATUS_SUCCESS; + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); + return status; +} + +PAGED_CODE_SEG +VOID +Acpi::UnRegisterNotificationCallback() +{ + PAGED_CODE(); + TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI); + + // + // Acquire the lock to synchronize with outstanding callbacks, and then clear the callback + // pointer to prevent making additional callbacks. The ACPI callback may still fire, because the + // ACPI driver does not guarantee that it won't make additional calls after + // UnregisterForDeviceNotifications has returned, so clearing the callback pointer prevents us + // from accidentally making more callbacks after this function returns. + // + AcquireCallbackLock(); + + m_CallbackContext.m_PpmObject = nullptr; + m_CallbackContext.m_CallbackFunction = nullptr; + + ReleaseCallbackLock(); + + m_AcpiInterface.UnregisterForDeviceNotifications(m_AcpiInterface.Context); + + TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] Unregistered ACPI notifications", m_OwningDevice); + + TRACE_FUNC_EXIT(TRACE_FLAG_ACPI); +} + +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Acpi.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Acpi.h new file mode 100644 index 00000000..469fbb0a --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Acpi.h @@ -0,0 +1,207 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Acpi.h + +Abstract: + + ACPI transport class for UCSI Cx Client. + +Environment: + + Kernel-mode. + +--*/ + +#pragma once + +namespace UcmUcsiAcpiClient +{ + +class Ppm; + +typedef +_IRQL_requires_max_(PASSIVE_LEVEL) +void +EVT_ACPI_NOTIFICATION_CALLBACK( + _In_ Ppm *PpmObject, + _In_ ULONG NotifyValue +); + +typedef EVT_ACPI_NOTIFICATION_CALLBACK *PFN_ACPI_NOTIFICATION_CALLBACK; + +typedef struct +{ + Ppm* m_PpmObject = nullptr; + PFN_ACPI_NOTIFICATION_CALLBACK m_CallbackFunction = nullptr; +}ACPI_NOTIFICATION_CALLBACK_CONTEXT, *PACPI_NOTIFICATION_CALLBACK_CONTEXT; + +class Acpi +{ +public: + + typedef struct _CONFIG + { + PHYSICAL_ADDRESS DataBlockAddress; + ULONG DataBlockLength; + } CONFIG, *PCONFIG; + + + Acpi() = default; + + ~Acpi() = default; + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Initialize ( + _In_ WDFDEVICE Device + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(_In_ PCONFIG Config); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + EnumChildren(_Out_ WDFMEMORY* EnumChildrenOutput); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + EvaluatePld ( + _In_ LPCSTR DeviceName, + _Out_ PACPI_PLD_BUFFER PldBuffer + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + CheckIfUsbDeviceControllerIsEnabled ( + _Inout_ bool& IsUsbDeviceControllerEnabled + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + ReleaseHardware(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SendData( + _In_ const PUCSI_DATA_BLOCK DataBlock + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReceiveData( + _Out_ PUCSI_DATA_BLOCK DataBlockOut + ); + + //template<typename F> + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + RegisterNotificationCallback( + _In_ PACPI_NOTIFICATION_CALLBACK_CONTEXT CallbackConext + ) + { + return RegisterNotificationCallbackInternal(CallbackConext); + } + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + UnRegisterNotificationCallback(); + + // + // The callback that is registered with ACPI to be called asynchronously when + // PPM firmware wants to send notification to the OPM. + // + static + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + NotificationCallback( + _In_ PVOID Context, + _In_ ULONG NotifyValue + ); + + FORCEINLINE + _IRQL_requires_max_(PASSIVE_LEVEL) + VOID + AcquireCallbackLock() + { + WdfWaitLockAcquire(m_CallbackLock, nullptr); + } + + FORCEINLINE + _IRQL_requires_max_(PASSIVE_LEVEL) + VOID + ReleaseCallbackLock() + { + WdfWaitLockRelease(m_CallbackLock); + } + + FORCEINLINE + _IRQL_requires_max_(DISPATCH_LEVEL) + VOID + InvokeCallback( + _In_ ULONG NotifyValue) + { + m_CallbackContext.m_CallbackFunction(m_CallbackContext.m_PpmObject, NotifyValue); + } + + FORCEINLINE + _IRQL_requires_max_(PASSIVE_LEVEL) + PUCSI_DATA_BLOCK + GetUcsiDataBlock() + { + return m_UcsiDataBlock; + } + +private: + + Acpi(_In_ const Acpi&) = delete; + Acpi& operator =(_In_ const Acpi&) = delete; + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + EvaluateUcsiDsm ( + _In_ ULONG FunctionIndex, + _Outptr_opt_ PACPI_EVAL_OUTPUT_BUFFER* Output + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + RegisterNotificationCallbackInternal( + _In_ PACPI_NOTIFICATION_CALLBACK_CONTEXT + ); + + // The owning client device. + WDFDEVICE m_OwningDevice = WDF_NO_HANDLE; + + bool m_InterfaceQueried = false; + ACPI_INTERFACE_STANDARD2 m_AcpiInterface; + + WDFWAITLOCK m_CallbackLock = nullptr; + + // The function to be ACPI notificaiton. + ACPI_NOTIFICATION_CALLBACK_CONTEXT m_CallbackContext; + + // Pointer to the mapped memory that contaisn UCSI Data block + // that is accessed by OS and firmware. + PUCSI_DATA_BLOCK m_UcsiDataBlock = nullptr; + ULONG m_MappedMemoryLength = 0; + +}; +}
\ No newline at end of file diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Driver.cpp b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Driver.cpp new file mode 100644 index 00000000..2c0ec33c --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Driver.cpp @@ -0,0 +1,128 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Driver.cpp + +Abstract: + + Driver-global types and functions. + +Environment: + + Kernel-mode. + +--*/ + +#include "Pch.h" +#include "Driver.tmh" + + +INIT_CODE_SEG +NTSTATUS +DriverEntry ( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +{ + return UcmUcsiAcpiClient::Driver::CreateAndInitialize(DriverObject, RegistryPath); +} + + +namespace UcmUcsiAcpiClient +{ + +INIT_CODE_SEG +NTSTATUS +Driver::CreateAndInitialize ( + PDRIVER_OBJECT DriverObject, + PUNICODE_STRING RegistryPath + ) +{ + WPP_INIT_TRACING(DriverObject, RegistryPath); + TRACE_FUNC_ENTRY(TRACE_FLAG_DRIVER); + + NTSTATUS status; + WDF_DRIVER_CONFIG config; + WDFDRIVER wdfDriver; + + WDF_DRIVER_CONFIG_INIT(&config, &Driver::EvtDriverDeviceAddThunk); + config.EvtDriverUnload = &Driver::EvtDriverUnloadThunk; + config.DriverPoolTag = Driver::c_PoolTag; + + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + &wdfDriver + ); + + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_DRIVER, "[PDRIVER_OBJECT: 0x%p] WdfDriverCreate failed - %!STATUS!", + DriverObject, status); + goto Exit; + } + + TRACE_INFO(TRACE_FLAG_DRIVER, "[WDFDRIVER: 0x%p] Driver entry completed", wdfDriver); + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_DRIVER); + + if (!NT_SUCCESS(status)) + { + WPP_CLEANUP(DriverObject); + } + + return status; +} + + +PAGED_CODE_SEG +void +Driver::EvtDriverUnloadThunk ( + WDFDRIVER WdfDriver + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_DRIVER); + PAGED_CODE(); + + PDRIVER_OBJECT driverObject; + + driverObject = WdfDriverWdmGetDriverObject(WdfDriver); + + TRACE_INFO(TRACE_FLAG_DRIVER, "[WDFDRIVER: 0x%p] Driver unloading", WdfDriver); + + TRACE_FUNC_EXIT(TRACE_FLAG_DRIVER); + WPP_CLEANUP(driverObject); +} + + +PAGED_CODE_SEG +NTSTATUS +Driver::EvtDriverDeviceAddThunk ( + WDFDRIVER /* WdfDriver */, + PWDFDEVICE_INIT DeviceInit + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_DRIVER); + PAGED_CODE(); + + NTSTATUS status; + + status = Fdo::CreateAndInitialize(DeviceInit); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_DRIVER); + return status; +} + +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Driver.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Driver.h new file mode 100644 index 00000000..5bbad1cb --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Driver.h @@ -0,0 +1,57 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Driver.h + +Abstract: + + Driver object callbacks, functions, and types. + +Environment: + + Kernel-mode. + +--*/ + +#pragma once + + +EXTERN_C DRIVER_INITIALIZE INIT_CODE_SEG DriverEntry; + +namespace UcmUcsiAcpiClient +{ + +#define TEST_BIT(value, bitNumber) ((value) & (1<<(bitNumber))) ? true : false + +class Driver +{ +public: + + static + DRIVER_INITIALIZE + INIT_CODE_SEG + CreateAndInitialize; + + static const ULONG c_PoolTag = 'ISCU'; + + Driver () = delete; + + ~Driver () = delete; + +private: + + static + EVT_WDF_DRIVER_DEVICE_ADD + PAGED_CODE_SEG + EvtDriverDeviceAddThunk; + + static + EVT_WDF_DRIVER_UNLOAD + PAGED_CODE_SEG + EvtDriverUnloadThunk; +}; + +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Fdo.cpp b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Fdo.cpp new file mode 100644 index 00000000..2b01bb02 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Fdo.cpp @@ -0,0 +1,387 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Fdo.cpp + +Abstract: + + FDO callbacks, functions, and types. + +Environment: + + Kernel-mode. + +--*/ + +#include "Pch.h" +#include "Fdo.tmh" + +namespace UcmUcsiAcpiClient +{ + +PAGED_CODE_SEG +NTSTATUS +Fdo::CreateAndInitialize ( + PWDFDEVICE_INIT DeviceInit + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + PAGED_CODE(); + + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attrib; + WDFDEVICE device; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + Fdo* fdo; + + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDevicePrepareHardware = Fdo::EvtDevicePrepareHardwareThunk; + pnpPowerCallbacks.EvtDeviceReleaseHardware = Fdo::EvtDeviceReleaseHardwareThunk; + pnpPowerCallbacks.EvtDeviceD0Entry = Fdo::EvtDeviceD0EntryThunk; + pnpPowerCallbacks.EvtDeviceD0Exit = Fdo::EvtDeviceD0ExitThunk; + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + status = UcmUcsiDeviceInitInitialize(DeviceInit); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_FDO, "[PWDFDEVICE_INIT: 0x%p] UcmUcsiDeviceInitInitialize failed - " + "%!STATUS!", DeviceInit, status); + goto Exit; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, Fdo); + Fdo::ObjectAttributesInit(&attrib); + + status = WdfDeviceCreate(&DeviceInit, &attrib, &device); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_FDO, "[PWDFDEVICE_INIT: 0x%p] WdfDeviceCreate failed - %!STATUS!", + DeviceInit, status); + goto Exit; + } + + fdo = new (GetFdoFromWdfDevice(device)) Fdo(device); + + status = fdo->Initialize(); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); + return status; +} + +Fdo* +Fdo::GetContextFromObject ( + WDFDEVICE WdfDevice + ) +{ + return GetFdoFromWdfDevice(WdfDevice); +} + +Fdo::Fdo ( + WDFDEVICE WdfDevice + ): + ObjectContext(WdfDevice) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Fdo constructed", GetObjectHandle()); + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); +} + +Fdo::~Fdo () +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Fdo destroy", GetObjectHandle()); + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); +} + +void +Fdo::EvtObjectContextCleanup () +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Fdo cleanup", GetObjectHandle()); + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); +} + +PAGED_CODE_SEG +NTSTATUS +Fdo::Initialize () +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + PAGED_CODE(); + + NTSTATUS status; + WDF_DEVICE_STATE deviceState; + WDFDEVICE device; + UCMUCSI_DEVICE_CONFIG config; + + device = GetObjectHandle(); + + UCMUCSI_DEVICE_CONFIG_INIT(&config); + status = UcmUcsiDeviceInitialize(device, &config); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] UcmUcsiDeviceInitialize failed - %!STATUS!", + device, status); + goto Exit; + } + + WDF_DEVICE_STATE_INIT(&deviceState); + deviceState.NotDisableable = WdfFalse; + WdfDeviceSetDeviceState(device, &deviceState); + + status = m_Acpi.Initialize(GetObjectHandle()); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] ACPI initialize failed - %!STATUS!", + device, status); + goto Exit; + } + + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Fdo initialized", device); + status = STATUS_SUCCESS; + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); + return status; +} + +Acpi* +Fdo::GetAcpiObject() +{ + return &m_Acpi; +} + +PAGED_CODE_SEG +NTSTATUS +Fdo::EvtDevicePrepareHardwareThunk ( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourcesRaw, + _In_ WDFCMRESLIST ResourcesTranslated + ) +{ + PAGED_CODE(); + + return Fdo::GetContextFromObject(Device)->EvtDevicePrepareHardware(ResourcesRaw, + ResourcesTranslated); +} + +PAGED_CODE_SEG +NTSTATUS +Fdo::EvtDevicePrepareHardware ( + WDFCMRESLIST ResourcesRaw, + WDFCMRESLIST ResourcesTranslated + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + PAGED_CODE(); + + NTSTATUS status; + WDFDEVICE device; + Acpi::CONFIG ucsiAcpiConfig; + ULONG index; + ULONG resourceCount; + bool allResourcesFound; + PCM_PARTIAL_RESOURCE_DESCRIPTOR res; + PCM_PARTIAL_RESOURCE_DESCRIPTOR rawRes; + + device = GetObjectHandle(); + + resourceCount = WdfCmResourceListGetCount(ResourcesTranslated); + allResourcesFound = false; + + for (index = 0; !allResourcesFound && (index < resourceCount); ++index) + { + res = WdfCmResourceListGetDescriptor(ResourcesTranslated, index); + if (res->Type != CmResourceTypeMemory) + { + continue; + } + + rawRes = WdfCmResourceListGetDescriptor(ResourcesRaw, index); + + // + // Verify if address is below 4GB and not straddling the 4GB boundary. + // + + if ((rawRes->u.Memory.Start.HighPart != 0) || + ((rawRes->u.Memory.Start.LowPart + rawRes->u.Memory.Length) < + rawRes->u.Memory.Start.LowPart)) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TRACE_ERROR(TRACE_FLAG_FDO, "[Device: 0x%p] Memory resource address (%I64x) not below 4GB", + device, rawRes->u.Memory.Start.QuadPart); + goto Exit; + } + + ucsiAcpiConfig.DataBlockAddress = res->u.Memory.Start; + ucsiAcpiConfig.DataBlockLength = res->u.Memory.Length; + + // prepare hardware for ACPI transport using the resources. + status = m_Acpi.PrepareHardware(&ucsiAcpiConfig); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[Device: 0x%p] ACPI Prepare hardware failed", device); + goto Exit; + } + + // This is a good time to create the PPM object with the Cx. + status = Ppm::CreateAndInitialize(this, &m_Ppm); + if (!NT_SUCCESS(status)) + { + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] PPM CreateAndInitialize Failed with %!STATUS!", + device, status); + goto Exit; + } + + allResourcesFound = true; + } + + if (allResourcesFound == false) + { + status = STATUS_INSUFFICIENT_RESOURCES; + TRACE_ERROR(TRACE_FLAG_FDO, "[Device: 0x%p] Could not find required resources", device); + goto Exit; + } + + status = m_Ppm->PrepareHardware(); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[Device: 0x%p] PPM prepare hardware failed with %!STATUS!", + device, status); + goto Exit; + } + + status = STATUS_SUCCESS; + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Fdo Prepare Hardware completed", device); + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); + return status; +} + + +PAGED_CODE_SEG +NTSTATUS +Fdo::EvtDeviceReleaseHardwareThunk ( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourcesTranslated + ) +{ + PAGED_CODE(); + + return Fdo::GetContextFromObject(Device)->EvtDeviceReleaseHardware(ResourcesTranslated); +} + + +PAGED_CODE_SEG +NTSTATUS +Fdo::EvtDeviceReleaseHardware ( + WDFCMRESLIST /* ResourcesTranslated */ + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + PAGED_CODE(); + + WDFDEVICE device = GetObjectHandle(); + + if (m_Ppm) + { + m_Ppm->ReleaseHardware(); + DestroyPpmObject(); + } + + m_Acpi.ReleaseHardware(); + + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Fdo Release Hardware completed", device); + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); + return STATUS_SUCCESS; +} + + +NTSTATUS +Fdo::EvtDeviceD0EntryThunk ( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE PreviousState + ) +{ + Fdo* fdo = Fdo::GetContextFromObject(Device); + return fdo->EvtDeviceD0Entry(PreviousState); +} + + +NTSTATUS +Fdo::EvtDeviceD0Entry ( + WDF_POWER_DEVICE_STATE PreviousState + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + + WDFDEVICE device = GetObjectHandle(); + + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Entering D0 from %!WDF_POWER_DEVICE_STATE!", + device, PreviousState); + + (VOID)m_Ppm->TurnOnPpmNotification(); + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); + return STATUS_SUCCESS; +} + +NTSTATUS +Fdo::EvtDeviceD0ExitThunk ( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE TargetState + ) +{ + Fdo* fdo = Fdo::GetContextFromObject(Device); + return fdo->EvtDeviceD0Exit(TargetState); +} + +NTSTATUS +Fdo::EvtDeviceD0Exit ( + WDF_POWER_DEVICE_STATE TargetState + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + + WDFDEVICE device = GetObjectHandle(); + + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Exiting D0 to %!WDF_POWER_DEVICE_STATE!", + device, TargetState); + + m_Ppm->TurnOffPpmNotification(); + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +VOID +Fdo::DestroyPpmObject() +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_FDO); + + WDFDEVICE device = GetObjectHandle(); + + TRACE_INFO(TRACE_FLAG_FDO, "[WDFDEVICE: 0x%p] Destroying UCMUCSIPPM object: 0x%p", + device, m_Ppm->GetObjectHandle()); + + WdfObjectDelete(m_Ppm->GetObjectHandle()); + m_Ppm = nullptr; + + TRACE_FUNC_EXIT(TRACE_FLAG_FDO); +} + +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Fdo.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Fdo.h new file mode 100644 index 00000000..dbed761d --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Fdo.h @@ -0,0 +1,138 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Fdo.h + +Abstract: + + The class defines the context attached to the FDO. It manages lifetime for + the PPM transport (ACPI in this case) and PPM object that it creates with + the class entension. + +Environment: + + Kernel-mode. + +--*/ + +#pragma once + +#include "ProjectCommon.h" + + +namespace UcmUcsiAcpiClient +{ + +class Ppm; + +class Fdo: public WdfCpp::ObjectContext<WDFDEVICE, Fdo> +{ +public: + + static + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + CreateAndInitialize ( + _Inout_ PWDFDEVICE_INIT DeviceInit + ); + + static + GET_CONTEXT_FROM_OBJECT + GetContextFromObject; + + // Since FDO owns the transport, we need a getter to get the object. + Acpi* + GetAcpiObject(); + +private: + + friend class WdfCpp::ObjectContext<WDFDEVICE, Fdo>; + + Fdo ( + _In_ WDFDEVICE WdfDevice + ); + + ~Fdo (); + + Fdo& + operator= ( + _In_ const Fdo& + ) = delete; + + Fdo ( + _In_ const Fdo& + ) = delete; + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Initialize (); + + EVT_OBJECT_CONTEXT_CLEANUP + EvtObjectContextCleanup; + + static + EVT_WDF_DEVICE_PREPARE_HARDWARE + PAGED_CODE_SEG + EvtDevicePrepareHardwareThunk; + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + EvtDevicePrepareHardware ( + _In_ WDFCMRESLIST ResourcesRaw, + _In_ WDFCMRESLIST ResourcesTranslated + ); + + static + EVT_WDF_DEVICE_RELEASE_HARDWARE + PAGED_CODE_SEG + EvtDeviceReleaseHardwareThunk; + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + EvtDeviceReleaseHardware ( + _In_ WDFCMRESLIST ResourcesTranslated + ); + + static + EVT_WDF_DEVICE_D0_ENTRY + EvtDeviceD0EntryThunk; + + _IRQL_requires_max_(PASSIVE_LEVEL) + NTSTATUS + EvtDeviceD0Entry ( + _In_ WDF_POWER_DEVICE_STATE PreviousState + ); + + static + EVT_WDF_DEVICE_D0_EXIT + EvtDeviceD0ExitThunk; + + _IRQL_requires_max_(PASSIVE_LEVEL) + NTSTATUS + EvtDeviceD0Exit ( + _In_ WDF_POWER_DEVICE_STATE TargetState + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + DestroyPpmObject(); + + // FDO own the transport because it needs to talk to PPM firmware even before + // UCMUCSIPPM object is created with UCSI Cx. + Acpi m_Acpi; + + Ppm* m_Ppm; + +}; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(Fdo, GetFdoFromWdfDevice); + +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/MemoryKm.cpp b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/MemoryKm.cpp new file mode 100644 index 00000000..bec3f00e --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/MemoryKm.cpp @@ -0,0 +1,60 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + MemoryKm.cpp + +Abstract: + + Memory allocation and delete definitions + +Environment: + + Kernel-mode. + +--*/ + +#include "Pch.h" + +#ifdef _KERNEL_MODE + +void +__cdecl +operator delete( + void* memory + ) noexcept +{ + ExFreePoolWithTag(memory, TAG_UCSI); +} + +void +__cdecl +operator delete[]( + void* memory + ) noexcept +{ + ExFreePoolWithTag(memory, TAG_UCSI); +} + +void* +__cdecl +operator new ( + size_t size + ) +{ + return ExAllocatePoolWithTag(NonPagedPoolNx, size, TAG_UCSI); +} + +void* +__cdecl +operator new[] ( + size_t size + ) +{ + return ExAllocatePoolWithTag(NonPagedPoolNx, size, TAG_UCSI); + +} + +#endif diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Pch.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Pch.h new file mode 100644 index 00000000..c5b94993 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Pch.h @@ -0,0 +1,41 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Pch.h + +Abstract: + + Precompiled header. + +Environment: + + Kernel-mode only. + +--*/ + +#pragma once + +#define TAG_UCSI 'cAcU' + +#include <initguid.h> +#include <ntddk.h> +#include <wdmguid.h> +#include <wdf.h> +#include <intsafe.h> +#include <ntstrsafe.h> +#include <acpiioct.h> +#include <acpitabl.h> + +#include <UcmUcsi\1.0\UcmucsiCx.h> +#include <UCm\1.0\UcmCx.h> + +#include "UCM.h" +#include "ProjectCommon.h" +#include "Trace.h" +#include "Driver.h" +#include "Acpi.h" +#include "Fdo.h" +#include "Ppm.h" diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Ppm.cpp b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Ppm.cpp new file mode 100644 index 00000000..8b2a5fe5 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Ppm.cpp @@ -0,0 +1,571 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Ppm.cpp + +Abstract: + + Platform Policy Manager functions + +Environment: + + Kernel-mode. + +--*/ + +#include "Pch.h" +#ifndef __INTELLISENSE__ +#include "Ppm.tmh" +#endif + +namespace UcmUcsiAcpiClient +{ + +const ULONG UCSI_EXPECTED_NOTIFY_CODE = 0x80; + +PAGED_CODE_SEG +NTSTATUS +Ppm::CreateAndInitialize( + Fdo *Device, + Ppm **PpmObject + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + PAGED_CODE(); + + NTSTATUS status; + UCMUCSI_PPM_CONFIG ucsiPpmConfig; + WDFDEVICE wdfDevice = Device->GetObjectHandle(); + UCMUCSIPPM ppmObject = WDF_NO_HANDLE; + WDF_OBJECT_ATTRIBUTES attrib; + Ppm* ppm; + + status = PreparePpmConfig(Device, &ucsiPpmConfig); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[Device: 0x%p] prepare PPM config failed with %!STATUS!", + Device->GetObjectHandle(), status); + goto Exit; + } + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attrib, Ppm); + Ppm::ObjectAttributesInit(&attrib); + status = UcmUcsiPpmCreate(wdfDevice, &ucsiPpmConfig, &attrib, &ppmObject); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] UcmUCsiPpmCreate failed %!STATUS!", + wdfDevice, status); + goto Exit; + } + + ppm = new (GetAcpiPpmFromUcmUcsiPpm(ppmObject)) Ppm(ppmObject); + + status = ppm->Initialize(Device); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + *PpmObject = ppm; + status = STATUS_SUCCESS; + +Exit: + return status; +} + +Ppm::Ppm( + UCMUCSIPPM PpmObject + ) :ObjectContext(PpmObject) +{ +} + +Ppm* +Ppm::GetContextFromObject ( + UCMUCSIPPM PpmObject + ) +{ + return GetAcpiPpmFromUcmUcsiPpm(PpmObject); +} + +PAGED_CODE_SEG +void +Ppm::PpmNotificationCallbackThunk( + Ppm* PpmObject, + ULONG NotifyValue +) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + PAGED_CODE(); + + PpmObject->PpmNotificationCallback(NotifyValue); + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + + +PAGED_CODE_SEG +NTSTATUS +Ppm::Initialize( + Fdo* FdoObject + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + PAGED_CODE(); + + NTSTATUS status; + WDFDEVICE device = FdoObject->GetObjectHandle(); + WDF_OBJECT_ATTRIBUTES attrib; + WDF_IO_QUEUE_CONFIG queueConfig; + + m_Device = FdoObject; + m_Acpi = FdoObject->GetAcpiObject(); + + WDF_OBJECT_ATTRIBUTES_INIT(&attrib); + attrib.ParentObject = GetObjectHandle(); + + // @@BEGIN_NOTPUBLICCODE + // Making the queue parallel dispatch should not make a difference since the Cx guarantees that + // it will not send another request until the previous one has been completed. + // @@END_NOTPUBLICCODE + + WDF_IO_QUEUE_CONFIG_INIT(&queueConfig, WdfIoQueueDispatchParallel); + + // Has to be power managed as per Cx requirements. + queueConfig.PowerManaged = WdfTrue; + queueConfig.EvtIoDeviceControl = Ppm::EvtIoDeviceControlThunk; + status = WdfIoQueueCreate(device, &queueConfig, &attrib, &m_UcsiCommandRequestQueue); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] WdfIoQueueCreate " + "for UCSI Command request queue failed - %!STATUS!", m_Device->GetObjectHandle(), status); + goto Exit; + } + + UcmUcsiPpmSetUcsiCommandRequestQueue(GetObjectHandle(), m_UcsiCommandRequestQueue); + + status = STATUS_SUCCESS; + +Exit: + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Ppm::PreparePpmConfig( + Fdo* FdoObject, + PUCMUCSI_PPM_CONFIG UcsiPpmConfig + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + NTSTATUS status; + bool IsUsbDeviceControllerEnabled; + Acpi* acpiObject; + UCMUCSI_CONNECTOR_COLLECTION connectorInfoCollection; + + acpiObject = FdoObject->GetAcpiObject(); + // @@BEGIN_NOTPUBLICCODE + // TODO: This should probably be done by the Cx, because this is a standard mechanism + // that any type of UCM would use. + // @@END_NOTPUBLICCODE + + status = QueryConnectorsAndInitCollection(FdoObject, &connectorInfoCollection); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + UCMUCSI_PPM_CONFIG_INIT(UcsiPpmConfig, connectorInfoCollection); + + status = acpiObject->CheckIfUsbDeviceControllerIsEnabled(IsUsbDeviceControllerEnabled); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + UcsiPpmConfig->UsbDeviceControllerEnabled = IsUsbDeviceControllerEnabled; + + if (IsUsbDeviceControllerEnabled) + { + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] USB Device Controller is enabled", FdoObject->GetObjectHandle()); + } + else + { + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] USB Device Controller is disabled", FdoObject->GetObjectHandle()); + } + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Ppm::PrepareHardware() +{ + NTSTATUS status; + + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + // Placeholder. Nothing to do here as of now. + + status = STATUS_SUCCESS; + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); + return status; +} + +PAGED_CODE_SEG +VOID +Ppm::ReleaseHardware() +{ + PAGED_CODE(); + + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + // No action needed here from the client driver. + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +PAGED_CODE_SEG +NTSTATUS +Ppm::QueryConnectorsAndInitCollection ( + _In_ Fdo* FdoObject, + _Out_ UCMUCSI_CONNECTOR_COLLECTION* ConnectorCollectionHandle + ) +{ + NTSTATUS status; + WDFDEVICE device; + WDFMEMORY enumChildrenMem; + PACPI_ENUM_CHILDREN_OUTPUT_BUFFER enumChildrenBuf; + PACPI_ENUM_CHILD enumChild; + ACPI_PLD_BUFFER pldBuffer; + ULONG64 connectorId; + ULONG i; + ULONG numConnectors; + Acpi* acpiObject; + UCMUCSI_CONNECTOR_INFO connectorInfo; + + PAGED_CODE(); + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + numConnectors = 0; + enumChildrenMem = WDF_NO_HANDLE; + device = FdoObject->GetObjectHandle(); + acpiObject = FdoObject->GetAcpiObject(); + + // Cx would parent the collection object to the device object anyway. So no need + // to parent the collection object here. + status = UcmUcsiConnectorCollectionCreate(FdoObject->GetObjectHandle(), + WDF_NO_OBJECT_ATTRIBUTES, + ConnectorCollectionHandle); + if (!NT_SUCCESS(status)) + { + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] UcmUcsiConnectorCollectionCreate failed with status %!STATUS!", + FdoObject->GetAcpiObject(), status); + goto Exit; + } + + status = acpiObject->EnumChildren(&enumChildrenMem); + if (!NT_SUCCESS(status)) + { + goto Exit; + } + + enumChildrenBuf = (PACPI_ENUM_CHILDREN_OUTPUT_BUFFER) WdfMemoryGetBuffer (enumChildrenMem, nullptr); + + // If there is only one child, which is this device itself, then there is no connector + // information available. Assume there is only one connector. + if (enumChildrenBuf->NumberOfChildren == 1) + { + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] Connector information not found. Assuming single-connector system", device); + + UCMUCSI_CONNECTOR_INFO_INIT(&connectorInfo); + connectorInfo.ConnectorId = 0; + + status = UcmUcsiConnectorCollectionAddConnector(*ConnectorCollectionHandle, &connectorInfo); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[Device: 0x%p] UcmUcsiConnectorCollectionAddConnector Failed with status %!STATUS!", + FdoObject->GetObjectHandle(), status); + goto Exit; + } + } + else + { + enumChild = enumChildrenBuf->Children; + for (i = 1; i < enumChildrenBuf->NumberOfChildren; ++i) + { + enumChild = ACPI_ENUM_CHILD_NEXT(enumChild); + + // + // Connectors are child devices that have a _PLD method. Skip any children + // that don't have any children, and attempt to evaluate _PLD on the ones that do. + // + + if ((enumChild->Flags & ACPI_OBJECT_HAS_CHILDREN) == 0) + { + continue; + } + + status = acpiObject->EvaluatePld(enumChild->Name, &pldBuffer); + if (!NT_SUCCESS(status)) + { + continue; + } + + connectorId = UCM_CONNECTOR_ID_FROM_ACPI_PLD(&pldBuffer); + + UCMUCSI_CONNECTOR_INFO_INIT(&connectorInfo); + connectorInfo.ConnectorId = connectorId; + + status = UcmUcsiConnectorCollectionAddConnector(*ConnectorCollectionHandle, &connectorInfo); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[Device: 0x%p] UcmUcsiConnectorCollectionAddConnector Failed with status %!STATUS!", + FdoObject->GetObjectHandle(), status); + goto Exit; + } + + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] Found connector %s with ID 0x%I64x", device, enumChild->Name, connectorId); + + numConnectors++; + } + } + + TRACE_INFO(TRACE_FLAG_PPM, "[Device: 0x%p] Found %lu connectors", device, numConnectors); + +Exit: + + if (enumChildrenMem != WDF_NO_HANDLE) + { + WdfObjectDelete(enumChildrenMem); + } + + if (!NT_SUCCESS(status) && *ConnectorCollectionHandle != WDF_NO_HANDLE) + { + WdfObjectDelete(*ConnectorCollectionHandle); + *ConnectorCollectionHandle = WDF_NO_HANDLE; + } + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Ppm::TurnOnPpmNotification() +{ + NTSTATUS status; + ACPI_NOTIFICATION_CALLBACK_CONTEXT callbackConext; + + PAGED_CODE(); + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + callbackConext.m_PpmObject = this; + callbackConext.m_CallbackFunction = PpmNotificationCallbackThunk; + status = m_Acpi->RegisterNotificationCallback(&callbackConext); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Registering for ACPI notifications failed - %!STATUS!", + GetOwningDevice(), status); + } + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); + return status; +} + + +PAGED_CODE_SEG +VOID +Ppm::TurnOffPpmNotification() +{ + PAGED_CODE(); + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + m_Acpi->UnRegisterNotificationCallback(); + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +PAGED_CODE_SEG +VOID +Ppm::PpmNotificationCallback( + ULONG NotifyValue + ) +{ + PAGED_CODE(); + if (NotifyValue != UCSI_EXPECTED_NOTIFY_CODE) + { + TRACE_WARN(TRACE_FLAG_PPM, "[Device: 0x%p] Unexpected notify code %lu", + GetOwningDevice(), NotifyValue); + goto Exit; + } + + UcmUcsiPpmNotification(GetObjectHandle(), m_Acpi->GetUcsiDataBlock()); + +Exit: + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +VOID +Ppm::EvtIoDeviceControlThunk ( + WDFQUEUE Queue, + WDFREQUEST Request, + size_t /* OutputBufferLength */, + size_t /* InputBufferLength */, + ULONG IoControlCode + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + NTSTATUS status; + + WDFDEVICE device = WdfIoQueueGetDevice(Queue); + UCMUCSIPPM* ucmUcsiPpmPtr; + Ppm* ppm; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(*ucmUcsiPpmPtr), + reinterpret_cast<PVOID*>(&ucmUcsiPpmPtr), nullptr); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] IOCTL with code " + "%!UCMUCSI_PPM_IOCTL! did not have input buffer of minimum expected size - " + "%!STATUS!", device, IoControlCode, status); + goto Exit; + } + + ppm = Ppm::GetContextFromObject(*ucmUcsiPpmPtr); + + ppm->EvtIoDeviceControl(Request, IoControlCode); + +Exit: + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +void +Ppm::EvtIoDeviceControl( + _In_ WDFREQUEST Request, + _In_ ULONG IoControlCode + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + NTSTATUS status; + + TRACE_INFO(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] Received " + "%!UCMUCSI_PPM_IOCTL!", m_Device->GetObjectHandle(), IoControlCode); + + switch (IoControlCode) + { + case IOCTL_UCMUCSI_PPM_SEND_UCSI_DATA_BLOCK: + EvtSendData(Request); + break; + + case IOCTL_UCMUCSI_PPM_GET_UCSI_DATA_BLOCK: + EvtReceiveData(Request); + break; + + default: + TRACE_INFO(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] Unrecognized IOCTL " + "%!UCMUCSI_PPM_IOCTL!", m_Device->GetObjectHandle(), IoControlCode); + status = STATUS_NOT_SUPPORTED; + goto Exit; + } + + status = STATUS_SUCCESS; + +Exit: + + if (!NT_SUCCESS(status)) + { + WdfRequestComplete(Request, status); + } + + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +PAGED_CODE_SEG +VOID +Ppm::EvtSendData( + WDFREQUEST Request + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + NTSTATUS status; + PUCMUCSI_PPM_SEND_UCSI_DATA_BLOCK_IN_PARAMS inParams; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(*inParams), + reinterpret_cast<PVOID*>(&inParams), nullptr); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] WdfRequestRetrieveInputBuffer failed - %!STATUS!", + m_Device->GetObjectHandle(), status); + goto Exit; + } + + status = m_Acpi->SendData(&inParams->UcmUcsiDataBlock); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] ACPI Send failed- %!STATUS!", + m_Device->GetObjectHandle(), status); + goto Exit; + } + +Exit: + WdfRequestComplete(Request, status); + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +PAGED_CODE_SEG +VOID +Ppm::EvtReceiveData( + WDFREQUEST Request + ) +{ + TRACE_FUNC_ENTRY(TRACE_FLAG_PPM); + + NTSTATUS status; + + PUCMUCSI_PPM_GET_UCSI_DATA_BLOCK_IN_PARAMS inParams; + PUCMUCSI_PPM_GET_UCSI_DATA_BLOCK_OUT_PARAMS outParams; + + status = WdfRequestRetrieveInputBuffer(Request, sizeof(*inParams), + reinterpret_cast<PVOID*>(&inParams), nullptr); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] WdfRequestRetrieveInputBuffer failed - %!STATUS!", + m_Device->GetObjectHandle(), status); + goto Exit; + } + + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(*outParams), + reinterpret_cast<PVOID*>(&outParams), nullptr); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] WdfRequestRetrieveOutputBuffer failed - %!STATUS!", + m_Device->GetObjectHandle(), status); + goto Exit; + } + + status = m_Acpi->ReceiveData(&outParams->UcmUcsiDataBlock); + if (!NT_SUCCESS(status)) + { + TRACE_ERROR(TRACE_FLAG_PPM, "[WDFDEVICE: 0x%p] ACPI Send failed- %!STATUS!", + m_Device->GetObjectHandle(), status); + goto Exit; + } + WdfRequestSetInformation(Request, sizeof(*outParams)); + +Exit: + WdfRequestComplete(Request, status); + TRACE_FUNC_EXIT(TRACE_FLAG_PPM); +} + +}
\ No newline at end of file diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Ppm.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Ppm.h new file mode 100644 index 00000000..340ab8c2 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Ppm.h @@ -0,0 +1,166 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Ppm.h + +Abstract: + + This class contaisn the contexts and methods necessary to interact with UCMUCSIPPM object + which is created with the class extension. + +Environment: + + Kernel-mode. + +--*/ + +#pragma once + +#include "ProjectCommon.h" + +namespace UcmUcsiAcpiClient +{ + +class Ppm :public WdfCpp::ObjectContext<UCMUCSIPPM, Ppm> +{ +public: + + static + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + CreateAndInitialize ( + _In_ Fdo* FdoObject, + _Deref_out_ Ppm** PpmObject + ); + + static + GET_CONTEXT_FROM_OBJECT + GetContextFromObject; + + static + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + EVT_ACPI_NOTIFICATION_CALLBACK + PpmNotificationCallbackThunk; + + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware (); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + ReleaseHardware (); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + TurnOnPpmNotification(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + TurnOffPpmNotification(); + + _IRQL_requires_max_(DISPATCH_LEVEL) + PAGED_CODE_SEG + VOID + PpmNotificationCallback( + _In_ ULONG NotifyValue + ); + + static + EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL + EvtIoDeviceControlThunk; + + void + EvtIoDeviceControl( + _In_ WDFREQUEST Request, + _In_ ULONG IoControlCode + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + EvtSendData( + _In_ WDFREQUEST Request + ); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + EvtReceiveData( + _In_ WDFREQUEST Request + ); + +private: + friend class WdfCpp::ObjectContext<UCMUCSIPPM, Ppm>; + + typedef struct _PPM_CONFIG + { + WDFMEMORY WdfObject; + UCMUCSI_PPM_CONFIG UcsiPpmConfig; + } PPM_CONFIG, *PPPM_CONFIG; + + Ppm (_In_ UCMUCSIPPM UcmUcsiPpm); + + ~Ppm() = default; + + Ppm(_In_ const Ppm&) = delete; + Ppm& operator =(_In_ const Ppm&) = delete; + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Initialize ( + _In_ Fdo* FdoObject + ); + + // This method needs to be static because we need to query connectors + // even before we have initialized PPM object with the Cx. + static + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + QueryConnectorsAndInitCollection( + _In_ Fdo* FdoObject, + _Out_ UCMUCSI_CONNECTOR_COLLECTION* ConnectorCollectionHandle + ); + + static + PAGED_CODE_SEG + NTSTATUS + PreparePpmConfig( + _In_ Fdo* FdoObject, + _Out_ PUCMUCSI_PPM_CONFIG UcsiPpmConfig + ); + + FORCEINLINE + WDFDEVICE + GetOwningDevice() + { + UCMUCSI_ASSERT(m_Device); + return m_Device->GetObjectHandle(); + } + + // Pointer to the owning WDFDEVICE. + Fdo* m_Device = nullptr; + + // Queue that is registered with the Cx for receiving UCSI Commands. + WDFQUEUE m_UcsiCommandRequestQueue = WDF_NO_HANDLE; + + // PPM Transport + Acpi* m_Acpi; + + bool m_IsUsbDeviceControllerEnabled = false; +}; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(Ppm, GetAcpiPpmFromUcmUcsiPpm); + +}
\ No newline at end of file diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/ProjectCommon.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/ProjectCommon.h new file mode 100644 index 00000000..2251fdfc --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/ProjectCommon.h @@ -0,0 +1,235 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + ProjectCommon.h + +Abstract: + + Common routines, types, macros, etc., for the UCM-UCSI project. + +Environment: + + Kernel-mode. + +--*/ + +#pragma once + +// Code section placement macros. + +#define PAGED_CODE_SEG __declspec(code_seg("PAGE")) +#define INIT_CODE_SEG __declspec(code_seg("INIT")) + +// The above macros are more convenient to use, but use these instead if for some reason the +// functions can't be declared as paged/non-paged, e.g., if the function is virtual and it doesn't +// make sense for the overridden function to be declared paged/non-paged. + +#define PAGED_CODE_SEG_BEGIN \ + __pragma(code_seg(push)) \ + __pragma(code_seg("PAGE")) + +#define PAGED_CODE_SEG_END \ + __pragma(code_seg(pop)) + +// Custom assert macros that: +// - behave like NT_ASSERT for chk binaries +// - break into verifier if it is enabled, regardless of whether binary is chk or fre. +// +// The expression will *not* be evaluated if a failure will not cause a break, i.e., if not chk +// binary and verifier is not enabled. However, the code expression will always be compiled into the code. + +#if DBG + +#define UCMUCSI_ASSERTMSG(_exp, _msg) \ + __pragma(warning(suppress: __WARNING_TRUE_CONSTANT_EXPR_IN_AND)) \ + NT_VERIFYMSG(_msg, _exp) + +#define UCMUCSI_ASSERT(_exp) \ + __pragma(warning(suppress: __WARNING_TRUE_CONSTANT_EXPR_IN_AND)) \ + NT_VERIFY(_exp) + +#else // #if DBG + +#define UCMUCSI_ASSERTMSG(_exp, _msg) \ + __pragma(warning(suppress: __WARNING_TRUE_CONSTANT_EXPR_IN_AND)) \ + WDFVERIFY(_exp) + +#define UCMUCSI_ASSERT(_exp) \ + __pragma(warning(suppress: __WARNING_TRUE_CONSTANT_EXPR_IN_AND)) \ + WDFVERIFY(_exp) + +#endif // #if DBG + + +// Intellisense definition for DbgRaiseAssertionFailure because for some reason Visual Studio can't +// find it. +#ifdef __INTELLISENSE__ +#define DbgRaiseAssertionFailure() ((void) 0) +#endif + + +namespace WdfCpp +{ + +// General note: The class(es) below use SFINAE to set the object callbacks only if the derived +// class has methods with specific names. + +// Templatized base class for creating C++ objects within the context-space of a WDFOBJECT. +template< + typename ObjectType, // The underlying WDF object type (e.g., WDFDEVICE). + typename ContextType // The context class type that derives from this. + > +class ObjectContext +{ +public: + + using HandleType = ObjectType; + + // Typedef for an object cleanup method. If you want to override the cleanup callback for + // the WDF object, provide a method in the derived class with this type and name + // "EvtObjectContextCleanup". You can omit it if you don't want to override cleanup. + typedef + _IRQL_requires_max_(DISPATCH_LEVEL) + void + EVT_OBJECT_CONTEXT_CLEANUP (); + + // Provide a method of this type and name "GetContextFromObject" in the derived class. The + // implementation of this method would typically just call the context accessor method that + // WDF defines for you. This is required; code will fail to compile if you do not provide this + // method. + typedef + ContextType* + GET_CONTEXT_FROM_OBJECT ( + _In_ ObjectType Object + ); + + ObjectContext& + operator= ( + _In_ const ObjectContext& + ) = delete; + + ObjectContext ( + _In_ const ObjectContext& + ) = delete; + + // Call this static method to set the callback pointers in the WDF_OBJECT_ATTRIBUTES after it + // has been initialized with WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE. + static + void + ObjectAttributesInit ( + _Inout_ PWDF_OBJECT_ATTRIBUTES Attributes + ) + { + SetEvtObjectContextCleanup(Attributes, true); + Attributes->EvtDestroyCallback = &EvtObjectContextDestroyThunk; + } + + ObjectType + GetObjectHandle () + { + return m_Object; + } + +protected: + + ObjectContext ( + _In_ ObjectType WdfObject + ) : + m_Object(WdfObject) + { + } + + // Note that this is not virtual since we are using CRTP and hence know the exact derived + // type statically. + ~ObjectContext () = default; + + // Placement-new to construct the object inside the WDF context space. + static + void* + operator new ( + _In_ size_t /* SizeInBytes */, + _In_ void* ContextMemory + ) + { + // We already have the memory courtesy of WDF so we don't have to allocate anything. + return ContextMemory; + } + + static + void + operator delete ( + _In_ void* /* ContextMemory */ + ) + { + // Since we didn't allocate the memory, don't try to deallocate it. + } + +private: + + // This method overload will get picked if the derived class has an "EvtObjectContextCleanup" + // method. If it doesn't SFINAE will cause this overload to get discarded. The return type + // exists simply to trigger SFINAE; we don't actually return anything useful. The second dummy + // bool parameter exists simply to give this overload precendence over the next one when called + // with a bool value. + template<typename U = ContextType> + static + decltype(&U::EvtObjectContextCleanup) + SetEvtObjectContextCleanup ( + _Inout_ PWDF_OBJECT_ATTRIBUTES Attributes, + _In_ bool /* OverloadDisambiguator */ + ) + { + Attributes->EvtCleanupCallback = &EvtObjectContextCleanupThunk; + return nullptr; + } + + // This method overload will get picked if the derived class does not have an + // "EvtObjectContextCleanup" method. + template<typename U = ContextType> + static + void + SetEvtObjectContextCleanup ( + _Inout_ PWDF_OBJECT_ATTRIBUTES /* Attributes */, + _In_ int /* OverloadDisambiguator */ + ) + { + } + + static + EVT_WDF_OBJECT_CONTEXT_DESTROY + EvtObjectContextDestroyThunk; + + static + EVT_WDF_OBJECT_CONTEXT_CLEANUP + EvtObjectContextCleanupThunk; + + ObjectType m_Object; +}; + +template<typename ObjectType, typename ContextType> +inline +VOID +ObjectContext<ObjectType, ContextType>::EvtObjectContextDestroyThunk ( + WDFOBJECT Object + ) +{ + // Invoke the destructor by calling delete. + ContextType* context = ContextType::GetContextFromObject(static_cast<ObjectType>(Object)); + delete context; +} + +template<typename ObjectType, typename ContextType> +inline +VOID +ObjectContext<ObjectType, ContextType>::EvtObjectContextCleanupThunk ( + WDFOBJECT Object + ) +{ + ContextType* context = ContextType::GetContextFromObject(static_cast<ObjectType>(Object)); + context->EvtObjectContextCleanup(); +} + +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Trace.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Trace.h new file mode 100644 index 00000000..fe90c35a --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/Trace.h @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Trace.h + +Abstract: + + WPP tracing definitions. + +Environment: + + Kernel-mode. + +--*/ + +// +// Tracing GUID - {EDEF8E04-4E22-4A95-9D04-539EBD112A5E} +// + +#pragma once + + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + UcmUcsiAcpiClient, (EDEF8E04,4E22,4A95,9D04,539EBD112A5E), \ + WPP_DEFINE_BIT(TRACE_FLAG_DRIVER) \ + WPP_DEFINE_BIT(TRACE_FLAG_FDO) \ + WPP_DEFINE_BIT(TRACE_FLAG_PPM) \ + WPP_DEFINE_BIT(TRACE_FLAG_ACPI) \ + ) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl, flags) \ + WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +// +// begin_wpp config +// +// FUNC TRACE_ERROR{LEVEL=TRACE_LEVEL_ERROR}(FLAGS, MSG,...); +// +// FUNC TRACE_WARN{LEVEL=TRACE_LEVEL_WARNING}(FLAGS, MSG, ...); +// +// FUNC TRACE_INFO{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS, MSG, ...); +// +// FUNC TRACE_VERBOSE{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// +// FUNC TRACE_FUNC_ENTRY{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, ...); +// USESUFFIX(TRACE_FUNC_ENTRY, "%!FUNC! Entry"); +// +// FUNC TRACE_FUNC_EXIT{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, ...); +// USESUFFIX(TRACE_FUNC_EXIT, "%!FUNC! Exit"); +// +// end_wpp +// + +// +// Definitions to satisy the Intellisense compiler in Visual Studio. +// Conditionally include the .tmh file as well, otherwise it will override these definitions. +// + + +#define TRACE_FLAG_DRIVER +#define TRACE_FLAG_FDO +#define TRACE_FLAG_PPM +#define TRACE_FLAG_ACPI +#define TRACE_ERROR(...) +#define TRACE_WARN(...) +#define TRACE_INFO(...) +#define TRACE_VERBOSE(...) +#define TRACE_FUNC_ENTRY(...) +#define TRACE_FUNC_EXIT(...) diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UCM.h b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UCM.h new file mode 100644 index 00000000..8e20c213 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UCM.h @@ -0,0 +1,39 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + UCM.h + +Abstract: + + Routines for interfacing with the system USB Connector Manager. + +Environment: + + Kernel-mode and user-mode. + +--*/ + +#pragma once + +#include <acpitabl.h> + + +_IRQL_requires_max_(HIGH_LEVEL) +ULONG64 +FORCEINLINE +UCM_CONNECTOR_ID_FROM_ACPI_PLD ( + _In_ PACPI_PLD_BUFFER PldBuffer + ) +{ + ULONG64 connectorId; + + connectorId = 0; + connectorId |= (PldBuffer->GroupToken & 0xFF); + connectorId <<= 8; + connectorId |= (PldBuffer->GroupPosition & 0xFF); + + return connectorId; +} diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.inf b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.inf new file mode 100644 index 00000000..04be1394 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.inf @@ -0,0 +1,58 @@ +; +; Copyright (c) Microsoft Corporation. All rights reserved. +; +; INF Name: +; +; UcmUcsiAcpiSample.inf +; +; Abstract: +; +; INF for installing the UCM-UCSI ACPI client driver. +; + +[Version] +Signature = "$WINDOWS NT$" +Class = UCM +ClassGuid = {e6f1aa1c-7f3b-4473-b2e8-c97d8ac71d53} +Provider = %ProviderName% +PnpLockdown = 1 +DriverVer = 06/21/2006,10.0.17741.1000 +CatalogFile = UcmUcsiAcpiSample.cat + +[SourceDisksNames] +3426 = windows cd + +[SourceDisksFiles] +UcmUcsiAcpiSample.sys = 3426 + +[DestinationDirs] +DefaultDestDir = 12 + +[Manufacturer] +%ProviderName% = UcmUcsiAcpiSample, NT$ARCH$ + +[UcmUcsiAcpiSample.NT$ARCH$] +%UcmUcsiAcpiSample.DeviceDesc% = UcmUcsiAcpiSample.Install, ACPI\USBC000, ACPI\PNP0CA0 + +[UcmUcsiAcpiSample.Install.NT] +CopyFiles = UcmUcsiAcpiSample.CopyFiles +FeatureScore = 80 ; The default value is 0xFF. Lower the feature score value, better the feature score rank. + +[UcmUcsiAcpiSample.Install.NT.Services] +AddService = UcmUcsiAcpiSample, 2, UcmUcsiAcpiSample.AddService + +[UcmUcsiAcpiSample.CopyFiles] +UcmUcsiAcpiSample.sys + +[UcmUcsiAcpiSample.AddService] +DisplayName = %UcmUcsiAcpiSample.ServiceName% +ServiceType = 1 +StartType = 3 +ErrorControl = 1 +ServiceBinary = %12%\UcmUcsiAcpiSample.sys +Dependencies = UcmUcsiCx + +[Strings] +ProviderName = "TODO update your provider name here" +UcmUcsiAcpiSample.DeviceDesc = "UCM-UCSI ACPI Device" +UcmUcsiAcpiSample.ServiceName = "UCM-UCSI ACPI Sample Cient" diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.vcxproj b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.vcxproj new file mode 100644 index 00000000..e892c2f0 --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.vcxproj @@ -0,0 +1,188 @@ +<?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|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <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|ARM"> + <Configuration>Debug</Configuration> + <Platform>ARM</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|ARM"> + <Configuration>Release</Configuration> + <Platform>ARM</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>{89486440-A6FB-4E95-9EE9-957B646F28DD}</ProjectGuid> + <TemplateGuid>{1bc93793-694f-48fe-9372-81e2b05556fd}</TemplateGuid> + <TargetFrameworkVersion>v4.5</TargetFrameworkVersion> + <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion> + <Configuration>Debug</Configuration> + <Platform Condition="'$(Platform)' == ''">Win32</Platform> + <RootNamespace>UcmUcsiAcpiSample</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" 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|Win32'" 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|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|ARM'" 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|ARM'" 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|Win32'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </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|ARM'"> + <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'"> + <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|Win32'"> + <ClCompile> + <WppEnabled>true</WppEnabled> + <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile> + <DisableSpecificWarnings>4100;4189;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <AdditionalDependencies>$(DDK_LIB_PATH)\UcmUcsi\1.0\UcmUcsiCxStub.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <WppEnabled>true</WppEnabled> + <DisableSpecificWarnings>4100;4189;%(DisableSpecificWarnings)</DisableSpecificWarnings> + </ClCompile> + <Link> + <AdditionalDependencies>$(DDK_LIB_PATH)\UcmUcsi\1.0\UcmUcsiCxStub.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <Inf Include="UcmUcsiAcpiSample.inf" /> + </ItemGroup> + <ItemGroup> + <FilesToPackage Include="$(TargetPath)" /> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Acpi.cpp" /> + <ClCompile Include="Driver.cpp" /> + <ClCompile Include="Fdo.cpp" /> + <ClCompile Include="MemoryKm.cpp" /> + <ClCompile Include="Ppm.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Acpi.h" /> + <ClInclude Include="Driver.h" /> + <ClInclude Include="Fdo.h" /> + <ClInclude Include="Pch.h" /> + <ClInclude Include="Ppm.h" /> + <ClInclude Include="ProjectCommon.h" /> + <ClInclude Include="Trace.h" /> + <ClInclude Include="UCM.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.vcxproj.filters b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.vcxproj.filters new file mode 100644 index 00000000..6be81c2c --- /dev/null +++ b/usb/UcmUcsiAcpiSample/UcmUcsiAcpiSample/UcmUcsiAcpiSample.vcxproj.filters @@ -0,0 +1,69 @@ +<?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="UcmUcsiAcpiSample.inf"> + <Filter>Driver Files</Filter> + </Inf> + </ItemGroup> + <ItemGroup> + <ClCompile Include="Acpi.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Driver.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Fdo.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="MemoryKm.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + <ClCompile Include="Ppm.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <ClInclude Include="Acpi.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Driver.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Fdo.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Pch.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Ppm.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="Trace.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="ProjectCommon.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="UCM.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project>
\ No newline at end of file |
