reactos/drivers/bus/acpi/eval.c
Cameron Gutman c2d0d784c7 [USB-BRINGUP-TRUNK]
- Create a branch to do a proper merge of USB work from a trunk base instead of from cmake-bringup
- In the future, DO NOT under any circumstances branch another branch. This leads to merge problems!

svn path=/branches/usb-bringup-trunk/; revision=55018
2012-01-20 20:58:46 +00:00

180 lines
5.7 KiB
C

#include <ntddk.h>
#include <acpi.h>
#include <acpisys.h>
#include <acpi_bus.h>
#include <acpi_drivers.h>
#include <acpiioct.h>
#include <glue.h>
#include <accommon.h>
#include <acobject.h>
#include <actypes.h>
#include <wdmguid.h>
#define NDEBUG
#include <debug.h>
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), 'IPCA');
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), 'IPCA');
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, 'IPCA');
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, 'IPCA');
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, 'IPCA');
return STATUS_SUCCESS;
}
else
{
ExFreePoolWithTag(OutputBuf, 'IPCA');
return STATUS_BUFFER_TOO_SMALL;
}
}
else
{
DPRINT1("Query method %s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle);
return STATUS_UNSUCCESSFUL;
}
}