1 #include "precomp.h" 2 3 #define NDEBUG 4 #include <debug.h> 5 6 static 7 NTSTATUS 8 GetPackageSize(ACPI_OBJECT *Package, 9 PULONG Count, 10 PULONG Size) 11 { 12 ULONG Length, RawLength, TotalLength; 13 UINT32 i; 14 15 TotalLength = 0; 16 for (i = 0; i < Package->Package.Count; i++) 17 { 18 switch (Package->Package.Elements[i].Type) 19 { 20 case ACPI_TYPE_INTEGER: 21 Length = sizeof(ACPI_METHOD_ARGUMENT); 22 DPRINT("Integer %lu -> %lu: %lu\n", sizeof(ULONG), Length, Package->Package.Elements[i].Integer.Value); 23 TotalLength += Length; 24 break; 25 26 case ACPI_TYPE_STRING: 27 RawLength = Package->Package.Elements[i].String.Length + 1; 28 Length = sizeof(ACPI_METHOD_ARGUMENT); 29 if (RawLength > sizeof(ULONG)) 30 Length += RawLength - sizeof(ULONG); 31 DPRINT("String %lu -> %lu: '%s'\n", RawLength, Length, Package->Package.Elements[i].String.Pointer); 32 TotalLength += Length; 33 break; 34 35 default: 36 DPRINT1("Unsupported element type %lu\n", Package->Package.Elements[i].Type); 37 return STATUS_UNSUCCESSFUL; 38 } 39 } 40 41 *Count = Package->Package.Count; 42 *Size = TotalLength; 43 44 return STATUS_SUCCESS; 45 } 46 47 48 static 49 NTSTATUS 50 ConvertPackageArguments(ACPI_METHOD_ARGUMENT *Argument, 51 ACPI_OBJECT *Package) 52 { 53 ACPI_METHOD_ARGUMENT *Ptr; 54 UINT32 i; 55 56 Ptr = Argument; 57 for (i = 0; i < Package->Package.Count; i++) 58 { 59 switch (Package->Package.Elements[i].Type) 60 { 61 case ACPI_TYPE_INTEGER: 62 DPRINT("Integer %lu\n", sizeof(ACPI_METHOD_ARGUMENT)); 63 ACPI_METHOD_SET_ARGUMENT_INTEGER(Ptr, Package->Package.Elements[i].Integer.Value); 64 break; 65 66 case ACPI_TYPE_STRING: 67 DPRINT("String %lu\n", Package->Package.Elements[i].String.Length); 68 ACPI_METHOD_SET_ARGUMENT_STRING(Ptr, Package->Package.Elements[i].String.Pointer); 69 break; 70 71 default: 72 DPRINT1("Unsupported element type %lu\n", Package->Package.Elements[i].Type); 73 return STATUS_UNSUCCESSFUL; 74 } 75 76 Ptr = ACPI_METHOD_NEXT_ARGUMENT(Ptr); 77 } 78 79 return STATUS_SUCCESS; 80 } 81 82 83 NTSTATUS 84 NTAPI 85 Bus_PDO_EvalMethod(PPDO_DEVICE_DATA DeviceData, 86 PIRP Irp) 87 { 88 ULONG Signature; 89 NTSTATUS Status; 90 ACPI_OBJECT_LIST ParamList; 91 PACPI_EVAL_INPUT_BUFFER EvalInputBuff = Irp->AssociatedIrp.SystemBuffer; 92 ACPI_BUFFER RetBuff = {ACPI_ALLOCATE_BUFFER, NULL}; 93 PACPI_EVAL_OUTPUT_BUFFER OutputBuf; 94 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); 95 ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER *SimpleInt; 96 ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING *SimpleStr; 97 CHAR MethodName[5]; 98 99 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) 100 return STATUS_INVALID_PARAMETER; 101 102 Signature = *((PULONG)Irp->AssociatedIrp.SystemBuffer); 103 104 switch (Signature) 105 { 106 case ACPI_EVAL_INPUT_BUFFER_SIGNATURE: 107 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER)) 108 return STATUS_INVALID_PARAMETER; 109 110 ParamList.Count = 0; 111 break; 112 113 case ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE: 114 SimpleInt = Irp->AssociatedIrp.SystemBuffer; 115 116 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER)) 117 return STATUS_INVALID_PARAMETER; 118 119 ParamList.Count = 1; 120 121 ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'OpcA'); 122 if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES; 123 124 ParamList.Pointer[0].Type = ACPI_TYPE_INTEGER; 125 ParamList.Pointer[0].Integer.Value = SimpleInt->IntegerArgument; 126 break; 127 128 case ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING_SIGNATURE: 129 SimpleStr = Irp->AssociatedIrp.SystemBuffer; 130 131 if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_STRING)) 132 return STATUS_INVALID_PARAMETER; 133 134 ParamList.Count = 1; 135 136 ParamList.Pointer = ExAllocatePoolWithTag(NonPagedPool, sizeof(ACPI_OBJECT), 'OpcA'); 137 if (!ParamList.Pointer) return STATUS_INSUFFICIENT_RESOURCES; 138 139 ParamList.Pointer[0].String.Pointer = (CHAR*)SimpleStr->String; 140 ParamList.Pointer[0].String.Length = SimpleStr->StringLength; 141 break; 142 143 default: 144 DPRINT1("Unsupported input buffer signature: %d\n", Signature); 145 return STATUS_NOT_IMPLEMENTED; 146 } 147 148 RtlCopyMemory(MethodName, 149 EvalInputBuff->MethodName, 150 sizeof(EvalInputBuff->MethodName)); 151 MethodName[4] = ANSI_NULL; 152 Status = AcpiEvaluateObject(DeviceData->AcpiHandle, 153 MethodName, 154 &ParamList, 155 &RetBuff); 156 157 if (ParamList.Count != 0) 158 ExFreePoolWithTag(ParamList.Pointer, 'OpcA'); 159 160 if (ACPI_SUCCESS(Status)) 161 { 162 ACPI_OBJECT *Obj = RetBuff.Pointer; 163 ULONG ExtraParamLength = 0; 164 ULONG Count = 1; 165 166 /* If we didn't get anything back then we're done */ 167 if (!RetBuff.Pointer || RetBuff.Length == 0) 168 return STATUS_SUCCESS; 169 170 switch (Obj->Type) 171 { 172 case ACPI_TYPE_INTEGER: 173 ExtraParamLength = sizeof(ACPI_METHOD_ARGUMENT); 174 break; 175 176 case ACPI_TYPE_STRING: 177 ExtraParamLength = sizeof(ACPI_METHOD_ARGUMENT); 178 if (Obj->String.Length + 1 > sizeof(ULONG)) 179 ExtraParamLength += Obj->String.Length + 1 - sizeof(ULONG); 180 break; 181 182 case ACPI_TYPE_BUFFER: 183 ExtraParamLength = sizeof(ACPI_METHOD_ARGUMENT); 184 if (Obj->Buffer.Length > sizeof(ULONG)) 185 ExtraParamLength += Obj->Buffer.Length + 1 - sizeof(ULONG); 186 break; 187 188 case ACPI_TYPE_PACKAGE: 189 Status = GetPackageSize(Obj, &Count, &ExtraParamLength); 190 if (!NT_SUCCESS(Status)) 191 return Status; 192 break; 193 194 default: 195 ASSERT(FALSE); 196 return STATUS_UNSUCCESSFUL; 197 } 198 199 DPRINT("ExtraParamLength %lu\n", ExtraParamLength); 200 OutputBuf = ExAllocatePoolWithTag(NonPagedPool, 201 sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) + ExtraParamLength, 202 'BpcA'); 203 if (!OutputBuf) 204 return STATUS_INSUFFICIENT_RESOURCES; 205 206 OutputBuf->Signature = ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE; 207 OutputBuf->Length = ExtraParamLength; 208 OutputBuf->Count = Count; 209 210 switch (Obj->Type) 211 { 212 case ACPI_TYPE_INTEGER: 213 ACPI_METHOD_SET_ARGUMENT_INTEGER(OutputBuf->Argument, Obj->Integer.Value); 214 break; 215 216 case ACPI_TYPE_STRING: 217 ACPI_METHOD_SET_ARGUMENT_STRING(OutputBuf->Argument, Obj->String.Pointer); 218 break; 219 220 case ACPI_TYPE_BUFFER: 221 ACPI_METHOD_SET_ARGUMENT_BUFFER(OutputBuf->Argument, Obj->Buffer.Pointer, Obj->Buffer.Length); 222 break; 223 224 case ACPI_TYPE_PACKAGE: 225 Status = ConvertPackageArguments(OutputBuf->Argument, Obj); 226 if (!NT_SUCCESS(Status)) 227 return Status; 228 break; 229 230 default: 231 ASSERT(FALSE); 232 return STATUS_UNSUCCESSFUL; 233 } 234 235 if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) + 236 ExtraParamLength) 237 { 238 RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, OutputBuf, sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) + 239 ExtraParamLength); 240 Irp->IoStatus.Information = sizeof(ACPI_EVAL_OUTPUT_BUFFER) - sizeof(ACPI_METHOD_ARGUMENT) + ExtraParamLength; 241 ExFreePoolWithTag(OutputBuf, 'BpcA'); 242 return STATUS_SUCCESS; 243 } 244 else 245 { 246 ExFreePoolWithTag(OutputBuf, 'BpcA'); 247 return STATUS_BUFFER_TOO_SMALL; 248 } 249 } 250 else 251 { 252 DPRINT1("Query method %4s failed on %p\n", EvalInputBuff->MethodName, DeviceData->AcpiHandle); 253 return STATUS_UNSUCCESSFUL; 254 } 255 } 256