NTSTATUS NTAPI Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData, PIRP Irp) { ULONG Signature; NTSTATUS Status; ACPI_OBJECT_LIST ParamList; PACPI_EVAL_INPUT_BUFFER EvalInputBuff = Irp->AssociatedIrp.SystemBuffer; ACPI_BUFFER RetBuff = {ACPI_ALLOCATE_BUFFER, NULL}; PACPI_EVAL_OUTPUT_BUFFER OutputBuf; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER *SimpleInt; ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING *SimpleStr; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) return STATUS_INVALID_PARAMETER; Signature = *((PULONG)Irp->AssociatedIrp.SystemBuffer); switch (Signature) { case ACPI_EVAL_INPUT_BUFFER_SIGNATURE: if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER)) return STATUS_INVALID_PARAMETER; ParamList.Count = 0; break; case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE: SimpleInt = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER)) return STATUS_INVALID_PARAMETER; ParamList.Count = 1; ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'OpcA'); if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES; ParamList.Pointer[0].Type = ACPI_TYPE_INTEGER; ParamList.Pointer[0].Integer.Value = SimpleInt->IntegerArgument; break; case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE: SimpleStr = Irp->AssociatedIrp.SystemBuffer; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING)) return STATUS_INVALID_PARAMETER; ParamList.Count = 1; ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'OpcA'); if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES; ParamList.Pointer[0].String.Pointer = (CHAR*)SimpleStr->String; ParamList.Pointer[0].String.Length = SimpleStr->StringLength; break; default: DPRINT1("Unsupported input buffer signature: %d\n", Signature); return STATUS_NOT_IMPLEMENTED; } Status = AcpiEvaluateObject(DeviceData->AcpiHandle, (CHAR*)EvalInputBuff->MethodName, &ParamList, &RetBuff); if (ParamList.Count != 0) ExFreePoolWithTag(ParamList.Pointer, 'OpcA'); if (ACPI_SUCCESS(Status)) { ACPI_OBJECT *Obj = RetBuff.Pointer; ULONG ExtraParamLength; /* If we didn't get anything back then we're done */ if (!RetBuff.Pointer || RetBuff.Length == 0) return STATUS_SUCCESS; switch (Obj->Type) { case ACPI_TYPE_INTEGER: ExtraParamLength = sizeof(ULONG); break; case ACPI_TYPE_STRING: ExtraParamLength = Obj->String.Length; break; case ACPI_TYPE_BUFFER: ExtraParamLength = Obj->Buffer.Length; break; case ACPI_TYPE_PACKAGE: DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n"); return STATUS_UNSUCCESSFUL; default: ASSERT(FALSE); return STATUS_UNSUCCESSFUL; } /* Enough space for a ULONG is always included */ if (ExtraParamLength >= sizeof(ULONG)) ExtraParamLength -= sizeof(ULONG); else ExtraParamLength = 0; OutputBuf = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength, 'BpcA'); if (!OutputBuf) return STATUS_INSUFFICIENT_RESOURCES; OutputBuf->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE; OutputBuf->Length = ExtraParamLength + sizeof(ACPI_METHOD_ARGUMENT); OutputBuf->Count = 1; switch (Obj->Type) { case ACPI_TYPE_INTEGER: ACPI_METHOD_SET_ARGUMENT_INTEGER(OutputBuf->Argument, Obj->Integer.Value); break; case ACPI_TYPE_STRING: ACPI_METHOD_SET_ARGUMENT_STRING(OutputBuf->Argument, Obj->String.Pointer); break; case ACPI_TYPE_BUFFER: ACPI_METHOD_SET_ARGUMENT_BUFFER(OutputBuf->Argument, Obj->Buffer.Pointer, Obj->Buffer.Length); break; case ACPI_TYPE_PACKAGE: DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n"); return STATUS_UNSUCCESSFUL; default: ASSERT(FALSE); return STATUS_UNSUCCESSFUL; } if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength) { RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, OutputBuf, sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength); Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength; ExFreePoolWithTag(OutputBuf, 'BpcA'); return STATUS_SUCCESS; } else { ExFreePoolWithTag(OutputBuf, 'BpcA'); return STATUS_BUFFER_TOO_SMALL; } } else { DPRINT1("Query method %s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle); return STATUS_UNSUCCESSFUL; } }
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; }