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