On Sun, Jul 23, 2023 at 09:16:40PM +0000, jon@elytron.openbsd.amsterdam wrote:
> If I'm not mistaken, all wskbd_{get,set}_backlight uses are in the
> following drivers: acpicbkbd, acpithinkpad, asmc, pwmleds, and now
> my implementation in adb. It is my impression that they are roughly
> the same code, I have collected them below to ease their inspection.

This doesn't look too bad actually but I am not quite sure about pwm.
A common way to solve this is adding a task to do the heavy lifiting and
then invoking that from interrupt context.

In wskbd.c there is a wskbd_brightness_task() which you could use as a
reference for a new wskbd_kbd_backlight_task().

> 
> I would also like to acknowledge the kind help of jcs@, whom I
> approached back when I made my first post on this matter (before
> the key shortcuts, wsconsctl only) upon coming across his acpicbkbd(4).
> 
> (installed in dev/acpi/amsc.c:319)
> 
> int
> asmc_get_backlight(struct wskbd_backlight *kbl)
> {
>   struct asmc_softc *sc = asmc_cd.cd_devs[0];
> 
>   KASSERT(sc != NULL);
>   kbl->min = 0;
>   kbl->max = 0xff;
>   kbl->curval = sc->sc_backlight;
>   return 0;
> }
> 
> int
> asmc_set_backlight(struct wskbd_backlight *kbl)
> {
>   struct asmc_softc *sc = asmc_cd.cd_devs[0];
> 
>   KASSERT(sc != NULL);
>   if (kbl->curval > 0xff)
>     return EINVAL;
>   sc->sc_backlight = kbl->curval;
>   task_add(systq, &sc->sc_task_backlight);
>   return 0;
> }
> 
> (installed in dev/acpi/acpicbkbd.c:94)
> 
> int
> acpicbkbd_get_backlight(struct wskbd_backlight *kbl)
> {
>   struct acpicbkbd_softc *sc = acpicbkbd_cd.cd_devs[0];
> 
>   KASSERT(sc != NULL);
> 
>   kbl->min = 0;
>   kbl->max = ACPICBKBD_MAX_BACKLIGHT;
>   kbl->curval = sc->sc_backlight;
> 
>   return 0;
> }
> 
> int
> acpicbkbd_set_backlight(struct wskbd_backlight *kbl)
> {
>   struct acpicbkbd_softc *sc = acpicbkbd_cd.cd_devs[0];
> 
>   KASSERT(sc != NULL);
> 
>   if (kbl->curval > ACPICBKBD_MAX_BACKLIGHT)
>     return EINVAL;
> 
>   sc->sc_backlight = kbl->curval;
> 
>   acpi_addtask(sc->sc_acpi, acpicbkbd_write_backlight, sc, 0);
>   acpi_wakeup(sc->sc_acpi);
> 
>   return 0;
> }
> 
> (installed in dev/acpi/acpithinkpad.c:347)
> 
> int
> thinkpad_get_kbd_backlight(struct wskbd_backlight *kbl)
> {
>   struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
> 
>   KASSERT(sc != NULL);
> 
>   kbl->min = 0;
>   kbl->max = (sc->sc_thinklight >> 8) & 0x0f;
>   kbl->curval = sc->sc_thinklight & 0x0f;
> 
>   if (kbl->max == 0)
>     return (ENOTTY);
> 
>   return 0;
> }
> 
> int
> thinkpad_set_kbd_backlight(struct wskbd_backlight *kbl)
> {
>   struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
>   int maxval;
> 
>   KASSERT(sc != NULL);
> 
>   maxval = (sc->sc_thinklight >> 8) & 0x0f;
> 
>   if (maxval == 0)
>     return (ENOTTY);
> 
>   if (kbl->curval > maxval)
>     return EINVAL;
> 
>   sc->sc_thinklight &= ~0xff;
>   sc->sc_thinklight |= kbl->curval;
>   acpi_addtask(sc->sc_acpi, thinkpad_set_thinklight, sc, 0);
>   acpi_wakeup(sc->sc_acpi);
>   return 0;
> }
> 
> (installed in pwmleds.c:102)
> int
> pwmleds_get_kbd_backlight(struct wskbd_backlight *kbl)
> {
>   struct pwmleds_softc *sc;
>   struct pwm_state ps;
>   int error;
> 
>   sc = pwmleds_kbd_backlight();
>   if (sc == NULL)
>     return ENOTTY;
> 
>   error = pwm_get_state(sc->sc_pwm, &ps);
>   if (error)
>     return error;
> 
>   kbl->min = 0;
>   kbl->max = sc->sc_max_brightness;
>   kbl->curval = (ps.ps_enabled) ?
>       ((uint64_t)ps.ps_pulse_width * kbl->max) / ps.ps_period : 0;
>   return 0;
> }
> 
> int
> pwmleds_set_kbd_backlight(struct wskbd_backlight *kbl)
> {
>   struct pwmleds_softc *sc;
>   struct pwm_state ps;
> 
>   sc = pwmleds_kbd_backlight();
>   if (sc == NULL)
>     return ENOTTY;
> 
>   if (kbl->curval < 0 || kbl->curval > sc->sc_max_brightness)
>     return EINVAL;
> 
>   pwm_init_state(sc->sc_pwm, &ps);
>   ps.ps_pulse_width =
>       ((uint64_t)kbl->curval * ps.ps_period) / sc->sc_max_brightness;
>   ps.ps_enabled = (ps.ps_pulse_width > 0);
>   return pwm_set_state(sc->sc_pwm, &ps);
> }

Reply via email to