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/cmbatt.c 5 * PURPOSE: Main Initialization Code and IRP Handling 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "cmbatt.h" 12 13 #include <debug.h> 14 15 /* GLOBALS ********************************************************************/ 16 17 ULONG CmBattDebug; 18 PCALLBACK_OBJECT CmBattPowerCallBackObject; 19 PVOID CmBattPowerCallBackRegistration; 20 UNICODE_STRING GlobalRegistryPath; 21 KTIMER CmBattWakeDpcTimerObject; 22 KDPC CmBattWakeDpcObject; 23 PDEVICE_OBJECT AcAdapterPdo; 24 LARGE_INTEGER CmBattWakeDpcDelay; 25 26 /* FUNCTIONS ******************************************************************/ 27 28 VOID 29 NTAPI 30 CmBattPowerCallBack(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 31 IN ULONG Action, 32 IN ULONG Value) 33 { 34 BOOLEAN Cancelled; 35 PDEVICE_OBJECT DeviceObject; 36 if (CmBattDebug & 0x10) 37 DbgPrint("CmBattPowerCallBack: action: %d, value: %d \n", Action, Value); 38 39 /* Check if a transition is going to happen */ 40 if (Action == PO_CB_SYSTEM_STATE_LOCK) 41 { 42 /* We have just re-entered S0: call the wake DPC in 10 seconds */ 43 if (Value == 1) 44 { 45 if (CmBattDebug & 0x10) 46 DbgPrint("CmBattPowerCallBack: Calling CmBattWakeDpc after 10 seconds.\n"); 47 Cancelled = KeSetTimer(&CmBattWakeDpcTimerObject, CmBattWakeDpcDelay, &CmBattWakeDpcObject); 48 if (CmBattDebug & 0x10) 49 DbgPrint("CmBattPowerCallBack: timerCanceled = %d.\n", Cancelled); 50 } 51 else if (Value == 0) 52 { 53 /* We are exiting the S0 state: loop all devices to set the delay flag */ 54 if (CmBattDebug & 0x10) 55 DbgPrint("CmBattPowerCallBack: Delaying Notifications\n"); 56 for (DeviceObject = DeviceExtension->DeviceObject; 57 DeviceObject; 58 DeviceObject = DeviceObject->NextDevice) 59 { 60 /* Set the delay flag */ 61 DeviceExtension = DeviceObject->DeviceExtension; 62 DeviceExtension->DelayNotification = TRUE; 63 } 64 } 65 else if (CmBattDebug & 0x10) 66 { 67 /* Unknown value */ 68 DbgPrint("CmBattPowerCallBack: unknown argument2 = %08x\n", Value); 69 } 70 } 71 } 72 73 VOID 74 NTAPI 75 CmBattWakeDpc(IN PKDPC Dpc, 76 IN PCMBATT_DEVICE_EXTENSION FdoExtension, 77 IN PVOID SystemArgument1, 78 IN PVOID SystemArgument2) 79 { 80 PDEVICE_OBJECT CurrentObject; 81 BOOLEAN AcNotify = FALSE; 82 PCMBATT_DEVICE_EXTENSION DeviceExtension; 83 ULONG ArFlag; 84 if (CmBattDebug & 2) DbgPrint("CmBattWakeDpc: Entered.\n"); 85 86 /* Loop all device objects */ 87 for (CurrentObject = FdoExtension->DeviceObject; 88 CurrentObject; 89 CurrentObject = CurrentObject->NextDevice) 90 { 91 /* Turn delay flag off, we're back in S0 */ 92 DeviceExtension = CurrentObject->DeviceExtension; 93 DeviceExtension->DelayNotification = 0; 94 95 /* Check if this is an AC adapter */ 96 if (DeviceExtension->FdoType == CmBattAcAdapter) 97 { 98 /* Was there a pending notify? */ 99 if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY) 100 { 101 /* We'll send a notify on the next pass */ 102 AcNotify = TRUE; 103 DeviceExtension->ArFlag = 0; 104 if (CmBattDebug & 0x20) 105 DbgPrint("CmBattWakeDpc: AC adapter notified\n"); 106 } 107 } 108 } 109 110 /* Loop the device objects again */ 111 for (CurrentObject = FdoExtension->DeviceObject; 112 CurrentObject; 113 CurrentObject = CurrentObject->NextDevice) 114 { 115 /* Check if this is a battery */ 116 DeviceExtension = CurrentObject->DeviceExtension; 117 if (DeviceExtension->FdoType == CmBattBattery) 118 { 119 /* Check what ARs are pending */ 120 ArFlag = DeviceExtension->ArFlag; 121 if (CmBattDebug & 0x20) 122 DbgPrint("CmBattWakeDpc: Performing delayed ARs: %01x\n", ArFlag); 123 124 /* Insert notification, clear the lock value */ 125 if (ArFlag & CMBATT_AR_INSERT) InterlockedExchange(&DeviceExtension->ArLockValue, 0); 126 127 /* Removal, clear the battery tag */ 128 if (ArFlag & CMBATT_AR_REMOVE) DeviceExtension->Tag = 0; 129 130 /* Notification (or AC/DC adapter change from first pass above) */ 131 if ((ArFlag & CMBATT_AR_NOTIFY) || (AcNotify)) 132 { 133 /* Notify the class driver */ 134 BatteryClassStatusNotify(DeviceExtension->ClassData); 135 } 136 } 137 } 138 } 139 140 VOID 141 NTAPI 142 CmBattNotifyHandler(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 143 IN ULONG NotifyValue) 144 { 145 ULONG ArFlag; 146 PCMBATT_DEVICE_EXTENSION FdoExtension; 147 PDEVICE_OBJECT DeviceObject; 148 149 if (CmBattDebug & (CMBATT_ACPI_ASSERT | CMBATT_PNP_INFO)) 150 DbgPrint("CmBattNotifyHandler: CmBatt 0x%08x Type %d Number %d Notify Value: %x\n", 151 DeviceExtension, 152 DeviceExtension->FdoType, 153 DeviceExtension->DeviceId, 154 NotifyValue); 155 156 /* Check what kind of notification was received */ 157 switch (NotifyValue) 158 { 159 /* ACPI Specification says is sends a "Bus Check" when power source changes */ 160 case ACPI_BUS_CHECK: 161 162 /* We treat it as possible physical change */ 163 DeviceExtension->ArFlag |= (CMBATT_AR_NOTIFY | CMBATT_AR_INSERT); 164 if ((DeviceExtension->Tag) && 165 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 166 DbgPrint("CmBattNotifyHandler: Received battery #%x insertion, but tag was not invalid.\n", 167 DeviceExtension->DeviceId); 168 break; 169 170 /* Status of the battery has changed */ 171 case ACPI_BATT_NOTIFY_STATUS: 172 173 /* All we'll do is notify the class driver */ 174 DeviceExtension->ArFlag |= CMBATT_AR_NOTIFY; 175 break; 176 177 /* Information on the battery has changed, such as physical presence */ 178 case ACPI_DEVICE_CHECK: 179 case ACPI_BATT_NOTIFY_INFO: 180 181 /* Reset all state and let the class driver re-evaluate it all */ 182 DeviceExtension->ArFlag |= (CMBATT_AR_NOTIFY | 183 CMBATT_AR_INSERT | 184 CMBATT_AR_REMOVE); 185 break; 186 187 default: 188 189 if (CmBattDebug & CMBATT_PNP_INFO) 190 DbgPrint("CmBattNotifyHandler: Unknown Notify Value: %x\n", NotifyValue); 191 } 192 193 /* Check if we're supposed to delay the notification till later */ 194 if (DeviceExtension->DelayNotification) 195 { 196 /* We'll handle this when we get a status query later on */ 197 if (CmBattDebug & CMBATT_PNP_INFO) 198 DbgPrint("CmBattNotifyHandler: Notification delayed: ARs = %01x\n", 199 DeviceExtension->ArFlag); 200 return; 201 } 202 203 /* We're going to handle this now */ 204 if (CmBattDebug & CMBATT_PNP_INFO) 205 DbgPrint("CmBattNotifyHandler: Performing ARs: %01x\n", DeviceExtension->ArFlag); 206 207 /* Check if this is a battery or AC adapter notification */ 208 if (DeviceExtension->FdoType == CmBattBattery) 209 { 210 /* Reset the current trip point */ 211 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 212 213 /* Check what ARs have to be done */ 214 ArFlag = DeviceExtension->ArFlag; 215 216 /* New battery inserted, reset lock value */ 217 if (ArFlag & CMBATT_AR_INSERT) InterlockedExchange(&DeviceExtension->ArLockValue, 0); 218 219 /* Check if the battery may have been removed */ 220 if (ArFlag & CMBATT_AR_REMOVE) DeviceExtension->Tag = 0; 221 222 /* Check if there's been any sort of change to the battery */ 223 if (ArFlag & CMBATT_AR_NOTIFY) 224 { 225 /* We'll probably end up re-evaluating _BIF and _BST */ 226 DeviceExtension->NotifySent = TRUE; 227 BatteryClassStatusNotify(DeviceExtension->ClassData); 228 } 229 } 230 else if (DeviceExtension->ArFlag & CMBATT_AR_NOTIFY) 231 { 232 /* The only known notification is AC/DC change. Loop device objects. */ 233 for (DeviceObject = DeviceExtension->FdoDeviceObject->DriverObject->DeviceObject; 234 DeviceObject; 235 DeviceObject = DeviceObject->NextDevice) 236 { 237 /* Is this a battery? */ 238 FdoExtension = DeviceObject->DeviceExtension; 239 if (FdoExtension->FdoType == CmBattBattery) 240 { 241 /* Send a notification to the class driver */ 242 FdoExtension->NotifySent = TRUE; 243 BatteryClassStatusNotify(FdoExtension->ClassData); 244 } 245 } 246 } 247 248 /* ARs have been processed */ 249 DeviceExtension->ArFlag = 0; 250 } 251 252 VOID 253 NTAPI 254 CmBattUnload(IN PDRIVER_OBJECT DriverObject) 255 { 256 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattUnload: \n"); 257 258 /* Check if we have a registered power callback */ 259 if (CmBattPowerCallBackObject) 260 { 261 /* Get rid of it */ 262 ExUnregisterCallback(CmBattPowerCallBackRegistration); 263 ObDereferenceObject(CmBattPowerCallBackObject); 264 } 265 266 /* Free the registry buffer if it exists */ 267 if (GlobalRegistryPath.Buffer) ExFreePool(GlobalRegistryPath.Buffer); 268 269 /* Make sure we don't still have references to the DO */ 270 if ((DriverObject->DeviceObject) && (CmBattDebug & CMBATT_GENERIC_WARNING)) 271 { 272 DbgPrint("Unload called before all devices removed.\n"); 273 } 274 } 275 276 NTSTATUS 277 NTAPI 278 CmBattVerifyStaticInfo(PCMBATT_DEVICE_EXTENSION DeviceExtension, 279 ULONG BatteryTag) 280 { 281 ACPI_BIF_DATA BifData; 282 PBATTERY_INFORMATION Info = &DeviceExtension->BatteryInformation; 283 NTSTATUS Status; 284 285 Status = CmBattGetBifData(DeviceExtension, &BifData); 286 if (NT_SUCCESS(Status)) 287 { 288 RtlZeroMemory(Info, sizeof(*Info)); 289 Info->Capabilities = BATTERY_SYSTEM_BATTERY; 290 Info->Technology = BifData.BatteryTechnology; 291 RtlCopyMemory(Info->Chemistry, BifData.BatteryType, 4); 292 // FIXME: take from _BIX method: Info->CycleCount 293 DeviceExtension->BifData = BifData; 294 295 if (BifData.PowerUnit == 1) 296 { 297 DPRINT1("FIXME: need to convert mAh into mWh\n"); 298 Info->DesignedCapacity = BATTERY_UNKNOWN_CAPACITY; 299 Info->FullChargedCapacity = BATTERY_UNKNOWN_CAPACITY; 300 Info->DefaultAlert1 = BATTERY_UNKNOWN_CAPACITY; 301 Info->DefaultAlert2 = BATTERY_UNKNOWN_CAPACITY; 302 } 303 else 304 { 305 Info->DesignedCapacity = BifData.DesignCapacity; 306 Info->FullChargedCapacity = BifData.LastFullCapacity; 307 Info->DefaultAlert1 = BifData.DesignCapacityLow; 308 Info->DefaultAlert2 = BifData.DesignCapacityWarning; 309 } 310 } 311 312 return Status; 313 } 314 315 NTSTATUS 316 NTAPI 317 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject, 318 IN PIRP Irp) 319 { 320 NTSTATUS Status = STATUS_SUCCESS; 321 PIO_STACK_LOCATION IoStackLocation; 322 UCHAR Major; 323 ULONG Count; 324 PCMBATT_DEVICE_EXTENSION DeviceExtension; 325 PAGED_CODE(); 326 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattOpenClose\n"); 327 328 /* Grab the device extension and lock it */ 329 DeviceExtension = DeviceObject->DeviceExtension; 330 ExAcquireFastMutex(&DeviceExtension->FastMutex); 331 332 /* Check if someone is trying to open a device that doesn't exist yet */ 333 Count = DeviceExtension->HandleCount; 334 if (Count == 0xFFFFFFFF) 335 { 336 /* Fail the request */ 337 Status = STATUS_NO_SUCH_DEVICE; 338 if (CmBattDebug & CMBATT_PNP_INFO) 339 { 340 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n", 341 DeviceExtension->Tag); 342 } 343 goto Complete; 344 } 345 346 /* Check if this is an open or close */ 347 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 348 Major = IoStackLocation->MajorFunction; 349 if (Major == IRP_MJ_CREATE) 350 { 351 /* Increment the open count */ 352 DeviceExtension->HandleCount = Count + 1; 353 if (CmBattDebug & CMBATT_PNP_INFO) 354 { 355 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n", 356 DeviceExtension->DeviceId, Count + 1); 357 } 358 } 359 else if (Major == IRP_MJ_CLOSE) 360 { 361 /* Decrement the open count */ 362 DeviceExtension->HandleCount = Count - 1; 363 if (CmBattDebug & CMBATT_PNP_INFO) 364 { 365 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n", 366 DeviceExtension->DeviceId, Count + 1); 367 } 368 } 369 370 Complete: 371 /* Release lock and complete request */ 372 ExReleaseFastMutex(&DeviceExtension->FastMutex); 373 Irp->IoStatus.Status = Status; 374 IoCompleteRequest(Irp, IO_NO_INCREMENT); 375 return Status; 376 } 377 378 NTSTATUS 379 NTAPI 380 CmBattIoctl(IN PDEVICE_OBJECT DeviceObject, 381 IN PIRP Irp) 382 { 383 PCMBATT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 384 NTSTATUS Status; 385 PIO_STACK_LOCATION IoStackLocation; 386 ULONG IoControlCode, OutputBufferLength, InputBufferLength; 387 PAGED_CODE(); 388 if (CmBattDebug & 2) DbgPrint("CmBattIoctl\n"); 389 390 /* Acquire the remove lock */ 391 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); 392 if (!NT_SUCCESS(Status)) 393 { 394 /* It's too late, fail */ 395 Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; 396 IoCompleteRequest(Irp, IO_NO_INCREMENT); 397 return STATUS_DEVICE_REMOVED; 398 } 399 400 /* There's nothing to do for an AC adapter */ 401 if (DeviceExtension->FdoType == CmBattAcAdapter) 402 { 403 /* Pass it down, and release the remove lock */ 404 IoSkipCurrentIrpStackLocation(Irp); 405 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 406 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 407 return Status; 408 } 409 410 /* Send to class driver */ 411 Status = BatteryClassIoctl(DeviceExtension->ClassData, Irp); 412 if (Status == STATUS_NOT_SUPPORTED) 413 { 414 /* Read IOCTL information from IRP stack */ 415 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 416 IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode; 417 OutputBufferLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; 418 InputBufferLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength; 419 if (CmBattDebug & 4) 420 DbgPrint("CmBattIoctl: Received Direct Access IOCTL %x\n", IoControlCode); 421 422 /* Handle internal IOCTLs */ 423 switch (IoControlCode) 424 { 425 case IOCTL_BATTERY_QUERY_UNIQUE_ID: 426 427 /* Data is 4 bytes long */ 428 if (OutputBufferLength == sizeof(ULONG)) 429 { 430 /* Query it */ 431 Status = CmBattGetUniqueId(DeviceExtension->PdoDeviceObject, 432 Irp->AssociatedIrp.SystemBuffer); 433 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 434 } 435 else 436 { 437 /* Buffer size invalid */ 438 Status = STATUS_INVALID_BUFFER_SIZE; 439 } 440 break; 441 442 case IOCTL_BATTERY_QUERY_STA: 443 444 /* Data is 4 bytes long */ 445 if (OutputBufferLength == sizeof(ULONG)) 446 { 447 /* Query it */ 448 Status = CmBattGetStaData(DeviceExtension->PdoDeviceObject, 449 Irp->AssociatedIrp.SystemBuffer); 450 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 451 } 452 else 453 { 454 /* Buffer size invalid */ 455 Status = STATUS_INVALID_BUFFER_SIZE; 456 } 457 break; 458 459 case IOCTL_BATTERY_QUERY_PSR: 460 461 /* Data is 4 bytes long */ 462 if (OutputBufferLength == sizeof(ULONG)) 463 { 464 /* Do we have an AC adapter? */ 465 if (AcAdapterPdo) 466 { 467 /* Query it */ 468 Status = CmBattGetPsrData(AcAdapterPdo, 469 Irp->AssociatedIrp.SystemBuffer); 470 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 471 } 472 else 473 { 474 /* No adapter, just a battery, so fail */ 475 Status = STATUS_NO_SUCH_DEVICE; 476 } 477 } 478 else 479 { 480 /* Buffer size invalid */ 481 Status = STATUS_INVALID_BUFFER_SIZE; 482 } 483 break; 484 485 case IOCTL_BATTERY_SET_TRIP_POINT: 486 487 /* Data is 4 bytes long */ 488 if (InputBufferLength == sizeof(ULONG)) 489 { 490 /* Query it */ 491 Status = CmBattSetTripPpoint(DeviceExtension, 492 *(PULONG)Irp->AssociatedIrp.SystemBuffer); 493 Irp->IoStatus.Information = 0; 494 } 495 else 496 { 497 /* Buffer size invalid */ 498 Status = STATUS_INVALID_BUFFER_SIZE; 499 } 500 break; 501 502 case IOCTL_BATTERY_QUERY_BIF: 503 504 /* Data is 1060 bytes long */ 505 if (OutputBufferLength == sizeof(ACPI_BIF_DATA)) 506 { 507 /* Query it */ 508 Status = CmBattGetBifData(DeviceExtension, 509 Irp->AssociatedIrp.SystemBuffer); 510 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BIF_DATA); 511 } 512 else 513 { 514 /* Buffer size invalid */ 515 Status = STATUS_INVALID_BUFFER_SIZE; 516 } 517 break; 518 519 case IOCTL_BATTERY_QUERY_BST: 520 521 /* Data is 16 bytes long */ 522 if (OutputBufferLength == sizeof(ACPI_BST_DATA)) 523 { 524 /* Query it */ 525 Status = CmBattGetBstData(DeviceExtension, 526 Irp->AssociatedIrp.SystemBuffer); 527 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BST_DATA); 528 } 529 else 530 { 531 /* Buffer size invalid */ 532 Status = STATUS_INVALID_BUFFER_SIZE; 533 } 534 break; 535 536 default: 537 538 /* Unknown, let us pass it on to ACPI */ 539 if (CmBattDebug & 0xC) 540 DbgPrint("CmBattIoctl: Unknown IOCTL %x\n", IoControlCode); 541 break; 542 } 543 544 /* Did someone pick it up? */ 545 if (Status != STATUS_NOT_SUPPORTED) 546 { 547 /* Complete the request */ 548 Irp->IoStatus.Status = Status; 549 IoCompleteRequest(Irp, IO_NO_INCREMENT); 550 } 551 else 552 { 553 /* Still unsupported, try ACPI */ 554 IoSkipCurrentIrpStackLocation(Irp); 555 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 556 } 557 } 558 559 /* Release the remove lock and return status */ 560 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 561 return Status; 562 } 563 564 NTSTATUS 565 NTAPI 566 CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 567 OUT PULONG Tag) 568 { 569 PDEVICE_OBJECT PdoDevice; 570 ULONG StaData; 571 ULONG NewTag; 572 NTSTATUS Status; 573 PAGED_CODE(); 574 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 575 DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n", 576 *Tag, DeviceExtension, DeviceExtension->DeviceId); 577 578 /* Get PDO and clear notification flag */ 579 PdoDevice = DeviceExtension->PdoDeviceObject; 580 DeviceExtension->NotifySent = 0; 581 582 /* Get _STA from PDO (we need the machine status, not the battery status) */ 583 Status = CmBattGetStaData(PdoDevice, &StaData); 584 if (NT_SUCCESS(Status)) 585 { 586 /* Is a battery present? */ 587 if (StaData & ACPI_STA_BATTERY_PRESENT) 588 { 589 /* Do we not have a tag yet? */ 590 if (!DeviceExtension->Tag) 591 { 592 /* Set the new tag value, reset tags if we reached the maximum */ 593 NewTag = DeviceExtension->TagData; 594 if (DeviceExtension->TagData++ == 0xFFFFFFFF) NewTag = 1; 595 DeviceExtension->Tag = NewTag; 596 if (CmBattDebug & CMBATT_GENERIC_INFO) 597 DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension->Tag); 598 599 /* Reset trip point data */ 600 DeviceExtension->TripPointOld = 0; 601 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 602 603 /* Clear AR lock and set new interrupt time */ 604 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 605 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 606 } 607 } 608 else 609 { 610 /* No battery, so no tag */ 611 DeviceExtension->Tag = 0; 612 Status = STATUS_NO_SUCH_DEVICE; 613 } 614 } 615 616 /* Return the tag and status result */ 617 *Tag = DeviceExtension->Tag; 618 if (CmBattDebug & CMBATT_ACPI_WARNING) 619 DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag, Status); 620 return Status; 621 } 622 623 NTSTATUS 624 NTAPI 625 CmBattDisableStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension) 626 { 627 NTSTATUS Status; 628 PAGED_CODE(); 629 if (CmBattDebug & 0xA) DbgPrint("CmBattDisableStatusNotify\n"); 630 631 /* Do we have a trip point */ 632 if (DeviceExtension->TripPointSet) 633 { 634 /* Is there a current value set? */ 635 if (DeviceExtension->TripPointValue) 636 { 637 /* Reset it back to 0 */ 638 DeviceExtension->TripPointValue = 0; 639 Status = CmBattSetTripPpoint(DeviceExtension, 0); 640 if (!NT_SUCCESS(Status)) 641 { 642 /* If it failed, set unknown/invalid value */ 643 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 644 if (CmBattDebug & 8) 645 DbgPrint("CmBattDisableStatusNotify: SetTripPoint failed - %x\n", Status); 646 } 647 } 648 else 649 { 650 /* No trip point set, so this is a successful no-op */ 651 Status = STATUS_SUCCESS; 652 } 653 } 654 else 655 { 656 /* Nothing we can do */ 657 Status = STATUS_OBJECT_NAME_NOT_FOUND; 658 } 659 660 /* Return status */ 661 return Status; 662 } 663 664 NTSTATUS 665 NTAPI 666 CmBattSetStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 667 IN ULONG BatteryTag, 668 IN PBATTERY_NOTIFY BatteryNotify) 669 { 670 NTSTATUS Status; 671 ACPI_BST_DATA BstData; 672 ULONG Capacity, NewTripPoint, TripPoint, DesignVoltage; 673 BOOLEAN Charging; 674 PAGED_CODE(); 675 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 676 DbgPrint("CmBattSetStatusNotify: Tag (%d) Target(0x%x)\n", 677 BatteryTag, BatteryNotify->LowCapacity); 678 679 /* Update any ACPI evaluations */ 680 Status = CmBattVerifyStaticInfo(DeviceExtension, BatteryTag); 681 if (!NT_SUCCESS(Status)) return Status; 682 683 /* Trip point not supported, fail */ 684 if (!DeviceExtension->TripPointSet) return STATUS_OBJECT_NAME_NOT_FOUND; 685 686 /* Are both capacities known? */ 687 if ((BatteryNotify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) || 688 (BatteryNotify->LowCapacity == BATTERY_UNKNOWN_CAPACITY)) 689 { 690 /* We can't set trip points without these */ 691 if (CmBattDebug & CMBATT_GENERIC_WARNING) 692 DbgPrint("CmBattSetStatusNotify: Failing request because of BATTERY_UNKNOWN_CAPACITY.\n"); 693 return STATUS_NOT_SUPPORTED; 694 } 695 696 /* Is the battery charging? */ 697 Charging = DeviceExtension->BstData.State & ACPI_BATT_STAT_CHARGING; 698 if (Charging) 699 { 700 /* Then the trip point is when we hit the cap */ 701 Capacity = BatteryNotify->HighCapacity; 702 NewTripPoint = BatteryNotify->HighCapacity; 703 } 704 else 705 { 706 /* Otherwise it's when we discharge to the bottom */ 707 Capacity = BatteryNotify->LowCapacity; 708 NewTripPoint = BatteryNotify->LowCapacity; 709 } 710 711 /* Do we have data in Amps or Watts? */ 712 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_AMPS) 713 { 714 /* We need the voltage to do the conversion */ 715 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 716 if ((DesignVoltage != BATTERY_UNKNOWN_VOLTAGE) && (DesignVoltage)) 717 { 718 /* Convert from mAh into Ah */ 719 TripPoint = 1000 * NewTripPoint; 720 if (Charging) 721 { 722 /* Scale the high trip point */ 723 NewTripPoint = (TripPoint + 500) / DesignVoltage + ((TripPoint + 500) % DesignVoltage != 0); 724 } 725 else 726 { 727 /* Scale the low trip point */ 728 NewTripPoint = (TripPoint - 500) / DesignVoltage - ((TripPoint - 500) % DesignVoltage == 0); 729 } 730 } 731 else 732 { 733 /* Without knowing the voltage, Amps are not enough data on consumption */ 734 Status = STATUS_NOT_SUPPORTED; 735 if (CmBattDebug & CMBATT_ACPI_WARNING) 736 DbgPrint("CmBattSetStatusNotify: Can't calculate BTP, DesignVoltage = 0x%08x\n", 737 DesignVoltage); 738 } 739 } 740 else if (Charging) 741 { 742 /* Make it trip just one past the charge cap */ 743 ++NewTripPoint; 744 } 745 else if (NewTripPoint > 0) 746 { 747 /* Make it trip just one below the drain cap */ 748 --NewTripPoint; 749 } 750 751 /* Do we actually have a new trip point? */ 752 if (NewTripPoint == DeviceExtension->TripPointValue) 753 { 754 /* No, so there is no work to be done */ 755 if (CmBattDebug & CMBATT_GENERIC_STATUS) 756 DbgPrint("CmBattSetStatusNotify: Keeping original setting: %X\n", DeviceExtension->TripPointValue); 757 return STATUS_SUCCESS; 758 } 759 760 /* Set the trip point with ACPI and check for success */ 761 DeviceExtension->TripPointValue = NewTripPoint; 762 Status = CmBattSetTripPpoint(DeviceExtension, NewTripPoint); 763 if (!(NewTripPoint) && (Capacity)) Status = STATUS_NOT_SUPPORTED; 764 if (!NT_SUCCESS(Status)) 765 { 766 /* We failed to set the trip point, or there wasn't one settable */ 767 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 768 if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING)) 769 DbgPrint("CmBattSetStatusNotify: SetTripPoint failed - %x\n", Status); 770 return Status; 771 } 772 773 /* Read the new BST data to see the latest state */ 774 Status = CmBattGetBstData(DeviceExtension, &BstData); 775 if (!NT_SUCCESS(Status)) 776 { 777 /* We'll return failure to the caller */ 778 if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING)) 779 DbgPrint("CmBattSetStatusNotify: GetBstData - %x\n", Status); 780 } 781 else if ((Charging) && (BstData.RemainingCapacity >= NewTripPoint)) 782 { 783 /* We are charging and our capacity is past the trip point, so trip now */ 784 if (CmBattDebug & CMBATT_GENERIC_WARNING) 785 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n", 786 NewTripPoint, BstData.RemainingCapacity); 787 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 788 } 789 else if ((BstData.RemainingCapacity) && (Capacity)) 790 { 791 /* We are discharging, and our capacity is below the trip point, trip now */ 792 if (CmBattDebug & CMBATT_GENERIC_WARNING) 793 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n", 794 NewTripPoint, BstData.RemainingCapacity); 795 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 796 } 797 798 /* All should've went well if we got here, unless BST failed... return! */ 799 if (CmBattDebug & CMBATT_GENERIC_STATUS) 800 DbgPrint("CmBattSetStatusNotify: Want %X CurrentCap %X\n", 801 Capacity, DeviceExtension->RemainingCapacity); 802 if (CmBattDebug & CMBATT_ACPI_WARNING) 803 DbgPrint("CmBattSetStatusNotify: Set to: [%#08lx][%#08lx][%#08lx] Status %lx\n", 804 BatteryNotify->PowerState, 805 BatteryNotify->LowCapacity, 806 BatteryNotify->HighCapacity, 807 Status); 808 return Status; 809 } 810 811 NTSTATUS 812 NTAPI 813 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 814 IN ULONG Tag) 815 { 816 ULONG PsrData = 0; 817 NTSTATUS Status; 818 ULONG BstState; 819 ULONG DesignVoltage, PresentRate, RemainingCapacity; 820 PAGED_CODE(); 821 if (CmBattDebug & CMBATT_GENERIC_INFO) 822 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension, Tag); 823 824 /* Validate ACPI data */ 825 Status = CmBattVerifyStaticInfo(DeviceExtension, Tag); 826 if (!NT_SUCCESS(Status)) return Status; 827 828 /* Check for delayed status notifications */ 829 if (DeviceExtension->DelayNotification) 830 { 831 /* Process them now and don't do any other work */ 832 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 833 return Status; 834 } 835 836 /* Get _BST from ACPI */ 837 Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData); 838 if (!NT_SUCCESS(Status)) 839 { 840 /* Fail */ 841 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 842 return Status; 843 } 844 845 /* Clear current BST information */ 846 DeviceExtension->State = 0; 847 DeviceExtension->RemainingCapacity = 0; 848 DeviceExtension->PresentVoltage = 0; 849 DeviceExtension->Rate = 0; 850 851 /* Get battery state */ 852 BstState = DeviceExtension->BstData.State; 853 854 /* Is the battery both charging and discharging? */ 855 if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState & ACPI_BATT_STAT_CHARGING) && 856 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 857 DbgPrint("************************ ACPI BIOS BUG ********************\n* " 858 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n" 859 "* One battery cannot be charging and discharging at the same time.\n", 860 BstState); 861 862 /* Is the battery discharging? */ 863 if (BstState & ACPI_BATT_STAT_DISCHARG) 864 { 865 /* Set power state and check if it just started discharging now */ 866 DeviceExtension->State |= BATTERY_DISCHARGING; 867 if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG)) 868 { 869 /* Remember the time when the state changed */ 870 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 871 } 872 } 873 else if (BstState & ACPI_BATT_STAT_CHARGING) 874 { 875 /* Battery is charging, update power state */ 876 DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE); 877 } 878 879 /* Is the battery in a critical state? */ 880 if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |= BATTERY_CRITICAL; 881 882 /* Read the voltage data */ 883 DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage; 884 885 /* Check if we have an A/C adapter */ 886 if (AcAdapterPdo) 887 { 888 /* Query information on it */ 889 CmBattGetPsrData(AcAdapterPdo, &PsrData); 890 } 891 else 892 { 893 /* Otherwise, check if the battery is charging */ 894 if (BstState & ACPI_BATT_STAT_CHARGING) 895 { 896 /* Then we'll assume there's a charger */ 897 PsrData = 1; 898 } 899 else 900 { 901 /* Assume no charger */ 902 PsrData = 0; 903 } 904 } 905 906 /* Is there a charger? */ 907 if (PsrData) 908 { 909 /* Set the power state flag to reflect this */ 910 DeviceExtension->State |= BATTERY_POWER_ON_LINE; 911 if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 912 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n"); 913 } 914 else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 915 { 916 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n"); 917 } 918 919 /* Get some data we'll need */ 920 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 921 PresentRate = DeviceExtension->BstData.PresentRate; 922 RemainingCapacity = DeviceExtension->BstData.RemainingCapacity; 923 924 /* Check if we have battery data in Watts instead of Amps */ 925 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS) 926 { 927 /* Get the data from the BST */ 928 DeviceExtension->RemainingCapacity = RemainingCapacity; 929 DeviceExtension->Rate = PresentRate; 930 931 /* Check if the rate is invalid */ 932 if (PresentRate > CM_MAX_VALUE) 933 { 934 /* Set an unknown rate and don't touch the old value */ 935 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 936 if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug & CMBATT_ACPI_WARNING)) 937 { 938 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n"); 939 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate); 940 } 941 } 942 } 943 else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage)) 944 { 945 /* We have voltage data, what about capacity? */ 946 if (RemainingCapacity == CM_UNKNOWN_VALUE) 947 { 948 /* Unable to calculate it */ 949 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 950 if (CmBattDebug & CMBATT_ACPI_WARNING) 951 { 952 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n"); 953 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n"); 954 } 955 } 956 else 957 { 958 /* Compute the capacity with the information we have */ 959 DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity + 500) / 1000; 960 } 961 962 /* Check if we have a rate */ 963 if (PresentRate != CM_UNKNOWN_VALUE) 964 { 965 /* Make sure the rate isn't too large */ 966 if (PresentRate > (-500 / DesignVoltage)) 967 { 968 /* It is, so set unknown state */ 969 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 970 if (CmBattDebug & CMBATT_ACPI_WARNING) 971 { 972 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 973 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate); 974 } 975 } 976 977 /* Compute the rate */ 978 DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000; 979 } 980 else 981 { 982 /* We don't have a rate, so set unknown value */ 983 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 984 if (CmBattDebug & CMBATT_ACPI_WARNING) 985 { 986 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 987 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n"); 988 } 989 } 990 } 991 else 992 { 993 /* We have no rate, and no capacity, set unknown values */ 994 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 995 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 996 if (CmBattDebug & CMBATT_ACPI_WARNING) 997 { 998 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n"); 999 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage); 1000 } 1001 } 1002 1003 /* Check if we have an unknown rate */ 1004 if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE) 1005 { 1006 /* The battery is discharging but we don't know by how much... this is bad! */ 1007 if ((BstState & ACPI_BATT_STAT_DISCHARG) && 1008 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 1009 DbgPrint("CmBattGetBatteryStatus: battery rate is unknown when battery is not charging!\n"); 1010 } 1011 else if (DeviceExtension->State & BATTERY_DISCHARGING) 1012 { 1013 /* The battery is discharging, so treat the rate as a negative rate */ 1014 DeviceExtension->Rate = -(LONG)DeviceExtension->Rate; 1015 } 1016 else if (!(DeviceExtension->State & BATTERY_CHARGING) && (DeviceExtension->Rate)) 1017 { 1018 /* We are not charging, not discharging, but have a rate? Ignore it! */ 1019 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1020 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n", 1021 DeviceExtension->Rate); 1022 DeviceExtension->Rate = 0; 1023 } 1024 1025 /* Done */ 1026 return STATUS_SUCCESS; 1027 } 1028 1029 NTSTATUS 1030 NTAPI 1031 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension, 1032 IN ULONG Tag, 1033 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel, 1034 IN OPTIONAL LONG AtRate, 1035 IN PVOID Buffer, 1036 IN ULONG BufferLength, 1037 OUT PULONG ReturnedLength) 1038 { 1039 NTSTATUS Status; 1040 PVOID QueryData = NULL; 1041 ULONG QueryLength = 0; 1042 ULONG RemainingTime = 0; 1043 ANSI_STRING TempString; 1044 UNICODE_STRING TempString2; 1045 WCHAR InfoBuffer[256]; 1046 WCHAR TempBuffer[256]; 1047 UNICODE_STRING InfoString; 1048 ULONG RemainingCapacity; 1049 BATTERY_REPORTING_SCALE BatteryReportingScale[2]; 1050 LONG Rate; 1051 PAGED_CODE(); 1052 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 1053 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n", 1054 Tag, 1055 FdoExtension->DeviceId, 1056 InfoLevel); 1057 1058 /* Check ACPI Data */ 1059 Status = CmBattVerifyStaticInfo(FdoExtension, Tag); 1060 if (!NT_SUCCESS(Status)) return Status; 1061 1062 /* Check what caller wants */ 1063 switch (InfoLevel) 1064 { 1065 case BatteryInformation: 1066 /* Just return our static information */ 1067 QueryData = &FdoExtension->BatteryInformation; 1068 QueryLength = sizeof(BATTERY_INFORMATION); 1069 break; 1070 1071 case BatteryGranularityInformation: 1072 1073 /* Return our static information, we have two scales */ 1074 BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1; 1075 BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1; 1076 BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2; 1077 BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity; 1078 QueryData = BatteryReportingScale; 1079 QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2; 1080 break; 1081 1082 case BatteryEstimatedTime: 1083 1084 /* Check if it's been more than 2 1/2 minutes since the last change */ 1085 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime)) 1086 { 1087 /* Get new battery status */ 1088 CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag); 1089 1090 /* If the caller didn't specify a rate, use our static one */ 1091 Rate = AtRate; 1092 if (!Rate) Rate = FdoExtension->Rate; 1093 1094 /* If we don't have a valid negative rate, use unknown value */ 1095 if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE; 1096 1097 /* Grab the remaining capacity */ 1098 RemainingCapacity = FdoExtension->RemainingCapacity; 1099 1100 /* See if we don't know one or the other */ 1101 if ((Rate == BATTERY_UNKNOWN_RATE) || 1102 (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)) 1103 { 1104 /* If the battery is discharging, we can't give out a time */ 1105 if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) && 1106 (CmBattDebug & CMBATT_GENERIC_WARNING)) 1107 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n"); 1108 1109 /* Check if we don't have a rate and capacity is going down */ 1110 if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) && 1111 (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG)) 1112 { 1113 /* We have to fail, since we lack data */ 1114 Status = STATUS_INVALID_DEVICE_REQUEST; 1115 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1116 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n"); 1117 } 1118 1119 /* If we don't have capacity, the rate is useless */ 1120 if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY) 1121 { 1122 /* We have to fail the request */ 1123 Status = STATUS_INVALID_DEVICE_REQUEST; 1124 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1125 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n"); 1126 } 1127 } 1128 else 1129 { 1130 /* We have data, but is it valid? */ 1131 if (RemainingCapacity > 0x123456) 1132 { 1133 /* The capacity seems bogus, so don't use it */ 1134 if (CmBattDebug & CMBATT_ACPI_WARNING) 1135 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n"); 1136 } 1137 else 1138 { 1139 /* Compute the remaining time in seconds, based on rate */ 1140 RemainingTime = (RemainingCapacity * 3600) / -Rate; 1141 } 1142 } 1143 } 1144 1145 /* Return the remaining time */ 1146 QueryData = &RemainingTime; 1147 QueryLength = sizeof(ULONG); 1148 break; 1149 1150 case BatteryDeviceName: 1151 1152 /* Build the model number string */ 1153 RtlInitAnsiString(&TempString, FdoExtension->BifData.ModelNumber); 1154 1155 /* Convert it to Unicode */ 1156 InfoString.Buffer = InfoBuffer; 1157 InfoString.MaximumLength = sizeof(InfoBuffer); 1158 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1159 1160 /* Return the unicode buffer */ 1161 QueryData = InfoString.Buffer; 1162 QueryLength = InfoString.Length; 1163 break; 1164 1165 case BatteryTemperature: 1166 case BatteryManufactureDate: 1167 1168 /* We don't support these */ 1169 Status = STATUS_INVALID_DEVICE_REQUEST; 1170 break; 1171 1172 case BatteryManufactureName: 1173 1174 /* Build the OEM info string */ 1175 RtlInitAnsiString(&TempString, FdoExtension->BifData.OemInfo); 1176 1177 /* Convert it to Unicode */ 1178 InfoString.Buffer = InfoBuffer; 1179 InfoString.MaximumLength = sizeof(InfoBuffer); 1180 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1181 1182 /* Return the unicode buffer */ 1183 QueryData = InfoString.Buffer; 1184 QueryLength = InfoString.Length; 1185 break; 1186 1187 case BatteryUniqueID: 1188 1189 /* Build the serial number string */ 1190 RtlInitAnsiString(&TempString, FdoExtension->BifData.SerialNumber); 1191 1192 /* Convert it to Unicode */ 1193 InfoString.Buffer = InfoBuffer; 1194 InfoString.MaximumLength = sizeof(InfoBuffer); 1195 RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1196 1197 /* Setup a temporary string for concatenation */ 1198 TempString2.Buffer = TempBuffer; 1199 TempString2.MaximumLength = sizeof(TempBuffer); 1200 1201 /* Check if there's an OEM string */ 1202 if (FdoExtension->BifData.OemInfo[0]) 1203 { 1204 /* Build the OEM info string */ 1205 RtlInitAnsiString(&TempString, FdoExtension->BifData.OemInfo); 1206 1207 /* Convert it to Unicode and append it */ 1208 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 1209 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 1210 } 1211 1212 /* Build the model number string */ 1213 RtlInitAnsiString(&TempString, FdoExtension->BifData.ModelNumber); 1214 1215 /* Convert it to Unicode and append it */ 1216 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 1217 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 1218 1219 /* Return the final appended string */ 1220 QueryData = InfoString.Buffer; 1221 QueryLength = InfoString.Length; 1222 break; 1223 1224 default: 1225 1226 /* Everything else is unknown */ 1227 Status = STATUS_INVALID_PARAMETER; 1228 break; 1229 } 1230 1231 /* Return the required length and check if the caller supplied enough */ 1232 *ReturnedLength = QueryLength; 1233 if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL; 1234 1235 /* Copy the data if there's enough space and it exists */ 1236 if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength); 1237 1238 /* Return function result */ 1239 return Status; 1240 } 1241 1242 NTSTATUS 1243 NTAPI 1244 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 1245 IN ULONG Tag, 1246 IN PBATTERY_STATUS BatteryStatus) 1247 { 1248 NTSTATUS Status; 1249 PAGED_CODE(); 1250 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 1251 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag, DeviceExtension->DeviceId); 1252 1253 /* Query ACPI information */ 1254 Status = CmBattGetBatteryStatus(DeviceExtension, Tag); 1255 if (NT_SUCCESS(Status)) 1256 { 1257 BatteryStatus->PowerState = DeviceExtension->State; 1258 BatteryStatus->Capacity = DeviceExtension->RemainingCapacity; 1259 BatteryStatus->Voltage = DeviceExtension->PresentVoltage; 1260 BatteryStatus->Rate = DeviceExtension->Rate; 1261 } 1262 1263 /* Return status */ 1264 if (CmBattDebug & (CMBATT_GENERIC_INFO)) 1265 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n", 1266 BatteryStatus->PowerState, 1267 BatteryStatus->Capacity, 1268 BatteryStatus->Voltage, 1269 BatteryStatus->Rate); 1270 return Status; 1271 } 1272 1273 NTSTATUS 1274 NTAPI 1275 DriverEntry(IN PDRIVER_OBJECT DriverObject, 1276 IN PUNICODE_STRING RegistryPath) 1277 { 1278 NTSTATUS Status; 1279 PDRIVER_EXTENSION DriverExtension; 1280 OBJECT_ATTRIBUTES ObjectAttributes; 1281 UNICODE_STRING CallbackName; 1282 1283 /* Allocate registry path */ 1284 GlobalRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); 1285 GlobalRegistryPath.Length = RegistryPath->Length; 1286 GlobalRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, 1287 GlobalRegistryPath.MaximumLength, 1288 'MtaB'); 1289 if (!GlobalRegistryPath.Buffer) 1290 { 1291 /* Fail if we're out of memory this early */ 1292 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1293 DbgPrint("CmBatt: Couldn't allocate pool for registry path."); 1294 return STATUS_INSUFFICIENT_RESOURCES; 1295 } 1296 1297 /* Buffer allocated, copy the string */ 1298 RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath); 1299 if (CmBattDebug & CMBATT_GENERIC_INFO) 1300 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%wZ\"\n", 1301 DriverObject, 1302 RegistryPath); 1303 1304 /* Setup the major dispatchers */ 1305 DriverObject->MajorFunction[IRP_MJ_CREATE] = CmBattOpenClose; 1306 DriverObject->MajorFunction[IRP_MJ_CLOSE] = CmBattOpenClose; 1307 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CmBattIoctl; 1308 DriverObject->MajorFunction[IRP_MJ_POWER] = CmBattPowerDispatch; 1309 DriverObject->MajorFunction[IRP_MJ_PNP] = CmBattPnpDispatch; 1310 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CmBattSystemControl; 1311 1312 /* And the unload routine */ 1313 DriverObject->DriverUnload = CmBattUnload; 1314 1315 /* And the add device routine */ 1316 DriverExtension = DriverObject->DriverExtension; 1317 DriverExtension->AddDevice = CmBattAddDevice; 1318 1319 /* Create a power callback */ 1320 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState"); 1321 InitializeObjectAttributes(&ObjectAttributes, 1322 &CallbackName, 1323 OBJ_KERNEL_HANDLE, 1324 NULL, 1325 NULL); 1326 Status = ExCreateCallback(&CmBattPowerCallBackObject, &ObjectAttributes, 0, TRUE); 1327 if (!NT_SUCCESS(Status)) 1328 { 1329 /* No callback, fail */ 1330 CmBattPowerCallBackObject = 0; 1331 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1332 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status); 1333 } 1334 else 1335 { 1336 /* Register the power callback now */ 1337 CmBattPowerCallBackRegistration = ExRegisterCallback(CmBattPowerCallBackObject, 1338 (PVOID)CmBattPowerCallBack, 1339 DriverObject); 1340 if (CmBattPowerCallBackRegistration) 1341 { 1342 /* Last thing: setup our DPC and timer for battery wake */ 1343 KeInitializeDpc(&CmBattWakeDpcObject, (PVOID)CmBattWakeDpc, DriverObject); 1344 KeInitializeTimer(&CmBattWakeDpcTimerObject); 1345 } 1346 else 1347 { 1348 ObDereferenceObject(CmBattPowerCallBackObject); 1349 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1350 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n"); 1351 } 1352 1353 /* All good */ 1354 Status = STATUS_SUCCESS; 1355 } 1356 1357 /* Return failure or success */ 1358 return Status; 1359 } 1360 1361 /* EOF */ 1362