Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 30 Apr 2025 07:49:12 GMT
From:      Vladimir Kondratyev <wulf@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 9b5f1a6cd682 - stable/14 - acpi_asus_wmi(4): Improve keyboard backlight support.
Message-ID:  <202504300749.53U7nCIw011130@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/14 has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=9b5f1a6cd68272d249a2fe236a1d292ae7fefac2

commit 9b5f1a6cd68272d249a2fe236a1d292ae7fefac2
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2025-03-17 15:45:14 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2025-04-30 07:32:22 +0000

    acpi_asus_wmi(4): Improve keyboard backlight support.
    
    - Fix maximal keyboard backlight level, Although Linux source code
      comment says that backlight level is encoded in 3 bits of data,
      actual code limits maximum level to 3.
    - Add backlight(9) support for keyboard
    - Turn off/on keyboard backlight on suspend/resume
    
    Sponsored by:   Future Crew LLC
    MFC after:      1 month
    Reviewed by:    mav
    Differential Revision:  https://reviews.freebsd.org/D48983
    
    (cherry picked from commit f134662a1a5726d78880385002a03b8fe68805f6)
---
 share/man/man4/acpi_asus_wmi.4          |  10 ++-
 sys/dev/acpi_support/acpi_asus_wmi.c    | 136 +++++++++++++++++++++++++++++++-
 sys/modules/acpi/acpi_asus_wmi/Makefile |   2 +-
 3 files changed, 142 insertions(+), 6 deletions(-)

diff --git a/share/man/man4/acpi_asus_wmi.4 b/share/man/man4/acpi_asus_wmi.4
index 10db9ba6ca59..438ac11b078a 100644
--- a/share/man/man4/acpi_asus_wmi.4
+++ b/share/man/man4/acpi_asus_wmi.4
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd July 2, 2012
+.Dd March 25, 2024
 .Dt ACPI_ASUS_WMI 4
 .Os
 .Sh NAME
@@ -72,11 +72,19 @@ Number of other variables under the same sysctl branch are model-specific.
 Defaults for these variables can be set in
 .Xr sysctl.conf 5 ,
 which is parsed at boot-time.
+.Sh FILES
+.Bl -tag -width "/dev/backlight/acpi_asus_wmi0" -compact
+.It Pa /dev/backlight/acpi_asus_wmi0
+Keyboard
+.Xr backlight 8
+device node.
+.El
 .Sh SEE ALSO
 .Xr acpi 4 ,
 .Xr acpi_asus 4 ,
 .Xr acpi_video 4 ,
 .Xr sysctl.conf 5 ,
+.Xr backlight 8 ,
 .Xr devd 8 ,
 .Xr sysctl 8
 .Sh HISTORY
diff --git a/sys/dev/acpi_support/acpi_asus_wmi.c b/sys/dev/acpi_support/acpi_asus_wmi.c
index 80beee2fea7f..968de5fe5e87 100644
--- a/sys/dev/acpi_support/acpi_asus_wmi.c
+++ b/sys/dev/acpi_support/acpi_asus_wmi.c
@@ -42,6 +42,9 @@
 #include <dev/acpica/acpivar.h>
 #include "acpi_wmi_if.h"
 
+#include <dev/backlight/backlight.h>
+#include "backlight_if.h"
+
 #ifdef EVDEV_SUPPORT
 #include <dev/evdev/input.h>
 #include <dev/evdev/evdev.h>
@@ -117,6 +120,8 @@ struct acpi_asus_wmi_softc {
 	struct sysctl_oid	*sysctl_tree;
 	int		dsts_id;
 	int		handle_keys;
+	struct cdev	*kbd_bkl;
+	uint32_t	kbd_bkl_level;
 #ifdef EVDEV_SUPPORT
 	struct evdev_dev	*evdev;
 #endif
@@ -345,6 +350,8 @@ static void	acpi_asus_wmi_identify(driver_t *driver, device_t parent);
 static int	acpi_asus_wmi_probe(device_t dev);
 static int	acpi_asus_wmi_attach(device_t dev);
 static int	acpi_asus_wmi_detach(device_t dev);
+static int	acpi_asus_wmi_suspend(device_t dev);
+static int	acpi_asus_wmi_resume(device_t dev);
 
 static int	acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS);
 static int	acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id,
@@ -357,12 +364,26 @@ static int	acpi_wpi_asus_get_devstate(struct acpi_asus_wmi_softc *sc,
 static int	acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
 		    UINT32 dev_id, UINT32 ctrl_param, UINT32 *retval);
 static void	acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context);
