Module Name: src
Committed By: maya
Date: Fri May 10 19:29:46 UTC 2024
Modified Files:
src/sys/dev/acpi: acpi_display.c
Log Message:
Add quirk for machines were the getting the brightness value always
returns the same result by keeping a local copy of the last set value.
This makes the brightness buttons work on my Thinkpad T450s, and will
probably fix PR kern/57825 as well.
To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/acpi/acpi_display.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/acpi/acpi_display.c
diff -u src/sys/dev/acpi/acpi_display.c:1.23 src/sys/dev/acpi/acpi_display.c:1.24
--- src/sys/dev/acpi/acpi_display.c:1.23 Fri Mar 17 17:16:06 2023
+++ src/sys/dev/acpi/acpi_display.c Fri May 10 19:29:46 2024
@@ -1,4 +1,4 @@
-/* $NetBSD: acpi_display.c,v 1.23 2023/03/17 17:16:06 andvar Exp $ */
+/* $NetBSD: acpi_display.c,v 1.24 2024/05/10 19:29:46 maya Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: acpi_display.c,v 1.23 2023/03/17 17:16:06 andvar Exp $");
+__KERNEL_RCSID(0, "$NetBSD: acpi_display.c,v 1.24 2024/05/10 19:29:46 maya Exp $");
#include <sys/param.h>
#include <sys/device.h>
@@ -270,6 +270,12 @@ struct acpidisp_brctl {
uint8_t *bc_level; /* Array of levels */
uint16_t bc_level_count; /* Number of levels */
uint8_t bc_current; /* Current level */
+
+ /*
+ * Quirk if firmware returns wrong values for _BQC
+ * (acpidisp_get_brightness)
+ */
+ bool bc_bqc_broken;
};
/*
@@ -376,6 +382,7 @@ static int acpidisp_get_brightness(const
uint8_t *);
static int acpidisp_set_brightness(const struct acpidisp_out_softc *,
uint8_t);
+static int acpidisp_quirk_get_brightness(const struct acpidisp_out_softc *);
static void acpidisp_print_odinfo(device_t, const struct acpidisp_odinfo *);
static void acpidisp_print_brctl(device_t, const struct acpidisp_brctl *);
@@ -717,6 +724,10 @@ acpidisp_out_attach(device_t parent, dev
kmem_free(bc, sizeof(*bc));
osc->sc_brctl = NULL;
} else {
+ if (acpidisp_quirk_get_brightness(osc)) {
+ aprint_error_dev(self,
+ "failed to test _BQC quirk\n");
+ }
acpidisp_print_brctl(self, osc->sc_brctl);
}
}
@@ -1860,6 +1871,11 @@ acpidisp_get_brightness(const struct acp
if (!(osc->sc_caps & ACPI_DISP_OUT_CAP__BQC))
return ENODEV;
+ if (osc->sc_brctl->bc_bqc_broken) {
+ *valuep = osc->sc_brctl->bc_current;
+ return 0;
+ }
+
rv = acpi_eval_integer(hdl, "_BQC", &val);
if (ACPI_FAILURE(rv)) {
aprint_error_dev(osc->sc_dev, "failed to evaluate %s.%s: %s\n",
@@ -1878,6 +1894,60 @@ acpidisp_get_brightness(const struct acp
return 0;
}
+/*
+ * Quirk for when getting the brightness value always returns the same
+ * result, which breaks brightness controls which try to lower the
+ * brightness by a specific value and then check if it worked.
+ */
+static int
+acpidisp_quirk_get_brightness(const struct acpidisp_out_softc *osc)
+{
+ struct acpidisp_brctl *bc;
+ uint8_t original_brightness, test_brightness;
+ int error;
+
+ bc = osc->sc_brctl;
+
+ /* Avoid false results if quirk already enabled */
+ bc->bc_bqc_broken = false;
+
+ error = acpidisp_get_brightness(osc, &bc->bc_current);
+ if (error)
+ return error;
+ original_brightness = bc->bc_current;
+
+ /* Find a different brightness value */
+ test_brightness = bc->bc_level[bc->bc_level_count - 1];
+ if (test_brightness == original_brightness)
+ test_brightness = bc->bc_level[0];
+
+ if (test_brightness == original_brightness) {
+ aprint_error_dev(osc->sc_dev,
+ "couldn't find different brightness levels"
+ " for _BQC quirk test\n");
+ return 0;
+ }
+
+ bc->bc_current = test_brightness;
+ error = acpidisp_set_brightness(osc, bc->bc_current);
+ if (error)
+ return error;
+
+ error = acpidisp_get_brightness(osc, &bc->bc_current);
+ if (error)
+ return error;
+
+ /* We set a different value, but got the original value back */
+ if (bc->bc_current == original_brightness) {
+ aprint_normal_dev(osc->sc_dev, "_BQC broken, enabling quirk\n");
+ bc->bc_bqc_broken = true;
+ }
+
+ /* Restore original value */
+ bc->bc_current = original_brightness;
+ return acpidisp_set_brightness(osc, bc->bc_current);
+}
+
static int
acpidisp_set_brightness(const struct acpidisp_out_softc *osc, uint8_t value)
{