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