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 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 %lx\n", 774 BatteryNotify->PowerState, 775 BatteryNotify->LowCapacity, 776 BatteryNotify->HighCapacity, 777 Status); 778 return Status; 779 } 780 781 NTSTATUS 782 NTAPI 783 CmBattGetBatteryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 784 IN ULONG Tag) 785 { 786 ULONG PsrData = 0; 787 NTSTATUS Status; 788 ULONG BstState; 789 ULONG DesignVoltage, PresentRate, RemainingCapacity; 790 PAGED_CODE(); 791 if (CmBattDebug & CMBATT_GENERIC_INFO) 792 DbgPrint("CmBattGetBatteryStatus - CmBatt (%08x) Tag (%d)\n", DeviceExtension, Tag); 793 794 /* Validate ACPI data */ 795 Status = CmBattVerifyStaticInfo(DeviceExtension, Tag); 796 if (!NT_SUCCESS(Status)) return Status; 797 798 /* Check for delayed status notifications */ 799 if (DeviceExtension->DelayNotification) 800 { 801 /* Process them now and don't do any other work */ 802 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 803 return Status; 804 } 805 806 /* Get _BST from ACPI */ 807 Status = CmBattGetBstData(DeviceExtension, &DeviceExtension->BstData); 808 if (!NT_SUCCESS(Status)) 809 { 810 /* Fail */ 811 InterlockedExchange(&DeviceExtension->ArLockValue, 0); 812 return Status; 813 } 814 815 /* Clear current BST information */ 816 DeviceExtension->State = 0; 817 DeviceExtension->RemainingCapacity = 0; 818 DeviceExtension->PresentVoltage = 0; 819 DeviceExtension->Rate = 0; 820 821 /* Get battery state */ 822 BstState = DeviceExtension->BstData.State; 823 824 /* Is the battery both charging and discharging? */ 825 if ((BstState & ACPI_BATT_STAT_DISCHARG) && (BstState & ACPI_BATT_STAT_CHARGING) && 826 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 827 DbgPrint("************************ ACPI BIOS BUG ********************\n* " 828 "CmBattGetBatteryStatus: Invalid state: _BST method returned 0x%08x for Battery State.\n" 829 "* One battery cannot be charging and discharging at the same time.\n", 830 BstState); 831 832 /* Is the battery discharging? */ 833 if (BstState & ACPI_BATT_STAT_DISCHARG) 834 { 835 /* Set power state and check if it just started discharging now */ 836 DeviceExtension->State |= BATTERY_DISCHARGING; 837 if (!(DeviceExtension->State & ACPI_BATT_STAT_DISCHARG)) 838 { 839 /* Remember the time when the state changed */ 840 DeviceExtension->InterruptTime = KeQueryInterruptTime(); 841 } 842 } 843 else if (BstState & ACPI_BATT_STAT_CHARGING) 844 { 845 /* Battery is charging, update power state */ 846 DeviceExtension->State |= (BATTERY_CHARGING | BATTERY_POWER_ON_LINE); 847 } 848 849 /* Is the battery in a critical state? */ 850 if (BstState & ACPI_BATT_STAT_CRITICAL) DeviceExtension->State |= BATTERY_CRITICAL; 851 852 /* Read the voltage data */ 853 DeviceExtension->PresentVoltage = DeviceExtension->BstData.PresentVoltage; 854 855 /* Check if we have an A/C adapter */ 856 if (AcAdapterPdo) 857 { 858 /* Query information on it */ 859 CmBattGetPsrData(AcAdapterPdo, &PsrData); 860 } 861 else 862 { 863 /* Otherwise, check if the battery is charging */ 864 if (BstState & ACPI_BATT_STAT_CHARGING) 865 { 866 /* Then we'll assume there's a charger */ 867 PsrData = 1; 868 } 869 else 870 { 871 /* Assume no charger */ 872 PsrData = 0; 873 } 874 } 875 876 /* Is there a charger? */ 877 if (PsrData) 878 { 879 /* Set the power state flag to reflect this */ 880 DeviceExtension->State |= BATTERY_POWER_ON_LINE; 881 if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 882 DbgPrint("CmBattGetBatteryStatus: AC adapter is connected\n"); 883 } 884 else if (CmBattDebug & (CMBATT_GENERIC_INFO | CMBATT_GENERIC_STATUS)) 885 { 886 DbgPrint("CmBattGetBatteryStatus: AC adapter is NOT connected\n"); 887 } 888 889 /* Get some data we'll need */ 890 DesignVoltage = DeviceExtension->BifData.DesignVoltage; 891 PresentRate = DeviceExtension->BstData.PresentRate; 892 RemainingCapacity = DeviceExtension->BstData.RemainingCapacity; 893 894 /* Check if we have battery data in Watts instead of Amps */ 895 if (DeviceExtension->BifData.PowerUnit == ACPI_BATT_POWER_UNIT_WATTS) 896 { 897 /* Get the data from the BST */ 898 DeviceExtension->RemainingCapacity = RemainingCapacity; 899 DeviceExtension->Rate = PresentRate; 900 901 /* Check if the rate is invalid */ 902 if (PresentRate > CM_MAX_VALUE) 903 { 904 /* Set an unknown rate and don't touch the old value */ 905 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 906 if ((PresentRate != CM_UNKNOWN_VALUE) && (CmBattDebug & CMBATT_ACPI_WARNING)) 907 { 908 DbgPrint("CmBattGetBatteryStatus - Rate is greater than CM_MAX_VALUE\n"); 909 DbgPrint("---------------------- PresentRate = 0x%08x\n", PresentRate); 910 } 911 } 912 } 913 else if ((DesignVoltage != CM_UNKNOWN_VALUE) && (DesignVoltage)) 914 { 915 /* We have voltage data, what about capacity? */ 916 if (RemainingCapacity == CM_UNKNOWN_VALUE) 917 { 918 /* Unable to calculate it */ 919 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 920 if (CmBattDebug & CMBATT_ACPI_WARNING) 921 { 922 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity \n"); 923 DbgPrint("---------------------- RemainingCapacity = CM_UNKNOWN_VALUE\n"); 924 } 925 } 926 else 927 { 928 /* Compute the capacity with the information we have */ 929 DeviceExtension->RemainingCapacity = (DesignVoltage * RemainingCapacity + 500) / 1000; 930 } 931 932 /* Check if we have a rate */ 933 if (PresentRate != CM_UNKNOWN_VALUE) 934 { 935 /* Make sure the rate isn't too large */ 936 if (PresentRate > (-500 / DesignVoltage)) 937 { 938 /* It is, so set unknown state */ 939 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 940 if (CmBattDebug & CMBATT_ACPI_WARNING) 941 { 942 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 943 DbgPrint("---------------------- Overflow: PresentRate = 0x%08x\n", PresentRate); 944 } 945 } 946 947 /* Compute the rate */ 948 DeviceExtension->Rate = (PresentRate * DesignVoltage + 500) / 1000; 949 } 950 else 951 { 952 /* We don't have a rate, so set unknown value */ 953 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 954 if (CmBattDebug & CMBATT_ACPI_WARNING) 955 { 956 DbgPrint("CmBattGetBatteryStatus - Can't calculate Rate \n"); 957 DbgPrint("---------------------- Present Rate = CM_UNKNOWN_VALUE\n"); 958 } 959 } 960 } 961 else 962 { 963 /* We have no rate, and no capacity, set unknown values */ 964 DeviceExtension->Rate = BATTERY_UNKNOWN_RATE; 965 DeviceExtension->RemainingCapacity = BATTERY_UNKNOWN_CAPACITY; 966 if (CmBattDebug & CMBATT_ACPI_WARNING) 967 { 968 DbgPrint("CmBattGetBatteryStatus - Can't calculate RemainingCapacity and Rate \n"); 969 DbgPrint("---------------------- DesignVoltage = 0x%08x\n", DesignVoltage); 970 } 971 } 972 973 /* Check if we have an unknown rate */ 974 if (DeviceExtension->Rate == BATTERY_UNKNOWN_RATE) 975 { 976 /* The battery is discharging but we don't know by how much... this is bad! */ 977 if ((BstState & ACPI_BATT_STAT_DISCHARG) && 978 (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_WARNING))) 979 DbgPrint("CmBattGetBatteryStatus: battery rate is unknown when battery is not charging!\n"); 980 } 981 else if (DeviceExtension->State & BATTERY_DISCHARGING) 982 { 983 /* The battery is discharging, so treat the rate as a negative rate */ 984 DeviceExtension->Rate = -(LONG)DeviceExtension->Rate; 985 } 986 else if (!(DeviceExtension->State & BATTERY_CHARGING) && (DeviceExtension->Rate)) 987 { 988 /* We are not charging, not discharging, but have a rate? Ignore it! */ 989 if (CmBattDebug & CMBATT_GENERIC_WARNING) 990 DbgPrint("CmBattGetBatteryStatus: battery is not charging or discharging, but rate = %x\n", 991 DeviceExtension->Rate); 992 DeviceExtension->Rate = 0; 993 } 994 995 /* Done */ 996 return STATUS_SUCCESS; 997 } 998 999 NTSTATUS 1000 NTAPI 1001 CmBattQueryInformation(IN PCMBATT_DEVICE_EXTENSION FdoExtension, 1002 IN ULONG Tag, 1003 IN BATTERY_QUERY_INFORMATION_LEVEL InfoLevel, 1004 IN OPTIONAL LONG AtRate, 1005 IN PVOID Buffer, 1006 IN ULONG BufferLength, 1007 OUT PULONG ReturnedLength) 1008 { 1009 NTSTATUS Status; 1010 PVOID QueryData = NULL; 1011 ULONG QueryLength = 0; 1012 ULONG RemainingTime = 0; 1013 ANSI_STRING TempString; 1014 UNICODE_STRING TempString2; 1015 WCHAR InfoBuffer[256]; 1016 WCHAR TempBuffer[256]; 1017 UNICODE_STRING InfoString; 1018 ULONG RemainingCapacity; 1019 BATTERY_REPORTING_SCALE BatteryReportingScale[2]; 1020 LONG Rate; 1021 PAGED_CODE(); 1022 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 1023 DbgPrint("CmBattQueryInformation - Tag (%d) Device %d, Informationlevel %d\n", 1024 Tag, 1025 FdoExtension->DeviceId, 1026 InfoLevel); 1027 1028 /* Check ACPI Data */ 1029 Status = CmBattVerifyStaticInfo(FdoExtension, Tag); 1030 if (!NT_SUCCESS(Status)) return Status; 1031 1032 /* Check what caller wants */ 1033 switch (InfoLevel) 1034 { 1035 case BatteryInformation: 1036 /* Just return our static information */ 1037 QueryData = &FdoExtension->BatteryInformation; 1038 QueryLength = sizeof(BATTERY_INFORMATION); 1039 break; 1040 1041 case BatteryGranularityInformation: 1042 1043 /* Return our static information, we have two scales */ 1044 BatteryReportingScale[0].Granularity = FdoExtension->BatteryCapacityGranularity1; 1045 BatteryReportingScale[0].Capacity = FdoExtension->BatteryInformation.DefaultAlert1; 1046 BatteryReportingScale[1].Granularity = FdoExtension->BatteryCapacityGranularity2; 1047 BatteryReportingScale[1].Capacity = FdoExtension->BatteryInformation.DesignedCapacity; 1048 QueryData = BatteryReportingScale; 1049 QueryLength = sizeof(BATTERY_REPORTING_SCALE) * 2; 1050 break; 1051 1052 case BatteryEstimatedTime: 1053 1054 /* Check if it's been more than 2 1/2 minutes since the last change */ 1055 if ((KeQueryInterruptTime() - 150000000) > (FdoExtension->InterruptTime)) 1056 { 1057 /* Get new battery status */ 1058 CmBattGetBatteryStatus(FdoExtension, FdoExtension->Tag); 1059 1060 /* If the caller didn't specify a rate, use our static one */ 1061 Rate = AtRate; 1062 if (!Rate) Rate = FdoExtension->Rate; 1063 1064 /* If we don't have a valid negative rate, use unknown value */ 1065 if (Rate >= 0) Rate = BATTERY_UNKNOWN_RATE; 1066 1067 /* Grab the remaining capacity */ 1068 RemainingCapacity = FdoExtension->RemainingCapacity; 1069 1070 /* See if we don't know one or the other */ 1071 if ((Rate == BATTERY_UNKNOWN_RATE) || 1072 (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY)) 1073 { 1074 /* If the battery is discharging, we can't give out a time */ 1075 if ((FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG) && 1076 (CmBattDebug & CMBATT_GENERIC_WARNING)) 1077 DbgPrint("CmBattQueryInformation: Can't calculate EstimatedTime.\n"); 1078 1079 /* Check if we don't have a rate and capacity is going down */ 1080 if ((FdoExtension->Rate == BATTERY_UNKNOWN_RATE) && 1081 (FdoExtension->BstData.State & ACPI_BATT_STAT_DISCHARG)) 1082 { 1083 /* We have to fail, since we lack data */ 1084 Status = STATUS_INVALID_DEVICE_REQUEST; 1085 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1086 DbgPrint("---------------------- PresentRate = BATTERY_UNKNOWN_RATE\n"); 1087 } 1088 1089 /* If we don't have capacity, the rate is useless */ 1090 if (RemainingCapacity == BATTERY_UNKNOWN_CAPACITY) 1091 { 1092 /* We have to fail the request */ 1093 Status = STATUS_INVALID_DEVICE_REQUEST; 1094 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1095 DbgPrint("---------------------- RemainingCapacity = BATTERY_UNKNOWN_CAPACITY\n"); 1096 } 1097 } 1098 else 1099 { 1100 /* We have data, but is it valid? */ 1101 if (RemainingCapacity > 0x123456) 1102 { 1103 /* The capacity seems bogus, so don't use it */ 1104 if (CmBattDebug & CMBATT_ACPI_WARNING) 1105 DbgPrint("CmBattQueryInformation: Data Overflow in calculating Remaining Capacity.\n"); 1106 } 1107 else 1108 { 1109 /* Compute the remaining time in seconds, based on rate */ 1110 RemainingTime = (RemainingCapacity * 3600) / -Rate; 1111 } 1112 } 1113 } 1114 1115 /* Return the remaining time */ 1116 QueryData = &RemainingTime; 1117 QueryLength = sizeof(ULONG); 1118 break; 1119 1120 case BatteryDeviceName: 1121 1122 /* Build the model number string */ 1123 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); 1124 1125 /* Convert it to Unicode */ 1126 InfoString.Buffer = InfoBuffer; 1127 InfoString.MaximumLength = sizeof(InfoBuffer); 1128 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1129 1130 /* Return the unicode buffer */ 1131 QueryData = InfoString.Buffer; 1132 QueryLength = InfoString.Length; 1133 break; 1134 1135 case BatteryTemperature: 1136 case BatteryManufactureDate: 1137 1138 /* We don't support these */ 1139 Status = STATUS_INVALID_DEVICE_REQUEST; 1140 break; 1141 1142 case BatteryManufactureName: 1143 1144 /* Build the OEM info string */ 1145 RtlInitAnsiString(&TempString, FdoExtension->OemInfo); 1146 1147 /* Convert it to Unicode */ 1148 InfoString.Buffer = InfoBuffer; 1149 InfoString.MaximumLength = sizeof(InfoBuffer); 1150 Status = RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1151 1152 /* Return the unicode buffer */ 1153 QueryData = InfoString.Buffer; 1154 QueryLength = InfoString.Length; 1155 break; 1156 1157 case BatteryUniqueID: 1158 1159 /* Build the serial number string */ 1160 RtlInitAnsiString(&TempString, FdoExtension->SerialNumber); 1161 1162 /* Convert it to Unicode */ 1163 InfoString.Buffer = InfoBuffer; 1164 InfoString.MaximumLength = sizeof(InfoBuffer); 1165 RtlAnsiStringToUnicodeString(&InfoString, &TempString, 0); 1166 1167 /* Setup a temporary string for concatenation */ 1168 TempString2.Buffer = TempBuffer; 1169 TempString2.MaximumLength = sizeof(TempBuffer); 1170 1171 /* Check if there's an OEM string */ 1172 if (FdoExtension->OemInfo[0]) 1173 { 1174 /* Build the OEM info string */ 1175 RtlInitAnsiString(&TempString, FdoExtension->OemInfo); 1176 1177 /* Convert it to Unicode and append it */ 1178 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 1179 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 1180 } 1181 1182 /* Build the model number string */ 1183 RtlInitAnsiString(&TempString, FdoExtension->ModelNumber); 1184 1185 /* Convert it to Unicode and append it */ 1186 RtlAnsiStringToUnicodeString(&TempString2, &TempString, 0); 1187 RtlAppendUnicodeStringToString(&InfoString, &TempString2); 1188 1189 /* Return the final appended string */ 1190 QueryData = InfoString.Buffer; 1191 QueryLength = InfoString.Length; 1192 break; 1193 1194 default: 1195 1196 /* Everything else is unknown */ 1197 Status = STATUS_INVALID_PARAMETER; 1198 break; 1199 } 1200 1201 /* Return the required length and check if the caller supplied enough */ 1202 *ReturnedLength = QueryLength; 1203 if (BufferLength < QueryLength) Status = STATUS_BUFFER_TOO_SMALL; 1204 1205 /* Copy the data if there's enough space and it exists */ 1206 if ((NT_SUCCESS(Status)) && (QueryData)) RtlCopyMemory(Buffer, QueryData, QueryLength); 1207 1208 /* Return function result */ 1209 return Status; 1210 } 1211 1212 NTSTATUS 1213 NTAPI 1214 CmBattQueryStatus(IN PCMBATT_DEVICE_EXTENSION DeviceExtension, 1215 IN ULONG Tag, 1216 IN PBATTERY_STATUS BatteryStatus) 1217 { 1218 NTSTATUS Status; 1219 PAGED_CODE(); 1220 if (CmBattDebug & (CMBATT_ACPI_WARNING | CMBATT_GENERIC_INFO)) 1221 DbgPrint("CmBattQueryStatus - Tag (%d) Device %x\n", Tag, DeviceExtension->DeviceId); 1222 1223 /* Query ACPI information */ 1224 Status = CmBattGetBatteryStatus(DeviceExtension, Tag); 1225 if (NT_SUCCESS(Status)) 1226 { 1227 BatteryStatus->PowerState = DeviceExtension->State; 1228 BatteryStatus->Capacity = DeviceExtension->RemainingCapacity; 1229 BatteryStatus->Voltage = DeviceExtension->PresentVoltage; 1230 BatteryStatus->Rate = DeviceExtension->Rate; 1231 } 1232 1233 /* Return status */ 1234 if (CmBattDebug & (CMBATT_GENERIC_INFO)) 1235 DbgPrint("CmBattQueryStatus: Returning [%#08lx][%#08lx][%#08lx][%#08lx]\n", 1236 BatteryStatus->PowerState, 1237 BatteryStatus->Capacity, 1238 BatteryStatus->Voltage, 1239 BatteryStatus->Rate); 1240 return Status; 1241 } 1242 1243 NTSTATUS 1244 NTAPI 1245 DriverEntry(IN PDRIVER_OBJECT DriverObject, 1246 IN PUNICODE_STRING RegistryPath) 1247 { 1248 NTSTATUS Status; 1249 PDRIVER_EXTENSION DriverExtension; 1250 OBJECT_ATTRIBUTES ObjectAttributes; 1251 UNICODE_STRING CallbackName; 1252 1253 /* Allocate registry path */ 1254 GlobalRegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL); 1255 GlobalRegistryPath.Length = RegistryPath->Length; 1256 GlobalRegistryPath.Buffer = ExAllocatePoolWithTag(PagedPool, 1257 GlobalRegistryPath.MaximumLength, 1258 'MtaB'); 1259 if (!GlobalRegistryPath.Buffer) 1260 { 1261 /* Fail if we're out of memory this early */ 1262 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1263 DbgPrint("CmBatt: Couldn't allocate pool for registry path."); 1264 return STATUS_INSUFFICIENT_RESOURCES; 1265 } 1266 1267 /* Buffer allocated, copy the string */ 1268 RtlCopyUnicodeString(&GlobalRegistryPath, RegistryPath); 1269 if (CmBattDebug & CMBATT_GENERIC_INFO) 1270 DbgPrint("CmBatt DriverEntry - Obj (%08x) Path \"%ws\"\n", 1271 DriverObject, 1272 RegistryPath->Buffer); 1273 1274 /* Setup the major dispatchers */ 1275 DriverObject->MajorFunction[IRP_MJ_CREATE] = CmBattOpenClose; 1276 DriverObject->MajorFunction[IRP_MJ_CLOSE] = CmBattOpenClose; 1277 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = CmBattIoctl; 1278 DriverObject->MajorFunction[IRP_MJ_POWER] = CmBattPowerDispatch; 1279 DriverObject->MajorFunction[IRP_MJ_PNP] = CmBattPnpDispatch; 1280 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = CmBattSystemControl; 1281 1282 /* And the unload routine */ 1283 DriverObject->DriverUnload = CmBattUnload; 1284 1285 /* And the add device routine */ 1286 DriverExtension = DriverObject->DriverExtension; 1287 DriverExtension->AddDevice = CmBattAddDevice; 1288 1289 /* Create a power callback */ 1290 RtlInitUnicodeString(&CallbackName, L"\\Callback\\PowerState"); 1291 InitializeObjectAttributes(&ObjectAttributes, 1292 &CallbackName, 1293 OBJ_KERNEL_HANDLE, 1294 NULL, 1295 NULL); 1296 Status = ExCreateCallback(&CmBattPowerCallBackObject, &ObjectAttributes, 0, TRUE); 1297 if (!NT_SUCCESS(Status)) 1298 { 1299 /* No callback, fail */ 1300 CmBattPowerCallBackObject = 0; 1301 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1302 DbgPrint("CmBattRegisterPowerCallBack: failed status=0x%08x\n", Status); 1303 } 1304 else 1305 { 1306 /* Register the power callback now */ 1307 CmBattPowerCallBackRegistration = ExRegisterCallback(CmBattPowerCallBackObject, 1308 (PVOID)CmBattPowerCallBack, 1309 DriverObject); 1310 if (CmBattPowerCallBackRegistration) 1311 { 1312 /* Last thing: setup our DPC and timer for battery wake */ 1313 KeInitializeDpc(&CmBattWakeDpcObject, (PVOID)CmBattWakeDpc, DriverObject); 1314 KeInitializeTimer(&CmBattWakeDpcTimerObject); 1315 } 1316 else 1317 { 1318 ObDereferenceObject(CmBattPowerCallBackObject); 1319 if (CmBattDebug & CMBATT_GENERIC_WARNING) 1320 DbgPrint("CmBattRegisterPowerCallBack: ExRegisterCallback failed.\n"); 1321 } 1322 1323 /* All good */ 1324 Status = STATUS_SUCCESS; 1325 } 1326 1327 /* Return failure or success */ 1328 return Status; 1329 } 1330 1331 /* EOF */ 1332