From: "Ted Unangst" Subject: a little more asus wmi To: tech@openbsd.org Date: Tue, 10 Jun 2025 02:36:44 -0400 We can support battery chargestop and a fan sensor. Only writing chargestop is supported, and it seems to reset after reboot, but otherwise works. Discharged a bit, set it to 90, battery is now idle at 95% instead of going up to 100%. Index: acpiwmi.c =================================================================== RCS file: /home/cvs/src/sys/dev/acpi/acpiwmi.c,v diff -u -p -r1.5 acpiwmi.c --- acpiwmi.c 21 May 2025 02:18:29 -0000 1.5 +++ acpiwmi.c 10 Jun 2025 06:30:17 -0000 @@ -250,6 +250,8 @@ struct wmiasus { int w_fnlock; int w_perf; int w_perfid; + struct ksensor w_sensfan; + struct ksensordev w_sensdev; }; #define ASUS_DSTS_PRESENCE 0x00010000 @@ -267,6 +269,7 @@ struct wmiasus { #define ASUS_DEV_FNLOCK 0x00100023 #define ASUS_DEV_CAMLED 0x00060079 #define ASUS_DEV_MICLED 0x00040017 +#define ASUS_DEV_CPUFAN 0x00110013 #define ASUS_FNLOCK_BIOS_DISABLED 0x1 @@ -311,6 +314,61 @@ asus_toggle(struct wmiasus *wh, int devi asus_dev_set(wh, devid, *val | mask); } +struct wmiasus *wmi_asus_cookie; +/* xxx the order may vary by machine... */ +static const char *asus_policies[] = { "standard,", "silent,", "perf," }; + +void +wmi_asus_setpolicy(char *policy) +{ + struct wmiasus *wh = wmi_asus_cookie; + int target = -1; + + for (int i = 0; i < nitems(asus_policies); i++) { + size_t len = strlen(asus_policies[i]); + if (strncmp(policy, asus_policies[i], len) == 0) { + target = i; + memmove(policy, policy + len, strlen(policy + len)+1); + break; + } + } + if (target != -1) { + wh->w_perf = target; + asus_dev_set(wh, wh->w_perfid, wh->w_perf); + } +} + +void +wmi_asus_getpolicy(char *policy, size_t len) +{ + struct wmiasus *wh = wmi_asus_cookie; + int target = wh->w_perf; + + if (target >= 0 && target < nitems(asus_policies)) + strlcpy(policy, asus_policies[target], len); +} + +int +wmi_asus_battery_setchargestop(int stop) +{ + struct wmiasus *wh = wmi_asus_cookie; + extern int hw_battery_chargestop; + + asus_dev_set(wh, ASUS_DEV_BATTERY, stop); + hw_battery_chargestop = stop; + return 0; +} + +void +wmi_asus_sensor_check(void *arg) +{ + struct wmiasus *wh = arg; + + int res = asus_dev_get(wh, ASUS_DEV_CPUFAN); + if (res > 0 && res & ASUS_DSTS_PRESENCE) + wh->w_sensfan.value = (res & 0xffff) * 100; +} + static int wmi_asus_init(struct acpiwmi_softc *sc, struct guidinfo *ginfo) { @@ -342,6 +400,28 @@ wmi_asus_init(struct acpiwmi_softc *sc, res = asus_dev_get(wh, ASUS_DEV_PERF_2); if (res >= 0) wh->w_perfid = ASUS_DEV_PERF_2; + if (wh->w_perfid != 0) { + extern void (*cpu_setpolicy)(char *); + extern void (*cpu_getpolicy)(char *, size_t); + cpu_getpolicy = wmi_asus_getpolicy; + cpu_setpolicy = wmi_asus_setpolicy; + } + res = asus_dev_get(wh, ASUS_DEV_BATTERY); + if (res > 0 && res & ASUS_DSTS_PRESENCE) { + extern int (*hw_battery_setchargestop)(int); + hw_battery_setchargestop = + wmi_asus_battery_setchargestop; + } + res = asus_dev_get(wh, ASUS_DEV_CPUFAN); + if (res > 0 && res & ASUS_DSTS_PRESENCE) { + strlcpy(wh->w_sensdev.xname, DEVNAME(sc), sizeof(wh->w_sensdev.xname)); + wh->w_sensfan.type = SENSOR_FANRPM; + wh->w_sensfan.value = (res & 0xffff) * 100; + sensor_attach(&wh->w_sensdev, &wh->w_sensfan); + sensordev_install(&wh->w_sensdev); + sensor_task_register(wh, wmi_asus_sensor_check, 2); + } + // turn on by default asus_toggle(wh, ASUS_DEV_KBDLIGHT, &wh->w_kbdlight); @@ -352,6 +432,7 @@ wmi_asus_init(struct acpiwmi_softc *sc, asus_toggle(wh, ASUS_DEV_FNLOCK, &wh->w_fnlock); } + wmi_asus_cookie = wh; return 0; }