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) {