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/cmbpnp.c 5 * PURPOSE: Plug-and-Play IOCTL/IRP Handling 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include "cmbatt.h" 12 13 /* FUNCTIONS ******************************************************************/ 14 15 VOID 16 NTAPI 17 CmBattWaitWakeLoop(IN PDEVICE_OBJECT DeviceObject, 18 IN UCHAR MinorFunction, 19 IN POWER_STATE PowerState, 20 IN PVOID Context, 21 IN PIO_STATUS_BLOCK IoStatusBlock) 22 { 23 NTSTATUS Status; 24 PCMBATT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; 25 if (CmBattDebug & 0x20) DbgPrint("CmBattWaitWakeLoop: Entered.\n"); 26 27 /* Check for success */ 28 if ((NT_SUCCESS(IoStatusBlock->Status)) && (DeviceExtension->WaitWakeEnable)) 29 { 30 /* Request a new power IRP */ 31 if (CmBattDebug & 2) DbgPrint("CmBattWaitWakeLoop: completed successfully\n"); 32 Status = PoRequestPowerIrp(DeviceObject, 33 MinorFunction, 34 PowerState, 35 CmBattWaitWakeLoop, 36 Context, 37 &DeviceExtension->PowerIrp); 38 if (CmBattDebug & 2) 39 DbgPrint("CmBattWaitWakeLoop: PoRequestPowerIrp: status = 0x%08x.\n", 40 Status); 41 } 42 else 43 { 44 /* Clear the power IRP, we failed */ 45 if (CmBattDebug & 0xC) 46 DbgPrint("CmBattWaitWakeLoop: failed: status = 0x%08x.\n", 47 IoStatusBlock->Status); 48 DeviceExtension->PowerIrp = NULL; 49 } 50 } 51 52 NTSTATUS 53 NTAPI 54 CmBattIoCompletion(IN PDEVICE_OBJECT DeviceObject, 55 IN PIRP Irp, 56 IN PKEVENT Event) 57 { 58 if (CmBattDebug & 2) DbgPrint("CmBattIoCompletion: Event (%x)\n", Event); 59 60 /* Set the completion event */ 61 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 62 return STATUS_MORE_PROCESSING_REQUIRED; 63 } 64 65 NTSTATUS 66 NTAPI 67 CmBattGetAcpiInterfaces(IN PDEVICE_OBJECT DeviceObject, 68 IN OUT PACPI_INTERFACE_STANDARD AcpiInterface) 69 { 70 PIRP Irp; 71 NTSTATUS Status; 72 PIO_STACK_LOCATION IoStackLocation; 73 KEVENT Event; 74 75 /* Allocate the IRP */ 76 Irp = IoAllocateIrp(DeviceObject->StackSize, 0); 77 if (!Irp) 78 { 79 /* Fail */ 80 if (CmBattDebug & 0xC) 81 DbgPrint("CmBattGetAcpiInterfaces: Failed to allocate Irp\n"); 82 return STATUS_INSUFFICIENT_RESOURCES; 83 } 84 85 /* Set default error code */ 86 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 87 88 /* Build the query */ 89 IoStackLocation = IoGetNextIrpStackLocation(Irp); 90 IoStackLocation->MajorFunction = IRP_MJ_PNP; 91 IoStackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE; 92 IoStackLocation->Parameters.QueryInterface.InterfaceType = &GUID_ACPI_INTERFACE_STANDARD; 93 IoStackLocation->Parameters.QueryInterface.Size = sizeof(ACPI_INTERFACE_STANDARD); 94 IoStackLocation->Parameters.QueryInterface.Version = 1; 95 IoStackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)AcpiInterface; 96 IoStackLocation->Parameters.QueryInterface.InterfaceSpecificData = NULL; 97 98 /* Set default ACPI interface data */ 99 AcpiInterface->Size = sizeof(ACPI_INTERFACE_STANDARD); 100 AcpiInterface->Version = 1; 101 102 /* Initialize our wait event */ 103 KeInitializeEvent(&Event, SynchronizationEvent, 0); 104 105 /* Set the completion routine */ 106 IoSetCompletionRoutine(Irp, 107 (PVOID)CmBattIoCompletion, 108 &Event, 109 TRUE, 110 TRUE, 111 TRUE); 112 113 /* Now call ACPI */ 114 Status = IoCallDriver(DeviceObject, Irp); 115 if (Status == STATUS_PENDING) 116 { 117 /* Wait for completion */ 118 KeWaitForSingleObject(&Event, 119 Executive, 120 KernelMode, 121 FALSE, 122 NULL); 123 Status = Irp->IoStatus.Status; 124 } 125 126 /* Free the IRP */ 127 IoFreeIrp(Irp); 128 129 /* Return status */ 130 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0xC)) 131 DbgPrint("CmBattGetAcpiInterfaces: Could not get ACPI driver interfaces, status = %x\n", Status); 132 return Status; 133 } 134 135 VOID 136 NTAPI 137 CmBattDestroyFdo(IN PDEVICE_OBJECT DeviceObject) 138 { 139 PAGED_CODE(); 140 if (CmBattDebug & 0x220) DbgPrint("CmBattDestroyFdo, Battery.\n"); 141 142 /* Delete the device */ 143 IoDeleteDevice(DeviceObject); 144 if (CmBattDebug & 0x220) DbgPrint("CmBattDestroyFdo: done.\n"); 145 } 146 147 NTSTATUS 148 NTAPI 149 CmBattRemoveDevice(IN PDEVICE_OBJECT DeviceObject, 150 IN PIRP Irp) 151 { 152 PCMBATT_DEVICE_EXTENSION DeviceExtension; 153 PVOID Context; 154 DeviceExtension = DeviceObject->DeviceExtension; 155 if (CmBattDebug & 2) 156 DbgPrint("CmBattRemoveDevice: CmBatt (%x), Type %d, _UID %d\n", 157 DeviceExtension, 158 DeviceExtension->FdoType, 159 DeviceExtension->DeviceId); 160 161 /* Make sure it's safe to go ahead */ 162 IoReleaseRemoveLockAndWait(&DeviceExtension->RemoveLock, 0); 163 164 /* Check for pending power IRP */ 165 if (DeviceExtension->PowerIrp) 166 { 167 /* Cancel and clear */ 168 IoCancelIrp(DeviceExtension->PowerIrp); 169 DeviceExtension->PowerIrp = NULL; 170 } 171 172 /* Check what type of FDO is being removed */ 173 Context = DeviceExtension->AcpiInterface.Context; 174 if (DeviceExtension->FdoType == CmBattBattery) 175 { 176 /* Unregister battery FDO */ 177 DeviceExtension->AcpiInterface.UnregisterForDeviceNotifications(Context, 178 (PVOID)CmBattNotifyHandler); 179 CmBattWmiDeRegistration(DeviceExtension); 180 if (!NT_SUCCESS(BatteryClassUnload(DeviceExtension->ClassData))) ASSERT(FALSE); 181 } 182 else 183 { 184 /* Unregister AC adapter FDO */ 185 DeviceExtension->AcpiInterface.UnregisterForDeviceNotifications(Context, 186 (PVOID)CmBattNotifyHandler); 187 CmBattWmiDeRegistration(DeviceExtension); 188 AcAdapterPdo = NULL; 189 } 190 191 /* Detach and delete */ 192 IoDetachDevice(DeviceExtension->AttachedDevice); 193 IoDeleteDevice(DeviceExtension->DeviceObject); 194 return STATUS_SUCCESS; 195 } 196 197 NTSTATUS 198 NTAPI 199 CmBattPowerDispatch(IN PDEVICE_OBJECT DeviceObject, 200 IN PIRP Irp) 201 { 202 PIO_STACK_LOCATION IoStackLocation; 203 PCMBATT_DEVICE_EXTENSION DeviceExtension; 204 NTSTATUS Status; 205 if (CmBattDebug & 0x210) DbgPrint("CmBattPowerDispatch\n"); 206 207 /* Get stack location and device extension */ 208 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 209 DeviceExtension = DeviceObject->DeviceExtension; 210 switch (IoStackLocation->MinorFunction) 211 { 212 case IRP_MN_WAIT_WAKE: 213 if (CmBattDebug & 0x10) 214 DbgPrint("CmBattPowerDispatch: IRP_MN_WAIT_WAKE\n"); 215 break; 216 217 case IRP_MN_POWER_SEQUENCE: 218 if (CmBattDebug & 0x10) 219 DbgPrint("CmBattPowerDispatch: IRP_MN_POWER_SEQUENCE\n"); 220 break; 221 222 case IRP_MN_QUERY_POWER: 223 if (CmBattDebug & 0x10) 224 DbgPrint("CmBattPowerDispatch: IRP_MN_WAIT_WAKE\n"); 225 break; 226 227 case IRP_MN_SET_POWER: 228 if (CmBattDebug & 0x10) 229 DbgPrint("CmBattPowerDispatch: IRP_MN_SET_POWER type: %d, State: %d \n", 230 IoStackLocation->Parameters.Power.Type, 231 IoStackLocation->Parameters.Power.State); 232 break; 233 234 default: 235 236 if (CmBattDebug & 1) 237 DbgPrint("CmBattPowerDispatch: minor %d\n", IoStackLocation->MinorFunction); 238 break; 239 } 240 241 /* Start the next IRP and see if we're attached */ 242 PoStartNextPowerIrp(Irp); 243 if (DeviceExtension->AttachedDevice) 244 { 245 /* Call ACPI */ 246 IoSkipCurrentIrpStackLocation(Irp); 247 Status = PoCallDriver(DeviceExtension->AttachedDevice, Irp); 248 } 249 else 250 { 251 /* Complete the request here */ 252 Status = Irp->IoStatus.Status; 253 IoCompleteRequest(Irp, IO_NO_INCREMENT); 254 } 255 256 /* Return status */ 257 return Status; 258 } 259 260 NTSTATUS 261 NTAPI 262 CmBattPnpDispatch(IN PDEVICE_OBJECT DeviceObject, 263 IN PIRP Irp) 264 { 265 PIO_STACK_LOCATION IoStackLocation; 266 PCMBATT_DEVICE_EXTENSION DeviceExtension; 267 NTSTATUS Status; 268 KEVENT Event; 269 PAGED_CODE(); 270 271 /* Get stack location and device extension */ 272 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 273 DeviceExtension = DeviceObject->DeviceExtension; 274 275 /* Set default error */ 276 Status = STATUS_NOT_SUPPORTED; 277 278 /* Try to acquire the lock before doing anything */ 279 Status = IoAcquireRemoveLock(&DeviceExtension->RemoveLock, Irp); 280 if (!NT_SUCCESS(Status)) 281 { 282 /* Complete the request */ 283 Irp->IoStatus.Status = STATUS_DEVICE_REMOVED; 284 IoCompleteRequest(Irp, IO_NO_INCREMENT); 285 return STATUS_DEVICE_REMOVED; 286 } 287 288 /* What's the operation? */ 289 switch (IoStackLocation->MinorFunction) 290 { 291 case IRP_MN_QUERY_PNP_DEVICE_STATE: 292 293 /* Initialize our wait event */ 294 KeInitializeEvent(&Event, SynchronizationEvent, 0); 295 296 /* Set the completion routine */ 297 IoCopyCurrentIrpStackLocationToNext(Irp); 298 IoSetCompletionRoutine(Irp, 299 (PVOID)CmBattIoCompletion, 300 &Event, 301 TRUE, 302 TRUE, 303 TRUE); 304 305 /* Now call ACPI to inherit its PnP Device State */ 306 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 307 if (Status == STATUS_PENDING) 308 { 309 /* Wait for completion */ 310 KeWaitForSingleObject(&Event, 311 Executive, 312 KernelMode, 313 FALSE, 314 NULL); 315 Status = Irp->IoStatus.Status; 316 } 317 318 /* However, a battery CAN be disabled */ 319 Irp->IoStatus.Information &= ~PNP_DEVICE_NOT_DISABLEABLE; 320 321 /* Release the remove lock and complete the request */ 322 IoCompleteRequest(Irp, IO_NO_INCREMENT); 323 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 324 return Status; 325 326 case IRP_MN_SURPRISE_REMOVAL: 327 if (CmBattDebug & 0x20) 328 DbgPrint("CmBattPnpDispatch: IRP_MN_SURPRISE_REMOVAL\n"); 329 330 /* Lock the device extension and set the handle count to invalid */ 331 ExAcquireFastMutex(&DeviceExtension->FastMutex); 332 DeviceExtension->HandleCount = -1; 333 ExReleaseFastMutex(&DeviceExtension->FastMutex); 334 Status = STATUS_SUCCESS; 335 break; 336 337 case IRP_MN_START_DEVICE: 338 if (CmBattDebug & 0x20) 339 DbgPrint("CmBattPnpDispatch: IRP_MN_START_DEVICE\n"); 340 341 /* Mark the extension as started */ 342 if (DeviceExtension->FdoType == CmBattBattery) DeviceExtension->Started = TRUE; 343 Status = STATUS_SUCCESS; 344 break; 345 346 case IRP_MN_STOP_DEVICE: 347 if (CmBattDebug & 0x20) 348 DbgPrint("CmBattPnpDispatch: IRP_MN_STOP_DEVICE\n"); 349 350 /* Mark the extension as stopped */ 351 if (DeviceExtension->FdoType == CmBattBattery) DeviceExtension->Started = FALSE; 352 Status = STATUS_SUCCESS; 353 break; 354 355 case IRP_MN_QUERY_REMOVE_DEVICE: 356 if (CmBattDebug & 0x20) 357 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_REMOVE_DEVICE\n"); 358 359 /* Lock the extension and get the current handle count */ 360 ExAcquireFastMutex(&DeviceExtension->FastMutex); 361 if (DeviceExtension->HandleCount == 0) 362 { 363 /* No handles. Mark it as invalid since it'll be removed */ 364 DeviceExtension->HandleCount = -1; 365 Status = STATUS_SUCCESS; 366 } 367 else if (DeviceExtension->HandleCount == -1) 368 { 369 /* Don't do anything, but this is strange since it's already removed */ 370 Status = STATUS_SUCCESS; 371 if (CmBattDebug & 4) 372 DbgPrint("CmBattPnpDispatch: Received two consecutive QUERY_REMOVE requests.\n"); 373 } 374 else 375 { 376 /* Fail because there's still open handles */ 377 Status = STATUS_UNSUCCESSFUL; 378 } 379 380 /* Release the lock and return */ 381 ExReleaseFastMutex(&DeviceExtension->FastMutex); 382 break; 383 384 case IRP_MN_REMOVE_DEVICE: 385 if (CmBattDebug & 0x20) 386 DbgPrint("CmBattPnpDispatch: IRP_MN_REMOVE_DEVICE\n"); 387 388 /* Call the remove code */ 389 Status = CmBattRemoveDevice(DeviceObject, Irp); 390 break; 391 392 case IRP_MN_CANCEL_REMOVE_DEVICE: 393 if (CmBattDebug & 0x20) 394 DbgPrint("CmBattPnpDispatch: IRP_MN_CANCEL_REMOVE_DEVICE\n"); 395 396 /* Lock the extension and get the handle count */ 397 ExAcquireFastMutex(&DeviceExtension->FastMutex); 398 if (DeviceExtension->HandleCount == -1) 399 { 400 /* A remove was in progress, set the handle count back to 0 */ 401 DeviceExtension->HandleCount = 0; 402 } 403 else if (CmBattDebug & 2) 404 { 405 /* Nop, but warn about it */ 406 DbgPrint("CmBattPnpDispatch: Received CANCEL_REMOVE when OpenCount == %x\n", 407 DeviceExtension->HandleCount); 408 } 409 410 /* Return success in all cases, and release the lock */ 411 Status = STATUS_SUCCESS; 412 ExReleaseFastMutex(&DeviceExtension->FastMutex); 413 break; 414 415 case IRP_MN_QUERY_STOP_DEVICE: 416 if (CmBattDebug & 0x20) 417 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_STOP_DEVICE\n"); 418 419 /* There's no real support for this */ 420 Status = STATUS_NOT_IMPLEMENTED; 421 break; 422 423 case IRP_MN_CANCEL_STOP_DEVICE: 424 if (CmBattDebug & 0x20) 425 DbgPrint("CmBattPnpDispatch: IRP_MN_CANCEL_STOP_DEVICE\n"); 426 427 /* There's no real support for this */ 428 Status = STATUS_NOT_IMPLEMENTED; 429 break; 430 431 case IRP_MN_QUERY_CAPABILITIES: 432 433 /* Initialize our wait event */ 434 KeInitializeEvent(&Event, SynchronizationEvent, 0); 435 436 /* Set the completion routine */ 437 IoCopyCurrentIrpStackLocationToNext(Irp); 438 IoSetCompletionRoutine(Irp, 439 (PVOID)CmBattIoCompletion, 440 &Event, 441 TRUE, 442 TRUE, 443 TRUE); 444 445 /* Now call ACPI */ 446 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 447 if (Status == STATUS_PENDING) 448 { 449 /* Wait for completion */ 450 KeWaitForSingleObject(&Event, 451 Executive, 452 KernelMode, 453 FALSE, 454 NULL); 455 Status = Irp->IoStatus.Status; 456 } 457 458 /* Get the wake power state */ 459 DeviceExtension->PowerState.SystemState = IoStackLocation->Parameters.DeviceCapabilities.Capabilities->SystemWake; 460 if (CmBattDebug & 0x20) 461 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES %d Capabilities->SystemWake = %x\n", 462 DeviceExtension->FdoType, 463 DeviceExtension->PowerState); 464 465 /* Check if it's invalid */ 466 if (DeviceExtension->PowerState.SystemState == PowerSystemUnspecified) 467 { 468 /* Wait wake is not supported in this scenario */ 469 DeviceExtension->WaitWakeEnable = FALSE; 470 if (CmBattDebug & 0x20) 471 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES Wake not supported.\n"); 472 } 473 else if (!(DeviceExtension->PowerIrp) && 474 (DeviceExtension->WaitWakeEnable)) 475 { 476 /* If it was requested in the registry, request the power IRP for it */ 477 PoRequestPowerIrp(DeviceExtension->DeviceObject, 478 0, 479 DeviceExtension->PowerState, 480 CmBattWaitWakeLoop, 481 0, 482 &DeviceExtension->PowerIrp); 483 if (CmBattDebug & 0x20) 484 DbgPrint("CmBattPnpDispatch: IRP_MN_QUERY_CAPABILITIES wait/Wake irp sent.\n"); 485 } 486 487 /* Release the remove lock and complete the request */ 488 IoCompleteRequest(Irp, IO_NO_INCREMENT); 489 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 490 return Status; 491 492 default: 493 /* Unsupported */ 494 if (CmBattDebug & 0x20) 495 DbgPrint("CmBattPnpDispatch: Unimplemented minor %0x\n", 496 IoStackLocation->MinorFunction); 497 break; 498 } 499 500 /* Release the remove lock */ 501 IoReleaseRemoveLock(&DeviceExtension->RemoveLock, Irp); 502 503 /* Set IRP status if we have one */ 504 if (Status != STATUS_NOT_SUPPORTED) Irp->IoStatus.Status = Status; 505 506 /* Did someone pick it up? */ 507 if ((NT_SUCCESS(Status)) || (Status == STATUS_NOT_SUPPORTED)) 508 { 509 /* Still unsupported, try ACPI */ 510 IoSkipCurrentIrpStackLocation(Irp); 511 Status = IoCallDriver(DeviceExtension->AttachedDevice, Irp); 512 } 513 else 514 { 515 /* Complete the request */ 516 Status = Irp->IoStatus.Status; 517 IoCompleteRequest(Irp, IO_NO_INCREMENT); 518 } 519 520 /* Release the remove lock and return status */ 521 return Status; 522 } 523 524 NTSTATUS 525 NTAPI 526 CmBattCreateFdo(IN PDRIVER_OBJECT DriverObject, 527 IN PDEVICE_OBJECT DeviceObject, 528 IN ULONG DeviceExtensionSize, 529 IN PDEVICE_OBJECT *NewDeviceObject) 530 { 531 PDEVICE_OBJECT FdoDeviceObject; 532 HANDLE KeyHandle; 533 PCMBATT_DEVICE_EXTENSION FdoExtension; 534 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 535 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer; 536 NTSTATUS Status; 537 UNICODE_STRING KeyString; 538 ULONG UniqueId; 539 ULONG ResultLength; 540 PAGED_CODE(); 541 if (CmBattDebug & 0x220) DbgPrint("CmBattCreateFdo: Entered\n"); 542 543 /* Get unique ID */ 544 Status = CmBattGetUniqueId(DeviceObject, &UniqueId); 545 if (!NT_SUCCESS(Status)) 546 { 547 /* Assume 0 */ 548 UniqueId = 0; 549 if (CmBattDebug & 2) 550 DbgPrint("CmBattCreateFdo: Error %x from _UID, assuming unit #0\n", Status); 551 } 552 553 /* Create the FDO */ 554 Status = IoCreateDevice(DriverObject, 555 DeviceExtensionSize, 556 0, 557 FILE_DEVICE_BATTERY, 558 FILE_DEVICE_SECURE_OPEN, 559 0, 560 &FdoDeviceObject); 561 if (!NT_SUCCESS(Status)) 562 { 563 /* Fail */ 564 if (CmBattDebug & 0xC) 565 DbgPrint("CmBattCreateFdo: error (0x%x) creating device object\n", Status); 566 return Status; 567 } 568 569 /* Set FDO flags */ 570 FdoDeviceObject->Flags |= (DO_POWER_PAGABLE | DO_BUFFERED_IO); 571 FdoDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 572 573 /* Initialize the extension */ 574 FdoExtension = FdoDeviceObject->DeviceExtension; 575 RtlZeroMemory(FdoExtension, DeviceExtensionSize); 576 FdoExtension->DeviceObject = FdoDeviceObject; 577 FdoExtension->FdoDeviceObject = FdoDeviceObject; 578 FdoExtension->PdoDeviceObject = DeviceObject; 579 580 /* Attach to ACPI */ 581 FdoExtension->AttachedDevice = IoAttachDeviceToDeviceStack(FdoDeviceObject, 582 DeviceObject); 583 if (!FdoExtension->AttachedDevice) 584 { 585 /* Destroy and fail */ 586 CmBattDestroyFdo(FdoExtension->FdoDeviceObject); 587 if (CmBattDebug & 0xC) 588 DbgPrint("CmBattCreateFdo: IoAttachDeviceToDeviceStack failed.\n"); 589 return STATUS_UNSUCCESSFUL; 590 } 591 592 /* Get ACPI interface for EVAL */ 593 Status = CmBattGetAcpiInterfaces(FdoExtension->AttachedDevice, 594 &FdoExtension->AcpiInterface); 595 if (!FdoExtension->AttachedDevice) 596 { 597 /* Detach, destroy, and fail */ 598 IoDetachDevice(FdoExtension->AttachedDevice); 599 CmBattDestroyFdo(FdoExtension->FdoDeviceObject); 600 if (CmBattDebug & 0xC) 601 DbgPrint("CmBattCreateFdo: Could not get ACPI interfaces: %x\n", Status); 602 return STATUS_UNSUCCESSFUL; 603 } 604 605 /* Setup the rest of the extension */ 606 ExInitializeFastMutex(&FdoExtension->FastMutex); 607 IoInitializeRemoveLock(&FdoExtension->RemoveLock, 'RbmC', 0, 0); 608 FdoExtension->HandleCount = 0; 609 FdoExtension->WaitWakeEnable = FALSE; 610 FdoExtension->DeviceId = UniqueId; 611 FdoExtension->DeviceName = NULL; 612 FdoExtension->DelayNotification = FALSE; 613 FdoExtension->ArFlag = 0; 614 615 /* Open the device key */ 616 Status = IoOpenDeviceRegistryKey(DeviceObject, 617 PLUGPLAY_REGKEY_DEVICE, 618 KEY_READ, 619 &KeyHandle); 620 if (NT_SUCCESS(Status)) 621 { 622 /* Read wait wake value */ 623 RtlInitUnicodeString(&KeyString, L"WaitWakeEnabled"); 624 Status = ZwQueryValueKey(KeyHandle, 625 &KeyString, 626 KeyValuePartialInformation, 627 PartialInfo, 628 sizeof(Buffer), 629 &ResultLength); 630 if (NT_SUCCESS(Status)) 631 { 632 /* Set value */ 633 FdoExtension->WaitWakeEnable = ((*(PULONG)PartialInfo->Data) != 0); 634 } 635 636 /* Close the handle */ 637 ZwClose(KeyHandle); 638 } 639 640 /* Return success and the new FDO */ 641 *NewDeviceObject = FdoDeviceObject; 642 if (CmBattDebug & 0x220) 643 DbgPrint("CmBattCreateFdo: Created FDO %x\n", FdoDeviceObject); 644 return STATUS_SUCCESS; 645 } 646 647 NTSTATUS 648 NTAPI 649 CmBattAddBattery(IN PDRIVER_OBJECT DriverObject, 650 IN PDEVICE_OBJECT DeviceObject) 651 { 652 BATTERY_MINIPORT_INFO MiniportInfo; 653 NTSTATUS Status; 654 PDEVICE_OBJECT FdoDeviceObject; 655 PCMBATT_DEVICE_EXTENSION FdoExtension; 656 PAGED_CODE(); 657 if (CmBattDebug & 0x220) 658 DbgPrint("CmBattAddBattery: pdo %x\n", DeviceObject); 659 660 /* Create the FDO */ 661 Status = CmBattCreateFdo(DriverObject, 662 DeviceObject, 663 sizeof(CMBATT_DEVICE_EXTENSION), 664 &FdoDeviceObject); 665 if (!NT_SUCCESS(Status)) 666 { 667 if (CmBattDebug & 0xC) 668 DbgPrint("CmBattAddBattery: error (0x%x) creating Fdo\n", Status); 669 return Status; 670 } 671 672 /* Build the FDO extension, check if we support trip points */ 673 FdoExtension = FdoDeviceObject->DeviceExtension; 674 FdoExtension->FdoType = CmBattBattery; 675 FdoExtension->Started = 0; 676 FdoExtension->NotifySent = TRUE; 677 InterlockedExchange(&FdoExtension->ArLockValue, 0); 678 FdoExtension->TripPointValue = BATTERY_UNKNOWN_CAPACITY; 679 FdoExtension->Tag = 0; 680 FdoExtension->InterruptTime = KeQueryInterruptTime(); 681 FdoExtension->TripPointSet = CmBattSetTripPpoint(FdoExtension, 0) != 682 STATUS_OBJECT_NAME_NOT_FOUND; 683 684 /* Setup the battery miniport information structure */ 685 RtlZeroMemory(&MiniportInfo, sizeof(MiniportInfo)); 686 MiniportInfo.Pdo = DeviceObject; 687 MiniportInfo.MajorVersion = BATTERY_CLASS_MAJOR_VERSION; 688 MiniportInfo.MinorVersion = BATTERY_CLASS_MINOR_VERSION; 689 MiniportInfo.Context = FdoExtension; 690 MiniportInfo.QueryTag = (PVOID)CmBattQueryTag; 691 MiniportInfo.QueryInformation = (PVOID)CmBattQueryInformation; 692 MiniportInfo.SetInformation = NULL; 693 MiniportInfo.QueryStatus = (PVOID)CmBattQueryStatus; 694 MiniportInfo.SetStatusNotify = (PVOID)CmBattSetStatusNotify; 695 MiniportInfo.DisableStatusNotify = (PVOID)CmBattDisableStatusNotify; 696 MiniportInfo.DeviceName = FdoExtension->DeviceName; 697 698 /* Register with the class driver */ 699 Status = BatteryClassInitializeDevice(&MiniportInfo, &FdoExtension->ClassData); 700 if (!NT_SUCCESS(Status)) 701 { 702 IoDetachDevice(FdoExtension->AttachedDevice); 703 CmBattDestroyFdo(FdoExtension->FdoDeviceObject); 704 if (CmBattDebug & 0xC) 705 DbgPrint("CmBattAddBattery: error (0x%x) registering with class\n", Status); 706 return Status; 707 } 708 709 /* Register WMI */ 710 Status = CmBattWmiRegistration(FdoExtension); 711 if (!NT_SUCCESS(Status)) 712 { 713 if (CmBattDebug & 0xC) 714 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status); 715 return Status; 716 } 717 718 /* Register ACPI */ 719 Status = FdoExtension->AcpiInterface.RegisterForDeviceNotifications(FdoExtension->AcpiInterface.Context, 720 (PVOID)CmBattNotifyHandler, 721 FdoExtension); 722 if (!NT_SUCCESS(Status)) 723 { 724 CmBattWmiDeRegistration(FdoExtension); 725 BatteryClassUnload(FdoExtension->ClassData); 726 IoDetachDevice(FdoExtension->AttachedDevice); 727 CmBattDestroyFdo(FdoExtension->FdoDeviceObject); 728 if (CmBattDebug & 0xC) 729 DbgPrint("CmBattAddBattery: Could not register for battery notify, status = %Lx\n", Status); 730 } 731 732 /* Return status */ 733 return Status; 734 } 735 736 NTSTATUS 737 NTAPI 738 CmBattAddAcAdapter(IN PDRIVER_OBJECT DriverObject, 739 IN PDEVICE_OBJECT PdoDeviceObject) 740 { 741 PDEVICE_OBJECT FdoDeviceObject; 742 NTSTATUS Status; 743 PCMBATT_DEVICE_EXTENSION DeviceExtension; 744 PAGED_CODE(); 745 if (CmBattDebug & 0x220) 746 DbgPrint("CmBattAddAcAdapter: pdo %x\n", PdoDeviceObject); 747 748 /* Check if we already have an AC adapter */ 749 if (AcAdapterPdo) 750 { 751 /* Don't do anything */ 752 if (CmBattDebug & 0xC) 753 DbgPrint("CmBatt: Second AC adapter found. Current version of driver only supports 1 adapter.\n"); 754 } 755 else 756 { 757 /* Set this as the AC adapter's PDO */ 758 AcAdapterPdo = PdoDeviceObject; 759 } 760 761 /* Create the FDO for the adapter */ 762 Status = CmBattCreateFdo(DriverObject, 763 PdoDeviceObject, 764 sizeof(CMBATT_DEVICE_EXTENSION), 765 &FdoDeviceObject); 766 if (!NT_SUCCESS(Status)) 767 { 768 /* Fail */ 769 if (CmBattDebug & 0xC) 770 DbgPrint("CmBattAddAcAdapter: error (0x%x) creating Fdo\n", Status); 771 return Status; 772 } 773 774 /* Set the type and do WMI registration */ 775 DeviceExtension = FdoDeviceObject->DeviceExtension; 776 DeviceExtension->FdoType = CmBattAcAdapter; 777 Status = CmBattWmiRegistration(DeviceExtension); 778 if (!NT_SUCCESS(Status)) 779 { 780 /* We can go on without WMI */ 781 if (CmBattDebug & 0xC) 782 DbgPrint("CmBattAddBattery: Could not register as a WMI provider, status = %Lx\n", Status); 783 } 784 785 /* Register with ACPI */ 786 Status = DeviceExtension->AcpiInterface.RegisterForDeviceNotifications(DeviceExtension->AcpiInterface.Context, 787 (PVOID)CmBattNotifyHandler, 788 DeviceExtension); 789 if (!(NT_SUCCESS(Status)) && (CmBattDebug & 0xC)) 790 DbgPrint("CmBattAddAcAdapter: Could not register for power notify, status = %Lx\n", Status); 791 792 /* Send the first manual notification */ 793 CmBattNotifyHandler(DeviceExtension, ACPI_BATT_NOTIFY_STATUS); 794 return STATUS_SUCCESS; 795 } 796 797 NTSTATUS 798 NTAPI 799 CmBattAddDevice(IN PDRIVER_OBJECT DriverObject, 800 IN PDEVICE_OBJECT PdoDeviceObject) 801 { 802 NTSTATUS Status; 803 HANDLE KeyHandle; 804 ULONG ResultLength; 805 UNICODE_STRING KeyString; 806 UCHAR Buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)]; 807 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)Buffer; 808 ULONG PowerSourceType; 809 PAGED_CODE(); 810 if (CmBattDebug & 0x220) 811 DbgPrint("CmBattAddDevice: Entered with pdo %x\n", PdoDeviceObject); 812 813 /* Make sure we have a PDO */ 814 if (!PdoDeviceObject) 815 { 816 /* Should not be having as one */ 817 if (CmBattDebug & 0x24) DbgPrint("CmBattAddDevice: Asked to do detection\n"); 818 return STATUS_NO_MORE_ENTRIES; 819 } 820 821 /* Open the driver key */ 822 Status = IoOpenDeviceRegistryKey(PdoDeviceObject, 823 PLUGPLAY_REGKEY_DRIVER, 824 KEY_READ, 825 &KeyHandle); 826 if (!NT_SUCCESS(Status)) 827 { 828 if (CmBattDebug & 0xC) 829 DbgPrint("CmBattAddDevice: Could not get the software branch: %x\n", Status); 830 return Status; 831 } 832 833 /* Read the power source type */ 834 RtlInitUnicodeString(&KeyString, L"PowerSourceType"); 835 Status = ZwQueryValueKey(KeyHandle, 836 &KeyString, 837 KeyValuePartialInformation, 838 PartialInfo, 839 sizeof(Buffer), 840 &ResultLength); 841 ZwClose(KeyHandle); 842 if (!NT_SUCCESS(Status)) 843 { 844 /* We need the data, fail without it */ 845 if (CmBattDebug & 0xC) 846 DbgPrint("CmBattAddDevice: Could not read the power type identifier: %x\n", Status); 847 return Status; 848 } 849 850 /* Check what kind of power source this is */ 851 PowerSourceType = *(PULONG)PartialInfo->Data; 852 if (PowerSourceType == 1) 853 { 854 /* Create an AC adapter */ 855 Status = CmBattAddAcAdapter(DriverObject, PdoDeviceObject); 856 } 857 else if (PowerSourceType == 0) 858 { 859 /* Create a battery */ 860 Status = CmBattAddBattery(DriverObject, PdoDeviceObject); 861 } 862 else 863 { 864 /* Unknown type, fail */ 865 if (CmBattDebug & 0xC) 866 DbgPrint("CmBattAddDevice: Invalid POWER_SOURCE_TYPE == %d \n", PowerSourceType); 867 return STATUS_UNSUCCESSFUL; 868 } 869 870 /* Return whatever the FDO creation routine did */ 871 return Status; 872 } 873 874 /* EOF */ 875