From: Mark Kettenis Subject: Re: a little more asus wmi To: "Ted Unangst" Cc: tech@openbsd.org Date: Tue, 10 Jun 2025 11:25:31 +0200 > From: "Ted Unangst" > Date: Tue, 10 Jun 2025 02:36:44 -0400 > > We can support battery chargestop and a fan sensor. The fan policy stuff needs more discussion. So if you want this to end up in OpenBSD you'll have to split these bits out. Probably best to send separate bits for the battery charging stuff and the fan sensor. This does need more work. There are several KNF issues with this code. > 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%. Typically the charge controllers implement some sort of hysteresis for charging the battery. So stop charging at a certain percentage, and start charging again at some lower percentage. If that lower value is known you can do what aplsmc(4) does, so set both stop and start in the _setchargestop() function and have a _setchargestart() that return EOPNOTSUPP. But if you don't know, then what you've implemented is fine. > > 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; > } > > >