Skip to content

Commit 571ac5e

Browse files
committed
[NTOS:PO] Implement SystemBatteryState in NtPowerInformation
This should get us proper battery status display.
1 parent 3a6e0d4 commit 571ac5e

File tree

2 files changed

+131
-10
lines changed

2 files changed

+131
-10
lines changed

ntoskrnl/po/power.c

Lines changed: 129 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,115 @@ NtInitiatePowerAction(IN POWER_ACTION SystemAction,
784784
return STATUS_NOT_IMPLEMENTED;
785785
}
786786

787+
static
788+
NTSTATUS
789+
PopQueryBatteryState(
790+
_Out_ PSYSTEM_BATTERY_STATE BatteryState)
791+
{
792+
static const UNICODE_STRING CompBattDeviceName =
793+
RTL_CONSTANT_STRING(L"\\Device\\CompositeBattery");
794+
OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(
795+
&CompBattDeviceName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE);
796+
HANDLE CompBattHandle;
797+
IO_STATUS_BLOCK IoStatusBlock;
798+
BATTERY_QUERY_INFORMATION BatteryQueryInfo = {0};
799+
BATTERY_INFORMATION BatteryInfo = { 0 };
800+
BATTERY_STATUS BatteryStatus;
801+
NTSTATUS Status;
802+
803+
/* Open the CompositeBattery device */
804+
Status = ZwOpenFile(&CompBattHandle,
805+
GENERIC_READ | SYNCHRONIZE,
806+
&ObjectAttributes,
807+
&IoStatusBlock,
808+
FILE_SHARE_READ | FILE_SHARE_WRITE,
809+
FILE_SYNCHRONOUS_IO_NONALERT);
810+
if (!NT_SUCCESS(Status))
811+
{
812+
DPRINT1("Failed to open CompositeBattery device: Status: 0x%08lX\n", Status);
813+
return Status;
814+
}
815+
816+
/* Query the battery tag */
817+
ULONG Wait = 0;
818+
Status = ZwDeviceIoControlFile(CompBattHandle,
819+
NULL,
820+
NULL,
821+
NULL,
822+
&IoStatusBlock,
823+
IOCTL_BATTERY_QUERY_TAG,
824+
&Wait,
825+
sizeof(Wait),
826+
&BatteryQueryInfo.BatteryTag,
827+
sizeof(BatteryQueryInfo.BatteryTag));
828+
if (!NT_SUCCESS(Status))
829+
{
830+
DPRINT1("Failed to query battery tag: Status: 0x%08lX\n", Status);
831+
goto Exit;
832+
}
833+
834+
/* Query the battery information */
835+
BatteryQueryInfo.InformationLevel = BatteryInformation;
836+
Status = ZwDeviceIoControlFile(CompBattHandle,
837+
NULL,
838+
NULL,
839+
NULL,
840+
&IoStatusBlock,
841+
IOCTL_BATTERY_QUERY_INFORMATION,
842+
&BatteryQueryInfo,
843+
sizeof(BatteryQueryInfo),
844+
&BatteryInfo,
845+
sizeof(BatteryInfo));
846+
if (!NT_SUCCESS(Status))
847+
{
848+
DPRINT1("Failed to query battery information: Status: 0x%08lX\n", Status);
849+
}
850+
851+
/* Query the battery status */
852+
BATTERY_WAIT_STATUS BatteryWait = {0};
853+
BatteryWait.BatteryTag = BatteryQueryInfo.BatteryTag;
854+
BatteryWait.PowerState = 0xF ; // Wait for all power states
855+
BatteryWait.HighCapacity = MAXULONG;
856+
Status = ZwDeviceIoControlFile(CompBattHandle,
857+
NULL,
858+
NULL,
859+
NULL,
860+
&IoStatusBlock,
861+
IOCTL_BATTERY_QUERY_STATUS,
862+
&BatteryWait,
863+
sizeof(BatteryWait),
864+
&BatteryStatus,
865+
sizeof(BatteryStatus));
866+
if (!NT_SUCCESS(Status))
867+
{
868+
DPRINT1("Failed to query battery status: Status: 0x%08lX\n", Status);
869+
goto Exit;
870+
}
871+
872+
RtlZeroMemory(BatteryState, sizeof(*BatteryState));
873+
BatteryState->BatteryPresent = TRUE;
874+
BatteryState->AcOnLine = BooleanFlagOn(BatteryStatus.PowerState, BATTERY_POWER_ON_LINE);
875+
BatteryState->Charging = BooleanFlagOn(BatteryStatus.PowerState, BATTERY_CHARGING);
876+
BatteryState->Discharging = BooleanFlagOn(BatteryStatus.PowerState, BATTERY_DISCHARGING);
877+
BatteryState->MaxCapacity = BatteryInfo.FullChargedCapacity;
878+
BatteryState->RemainingCapacity = BatteryStatus.Capacity;
879+
BatteryState->Rate = BatteryStatus.Rate;
880+
if (BatteryState->Discharging && BatteryStatus.Rate < 0)
881+
{
882+
BatteryState->EstimatedTime =
883+
3600 * BatteryInfo.FullChargedCapacity / -BatteryStatus.Rate;
884+
}
885+
else
886+
{
887+
BatteryState->EstimatedTime = 0;
888+
}
889+
890+
Exit:
891+
ZwClose(CompBattHandle);
892+
return Status;
893+
}
894+
895+
787896
/*
788897
* @unimplemented
789898
*/
@@ -824,23 +933,34 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
824933
{
825934
case SystemBatteryState:
826935
{
827-
PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
936+
SYSTEM_BATTERY_STATE BatteryState;
828937

829938
if (InputBuffer != NULL)
830939
return STATUS_INVALID_PARAMETER;
831940
if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
832941
return STATUS_BUFFER_TOO_SMALL;
833942

834-
_SEH2_TRY
943+
if (PopCapabilities.SystemBatteriesPresent)
835944
{
836-
/* Just zero the struct */
837-
RtlZeroMemory(BatteryState, sizeof(*BatteryState));
838-
BatteryState->EstimatedTime = MAXULONG;
839-
BatteryState->BatteryPresent = PopCapabilities.SystemBatteriesPresent;
840-
// BatteryState->AcOnLine = TRUE;
841-
// BatteryState->MaxCapacity = ;
842-
// BatteryState->RemainingCapacity = ;
945+
/* Open the battery driver and query the battery state */
946+
Status = PopQueryBatteryState(&BatteryState);
947+
if (!NT_SUCCESS(Status))
948+
{
949+
DPRINT1("Failed to query battery state: Status: 0x%08X\n", Status);
950+
return Status;
951+
}
952+
}
953+
else
954+
{
955+
/* No batteries present, set defaults */
956+
RtlZeroMemory(&BatteryState, sizeof(BatteryState));
957+
BatteryState.AcOnLine = TRUE;
958+
}
843959

960+
_SEH2_TRY
961+
{
962+
/* Copy the battery state to the output buffer */
963+
RtlCopyMemory(OutputBuffer, &BatteryState, sizeof(BatteryState));
844964
Status = STATUS_SUCCESS;
845965
}
846966
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)

sdk/include/ddk/ntpoapi.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,8 @@ typedef struct {
386386
BOOLEAN BatteryPresent;
387387
BOOLEAN Charging;
388388
BOOLEAN Discharging;
389-
BOOLEAN Spare1[4];
389+
BOOLEAN Spare1[3];
390+
UCHAR Tag;
390391
ULONG MaxCapacity;
391392
ULONG RemainingCapacity;
392393
ULONG Rate;

0 commit comments

Comments
 (0)