Hi, this is the second attempt of a diff that prepares acpivout(4) to work with the X395. The previous one broke due to recursive ACPI locking.
So apparently we cannot change the brightness using the acpivout(4) ACPI methods. Instead we need to call amdgpu(4) to change the brightness. But the brightness key events are still reported by acpivout(4). That means that we need to seperate the keystroke events from the actual brightness change. This diff changes the code to always use ws_[gs]et_param instead of just calling the ACPI methods. This means that the function pointers can point to acpivout(4) or amdgpu(4), it shouldn't matter. Unfortunately there's an issue with acpivout(4) calling itself. The keystroke event handler runs with the ACPI lock, so if we call our own function, we try to grab the ACPI lock again and panic. So, in this diff I check whether we already have it and skip taking it again. I'm sure this looks ugly, and I'm wondering if it's too ugly. If it is indeed too ugly, I hope you'll also provide another idea how we can work around it. More testing would be appreciated. Thanks, Patrick diff --git a/sys/dev/acpi/acpivout.c b/sys/dev/acpi/acpivout.c index 58e8e3d431c..f3de0c582fb 100644 --- a/sys/dev/acpi/acpivout.c +++ b/sys/dev/acpi/acpivout.c @@ -66,6 +66,7 @@ void acpivout_brightness_cycle(struct acpivout_softc *); void acpivout_brightness_step(struct acpivout_softc *, int); void acpivout_brightness_zero(struct acpivout_softc *); int acpivout_get_brightness(struct acpivout_softc *); +int acpivout_select_brightness(struct acpivout_softc *, int); int acpivout_find_brightness(struct acpivout_softc *, int); void acpivout_set_brightness(struct acpivout_softc *, int); void acpivout_get_bcl(struct acpivout_softc *); @@ -124,6 +125,9 @@ acpivout_notify(struct aml_node *node, int notify, void *arg) { struct acpivout_softc *sc = arg; + if (ws_get_param == NULL || ws_set_param == NULL) + return (0); + switch (notify) { case NOTIFY_BRIGHTNESS_CYCLE: acpivout_brightness_cycle(sc); @@ -151,12 +155,13 @@ acpivout_notify(struct aml_node *node, int notify, void *arg) void acpivout_brightness_cycle(struct acpivout_softc *sc) { - int cur_level; + struct wsdisplay_param dp; - if (sc->sc_bcl_len == 0) + dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS; + if (ws_get_param(&dp)) return; - cur_level = acpivout_get_brightness(sc); - if (cur_level == sc->sc_bcl[sc->sc_bcl_len - 1]) + + if (dp.curval == dp.max) acpivout_brightness_zero(sc); else acpivout_brightness_step(sc, 1); @@ -165,33 +170,45 @@ acpivout_brightness_cycle(struct acpivout_softc *sc) void acpivout_brightness_step(struct acpivout_softc *sc, int dir) { - int level, nindex; + struct wsdisplay_param dp; + int delta, new; - if (sc->sc_bcl_len == 0) - return; - level = acpivout_get_brightness(sc); - if (level == -1) + dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS; + if (ws_get_param(&dp)) return; - nindex = acpivout_find_brightness(sc, level + (dir * BRIGHTNESS_STEP)); - if (sc->sc_bcl[nindex] == level) { - if (dir == 1 && (nindex + 1 < sc->sc_bcl_len)) - nindex++; - else if (dir == -1 && (nindex - 1 >= 0)) - nindex--; + new = dp.curval; + delta = ((dp.max - dp.min) * BRIGHTNESS_STEP) / 100; + if (dir > 0) { + if (delta > dp.max - dp.curval) + new = dp.max; + else + new += delta; + } else if (dir < 0) { + if (delta > dp.curval - dp.min) + new = dp.min; + else + new -= delta; } - if (sc->sc_bcl[nindex] == level) + + if (dp.curval == new) return; - acpivout_set_brightness(sc, sc->sc_bcl[nindex]); + dp.curval = new; + ws_set_param(&dp); } void acpivout_brightness_zero(struct acpivout_softc *sc) { - if (sc->sc_bcl_len == 0) + struct wsdisplay_param dp; + + dp.param = WSDISPLAYIO_PARAM_BRIGHTNESS; + if (ws_get_param(&dp)) return; - acpivout_set_brightness(sc, sc->sc_bcl[0]); + + dp.curval = dp.min; + ws_set_param(&dp); } int @@ -211,6 +228,26 @@ acpivout_get_brightness(struct acpivout_softc *sc) return (level); } +int +acpivout_select_brightness(struct acpivout_softc *sc, int nlevel) +{ + int nindex, level; + + level = acpivout_get_brightness(sc); + if (level == -1) + return level; + + nindex = acpivout_find_brightness(sc, nlevel); + if (sc->sc_bcl[nindex] == level) { + if (nlevel > level && (nindex + 1 < sc->sc_bcl_len)) + nindex++; + else if (nlevel < level && (nindex - 1 >= 0)) + nindex--; + } + + return nindex; +} + int acpivout_find_brightness(struct acpivout_softc *sc, int level) { @@ -290,7 +327,7 @@ int acpivout_get_param(struct wsdisplay_param *dp) { struct acpivout_softc *sc = NULL; - int i; + int i, needlock; switch (dp->param) { case WSDISPLAYIO_PARAM_BRIGHTNESS: @@ -304,10 +341,13 @@ acpivout_get_param(struct wsdisplay_param *dp) } if (sc != NULL && sc->sc_bcl_len != 0) { dp->min = 0; - dp->max = sc->sc_bcl[sc->sc_bcl_len - 1]; - rw_enter_write(&sc->sc_acpi->sc_lck); + dp->max = sc->sc_bcl[sc->sc_bcl_len - 1]; + needlock = rw_status(&sc->sc_acpi->sc_lck) != RW_WRITE; + if (needlock) + rw_enter_write(&sc->sc_acpi->sc_lck); dp->curval = acpivout_get_brightness(sc); - rw_exit_write(&sc->sc_acpi->sc_lck); + if (needlock) + rw_exit_write(&sc->sc_acpi->sc_lck); if (dp->curval != -1) return 0; } @@ -321,7 +361,7 @@ int acpivout_set_param(struct wsdisplay_param *dp) { struct acpivout_softc *sc = NULL; - int i, nindex; + int i, nindex, needlock; switch (dp->param) { case WSDISPLAYIO_PARAM_BRIGHTNESS: @@ -334,10 +374,14 @@ acpivout_set_param(struct wsdisplay_param *dp) break; } if (sc != NULL && sc->sc_bcl_len != 0) { - rw_enter_write(&sc->sc_acpi->sc_lck); - nindex = acpivout_find_brightness(sc, dp->curval); - acpivout_set_brightness(sc, sc->sc_bcl[nindex]); - rw_exit_write(&sc->sc_acpi->sc_lck); + needlock = rw_status(&sc->sc_acpi->sc_lck) != RW_WRITE; + if (needlock) + rw_enter_write(&sc->sc_acpi->sc_lck); + nindex = acpivout_select_brightness(sc, dp->curval); + if (nindex != -1) + acpivout_set_brightness(sc, sc->sc_bcl[nindex]); + if (needlock) + rw_exit_write(&sc->sc_acpi->sc_lck); return 0; } return -1;