Sync with trunk r64222.
[reactos.git] / drivers / bus / acpi / eval.c
1 #include "precomp.h"
2
3 #define NDEBUG
4 #include <debug.h>
5
6 NTSTATUS
7 NTAPI
8 Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData,
9 PIRP Irp)
10 {
11 ULONG Signature;
12 NTSTATUS Status;
13 ACPI_OBJECT_LIST ParamList;
14 PACPI_EVAL_INPUT_BUFFER EvalInputBuff = Irp->AssociatedIrp.SystemBuffer;
15 ACPI_BUFFER RetBuff = {ACPI_ALLOCATE_BUFFER, NULL};
16 PACPI_EVAL_OUTPUT_BUFFER OutputBuf;
17 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
18 ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER *SimpleInt;
19 ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING *SimpleStr;
20
21 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG))
22 return STATUS_INVALID_PARAMETER;
23
24 Signature = *((PULONG)Irp->AssociatedIrp.SystemBuffer);
25
26 switch (Signature)
27 {
28 case ACPI_EVAL_INPUT_BUFFER_SIGNATURE:
29 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER))
30 return STATUS_INVALID_PARAMETER;
31
32 ParamList.Count = 0;
33 break;
34
35 case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE:
36 SimpleInt = Irp->AssociatedIrp.SystemBuffer;
37
38 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER))
39 return STATUS_INVALID_PARAMETER;
40
41 ParamList.Count = 1;
42
43 ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'IPCA');
44 if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES;
45
46 ParamList.Pointer[0].Type = ACPI_TYPE_INTEGER;
47 ParamList.Pointer[0].Integer.Value = SimpleInt->IntegerArgument;
48 break;
49
50 case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE:
51 SimpleStr = Irp->AssociatedIrp.SystemBuffer;
52
53 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING))
54 return STATUS_INVALID_PARAMETER;
55
56 ParamList.Count = 1;
57
58 ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'IPCA');
59 if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES;
60
61 ParamList.Pointer[0].String.Pointer = (CHAR*)SimpleStr->String;
62 ParamList.Pointer[0].String.Length = SimpleStr->StringLength;
63 break;
64
65 default:
66 DPRINT1("Unsupported input buffer signature: %d\n", Signature);
67 return STATUS_NOT_IMPLEMENTED;
68 }
69
70 Status = AcpiEvaluateObject(DeviceData->AcpiHandle,
71 (CHAR*)EvalInputBuff->MethodName,
72 &ParamList,
73 &RetBuff);
74
75 if (ParamList.Count != 0)
76 ExFreePoolWithTag(ParamList.Pointer, 'IPCA');
77
78 if (ACPI_SUCCESS(Status))
79 {
80 ACPI_OBJECT *Obj = RetBuff.Pointer;
81 ULONG ExtraParamLength;
82
83 /* If we didn't get anything back then we're done */
84 if (!RetBuff.Pointer || RetBuff.Length == 0)
85 return STATUS_SUCCESS;
86
87 switch (Obj->Type)
88 {
89 case ACPI_TYPE_INTEGER:
90 ExtraParamLength = sizeof(ULONG);
91 break;
92
93 case ACPI_TYPE_STRING:
94 ExtraParamLength = Obj->String.Length;
95 break;
96
97 case ACPI_TYPE_BUFFER:
98 ExtraParamLength = Obj->Buffer.Length;
99 break;
100
101 case ACPI_TYPE_PACKAGE:
102 DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n");
103 return STATUS_UNSUCCESSFUL;
104
105 default:
106 ASSERT(FALSE);
107 return STATUS_UNSUCCESSFUL;
108 }
109
110 /* Enough space for a ULONG is always included */
111 if (ExtraParamLength >= sizeof(ULONG))
112 ExtraParamLength -= sizeof(ULONG);
113 else
114 ExtraParamLength = 0;
115
116 OutputBuf = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
117 ExtraParamLength, 'IPCA');
118 if (!OutputBuf) return STATUS_INSUFFICIENT_RESOURCES;
119
120 OutputBuf->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE;
121 OutputBuf->Length = ExtraParamLength + sizeof(ACPI_METHOD_ARGUMENT);
122 OutputBuf->Count = 1;
123
124 switch (Obj->Type)
125 {
126 case ACPI_TYPE_INTEGER:
127 ACPI_METHOD_SET_ARGUMENT_INTEGER(OutputBuf->Argument, Obj->Integer.Value);
128 break;
129
130 case ACPI_TYPE_STRING:
131 ACPI_METHOD_SET_ARGUMENT_STRING(OutputBuf->Argument, Obj->String.Pointer);
132 break;
133
134 case ACPI_TYPE_BUFFER:
135 ACPI_METHOD_SET_ARGUMENT_BUFFER(OutputBuf->Argument, Obj->Buffer.Pointer, Obj->Buffer.Length);
136 break;
137
138 case ACPI_TYPE_PACKAGE:
139 DPRINT1("ACPI_TYPE_PACKAGE not supported yet!\n");
140 return STATUS_UNSUCCESSFUL;
141
142 default:
143 ASSERT(FALSE);
144 return STATUS_UNSUCCESSFUL;
145 }
146
147 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
148 ExtraParamLength)
149 {
150 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, OutputBuf, sizeof(ACPI_EVAL_OUTPUT_BUFFER) +
151 ExtraParamLength);
152 Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER) + ExtraParamLength;
153 ExFreePoolWithTag(OutputBuf, 'IPCA');
154 return STATUS_SUCCESS;
155 }
156 else
157 {
158 ExFreePoolWithTag(OutputBuf, 'IPCA');
159 return STATUS_BUFFER_TOO_SMALL;
160 }
161 }
162 else
163 {
164 DPRINT1("Query method %s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle);
165 return STATUS_UNSUCCESSFUL;
166 }
167 }