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"); 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 UNIMPLEMENTED; 282 return STATUS_NOT_IMPLEMENTED; 283 } 284 285 NTSTATUS 286 NTAPI 287 CmBattOpenClose(IN PDEVICE_OBJECT DeviceObject, 288 IN PIRP Irp) 289 { 290 NTSTATUS Status = STATUS_SUCCESS; 291 PIO_STACK_LOCATION IoStackLocation; 292 UCHAR Major; 293 ULONG Count; 294 PCMBATT_DEVICE_EXTENSION DeviceExtension; 295 PAGED_CODE(); 296 if (CmBattDebug & CMBATT_GENERIC_INFO) DPRINT("CmBattOpenClose\n"); 297 298 /* Grab the device extension and lock it */ 299 DeviceExtension = DeviceObject->DeviceExtension; 300 ExAcquireFastMutex(&DeviceExtension->FastMutex); 301 302 /* Check if someone is trying to open a device that doesn't exist yet */ 303 Count = DeviceExtension->HandleCount; 304 if (Count == 0xFFFFFFFF) 305 { 306 /* Fail the request */ 307 Status = STATUS_NO_SUCH_DEVICE; 308 if (CmBattDebug & CMBATT_PNP_INFO) 309 { 310 DbgPrint("CmBattOpenClose: Failed (UID = %x)(device being removed).\n", 311 DeviceExtension->Tag); 312 } 313 goto Complete; 314 } 315 316 /* Check if this is an open or close */ 317 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 318 Major = IoStackLocation->MajorFunction; 319 if (Major == IRP_MJ_CREATE) 320 { 321 /* Increment the open count */ 322 DeviceExtension->HandleCount = Count + 1; 323 if (CmBattDebug & CMBATT_PNP_INFO) 324 { 325 DbgPrint("CmBattOpenClose: Open (DeviceNumber = %x)(count = %x).\n", 326 DeviceExtension->DeviceId, Count + 1); 327 } 328 } 329 else if (Major == IRP_MJ_CLOSE) 330 { 331 /* Decrement the open count */ 332 DeviceExtension->HandleCount = Count - 1; 333 if (CmBattDebug & CMBATT_PNP_INFO) 334 { 335 DbgPrint("CmBattOpenClose: Close (DeviceNumber = %x)(count = %x).\n", 336 DeviceExtension->DeviceId, Count + 1); 337 } 338 } 339 340 Complete: 341 /* Release lock and complete request */ 342 ExReleaseFastMutex(&DeviceExtension->FastMutex); 343 Irp->IoStatus.Status = Status; 344 IoCompleteRequest(Irp, IO_NO_INCREMENT); 345 return Status; 346 } 347 348 NTSTATUS 349 NTAPI 350 CmBattIoctl(IN PDEVICE_OBJECT DeviceObject, 351 IN PIRP Irp) 352 { 353 PCMBATT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 354 NTSTATUS Status; 355 PIO_STACK_LOCATION IoStackLocation; 356 ULONG IoControlCode, OutputBufferLength, InputBufferLength; 357 PAGED_CODE(); 358 if (CmBattDebug & 2) DbgPrint("CmBattIoctl\n"); 359 360 /* Acquire the remove lock */ 361 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, 0); 362 if (!NT_SUCCESS(Status)) 363 { 364 /* It's too late, fail */ 365 Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; 366 IoCompleteRequest(Irp, IO_NO_INCREMENT); 367 return STATUS_DEVICE_REMOVED; 368 } 369 370 /* There's nothing to do for an AC adapter */ 371 if (DeviceExtension->FdoType == CmBattAcAdapter) 372 { 373 /* Pass it down, and release the remove lock */ 374 IoSkipCurrentIrpStackLocation(Irp); 375 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 376 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 377 return Status; 378 } 379 380 /* Send to class driver */ 381 Status = BatteryClassIoctl(DeviceExtension->ClassData, Irp); 382 if (Status == STATUS_NOT_SUPPORTED) 383 { 384 /* Read IOCTL information from IRP stack */ 385 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 386 IoControlCode = IoStackLocation->Parameters.DeviceIoControl.IoControlCode; 387 OutputBufferLength = IoStackLocation->Parameters.DeviceIoControl.OutputBufferLength; 388 InputBufferLength = IoStackLocation->Parameters.DeviceIoControl.InputBufferLength; 389 if (CmBattDebug & 4) 390 DbgPrint("CmBattIoctl: Received Direct Access IOCTL %x\n", IoControlCode); 391 392 /* Handle internal IOCTLs */ 393 switch (IoControlCode) 394 { 395 case IOCTL_BATTERY_QUERY_UNIQUE_ID: 396 397 /* Data is 4 bytes long */ 398 if (OutputBufferLength == sizeof(ULONG)) 399 { 400 /* Query it */ 401 Status = CmBattGetUniqueId(DeviceExtension->PdoDeviceObject, 402 Irp->AssociatedIrp.SystemBuffer); 403 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 404 } 405 else 406 { 407 /* Buffer size invalid */ 408 Status = STATUS_INVALID_BUFFER_SIZE; 409 } 410 break; 411 412 case IOCTL_BATTERY_QUERY_STA: 413 414 /* Data is 4 bytes long */ 415 if (OutputBufferLength == sizeof(ULONG)) 416 { 417 /* Query it */ 418 Status = CmBattGetStaData(DeviceExtension->PdoDeviceObject, 419 Irp->AssociatedIrp.SystemBuffer); 420 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 421 } 422 else 423 { 424 /* Buffer size invalid */ 425 Status = STATUS_INVALID_BUFFER_SIZE; 426 } 427 break; 428 429 case IOCTL_BATTERY_QUERY_PSR: 430 431 /* Data is 4 bytes long */ 432 if (OutputBufferLength == sizeof(ULONG)) 433 { 434 /* Do we have an AC adapter? */ 435 if (AcAdapterPdo) 436 { 437 /* Query it */ 438 Status = CmBattGetPsrData(AcAdapterPdo, 439 Irp->AssociatedIrp.SystemBuffer); 440 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ULONG); 441 } 442 else 443 { 444 /* No adapter, just a battery, so fail */ 445 Status = STATUS_NO_SUCH_DEVICE; 446 } 447 } 448 else 449 { 450 /* Buffer size invalid */ 451 Status = STATUS_INVALID_BUFFER_SIZE; 452 } 453 break; 454 455 case IOCTL_BATTERY_SET_TRIP_POINT: 456 457 /* Data is 4 bytes long */ 458 if (InputBufferLength == sizeof(ULONG)) 459 { 460 /* Query it */ 461 Status = CmBattSetTripPpoint(DeviceExtension, 462 *(PULONG)Irp->AssociatedIrp.SystemBuffer); 463 Irp->IoStatus.Information = 0; 464 } 465 else 466 { 467 /* Buffer size invalid */ 468 Status = STATUS_INVALID_BUFFER_SIZE; 469 } 470 break; 471 472 case IOCTL_BATTERY_QUERY_BIF: 473 474 /* Data is 1060 bytes long */ 475 if (OutputBufferLength == sizeof(ACPI_BIF_DATA)) 476 { 477 /* Query it */ 478 Status = CmBattGetBifData(DeviceExtension, 479 Irp->AssociatedIrp.SystemBuffer); 480 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BIF_DATA); 481 } 482 else 483 { 484 /* Buffer size invalid */ 485 Status = STATUS_INVALID_BUFFER_SIZE; 486 } 487 break; 488 489 case IOCTL_BATTERY_QUERY_BST: 490 491 /* Data is 16 bytes long */ 492 if (OutputBufferLength == sizeof(ACPI_BST_DATA)) 493 { 494 /* Query it */ 495 Status = CmBattGetBstData(DeviceExtension, 496 Irp->AssociatedIrp.SystemBuffer); 497 if (NT_SUCCESS(Status)) Irp->IoStatus.Information = sizeof(ACPI_BST_DATA); 498 } 499 else 500 { 501 /* Buffer size invalid */ 502 Status = STATUS_INVALID_BUFFER_SIZE; 503 } 504 break; 505 506 default: 507 508 /* Unknown, let us pass it on to ACPI */ 509 if (CmBattDebug & 0xC) 510 DbgPrint("CmBattIoctl: Unknown IOCTL %x\n", IoControlCode); 511 break; 512 } 513 514 /* Did someone pick it up? */ 515 if (Status != STATUS_NOT_SUPPORTED) 516 { 517 /* Complete the request */ 518 Irp->IoStatus.Status = Status; 519 IoCompleteRequest(Irp, IO_NO_INCREMENT); 520 } 521 else 522 { 523 /* Still unsupported, try ACPI */ 524 IoSkipCurrentIrpStackLocation(Irp); 525 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 526 } 527 } 528 529 /* Release the remove lock and return status */ 530 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 531 return Status; 532 } 533 534 NTSTATUS 535 NTAPI 536 CmBattQueryTag(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 537 OUT PULONG Tag) 538 { 539 PDEVICE_OBJECT PdoDevice; 540 ULONG StaData; 541 ULONG NewTag; 542 NTSTATUS Status; 543 PAGED_CODE(); 544 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 545 DbgPrint("CmBattQueryTag - Tag (%d), Battery %x, Device %d\n", 546 *Tag, DeviceExtension, DeviceExtension->DeviceId); 547 548 /* Get PDO and clear notification flag */ 549 PdoDevice = DeviceExtension->PdoDeviceObject; 550 DeviceExtension->NotifySent = 0; 551 552 /* Get _STA from PDO (we need the machine status, not the battery status) */ 553 Status = CmBattGetStaData(PdoDevice, &StaData); 554 if (NT_SUCCESS(Status)) 555 { 556 /* Is a battery present? */ 557 if (StaData & ACPI_STA_BATTERY_PRESENT) 558 { 559 /* Do we not have a tag yet? */ 560 if (!DeviceExtension->Tag) 561 { 562 /* Set the new tag value, reset tags if we reached the maximum */ 563 NewTag = DeviceExtension->TagData; 564 if (DeviceExtension->TagData++ == 0xFFFFFFFF) NewTag = 1; 565 DeviceExtension->Tag = NewTag; 566 if (CmBattDebug & CMBATT_GENERIC_INFO) 567 DbgPrint("CmBattQueryTag - New Tag: (%d)\n", DeviceExtension->Tag); 568 569 /* Reset trip point data */ 570 DeviceExtension->TripPointOld = 0; 571 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 572 573 /* Clear AR lock and set new interrupt time */ 574 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 575 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 576 } 577 } 578 else 579 { 580 /* No battery, so no tag */ 581 DeviceExtension->Tag = 0; 582 Status = STATUS_NO_SUCH_DEVICE; 583 } 584 } 585 586 /* Return the tag and status result */ 587 *Tag = DeviceExtension->Tag; 588 if (CmBattDebug & CMBATT_ACPI_WARNING) 589 DbgPrint("CmBattQueryTag: Returning Tag: 0x%x, status 0x%x\n", *Tag, Status); 590 return Status; 591 } 592 593 NTSTATUS 594 NTAPI 595 CmBattDisableStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension) 596 { 597 NTSTATUS Status; 598 PAGED_CODE(); 599 if (CmBattDebug & 0xA) DbgPrint("CmBattDisableStatusNotify\n"); 600 601 /* Do we have a trip point */ 602 if (DeviceExtension->TripPointSet) 603 { 604 /* Is there a current value set? */ 605 if (DeviceExtension->TripPointValue) 606 { 607 /* Reset it back to 0 */ 608 DeviceExtension->TripPointValue = 0; 609 Status = CmBattSetTripPpoint(DeviceExtension, 0); 610 if (!NT_SUCCESS(Status)) 611 { 612 /* If it failed, set unknown/invalid value */ 613 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 614 if (CmBattDebug & 8) 615 DbgPrint("CmBattDisableStatusNotify: SetTripPoint failed - %x\n", Status); 616 } 617 } 618 else 619 { 620 /* No trip point set, so this is a successful no-op */ 621 Status = STATUS_SUCCESS; 622 } 623 } 624 else 625 { 626 /* Nothing we can do */ 627 Status = STATUS_OBJECT_NAME_NOT_FOUND; 628 } 629 630 /* Return status */ 631 return Status; 632 } 633 634 NTSTATUS 635 NTAPI 636 CmBattSetStatusNotify(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 637 IN ULONG BatteryTag, 638 IN PBATTERY_NOTIFY BatteryNotify) 639 { 640 NTSTATUS Status; 641 ACPI_BST_DATA BstData; 642 ULONG Capacity, NewTripPoint, TripPoint, DesignVoltage; 643 BOOLEAN Charging; 644 PAGED_CODE(); 645 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 646 DbgPrint("CmBattSetStatusNotify: Tag (%d) Target(0x%x)\n", 647 BatteryTag, BatteryNotify->LowCapacity); 648 649 /* Update any ACPI evaluations */ 650 Status = CmBattVerifyStaticInfo(DeviceExtension, BatteryTag); 651 if (!NT_SUCCESS(Status)) return Status; 652 653 /* Trip point not supported, fail */ 654 if (!DeviceExtension->TripPointSet) return STATUS_OBJECT_NAME_NOT_FOUND; 655 656 /* Are both capacities known? */ 657 if ((BatteryNotify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) || 658 (BatteryNotify->LowCapacity == BATTERY_UNKNOWN_CAPACITY)) 659 { 660 /* We can't set trip points without these */ 661 if (CmBattDebug & CMBATT_GENERIC_WARNING) 662 DbgPrint("CmBattSetStatusNotify: Failing request because of BATTERY_UNKNOWN_CAPACITY.\n"); 663 return STATUS_NOT_SUPPORTED; 664 } 665 666 /* Is the battery charging? */ 667 Charging = DeviceExtension->BstData.State & ACPI_BATT_STAT_CHARGING; 668 if (Charging) 669 { 670 /* Then the trip point is when we hit the cap */ 671 Capacity = BatteryNotify->HighCapacity; 672 NewTripPoint = BatteryNotify->HighCapacity; 673 } 674 else 675 { 676 /* Otherwise it's when we discharge to the bottom */ 677 Capacity = BatteryNotify->LowCapacity; 678 NewTripPoint = BatteryNotify->LowCapacity; 679 } 680 681 /* Do we have data in Amps or Watts? */ 682 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_AMPS) 683 { 684 /* We need the voltage to do the conversion */ 685 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 686 if ((DesignVoltage != BATTERY_UNKNOWN_VOLTAGE) && (DesignVoltage)) 687 { 688 /* Convert from mAh into Ah */ 689 TripPoint = 1000 * NewTripPoint; 690 if (Charging) 691 { 692 /* Scale the high trip point */ 693 NewTripPoint = (TripPoint + 500) / DesignVoltage + ((TripPoint + 500) % DesignVoltage != 0); 694 } 695 else 696 { 697 /* Scale the low trip point */ 698 NewTripPoint = (TripPoint - 500) / DesignVoltage - ((TripPoint - 500) % DesignVoltage == 0); 699 } 700 } 701 else 702 { 703 /* Without knowing the voltage, Amps are not enough data on consumption */ 704 Status = STATUS_NOT_SUPPORTED; 705 if (CmBattDebug & CMBATT_ACPI_WARNING) 706 DbgPrint("CmBattSetStatusNotify: Can't calculate BTP, DesignVoltage = 0x%08x\n", 707 DesignVoltage); 708 } 709 } 710 else if (Charging) 711 { 712 /* Make it trip just one past the charge cap */ 713 ++NewTripPoint; 714 } 715 else if (NewTripPoint > 0) 716 { 717 /* Make it trip just one below the drain cap */ 718 --NewTripPoint; 719 } 720 721 /* Do we actually have a new trip point? */ 722 if (NewTripPoint == DeviceExtension->TripPointValue) 723 { 724 /* No, so there is no work to be done */ 725 if (CmBattDebug & CMBATT_GENERIC_STATUS) 726 DbgPrint("CmBattSetStatusNotify: Keeping original setting: %X\n", DeviceExtension->TripPointValue); 727 return STATUS_SUCCESS; 728 } 729 730 /* Set the trip point with ACPI and check for success */ 731 DeviceExtension->TripPointValue = NewTripPoint; 732 Status = CmBattSetTripPpoint(DeviceExtension, NewTripPoint); 733 if (!(NewTripPoint) && (Capacity)) Status = STATUS_NOT_SUPPORTED; 734 if (!NT_SUCCESS(Status)) 735 { 736 /* We failed to set the trip point, or there wasn't one settable */ 737 DeviceExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 738 if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING)) 739 DbgPrint("CmBattSetStatusNotify: SetTripPoint failed - %x\n", Status); 740 return Status; 741 } 742 743 /* Read the new BST data to see the latest state */ 744 Status = CmBattGetBstData(DeviceExtension, &BstData); 745 if (!NT_SUCCESS(Status)) 746 { 747 /* We'll return failure to the caller */ 748 if (CmBattDebug & (CMBATT_GENERIC_WARNING | CMBATT_ACPI_WARNING)) 749 DbgPrint("CmBattSetStatusNotify: GetBstData - %x\n", Status); 750 } 751 else if ((Charging) && (BstData.RemainingCapacity >= NewTripPoint)) 752 { 753 /* We are charging and our capacity is past the trip point, so trip now */ 754 if (CmBattDebug & CMBATT_GENERIC_WARNING) 755 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n", 756 NewTripPoint, BstData.RemainingCapacity); 757 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 758 } 759 else if ((BstData.RemainingCapacity) && (Capacity)) 760 { 761 /* We are discharging, and our capacity is below the trip point, trip now */ 762 if (CmBattDebug & CMBATT_GENERIC_WARNING) 763 DbgPrint("CmBattSetStatusNotify: Trip point already crossed (1): TP = %08x, remaining capacity = %08x\n", 764 NewTripPoint, BstData.RemainingCapacity); 765 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 766 } 767 768 /* All should've went well if we got here, unless BST failed... return! */ 769 if (CmBattDebug & CMBATT_GENERIC_STATUS) 770 DbgPrint("CmBattSetStatusNotify: Want %X CurrentCap %X\n", 771 Capacity, DeviceExtension->RemainingCapacity); 772 if (CmBattDebug & CMBATT_ACPI_WARNING) 773 DbgPrint("CmBattSetStatusNotify: Set to: [%#08lx][%#08lx][%#08lx] Status %x\n", 774 BatteryNotify->PowerState, 775 BatteryNotify->LowCapacity, 776 BatteryNotify->HighCapacity); 777 return Status; 778 } 779 780 NTSTATUS 781 NTAPI 782 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 783 IN ULONG Tag) 784 { 785 ULONG PsrData = 0; 786 NTSTATUS Status; 787 ULONG BstState; 788 ULONG DesignVoltage, PresentRate, RemainingCapacity; 789 PAGED_CODE(); 790 if (CmBattDebug & CMBATT_GENERIC_INFO) 791 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension, Tag); 792 793 /* Validate ACPI data */ 794 Status = CmBattVerifyStaticInfo(DeviceExtension, Tag); 795 if (!NT_SUCCESS(Status)) return Status; 796 797 /* Check for delayed status notifications */ 798 if (DeviceExtension->DelayNotification) 799 { 800 /* Process them now and don't do any other work */ 801 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 802 return Status; 803 } 804 805 /* Get _BST from ACPI */ 806 Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData); 807 if (!NT_SUCCESS(Status)) 808 { 809 /* Fail */ 810 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 811 return Status; 812 } 813 814 /* Clear current BST information */ 815 DeviceExtension->State = 0; 816 DeviceExtension->RemainingCapacity = 0; 817 DeviceExtension->PresentVoltage = 0; 818 DeviceExtension->Rate = 0; 819 820 /* Get battery state */ 821 BstState = DeviceExtension->BstData.State; 822 823 /* Is the battery both charging and discharging? */ 824 if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState & ACPI_BATT_STAT_CHARGING) && 825 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 826 DbgPrint("************************ ACPI BIOS BUG ********************\n* " 827 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n" 828 "* One battery cannot be charging and discharging at the same time.\n", 829 BstState); 830 831 /* Is the battery discharging? */ 832 if (BstState & ACPI_BATT_STAT_DISCHARG) 833 { 834 /* Set power state and check if it just started discharging now */ 835 DeviceExtension->State |= BATTERY_DISCHARGING; 836 if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG)) 837 { 838 /* Remember the time when the state changed */ 839 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 840 } 841 } 842 else if (BstState & ACPI_BATT_STAT_CHARGING) 843 { 844 /* Battery is charging, update power state */ 845 DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE); 846 } 847 848 /* Is the battery in a critical state? */ 849 if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |= BATTERY_CRITICAL; 850 851 /* Read the voltage data */ 852 DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage; 853 854 /* Check if we have an A/C adapter */ 855 if (AcAdapterPdo) 856 { 857 /* Query information on it */ 858 CmBattGetPsrData(AcAdapterPdo, &PsrData); 859 } 860 else 861 { 862 /* Otherwise, check if the battery is charging */ 863 if (BstState & ACPI_BATT_STAT_CHARGING) 864 { 865 /* Then we'll assume there's a charger */ 866 PsrData = 1; 867 } 868 else 869 { 870 /* Assume no charger */ 871 PsrData = 0; 872 } 873 } 874 875 /* Is there a charger? */ 876 if (PsrData) 877 { 878 /* Set the power state flag to reflect this */ 879 DeviceExtension->State |= BATTERY_POWER_ON_LINE; 880 if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 881 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n"); 882 } 883 else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 884 { 885 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n"); 886 } 887 888 /* Get some data we'll need */ 889 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 890 PresentRate = DeviceExtension->BstData.PresentRate; 891 RemainingCapacity = DeviceExtension->BstData.RemainingCapacity; 892 893 /* Check if we have battery data in Watts instead of Amps */ 894 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS) 895 { 896 /* Get the data from the BST */ 897 DeviceExtension->RemainingCapacity = RemainingCapacity; 898 DeviceExtension->Rate = PresentRate; 899 900 /* Check if the rate is invalid */ 901 if (PresentRate > CM_MAX_VALUE) 902 { 903 /* Set an unknown rate and don't touch the old value */ 904 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 905 if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug & CMBATT_ACPI_WARNING)) 906 { 907 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n"); 908 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate); 909 } 910 } 911 } 912 else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage)) 913 { 914 /* We have voltage data, what about capacity? */ 915 if (RemainingCapacity == CM_UNKNOWN_VALUE) 916 { 917 /* Unable to calculate it */ 918 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 919 if (CmBattDebug & CMBATT_ACPI_WARNING) 920 { 921 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n"); 922 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n"); 923 } 924 } 925 else 926 { 927 /* Compute the capacity with the information we have */ 928 DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity + 500) / 1000; 929 } 930 931 /* Check if we have a rate */ 932 if (PresentRate != CM_UNKNOWN_VALUE) 933 { 934 /* Make sure the rate isn't too large */ 935 if (PresentRate > (-500 / DesignVoltage)) 936 { 937 /* It is, so set unknown state */ 938 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 939 if (CmBattDebug & CMBATT_ACPI_WARNING) 940 { 941 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 942 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate); 943 } 944 } 945 946 /* Compute the rate */ 947 DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000; 948 } 949 else 950 { 951 /* We don't have a rate, so set unknown value */ 952 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 953 if (CmBattDebug & CMBATT_ACPI_WARNING) 954 { 955 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 956 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n"); 957 } 958 } 959 } 960 else 961 { 962 /* We have no rate, and no capacity, set unknown values */ 963 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 964 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 965 if (CmBattDebug & CMBATT_ACPI_WARNING) 966 { 967 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n"); 968 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage); 969 } 970 } 971 972 /* Check if we have an unknown rate */ 973 if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE) 974 { 975 /* The battery is discharging but we don't know by how much... this is bad! */ 976 if ((BstState & ACPI_BATT_STAT_DISCHARG) && 977 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 978 DbgPrint("CmBattGetBatteryStatus: battery rate is unknown when battery is not charging!\n"); 979 } 980 else if (DeviceExtension->State & BATTERY_DISCHARGING) 981 { 982 /* The battery is discharging, so treat the rate as a negative rate */ 983 DeviceExtension->Rate = -DeviceExtension->Rate; 984 } 985 else if (!(DeviceExtension->State & BATTERY_CHARGING) && (DeviceExtension->Rate)) 986 { 987 /* We are not charging, not discharging, but have a rate? Ignore it! */ 988 if (CmBattDebug & CMBATT_GENERIC_WARNING) 989 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n", 990 DeviceExtension->Rate); 991 DeviceExtension->Rate = 0; 992 } 993 994 /* Done */ 995 return STATUS_SUCCESS; 996 } 997 998 NTSTATUS 999 NTAPI 1000 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension, 1001 IN ULONG Tag, 1002 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel, 1003 IN OPTIONAL LONG AtRate, 1004 IN PVOID Buffer, 1005 IN ULONG BufferLength, 1006 OUT PULONG ReturnedLength) 1007 { 1008 NTSTATUS Status; 1009 PVOID QueryData = NULL; 1010 ULONG QueryLength = 0; 1011 ULONG RemainingTime = 0; 1012 ANSI_STRING TempString; 1013 UNICODE_STRING TempString2; 1014 WCHAR InfoBuffer[256]; 1015 WCHAR TempBuffer[256]; 1016 UNICODE_STRING InfoString; 1017 ULONG RemainingCapacity; 1018 BATTERY_REPORTING_SCALE BatteryReportingScale[2]; 1019 LONG Rate; 1020 PAGED_CODE(); 1021 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 1022 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n", 1023 Tag, 1024 FdoExtension->DeviceId, 1025 InfoLevel); 1026 1027 /* Check ACPI Data */ 1028 Status = CmBattVerifyStaticInfo(FdoExtension, Tag); 1029 if (!NT_SUCCESS(Status)) return Status; 1030 1031 /* Check what caller wants */ 1032 switch (InfoLevel) 1033 { 1034 case BatteryInformation: 1035 /* Just return our static information */ 1036 QueryData = &FdoExtension->BatteryInformation; 1037 QueryLength = sizeof(BATTERY_INFORMATION); 1038 break; 1039 1040 case BatteryGranularityInformation: 1041 1042 /* Return our static information, we have two scales */ 1043 BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1; 1044 BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1; 1045 BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2; 1046 BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity; 1047 QueryData = BatteryReportingScale; 1048 QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2; 1049 break; 1050 1051 case BatteryEstimatedTime: 1052 1053 /* Check if it's been more than 2 1/2 minutes since the last change */ 1054 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime)) 1055 { 1056 /* Get new battery status */ 1057 CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag); 1058 1059 /* If the caller didn't specify a rate, use our static one */ 1060 Rate = AtRate; 1061 if (!Rate) Rate = FdoExtension->Rate; 1062 1063 /* If we don't have a valid negative rate, use unknown value */ 1064 if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE; 1065 1066 /* Grab the remaining capacity */ 1067 RemainingCapacity = FdoExtension->RemainingCapacity; 1068 1069 /* See if we don't know one or the other */ 1070 if ((Rate == BATTERY_UNKNOWN_RATE) || 1071 (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)) 1072 { 1073 /* If the battery is discharging, we can't give out a time */ 1074 if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) && 1075 (CmBattDebug & CMBATT_GENERIC_WARNING)) 1076 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n"); 1077 1078 /* Check if we don't have a rate and capacity is going down */ 1079 if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) && 1080 (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG)) 1081 { 1082 /* We have to fail, since we lack data */ 1083 Status = STATUS_INVALID_DEVICE_REQUEST; 1084 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1085 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n"); 1086 } 1087 1088 /* If we don't have capacity, the rate is useless */ 1089 if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY) 1090 { 1091 /* We have to fail the request */ 1092 Status = STATUS_INVALID_DEVICE_REQUEST; 1093 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1094 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n"); 1095 } 1096 } 1097 else 1098 { 1099 /* We have data, but is it valid? */ 1100 if (RemainingCapacity > 0x123456) 1101 { 1102 /* The capacity seems bogus, so don't use it */ 1103 if (CmBattDebug & CMBATT_ACPI_WARNING) 1104 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n"); 1105 } 1106 else 1107 { 1108 /* Compute the remaining time in seconds, based on rate */ 1109 RemainingTime = (RemainingCapacity * 3600) / -Rate; 1110 } 1111 } 1112 } 1113 1114 /* Return the remaining time */ 1115 QueryData = &RemainingTime; 1116 QueryLength = sizeof(ULONG); 1117 break; 1118 1119 case BatteryDeviceName: 1120 1121 /* Build the model number string */ 1122 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); 1123 1124 /* Convert it to Unicode */ 1125 InfoString.Buffer = InfoBuffer; 1126 InfoString.MaximumLength = sizeof(InfoBuffer); 1127 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1128 1129 /* Return the unicode buffer */ 1130 QueryData = InfoString.Buffer; 1131 QueryLength = InfoString.Length; 1132 break; 1133 1134 case BatteryTemperature: 1135 case BatteryManufactureDate: 1136 1137 /* We don't support these */ 1138 Status = STATUS_INVALID_DEVICE_REQUEST; 1139 break; 1140 1141 case BatteryManufactureName: 1142 1143 /* Build the OEM info string */ 1144 RtlInitAnsiString(&TempString, FdoExtension->OemInfo); 1145 1146 /* Convert it to Unicode */ 1147 InfoString.Buffer = InfoBuffer; 1148 InfoString.MaximumLength = sizeof(InfoBuffer); 1149 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1150 1151 /* Return the unicode buffer */ 1152 QueryData = InfoString.Buffer; 1153 QueryLength = InfoString.Length; 1154 break; 1155 1156 case BatteryUniqueID: 1157 1158 /* Build the serial number string */ 1159 RtlInitAnsiString(&TempString, FdoExtension->SerialNumber); 1160 1161 /* Convert it to Unicode */ 1162 InfoString.Buffer = InfoBuffer; 1163 InfoString.MaximumLength = sizeof(InfoBuffer); 1164 RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1165 1166 /* Setup a temporary string for concatenation */ 1167 TempString2.Buffer = TempBuffer; 1168 TempString2.MaximumLength = sizeof(TempBuffer); 1169 1170 /* Check if there's an OEM string */ 1171 if (FdoExtension->OemInfo[0]) 1172 { 1173 /* Build the OEM info string */ 1174 RtlInitAnsiString(&TempString, FdoExtension->OemInfo); 1175 1176 /* Convert it to Unicode and append it */ 1177 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 1178 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 1179 } 1180 1181 /* Build the model number string */ 1182 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); 1183 1184 /* Convert it to Unicode and append it */ 1185 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 1186 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 1187 1188 /* Return the final appended string */ 1189 QueryData = InfoString.Buffer; 1190 QueryLength = InfoString.Length; 1191 break; 1192 1193 default: 1194 1195 /* Everything else is unknown */ 1196 Status = STATUS_INVALID_PARAMETER; 1197 break; 1198 } 1199 1200 /* Return the required length and check if the caller supplied enough */ 1201 *ReturnedLength = QueryLength; 1202 if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL; 1203 1204 /* Copy the data if there's enough space and it exists */ 1205 if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength); 1206 1207 /* Return function result */ 1208 return Status; 1209 } 1210 1211 NTSTATUS 1212 NTAPI 1213 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 1214 IN ULONG Tag, 1215 IN PBATTERY_STATUS BatteryStatus) 1216 { 1217 NTSTATUS Status; 1218 PAGED_CODE(); 1219 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 1220 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag, DeviceExtension->DeviceId); 1221 1222 /* Query ACPI information */ 1223 Status = CmBattGetBatteryStatus(DeviceExtension, Tag); 1224 if (NT_SUCCESS(Status)) 1225 { 1226 BatteryStatus->PowerState = DeviceExtension->State; 1227 BatteryStatus->Capacity = DeviceExtension->RemainingCapacity; 1228 BatteryStatus->Voltage = DeviceExtension->PresentVoltage; 1229 BatteryStatus->Rate = DeviceExtension->Rate; 1230 } 1231 1232 /* Return status */ 1233 if (CmBattDebug & (CMBATT_GENERIC_INFO)) 1234 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n", 1235 BatteryStatus->PowerState, 1236 BatteryStatus->Capacity, 1237 BatteryStatus->Voltage, 1238 BatteryStatus->Rate); 1239 return Status; 1240 } 1241 1242 NTSTATUS 1243 NTAPI 1244 DriverEntry(IN PDRIVER_OBJECT DriverObject, 1245 IN PUNICODE_STRING RegistryPath) 1246 { 1247 NTSTATUS Status; 1248 PDRIVER_EXTENSION DriverExtension; 1249 OBJECT_ATTRIBUTES ObjectAttributes; 1250 UNICODE_STRING CallbackName; 1251 1252 /* Allocate registry path */ 1253 GlobalRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); 1254 GlobalRegistryPath.Length = RegistryPath->Length; 1255 GlobalRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, 1256 GlobalRegistryPath.MaximumLength, 1257 'MtaB'); 1258 if (!GlobalRegistryPath.Buffer) 1259 { 1260 /* Fail if we're out of memory this early */ 1261 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1262 DbgPrint("CmBatt: Couldn't allocate pool for registry path."); 1263 return STATUS_INSUFFICIENT_RESOURCES; 1264 } 1265 1266 /* Buffer allocated, copy the string */ 1267 RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath); 1268 if (CmBattDebug & CMBATT_GENERIC_INFO) 1269 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n", 1270 DriverObject, 1271 RegistryPath->Buffer); 1272 1273 /* Setup the major dispatchers */ 1274 DriverObject->MajorFunction[IRP_MJ_CREATE] = CmBattOpenClose; 1275 DriverObject->MajorFunction[IRP_MJ_CLOSE] = CmBattOpenClose; 1276 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CmBattIoctl; 1277 DriverObject->MajorFunction[IRP_MJ_POWER] = CmBattPowerDispatch; 1278 DriverObject->MajorFunction[IRP_MJ_PNP] = CmBattPnpDispatch; 1279 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CmBattSystemControl; 1280 1281 /* And the unload routine */ 1282 DriverObject->DriverUnload = CmBattUnload; 1283 1284 /* And the add device routine */ 1285 DriverExtension = DriverObject->DriverExtension; 1286 DriverExtension->AddDevice = CmBattAddDevice; 1287 1288 /* Create a power callback */ 1289 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState"); 1290 InitializeObjectAttributes(&ObjectAttributes, 1291 &CallbackName, 1292 OBJ_KERNEL_HANDLE, 1293 NULL, 1294 NULL); 1295 Status = ExCreateCallback(&CmBattPowerCallBackObject, &ObjectAttributes, 0, TRUE); 1296 if (!NT_SUCCESS(Status)) 1297 { 1298 /* No callback, fail */ 1299 CmBattPowerCallBackObject = 0; 1300 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1301 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status); 1302 } 1303 else 1304 { 1305 /* Register the power callback now */ 1306 CmBattPowerCallBackRegistration = ExRegisterCallback(CmBattPowerCallBackObject, 1307 (PVOID)CmBattPowerCallBack, 1308 DriverObject); 1309 if (CmBattPowerCallBackRegistration) 1310 { 1311 /* Last thing: setup our DPC and timer for battery wake */ 1312 KeInitializeDpc(&CmBattWakeDpcObject, (PVOID)CmBattWakeDpc, DriverObject); 1313 KeInitializeTimer(&CmBattWakeDpcTimerObject); 1314 } 1315 else 1316 { 1317 ObDereferenceObject(CmBattPowerCallBackObject); 1318 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1319 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n"); 1320 } 1321 1322 /* All good */ 1323 Status = STATUS_SUCCESS; 1324 } 1325 1326 /* Return failure or success */ 1327 return Status; 1328 } 1329 1330 /* EOF */ 1331