[PATCH v2] ntdll: Check for several common battery and AC adapter names on Linux

Alex Henrie alexhenrie24 at gmail.com
Fri Apr 22 03:20:01 CDT 2022


These names come from ACPI, but the exact naming convention varies
between hardware manufacturers. Try all of them and take the statistics
from the first one that exists.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=52831
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
v2: Remove the bitwise ORs that are now unnecessary because we're only
looking at the first battery
---
 dlls/ntdll/unix/system.c | 61 +++++++++++++++++++++++++++-------------
 1 file changed, 41 insertions(+), 20 deletions(-)

diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index 65c49b6ccd1..b51f2dddd6d 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -3425,10 +3425,14 @@ static ULONG mhz_from_cpuinfo(void)
     return cmz;
 }
 
-static const char * get_sys_str(const char *path, char *s)
+static const char * get_sys_str(const char *dirname, const char *basename, char *s)
 {
-    FILE *f = fopen(path, "r");
+    FILE *f;
     const char *ret = NULL;
+    char path[64];
+
+    sprintf(path, "%s/%s", dirname, basename);
+    f = fopen(path, "r");
 
     if (f)
     {
@@ -3438,40 +3442,57 @@ static const char * get_sys_str(const char *path, char *s)
     return ret;
 }
 
-static int get_sys_int(const char *path, int def)
+static int get_sys_int(const char *dirname, const char *basename, int def)
 {
     char s[16];
-    return get_sys_str(path, s) ? atoi(s) : def;
+    return get_sys_str(dirname, basename, s) ? atoi(s) : def;
 }
 
 static NTSTATUS fill_battery_state( SYSTEM_BATTERY_STATE *bs )
 {
-    char s[16], path[64];
-    unsigned int i = 0;
+    static const char* ac_names[] =
+    {
+        "AC",
+        "ACAD",
+        "ADP0",
+        "ADP1",
+        NULL
+    };
+    static const char* bat_names[] =
+    {
+        "BAT0",
+        "BAT1",
+        NULL
+    };
+    char s[16], dirname[64];
+    const char** name;
     LONG64 voltage; /* microvolts */
 
-    bs->AcOnLine = get_sys_int("/sys/class/power_supply/AC/online", 1);
-
-    for (;;)
+    bs->AcOnLine = TRUE;
+    for (name = ac_names; name; name++)
     {
-        sprintf(path, "/sys/class/power_supply/BAT%u/status", i);
-        if (!get_sys_str(path, s)) break;
-        bs->Charging |= (strcmp(s, "Charging\n") == 0);
-        bs->Discharging |= (strcmp(s, "Discharging\n") == 0);
-        bs->BatteryPresent = TRUE;
-        i++;
+        sprintf(dirname, "/sys/class/power_supply/%s", *name);
+        if (!get_sys_str(dirname, "online", s)) continue;
+        bs->AcOnLine = atoi(s);
+        break;
     }
 
-    if (bs->BatteryPresent)
+    for (name = bat_names; name; name++)
     {
-        voltage = get_sys_int("/sys/class/power_supply/BAT0/voltage_now", 0);
-        bs->MaxCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_full", 0) * voltage / 1e9;
-        bs->RemainingCapacity = get_sys_int("/sys/class/power_supply/BAT0/charge_now", 0) * voltage / 1e9;
-        bs->Rate = -get_sys_int("/sys/class/power_supply/BAT0/current_now", 0) * voltage / 1e9;
+        sprintf(dirname, "/sys/class/power_supply/%s", *name);
+        if (!get_sys_str(dirname, "status", s)) continue;
+        bs->Charging = (strcmp(s, "Charging\n") == 0);
+        bs->Discharging = (strcmp(s, "Discharging\n") == 0);
+        bs->BatteryPresent = TRUE;
+        voltage = get_sys_int(dirname, "voltage_now", 0);
+        bs->MaxCapacity = get_sys_int(dirname, "charge_full", 0) * voltage / 1e9;
+        bs->RemainingCapacity = get_sys_int(dirname, "charge_now", 0) * voltage / 1e9;
+        bs->Rate = -get_sys_int(dirname, "current_now", 0) * voltage / 1e9;
         if (!bs->Charging && (LONG)bs->Rate < 0)
             bs->EstimatedTime = 3600 * bs->RemainingCapacity / -(LONG)bs->Rate;
         else
             bs->EstimatedTime = ~0u;
+        break;
     }
 
     return STATUS_SUCCESS;
-- 
2.36.0




More information about the wine-devel mailing list