Commit f715f400 authored by Marc-Aurel Zent's avatar Marc-Aurel Zent Committed by Alexandre Julliard

ntdll: Use IOPowerSources API to fill battery info on macOS.

parent 2dd3a205
...@@ -57,8 +57,7 @@ ...@@ -57,8 +57,7 @@
#ifdef __APPLE__ #ifdef __APPLE__
# include <CoreFoundation/CoreFoundation.h> # include <CoreFoundation/CoreFoundation.h>
# include <IOKit/IOKitLib.h> # include <IOKit/IOKitLib.h>
# include <IOKit/pwr_mgt/IOPM.h> # include <IOKit/ps/IOPSKeys.h>
# include <IOKit/pwr_mgt/IOPMLib.h>
# include <IOKit/ps/IOPowerSources.h> # include <IOKit/ps/IOPowerSources.h>
# include <mach/mach.h> # include <mach/mach.h>
# include <mach/machine.h> # include <mach/machine.h>
...@@ -3580,66 +3579,106 @@ static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs ) ...@@ -3580,66 +3579,106 @@ static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs ) static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
{ {
CFArrayRef batteries; CFTypeRef blob = IOPSCopyPowerSourcesInfo();
CFDictionaryRef battery; CFArrayRef sources = IOPSCopyPowerSourcesList( blob );
CFNumberRef prop; CFIndex count, i;
uint32_t value, voltage; CFDictionaryRef source = NULL;
CFTimeInterval remain; CFTypeRef prop;
Boolean is_charging, is_internal, is_present;
int32_t value, voltage;
if (IOPMCopyBatteryInfo( 0, &batteries ) != kIOReturnSuccess) if (!sources)
{
if (blob) CFRelease( blob );
return STATUS_ACCESS_DENIED; return STATUS_ACCESS_DENIED;
}
count = CFArrayGetCount( sources );
for (i = 0; i < count; i++)
{
source = IOPSGetPowerSourceDescription( blob, CFArrayGetValueAtIndex( sources, i ) );
if (!source)
continue;
prop = CFDictionaryGetValue( source, CFSTR(kIOPSTransportTypeKey) );
is_internal = !CFStringCompare( prop, CFSTR(kIOPSInternalType), 0 );
prop = CFDictionaryGetValue( source, CFSTR(kIOPSIsPresentKey) );
is_present = CFBooleanGetValue( prop );
if (is_internal && is_present)
break;
}
if (CFArrayGetCount( batteries ) == 0) CFRelease( blob );
if (!source)
{ {
/* Just assume we're on AC with no battery. */ /* Just assume we're on AC with no internal power source. */
bs->AcOnLine = TRUE; bs->AcOnLine = TRUE;
CFRelease( sources );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
/* Just use the first battery. */
battery = CFArrayGetValueAtIndex( batteries, 0 );
prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryFlagsKey) ); bs->BatteryPresent = TRUE;
CFNumberGetValue( prop, kCFNumberSInt32Type, &value );
if (value & kIOBatteryInstalled) prop = CFDictionaryGetValue( source, CFSTR(kIOPSIsChargingKey) );
bs->BatteryPresent = TRUE; is_charging = CFBooleanGetValue( prop );
else
/* Since we are executing code, we must have AC power. */ prop = CFDictionaryGetValue( source, CFSTR(kIOPSPowerSourceStateKey) );
bs->AcOnLine = TRUE;
if (value & kIOBatteryChargerConnect) if (!CFStringCompare( prop, CFSTR(kIOPSACPowerValue), 0 ))
{ {
bs->AcOnLine = TRUE; bs->AcOnLine = TRUE;
if (value & kIOBatteryCharge) if (is_charging)
bs->Charging = TRUE; bs->Charging = TRUE;
} }
else else
bs->Discharging = TRUE; bs->Discharging = TRUE;
/* We'll need the voltage to be able to interpret the other values. */ /* We'll need the voltage to be able to interpret the other values. */
prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryVoltageKey) ); prop = CFDictionaryGetValue( source, CFSTR(kIOPSVoltageKey) );
CFNumberGetValue( prop, kCFNumberSInt32Type, &voltage ); if (prop)
CFNumberGetValue( prop, kCFNumberIntType, &voltage );
else
/* kIOPSVoltageKey is optional and might not be populated.
* Assume 11.4 V then, which is a common value for Apple laptops. */
voltage = 11400;
prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCapacityKey) ); prop = CFDictionaryGetValue( source, CFSTR(kIOPSMaxCapacityKey) );
CFNumberGetValue( prop, kCFNumberSInt32Type, &value ); CFNumberGetValue( prop, kCFNumberIntType, &value );
bs->MaxCapacity = value * voltage; bs->MaxCapacity = value * voltage;
/* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow /* Apple uses "estimated time < 10:00" and "22%" for these, but we'll follow
* Windows for now (5% and 33%). */ * Windows for now (5% and 33%). */
bs->DefaultAlert1 = bs->MaxCapacity / 20; bs->DefaultAlert1 = bs->MaxCapacity / 20;
bs->DefaultAlert2 = bs->MaxCapacity / 3; bs->DefaultAlert2 = bs->MaxCapacity / 3;
prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryCurrentChargeKey) ); prop = CFDictionaryGetValue( source, CFSTR(kIOPSCurrentCapacityKey) );
CFNumberGetValue( prop, kCFNumberSInt32Type, &value ); CFNumberGetValue( prop, kCFNumberIntType, &value );
bs->RemainingCapacity = value * voltage; bs->RemainingCapacity = value * voltage;
prop = CFDictionaryGetValue( battery, CFSTR(kIOBatteryAmperageKey) ); prop = CFDictionaryGetValue( source, CFSTR(kIOPSCurrentKey) );
CFNumberGetValue( prop, kCFNumberSInt32Type, &value ); if (prop)
bs->Rate = value * voltage; CFNumberGetValue( prop, kCFNumberIntType, &value );
else
/* kIOPSCurrentKey is optional and might not be populated. */
value = 0;
bs->Rate = value * voltage / 1000;
remain = IOPSGetTimeRemainingEstimate(); prop = CFDictionaryGetValue( source, CFSTR(kIOPSTimeToEmptyKey) );
if (remain != kIOPSTimeRemainingUnknown && remain != kIOPSTimeRemainingUnlimited) if (prop)
bs->EstimatedTime = (ULONG)remain; {
CFNumberGetValue( prop, kCFNumberIntType, &value );
if (value > 0)
/* A value of -1 indicates "Still Calculating the Time",
* otherwise estimated minutes left on the battery. */
bs->EstimatedTime = value * 60;
}
CFRelease( batteries ); CFRelease( sources );
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment