1 /* 2 * PROJECT: ReactOS ACPI-Compliant Control Method Battery 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: boot/drivers/bus/acpi/cmbatt/cmexec.c 5 * PURPOSE: ACPI Method Execution/Evaluation Glue 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "cmbatt.h" 12 13 #include <acpiioct.h> 14 #include <debug.h> 15 16 typedef struct 17 { 18 LPSTR Name; 19 BOOLEAN IsString; 20 PVOID Data; 21 } ACPI_PACKAGE_FIELD, *PACPI_PACKAGE_FIELD; 22 23 /* FUNCTIONS ******************************************************************/ 24 25 NTSTATUS 26 NTAPI 27 GetDwordElement(IN PACPI_METHOD_ARGUMENT Argument, 28 OUT PULONG Value) 29 { 30 NTSTATUS Status; 31 32 /* Must have an integer */ 33 if (Argument->Type != ACPI_METHOD_ARGUMENT_INTEGER) 34 { 35 /* Not an integer, fail */ 36 Status = STATUS_ACPI_INVALID_DATA; 37 if (CmBattDebug & 0x4C) 38 DbgPrint("GetDwordElement: Object contained wrong data type - %d\n", 39 Argument->Type); 40 } 41 else 42 { 43 /* Read the integer value */ 44 *Value = Argument->Argument; 45 Status = STATUS_SUCCESS; 46 } 47 48 /* Return status */ 49 return Status; 50 } 51 52 NTSTATUS 53 NTAPI 54 GetStringElement(IN PACPI_METHOD_ARGUMENT Argument, 55 OUT PCHAR Value) 56 { 57 NTSTATUS Status; 58 59 /* Must have a string of buffer */ 60 if ((Argument->Type == ACPI_METHOD_ARGUMENT_STRING) || 61 (Argument->Type == ACPI_METHOD_ARGUMENT_BUFFER)) 62 { 63 /* String must be less than 256 characters */ 64 if (Argument->DataLength < 256) 65 { 66 /* Copy the buffer */ 67 RtlCopyMemory(Value, Argument->Data, Argument->DataLength); 68 Status = STATUS_SUCCESS; 69 } 70 else 71 { 72 /* The buffer is too small (the string is too large) */ 73 Status = STATUS_BUFFER_TOO_SMALL; 74 if (CmBattDebug & 0x4C) 75 DbgPrint("GetStringElement: return buffer not big enough - %d\n", Argument->DataLength); 76 } 77 } 78 else 79 { 80 /* Not valid string data */ 81 Status = STATUS_ACPI_INVALID_DATA; 82 if (CmBattDebug & 0x4C) 83 DbgPrint("GetStringElement: Object contained wrong data type - %d\n", Argument->Type); 84 } 85 86 /* Return the status */ 87 return Status; 88 } 89 90 NTSTATUS 91 NTAPI 92 CmBattSendDownStreamIrp(IN PDEVICE_OBJECT DeviceObject, 93 IN ULONG IoControlCode, 94 IN PVOID InputBuffer, 95 IN ULONG InputBufferLength, 96 IN PACPI_EVAL_OUTPUT_BUFFER OutputBuffer, 97 IN ULONG OutputBufferLength) 98 { 99 PIRP Irp; 100 NTSTATUS Status; 101 KEVENT Event; 102 IO_STATUS_BLOCK IoStatusBlock; 103 PAGED_CODE(); 104 105 /* Initialize our wait event */ 106 KeInitializeEvent(&Event, SynchronizationEvent, 0); 107 108 /* Allocate the IRP */ 109 Irp = IoBuildDeviceIoControlRequest(IoControlCode, 110 DeviceObject, 111 InputBuffer, 112 InputBufferLength, 113 OutputBuffer, 114 OutputBufferLength, 115 0, 116 &Event, 117 &IoStatusBlock); 118 if (!Irp) 119 { 120 /* No IRP, fail */ 121 if (CmBattDebug & 0x4C) 122 DbgPrint("CmBattSendDownStreamIrp: Failed to allocate Irp\n"); 123 return STATUS_INSUFFICIENT_RESOURCES; 124 } 125 126 /* Call ACPI */ 127 if (CmBattDebug & 0x40) 128 DbgPrint("CmBattSendDownStreamIrp: Irp %x [Tid] %x\n", 129 Irp, KeGetCurrentThread()); 130 Status = IoCallDriver(DeviceObject, Irp); 131 if (Status == STATUS_PENDING) 132 { 133 /* Wait for completion */ 134 KeWaitForSingleObject(&Event, 135 Executive, 136 KernelMode, 137 FALSE, 138 NULL); 139 Status = Irp->IoStatus.Status; 140 } 141 142 /* Check if caller wanted output */ 143 if (OutputBuffer) 144 { 145 /* Make sure it's valid ACPI output buffer */ 146 if ((OutputBuffer->Signature != ACPI_EVAL_OUTPUT_BUFFER_SIGNATURE) || 147 !(OutputBuffer->Count)) 148 { 149 /* It isn't, so set failure code */ 150 Status = STATUS_ACPI_INVALID_DATA; 151 } 152 } 153 154 /* Return status */ 155 if (CmBattDebug & 0x40) 156 DbgPrint("CmBattSendDownStreamIrp: Irp %x completed %x! [Tid] %x\n", 157 Irp, Status, KeGetCurrentThread()); 158 return Status; 159 } 160 161 static 162 NTSTATUS 163 CmBattCallAcpiPackage( 164 _In_ LPCSTR FunctionName, 165 _In_ PCMBATT_DEVICE_EXTENSION DeviceExtension, 166 _In_ ULONG PackageName, 167 _In_ ULONG OutputBufferSize, 168 _In_ PACPI_PACKAGE_FIELD PackageFields, 169 _In_ ULONG PackageFieldCount) 170 { 171 NTSTATUS Status; 172 PACPI_EVAL_OUTPUT_BUFFER OutputBuffer; 173 ACPI_EVAL_INPUT_BUFFER InputBuffer; 174 PACPI_METHOD_ARGUMENT Argument; 175 ULONG i; 176 PAGED_CODE(); 177 178 OutputBuffer = ExAllocatePoolWithTag(PagedPool, 179 OutputBufferSize, 180 'MtaB'); 181 if (!OutputBuffer) 182 { 183 if (CmBattDebug & (CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)) 184 DbgPrint("%s: Failed to allocate Buffer\n", FunctionName); 185 return STATUS_INSUFFICIENT_RESOURCES; 186 } 187 188 /* Initialize to zero */ 189 RtlZeroMemory(OutputBuffer, OutputBufferSize); 190 191 /* Request the ACPI method */ 192 *(PULONG)InputBuffer.MethodName = PackageName; 193 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE; 194 195 /* Send it to ACPI */ 196 Status = CmBattSendDownStreamIrp(DeviceExtension->AttachedDevice, 197 IOCTL_ACPI_EVAL_METHOD, 198 &InputBuffer, 199 sizeof(InputBuffer), 200 OutputBuffer, 201 OutputBufferSize); 202 if (!NT_SUCCESS(Status)) 203 { 204 if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)) 205 DbgPrint("%s: Failed 0x%08x method on device %x - Status (0x%x)\n", 206 FunctionName, PackageName, DeviceExtension->DeviceId, Status); 207 ExFreePoolWithTag(OutputBuffer, 'MtaB'); 208 return Status; 209 } 210 211 /* Check if we got the right number of elements */ 212 if (OutputBuffer->Count != PackageFieldCount) 213 { 214 if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)) 215 DbgPrint("%s: 0x%08x method returned %d elements (requires %d)\n", 216 FunctionName, PackageName, OutputBuffer->Count, PackageFieldCount); 217 ExFreePoolWithTag(OutputBuffer, 'MtaB'); 218 return STATUS_ACPI_INVALID_DATA; 219 } 220 221 Argument = OutputBuffer->Argument; 222 for (i = 0; i < PackageFieldCount && NT_SUCCESS(Status); i++) 223 { 224 if (PackageFields[i].IsString) 225 Status = GetStringElement(Argument, PackageFields[i].Data); 226 else 227 Status = GetDwordElement(Argument, PackageFields[i].Data); 228 if (!NT_SUCCESS(Status)) 229 { 230 if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_ACPI_ENTRY_EXIT | CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING)) 231 DbgPrint("%s: Failed to get %s\n", FunctionName, PackageFields[i].Name); 232 break; 233 } 234 Argument = ACPI_METHOD_NEXT_ARGUMENT(Argument); 235 } 236 237 ExFreePoolWithTag(OutputBuffer, 'MtaB'); 238 return Status; 239 } 240 241 NTSTATUS 242 NTAPI 243 CmBattGetPsrData(IN PDEVICE_OBJECT DeviceObject, 244 OUT PULONG PsrData) 245 { 246 NTSTATUS Status; 247 ACPI_EVAL_OUTPUT_BUFFER OutputBuffer; 248 ACPI_EVAL_INPUT_BUFFER InputBuffer; 249 PAGED_CODE(); 250 if (CmBattDebug & 0x40) 251 DbgPrint("CmBattGetPsrData: Entered with Pdo %x Tid %x\n", 252 DeviceObject, KeGetCurrentThread()); 253 254 /* Initialize to zero */ 255 ASSERT(PsrData != NULL); 256 *PsrData = 0; 257 258 /* Request the _PSR method */ 259 *(PULONG)InputBuffer.MethodName = 'RSP_'; 260 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE; 261 262 /* Send it to ACPI */ 263 Status = CmBattSendDownStreamIrp(DeviceObject, 264 IOCTL_ACPI_EVAL_METHOD, 265 &InputBuffer, 266 sizeof(InputBuffer), 267 &OutputBuffer, 268 sizeof(OutputBuffer)); 269 if (NT_SUCCESS(Status)) 270 { 271 /* Read the result */ 272 Status = GetDwordElement(OutputBuffer.Argument, PsrData); 273 if (CmBattDebug & 0x440) 274 DbgPrint("CmBattGetPsrData: _PSR method returned %x \n", *PsrData); 275 } 276 else if (CmBattDebug & 0x44C) 277 { 278 /* Failure */ 279 DbgPrint("CmBattGetPsrData: Failed _PSR method - Status (0x%x)\n", Status); 280 } 281 282 /* Return status */ 283 return Status; 284 } 285 286 NTSTATUS 287 NTAPI 288 CmBattGetStaData(IN PDEVICE_OBJECT DeviceObject, 289 OUT PULONG StaData) 290 { 291 NTSTATUS Status; 292 ACPI_EVAL_OUTPUT_BUFFER OutputBuffer; 293 ACPI_EVAL_INPUT_BUFFER InputBuffer; 294 PAGED_CODE(); 295 if (CmBattDebug & 0x40) 296 DbgPrint("CmBattGetStaData: Entered with Pdo %x Tid %x\n", 297 DeviceObject, KeGetCurrentThread()); 298 299 /* Initialize to zero */ 300 ASSERT(StaData != NULL); 301 *StaData = 0; 302 303 /* Request the _PSR method */ 304 *(PULONG)InputBuffer.MethodName = 'ATS_'; 305 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE; 306 307 /* Send it to ACPI */ 308 Status = CmBattSendDownStreamIrp(DeviceObject, 309 IOCTL_ACPI_EVAL_METHOD, 310 &InputBuffer, 311 sizeof(InputBuffer), 312 &OutputBuffer, 313 sizeof(OutputBuffer)); 314 if (NT_SUCCESS(Status)) 315 { 316 /* Read the result */ 317 Status = GetDwordElement(OutputBuffer.Argument, StaData); 318 if (CmBattDebug & 0x440) 319 DbgPrint("CmBattGetStaData: _STA method returned %x \n", *StaData); 320 } 321 else if (CmBattDebug & 0x44C) 322 { 323 /* Failure */ 324 DbgPrint("CmBattGetStaData: Failed _STA method - Status (0x%x)\n", Status); 325 Status = STATUS_NO_SUCH_DEVICE; 326 } 327 328 /* Return status */ 329 return Status; 330 } 331 332 NTSTATUS 333 NTAPI 334 CmBattGetUniqueId(IN PDEVICE_OBJECT DeviceObject, 335 OUT PULONG UniqueId) 336 { 337 NTSTATUS Status; 338 ACPI_EVAL_OUTPUT_BUFFER OutputBuffer; 339 ACPI_EVAL_INPUT_BUFFER InputBuffer; 340 PAGED_CODE(); 341 if (CmBattDebug & 0x40) 342 DbgPrint("CmBattGetUniqueId: Entered with Pdo %x Tid %x\n", 343 DeviceObject, KeGetCurrentThread()); 344 345 /* Initialize to zero */ 346 ASSERT(UniqueId != NULL); 347 *UniqueId = 0; 348 349 /* Request the _PSR method */ 350 *(PULONG)InputBuffer.MethodName = 'DIU_'; 351 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE; 352 353 /* Send it to ACPI */ 354 Status = CmBattSendDownStreamIrp(DeviceObject, 355 IOCTL_ACPI_EVAL_METHOD, 356 &InputBuffer, 357 sizeof(InputBuffer), 358 &OutputBuffer, 359 sizeof(OutputBuffer)); 360 if (NT_SUCCESS(Status)) 361 { 362 /* Read the result */ 363 Status = GetDwordElement(OutputBuffer.Argument, UniqueId); 364 if (CmBattDebug & 0x440) 365 DbgPrint("CmBattGetUniqueId: _UID method returned %x \n", *UniqueId); 366 } 367 else if (CmBattDebug & 0x44C) 368 { 369 /* Failure */ 370 DbgPrint("CmBattGetUniqueId: Failed _UID method - Status (0x%x)\n", Status); 371 Status = STATUS_NO_SUCH_DEVICE; 372 } 373 374 /* Return status */ 375 return Status; 376 } 377 378 NTSTATUS 379 NTAPI 380 CmBattSetTripPpoint(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 381 IN ULONG AlarmValue) 382 { 383 NTSTATUS Status; 384 ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER InputBuffer; 385 PAGED_CODE(); 386 if (CmBattDebug & 0x440) 387 DbgPrint("CmBattSetTripPpoint: _BTP Alarm Value %x Device %x Tid %x\n", 388 AlarmValue, DeviceExtension->DeviceId, KeGetCurrentThread); 389 390 /* Request the _BTP method */ 391 *(PULONG)InputBuffer.MethodName = 'PTB_'; 392 InputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE; 393 InputBuffer.IntegerArgument = AlarmValue; 394 395 /* Send it to ACPI */ 396 Status = CmBattSendDownStreamIrp(DeviceExtension->AttachedDevice, 397 IOCTL_ACPI_EVAL_METHOD, 398 &InputBuffer, 399 sizeof(InputBuffer), 400 NULL, 401 0); 402 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0x440)) 403 DbgPrint("CmBattSetTripPpoint: Failed _BTP method on device %x - Status (0x%x)\n", 404 DeviceExtension->DeviceId, Status); 405 406 /* Return status */ 407 return Status; 408 } 409 410 NTSTATUS 411 NTAPI 412 CmBattGetBifData(PCMBATT_DEVICE_EXTENSION DeviceExtension, 413 PACPI_BIF_DATA BifData) 414 { 415 ACPI_PACKAGE_FIELD BifFields[] = { 416 { "PowerUnit", FALSE, &BifData->PowerUnit }, 417 { "DesignCapacity", FALSE, &BifData->DesignCapacity }, 418 { "LastFullCapacity", FALSE, &BifData->LastFullCapacity }, 419 { "BatteryTechnology", FALSE, &BifData->BatteryTechnology }, 420 { "DesignVoltage", FALSE, &BifData->DesignVoltage }, 421 { "DesignCapacityWarning", FALSE, &BifData->DesignCapacityWarning }, 422 { "DesignCapacityLow", FALSE, &BifData->DesignCapacityLow }, 423 { "BatteryCapacityGranularity1", FALSE, &BifData->BatteryCapacityGranularity1 }, 424 { "BatteryCapacityGranularity2", FALSE, &BifData->BatteryCapacityGranularity2 }, 425 { "ModelNumber", TRUE, &BifData->ModelNumber }, 426 { "SerialNumber", TRUE, &BifData->SerialNumber }, 427 { "BatteryType", TRUE, &BifData->BatteryType }, 428 { "OemInfo", TRUE, &BifData->OemInfo }, 429 }; 430 PAGED_CODE(); 431 432 if (CmBattDebug & CMBATT_ACPI_ENTRY_EXIT) 433 DbgPrint("CmBattGetBifData: Buffer (0x%x) Device %x Tid %x\n", 434 BifData, DeviceExtension->DeviceId, KeGetCurrentThread()); 435 436 /* Request the _BIF method */ 437 /* Note that _BIF method is deprecated since ACPI 4.0, and replaced by _BIX method. 438 * However, VirtualBox 7.0 only support _BIF method. 439 */ 440 return CmBattCallAcpiPackage("CmBattGetBifData", 441 DeviceExtension, 442 'FIB_', 443 512, 444 BifFields, 445 RTL_NUMBER_OF(BifFields)); 446 } 447 448 NTSTATUS 449 NTAPI 450 CmBattGetBstData(PCMBATT_DEVICE_EXTENSION DeviceExtension, 451 PACPI_BST_DATA BstData) 452 { 453 ACPI_PACKAGE_FIELD BstFields[] = { 454 { "State", FALSE, &BstData->State }, 455 { "PresentRate", FALSE, &BstData->PresentRate }, 456 { "RemainingCapacity", FALSE, &BstData->RemainingCapacity }, 457 { "PresentVoltage", FALSE, &BstData->PresentVoltage }, 458 }; 459 PAGED_CODE(); 460 461 if (CmBattDebug & CMBATT_ACPI_ENTRY_EXIT) 462 DbgPrint("CmBattGetBstData: Buffer (0x%x) Device %x Tid %x\n", 463 BstData, DeviceExtension->DeviceId, KeGetCurrentThread()); 464 465 466 return CmBattCallAcpiPackage("CmBattGetBstData", 467 DeviceExtension, 468 'TSB_', 469 512, 470 BstFields, 471 RTL_NUMBER_OF(BstFields)); 472 } 473 474 /* EOF */ 475