[ACPI] Add code to retrieve packet type data from ACPI methods. This will enable the cmbatt driver to retrieve _BIF (battery information) or _BST (battery status) data. Also fix the buffer size calculation for integer and string data.

This commit is contained in:
Eric Kohl 2019-01-02 23:29:12 +01:00
parent 9d0eb9b7b8
commit 60f018aea6

View file

@ -3,6 +3,83 @@
#define NDEBUG #define NDEBUG
#include <debug.h> #include <debug.h>
static
NTSTATUS
GetPackageSize(ACPI_OBJECT *Package,
PULONG Count,
PULONG Size)
{
ULONG Length, RawLength, TotalLength;
UINT32 i;
TotalLength = 0;
for (i = 0; i < Package->Package.Count; i++)
{
switch (Package->Package.Elements[i].Type)
{
case ACPI_TYPE_INTEGER:
Length = sizeof(ACPI_METHOD_ARGUMENT);
DPRINT("Integer %lu -> %lu: %lu (0x%lx)\n", sizeof(ULONG), Length, Package->Package.Elements[i].Integer.Value);
TotalLength += Length;
break;
case ACPI_TYPE_STRING:
RawLength = Package->Package.Elements[i].String.Length + 1;
Length = sizeof(ACPI_METHOD_ARGUMENT);
if (RawLength > sizeof(ULONG))
Length += RawLength - sizeof(ULONG);
DPRINT("String %lu -> %lu: '%s'\n", RawLength, Length, Package->Package.Elements[i].String.Pointer);
TotalLength += Length;
break;
default:
DPRINT1("Unsupported element type %lu\n", Package->Package.Elements[i].Type);
return STATUS_UNSUCCESSFUL;
}
}
*Count = Package->Package.Count;
*Size = TotalLength;
return STATUS_SUCCESS;
}
static
NTSTATUS
ConvertPackageArguments(ACPI_METHOD_ARGUMENT *Argument,
ACPI_OBJECT *Package)
{
ACPI_METHOD_ARGUMENT *Ptr;
UINT32 i;
Ptr = Argument;
for (i = 0; i < Package->Package.Count; i++)
{
switch (Package->Package.Elements[i].Type)
{
case ACPI_TYPE_INTEGER:
DPRINT("Integer %lu\n", sizeof(ACPI_METHOD_ARGUMENT));
ACPI_METHOD_SET_ARGUMENT_INTEGER(Ptr, Package->Package.Elements[i].Integer.Value);
break;
case ACPI_TYPE_STRING:
DPRINT("String %lu\n", Package->Package.Elements[i].String.Length);
ACPI_METHOD_SET_ARGUMENT_STRING(Ptr, Package->Package.Elements[i].String.Pointer);
break;
default:
DPRINT1("Unsupported element type %lu\n", Package->Package.Elements[i].Type);
return STATUS_UNSUCCESSFUL;
}
Ptr = ACPI_METHOD_NEXT_ARGUMENT(Ptr);
}
return STATUS_SUCCESS;
}
NTSTATUS NTSTATUS
NTAPI NTAPI
Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData, Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
@ -83,7 +160,8 @@ Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
if (ACPI_SUCCESS(Status)) if (ACPI_SUCCESS(Status))
{ {
ACPI_OBJECT *Obj = RetBuff.Pointer; ACPI_OBJECT *Obj = RetBuff.Pointer;
ULONG ExtraParamLength; ULONG ExtraParamLength = 0;
ULONG Count = 1;
/* If we didn't get anything back then we're done */ /* If we didn't get anything back then we're done */
if (!RetBuff.Pointer || RetBuff.Length == 0) if (!RetBuff.Pointer || RetBuff.Length == 0)
@ -92,39 +170,43 @@ Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
switch (Obj->Type) switch (Obj->Type)
{ {
case ACPI_TYPE_INTEGER: case ACPI_TYPE_INTEGER:
ExtraParamLength = sizeof(ULONG); ExtraParamLength = sizeof(ACPI_METHOD_ARGUMENT);
break; break;
case ACPI_TYPE_STRING: case ACPI_TYPE_STRING:
ExtraParamLength = Obj->String.Length; ExtraParamLength = sizeof(ACPI_METHOD_ARGUMENT);
if (Obj->String.Length + 1 > sizeof(ULONG))
ExtraParamLength += Obj->String.Length + 1 - sizeof(ULONG);
break; break;
case ACPI_TYPE_BUFFER: case ACPI_TYPE_BUFFER:
ExtraParamLength = Obj->Buffer.Length; ExtraParamLength = sizeof(ACPI_METHOD_ARGUMENT);
if (Obj->Buffer.Length > sizeof(ULONG))
ExtraParamLength += Obj->Buffer.Length + 1 - sizeof(ULONG);
break; break;
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n"); DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n");
return STATUS_UNSUCCESSFUL; Status = GetPackageSize(Obj, &Count, &ExtraParamLength);
if (!NT_SUCCESS(Status))
return Status;
break;
default: default:
ASSERT(FALSE); ASSERT(FALSE);
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
/* Enough space for a ULONG is always included */ DPRINT("ExtraParamLength %lu\n", ExtraParamLength);
if (ExtraParamLength >= sizeof(ULONG)) OutputBuf = ExAllocatePoolWithTag(NonPagedPool,
ExtraParamLength -= sizeof(ULONG); sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) + ExtraParamLength,
else 'BpcA');
ExtraParamLength = 0; if (!OutputBuf)
return STATUS_INSUFFICIENT_RESOURCES;
OutputBuf = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
ExtraParamLength, 'BpcA');
if (!OutputBuf) return STATUS_INSUFFICIENT_RESOURCES;
OutputBuf->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE; OutputBuf->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE;
OutputBuf->Length = ExtraParamLength + sizeof(ACPI_METHOD_ARGUMENT); OutputBuf->Length = ExtraParamLength;
OutputBuf->Count = 1; OutputBuf->Count = Count;
switch (Obj->Type) switch (Obj->Type)
{ {
@ -142,19 +224,22 @@ Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n"); DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n");
return STATUS_UNSUCCESSFUL; Status = ConvertPackageArguments(OutputBuf->Argument, Obj);
if (!NT_SUCCESS(Status))
return Status;
break;
default: default:
ASSERT(FALSE); ASSERT(FALSE);
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) + if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) +
ExtraParamLength) ExtraParamLength)
{ {
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, OutputBuf, sizeof(ACPI_EVAL_OUTPUT_BUFFER) + RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, OutputBuf, sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) +
ExtraParamLength); ExtraParamLength);
Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength; Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) + ExtraParamLength;
ExFreePoolWithTag(OutputBuf, 'BpcA'); ExFreePoolWithTag(OutputBuf, 'BpcA');
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -166,7 +251,7 @@ Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
} }
else else
{ {
DPRINT1("Query method %s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle); DPRINT1("Query method %4s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle);
return STATUS_UNSUCCESSFUL; return STATUS_UNSUCCESSFUL;
} }
} }