summaryrefslogtreecommitdiff
path: root/usb/UcmCxUcsi/Acpi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'usb/UcmCxUcsi/Acpi.cpp')
-rw-r--r--usb/UcmCxUcsi/Acpi.cpp775
1 files changed, 775 insertions, 0 deletions
diff --git a/usb/UcmCxUcsi/Acpi.cpp b/usb/UcmCxUcsi/Acpi.cpp
new file mode 100644
index 00000000..d905a3c7
--- /dev/null
+++ b/usb/UcmCxUcsi/Acpi.cpp
@@ -0,0 +1,775 @@
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+Module Name:
+
+ Acpi.cpp
+
+Abstract:
+
+ ACPI method evaluation helper routines.
+
+Environment:
+
+ Kernel-mode only.
+
+--*/
+
+#include "Pch.h"
+#include "Acpi.tmh"
+
+
+#define ACPI_METHOD_OUTPUT_BUFFER_SIZE 1024
+
+// {6F8398C2-7CA4-11E4-AD36-631042B5008F}
+DEFINE_GUID(GUID_UCSI_DSM,
+0x6f8398c2, 0x7ca4, 0x11e4, 0xad, 0x36, 0x63, 0x10, 0x42, 0xb5, 0x00, 0x8f);
+
+#define UCSI_DSM_REVISION 0
+#define UCSI_DSM_FUNCTION_SUPPORTED_FUNCTIONS_INDEX 0x0
+#define UCSI_DSM_FUNCTION_SEND_DATA_INDEX 0x1
+#define UCSI_DSM_FUNCTION_RECEIVE_DATA_INDEX 0x2
+#define UCSI_DSM_FUNCTION_USB_DEVICE_CONTROLLER_STATUS_INDEX 0x3
+
+#define UCSI_DSM_EXECUTION_TIMEOUT_IN_MS 3000
+
+EXTERN_C_START
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_EvaluateUcsiDsm (
+ _In_ PACPI_CONTEXT AcpiCtx,
+ _In_ ULONG FunctionIndex,
+ _Outptr_opt_ PACPI_EVAL_OUTPUT_BUFFER* Output
+ );
+
+EXTERN_C_END
+
+#pragma alloc_text(PAGE, Acpi_PrepareHardware)
+#pragma alloc_text(PAGE, Acpi_ReleaseHardware)
+#pragma alloc_text(PAGE, Acpi_UcsiDsmSendData)
+#pragma alloc_text(PAGE, Acpi_UcsiDsmReceiveData)
+#pragma alloc_text(PAGE, Acpi_EnumChildren)
+#pragma alloc_text(PAGE, Acpi_EvaluatePld)
+#pragma alloc_text(PAGE, Acpi_EvaluateUcsiDsm)
+#pragma alloc_text(PAGE, Acpi_UcsiDsmIsUsbDeviceControllerEnabled)
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_PrepareHardware (
+ _In_ PACPI_CONTEXT AcpiCtx
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+
+ PAGED_CODE();
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ device = Context_GetWdfDevice(AcpiCtx);
+
+ if (AcpiCtx->Initialized != FALSE)
+ {
+ status = STATUS_INVALID_DEVICE_STATE;
+ TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI already initialized", device);
+ goto Exit;
+ }
+
+ status = WdfFdoQueryForInterface(device,
+ &GUID_ACPI_INTERFACE_STANDARD2,
+ (PINTERFACE) &AcpiCtx->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!", device, status);
+ goto Exit;
+ }
+
+ AcpiCtx->Initialized = TRUE;
+
+ TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI prepare hardware completed", device);
+
+Exit:
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+
+ return status;
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+VOID
+Acpi_ReleaseHardware (
+ _In_ PACPI_CONTEXT AcpiCtx
+ )
+{
+ WDFDEVICE device;
+
+ PAGED_CODE();
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ if (AcpiCtx->Initialized == FALSE)
+ {
+ goto Exit;
+ }
+
+ device = Context_GetWdfDevice(AcpiCtx);
+
+ AcpiCtx->AcpiInterface.InterfaceDereference(AcpiCtx->AcpiInterface.Context);
+ RtlZeroMemory(&AcpiCtx->AcpiInterface, sizeof(AcpiCtx->AcpiInterface));
+
+ AcpiCtx->Initialized = FALSE;
+
+ TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] ACPI release hardware completed", device);
+
+Exit:
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_UcsiDsmSendData (
+ _In_ PACPI_CONTEXT AcpiCtx
+ )
+{
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ status = Acpi_EvaluateUcsiDsm(AcpiCtx,
+ UCSI_DSM_FUNCTION_SEND_DATA_INDEX,
+ nullptr);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+
+ return status;
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_UcsiDsmReceiveData (
+ _In_ PACPI_CONTEXT AcpiCtx
+ )
+{
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ status = Acpi_EvaluateUcsiDsm(AcpiCtx,
+ UCSI_DSM_FUNCTION_RECEIVE_DATA_INDEX,
+ nullptr);
+ if (!NT_SUCCESS(status))
+ {
+ goto Exit;
+ }
+
+Exit:
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+
+ return status;
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_EnumChildren (
+ _In_ PACPI_CONTEXT AcpiCtx,
+ _Out_ WDFMEMORY* EnumChildrenOutput
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ 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);
+
+ device = Context_GetWdfDevice(AcpiCtx);
+ inputMem = WDF_NO_HANDLE;
+ outputMem = WDF_NO_HANDLE;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = device;
+
+ 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", device, 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 = device;
+
+ 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", device, outputBufSize);
+ goto Exit;
+ }
+
+ WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(&outputMemDesc, outputMem, nullptr);
+
+ status = WdfIoTargetSendIoctlSynchronously(WdfDeviceGetIoTarget(device),
+ 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", device);
+ 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", device);
+ goto Exit;
+ }
+
+ break;
+ }
+
+ if (status != STATUS_BUFFER_OVERFLOW)
+ {
+ TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] IOCTL_ACPI_ENUM_CHILDREN failed - %!STATUS!", device, 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", device);
+ goto Exit;
+ }
+
+ 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;
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_EvaluatePld (
+ _In_ PACPI_CONTEXT AcpiCtx,
+ _In_ LPCSTR DeviceName,
+ _Out_ PACPI_PLD_BUFFER PldBuffer
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ 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();
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ device = Context_GetWdfDevice(AcpiCtx);
+ 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!", device, status);
+ goto Exit;
+ }
+
+ outputArgumentBufferSize = 1024;
+ outputBufferSize =
+ FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
+ outputArgumentBufferSize;
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ attributes.ParentObject = device;
+
+ 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!", device, 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(device),
+ 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!", device, 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", device);
+ 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", device, 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", device, 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", device, 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;
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_EvaluateUcsiDsm (
+ _In_ PACPI_CONTEXT AcpiCtx,
+ _In_ ULONG FunctionIndex,
+ _Outptr_opt_ PACPI_EVAL_OUTPUT_BUFFER* Output
+ )
+/*++
+
+ N.B. Caller is expected to free the Output buffer.
+
+--*/
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ 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);
+
+ device = Context_GetWdfDevice(AcpiCtx);
+ 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 = device;
+
+ 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!", device, 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;
+
+ outputArgumentBufferSize = ACPI_METHOD_ARGUMENT_LENGTH(sizeof(ULONG));
+ outputBufferSize =
+ FIELD_OFFSET(ACPI_EVAL_OUTPUT_BUFFER, Argument) +
+ outputArgumentBufferSize;
+
+ outputBuffer = (PACPI_EVAL_OUTPUT_BUFFER) ExAllocatePoolWithTag(NonPagedPoolNx,
+ outputBufferSize,
+ TAG_UCSI);
+
+ if (outputBuffer == nullptr)
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] ExAllocatePoolWithTag failed for %Iu bytes", device, 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(device),
+ 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!", device, 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", device);
+ status = STATUS_ACPI_INVALID_DATA;
+ goto Exit;
+ }
+
+Exit:
+
+ if (inputMemory != WDF_NO_HANDLE)
+ {
+ WdfObjectDelete(inputMemory);
+ }
+
+ if (!NT_SUCCESS(status) || (Output == nullptr))
+ {
+ if (outputBuffer)
+ {
+ ExFreePoolWithTag(outputBuffer, TAG_UCSI);
+ }
+ }
+ else
+ {
+ *Output = outputBuffer;
+ }
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+
+ return status;
+}
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+NTSTATUS
+Acpi_RegisterNotificationCallback (
+ _In_ PACPI_CONTEXT AcpiCtx,
+ _In_ PFN_ACPI_NOTIFY_CALLBACK Callback,
+ _In_ PVOID Context
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ device = Context_GetWdfDevice(AcpiCtx);
+
+ if (AcpiCtx->RegisteredForNotifications != FALSE)
+ {
+ status = STATUS_INVALID_DEVICE_STATE;
+ TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Already registered for ACPI notifications", device);
+ goto Exit;
+ }
+
+ status = AcpiCtx->AcpiInterface.RegisterForDeviceNotifications(AcpiCtx->AcpiInterface.Context,
+ Callback,
+ Context);
+ if (!NT_SUCCESS(status))
+ {
+ TRACE_ERROR(TRACE_FLAG_ACPI, "[Device: 0x%p] Registering for ACPI notifications failed - %!STATUS!", device, status);
+ goto Exit;
+ }
+
+ AcpiCtx->RegisteredForNotifications = TRUE;
+
+ TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] Registered for ACPI notifications", device);
+
+Exit:
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+
+ return status;
+}
+
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+Acpi_UnregisterNotificationCallback (
+ _In_ PACPI_CONTEXT AcpiCtx
+ )
+{
+ WDFDEVICE device;
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ if (AcpiCtx->RegisteredForNotifications == FALSE)
+ {
+ goto Exit;
+ }
+
+ device = Context_GetWdfDevice(AcpiCtx);
+
+ AcpiCtx->AcpiInterface.UnregisterForDeviceNotifications(AcpiCtx->AcpiInterface.Context);
+ AcpiCtx->RegisteredForNotifications = FALSE;
+
+ TRACE_INFO(TRACE_FLAG_ACPI, "[Device: 0x%p] Unregistered ACPI notifications", device);
+
+Exit:
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+}
+
+
+_IRQL_requires_max_(PASSIVE_LEVEL)
+NTSTATUS
+Acpi_UcsiDsmIsUsbDeviceControllerEnabled (
+ _In_ PACPI_CONTEXT AcpiCtx,
+ _Out_ PBOOLEAN IsUsbDeviceControllerEnabled
+ )
+{
+ NTSTATUS status;
+ WDFDEVICE device;
+ PACPI_EVAL_OUTPUT_BUFFER output;
+
+ PAGED_CODE();
+
+ TRACE_FUNC_ENTRY(TRACE_FLAG_ACPI);
+
+ output = nullptr;
+ device = Context_GetWdfDevice(AcpiCtx);
+
+ status = Acpi_EvaluateUcsiDsm(AcpiCtx, 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!", device, 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", device, 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", device, 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.
+ //
+
+ status = STATUS_SUCCESS;
+ *IsUsbDeviceControllerEnabled = TRUE;
+ goto Exit;
+ }
+
+ ExFreePoolWithTag(output, TAG_UCSI);
+ output = nullptr;
+
+ status = Acpi_EvaluateUcsiDsm(AcpiCtx,
+ 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!", device, 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", device, 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)
+ {
+ ExFreePoolWithTag(output, TAG_UCSI);
+ }
+
+ TRACE_FUNC_EXIT(TRACE_FLAG_ACPI);
+
+ return status;
+}