+static int	acpi_asus_wmi_backlight_update_status(device_t dev,
+		    struct backlight_props *props);
+static int	acpi_asus_wmi_backlight_get_status(device_t dev,
+		    struct backlight_props *props);
+static int	acpi_asus_wmi_backlight_get_info(device_t dev,
+		    struct backlight_info *info);
 
 static device_method_t acpi_asus_wmi_methods[] = {
+	/* Device interface */
 	DEVMETHOD(device_identify, acpi_asus_wmi_identify),
 	DEVMETHOD(device_probe, acpi_asus_wmi_probe),
 	DEVMETHOD(device_attach, acpi_asus_wmi_attach),
 	DEVMETHOD(device_detach, acpi_asus_wmi_detach),
+	DEVMETHOD(device_suspend, acpi_asus_wmi_suspend),
+	DEVMETHOD(device_resume, acpi_asus_wmi_resume),
+
+	/* Backlight interface */
+        DEVMETHOD(backlight_update_status, acpi_asus_wmi_backlight_update_status),
+        DEVMETHOD(backlight_get_status, acpi_asus_wmi_backlight_get_status),
+        DEVMETHOD(backlight_get_info, acpi_asus_wmi_backlight_get_info),
 
 	DEVMETHOD_END
 };
@@ -376,10 +397,35 @@ static driver_t	acpi_asus_wmi_driver = {
 DRIVER_MODULE(acpi_asus_wmi, acpi_wmi, acpi_asus_wmi_driver, 0, 0);
 MODULE_DEPEND(acpi_asus_wmi, acpi_wmi, 1, 1, 1);
 MODULE_DEPEND(acpi_asus_wmi, acpi, 1, 1, 1);
+MODULE_DEPEND(acpi_asus_wmi, backlight, 1, 1, 1);
 #ifdef EVDEV_SUPPORT
 MODULE_DEPEND(acpi_asus_wmi, evdev, 1, 1, 1);
 #endif
 
+static const uint32_t acpi_asus_wmi_backlight_levels[] = { 0, 33, 66, 100 };
+
+static inline uint32_t
+devstate_to_kbd_bkl_level(UINT32 val)
+{
+	return (acpi_asus_wmi_backlight_levels[val & 0x3]);
+}
+
+static inline UINT32
+kbd_bkl_level_to_devstate(uint32_t bkl)
+{
+	UINT32 val;
+	int i;
+
+	for (i = 0; i < nitems(acpi_asus_wmi_backlight_levels); i++) {
+		if (bkl < acpi_asus_wmi_backlight_levels[i])
+			break;
+	}
+	val = (i - 1) & 0x3;
+	if (val != 0)
+		val |= 0x80;
+	return(val);
+}
+
 static void
 acpi_asus_wmi_identify(driver_t *driver, device_t parent)
 {
@@ -418,6 +464,7 @@ acpi_asus_wmi_attach(device_t dev)
 	struct acpi_asus_wmi_softc	*sc;
 	UINT32			val;
 	int			dev_id, i;
+	bool			have_kbd_bkl = false;
 
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
 
@@ -502,6 +549,10 @@ next:
 			if (val == 0)
 				continue;
 			break;
+		case ASUS_WMI_DEVID_KBD_BACKLIGHT:
+			sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
+			have_kbd_bkl = true;
+			/* FALLTHROUGH */
 		default:
 			if ((val & ASUS_WMI_DSTS_PRESENCE_BIT) == 0)
 				continue;
@@ -541,12 +592,22 @@ next:
 		}
 
 		if (evdev_register(sc->evdev) != 0) {
+			device_printf(dev, "Can not register evdev\n");
 			acpi_asus_wmi_detach(dev);
 			return (ENXIO);
 		}
 	}
 #endif
 
+	if (have_kbd_bkl) {
+		sc->kbd_bkl = backlight_register("acpi_asus_wmi", dev);
+		if (sc->kbd_bkl == NULL) {
+			device_printf(dev, "Can not register backlight\n");
+			acpi_asus_wmi_detach(dev);
+			return (ENXIO);
+		}
+	}
+
 	return (0);
 }
 
@@ -557,6 +618,9 @@ acpi_asus_wmi_detach(device_t dev)
 
 	ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
 
+	if (sc->kbd_bkl != NULL)
+		backlight_destroy(sc->kbd_bkl);
+
 	if (sc->notify_guid) {
 		ACPI_WMI_REMOVE_EVENT_HANDLER(dev, sc->notify_guid);
 #ifdef EVDEV_SUPPORT
@@ -567,6 +631,34 @@ acpi_asus_wmi_detach(device_t dev)
 	return (0);
 }
 
