Index | Thread | Search

From:
"Ted Unangst" <tedu@tedunangst.com>
Subject:
a little more asus wmi
To:
tech@openbsd.org
Date:
Tue, 10 Jun 2025 02:36:44 -0400

Download raw body.

Thread
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;
 }