diff options
Diffstat (limited to 'usb/UcmCxUcsi/Acpi.cpp')
| -rw-r--r-- | usb/UcmCxUcsi/Acpi.cpp | 775 |
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; +} |