+static int
+acpi_asus_wmi_suspend(device_t dev)
+{
+	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
+
+	if (sc->kbd_bkl != NULL) {
+		ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
+		acpi_wpi_asus_set_devstate(sc,
+		    ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, NULL);
+	}
+
+	return (0);
+}
+
+static int
+acpi_asus_wmi_resume(device_t dev)
+{
+	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
+
+	if (sc->kbd_bkl != NULL) {
+		ACPI_FUNCTION_TRACE((char *)(uintptr_t) __func__);
+		acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
+		    kbd_bkl_level_to_devstate(sc->kbd_bkl_level), NULL);
+	}
+
+	return (0);
+}
+
 static int
 acpi_asus_wmi_sysctl(SYSCTL_HANDLER_ARGS)
 {
@@ -615,7 +707,7 @@ acpi_asus_wmi_sysctl_get(struct acpi_asus_wmi_softc *sc, int dev_id)
 		val &= ASUS_WMI_DSTS_BRIGHTNESS_MASK;
 		break;
 	case ASUS_WMI_DEVID_KBD_BACKLIGHT:
-		val &= 0x7;
+		val &= 0x3;
 		break;
 	default:
 		if (val & ASUS_WMI_DSTS_UNKNOWN_BIT)
@@ -636,7 +728,7 @@ acpi_asus_wmi_sysctl_set(struct acpi_asus_wmi_softc *sc, int dev_id, int arg, in
 
 	switch(dev_id) {
 	case ASUS_WMI_DEVID_KBD_BACKLIGHT:
-		arg = min(0x7, arg);
+		arg = min(0x3, arg);
 		if (arg != 0)
 			arg |= 0x80;
 		break;
@@ -701,9 +793,9 @@ acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
 		if (code == 0xc4 || code == 0xc5) {
 			acpi_wpi_asus_get_devstate(sc,
 			    ASUS_WMI_DEVID_KBD_BACKLIGHT, &val);
-			val &= 0x7;
+			val &= 0x3;
 			if (code == 0xc4) {
-				if (val < 0x7)
+				if (val < 0x3)
 					val++;
 			} else if (val > 0)
 				val--;
@@ -711,6 +803,7 @@ acpi_asus_wmi_notify(ACPI_HANDLE h, UINT32 notify, void *context)
 				val |= 0x80;
 			acpi_wpi_asus_set_devstate(sc,
 			    ASUS_WMI_DEVID_KBD_BACKLIGHT, val, NULL);
+			sc->kbd_bkl_level = devstate_to_kbd_bkl_level(val);
 		}
 		/* Touchpad control. */
 		if (code == 0x6b) {
@@ -767,3 +860,38 @@ acpi_wpi_asus_set_devstate(struct acpi_asus_wmi_softc *sc,
 	return (acpi_asus_wmi_evaluate_method(sc->wmi_dev,
 	    ASUS_WMI_METHODID_DEVS, dev_id, ctrl_param, retval));
 }
+
+static int
+acpi_asus_wmi_backlight_update_status(device_t dev, struct backlight_props
+    *props)
+{
+	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
+
+	acpi_wpi_asus_set_devstate(sc, ASUS_WMI_DEVID_KBD_BACKLIGHT,
+	    kbd_bkl_level_to_devstate(props->brightness), NULL);
+	sc->kbd_bkl_level = props->brightness;
+
+	return (0);
+}
+
+static int
+acpi_asus_wmi_backlight_get_status(device_t dev, struct backlight_props *props)
+{
+	struct acpi_asus_wmi_softc *sc = device_get_softc(dev);
+
+	props->brightness = sc->kbd_bkl_level;
+	props->nlevels = nitems(acpi_asus_wmi_backlight_levels);
+	memcpy(props->levels, acpi_asus_wmi_backlight_levels,
+	    sizeof(acpi_asus_wmi_backlight_levels));
+
+        return (0);
+}
+
+static int
+acpi_asus_wmi_backlight_get_info(device_t dev, struct backlight_info *info)
+{
+        info->type = BACKLIGHT_TYPE_KEYBOARD;
+        strlcpy(info->name, "ASUS Keyboard", BACKLIGHTMAXNAMELENGTH);
+
+        return (0);
+}
diff --git a/sys/modules/acpi/acpi_asus_wmi/Makefile b/sys/modules/acpi/acpi_asus_wmi/Makefile
index e0e21fa05d8c..52f48f953125 100644
--- a/sys/modules/acpi/acpi_asus_wmi/Makefile
+++ b/sys/modules/acpi/acpi_asus_wmi/Makefile
@@ -4,6 +4,6 @@
 KMOD=	acpi_asus_wmi
 CFLAGS+=-I${SRCTOP}/sys/dev/acpi_support
 SRCS=	acpi_asus_wmi.c opt_acpi.h acpi_if.h acpi_wmi_if.h device_if.h bus_if.h
-SRCS+=	opt_evdev.h
+SRCS+=	opt_evdev.h backlight_if.h
 
 .include <bsd.kmod.mk>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202504300749.53U7nCIw011130>