On Wed, Dec 16, 2015 at 07:48:23PM +0100, Mark Kettenis wrote:
> Most, if not all, somewhat recent Thinkpads have some subtle issues
> with display brightness control.  For example,if you change the
> display brightness using wsconsctl(8) or cbacklight(1), and later use
> the brightness control buttons on the keyboard, you're likely to see a
> big jump in brightness.  or if you plug or unplug the power, the
> display brightness will suddenly change.  The problem here is that on
> these machines we us the display brightness interface provided by
> inteldrm(4), which doesn't coordinate changes with the firmware.
> 
> In principle these machines support the standard acpi brightness
> control interface.  However that interface is quite badly broken if
> the OS claims to be Windows 8.  Unfortunately that is what we do on
> OpenBSD because otherwise some other machines don't work properly.
> 
> Fortunately Thinkpads provide an alternative acpi interface through
> the "hotkey" device that is handled by acpithinkpad(4).  The diff
> below implements that interface.
> 
> The downside of this diff is that number of levels is limited to 16
> whereas we currently have much finer granularity.  But I think that is
> acceptable.  The levels are probably better calibrated and we now have
> proper coordination between the OS and the firmware when it comes to
> brightness changes.  On top of that, this diff will almost certainly
> result in working brightness control on machines that don't have Intel
> graphics.
> 
> ok?
> 

I'm ok with this. Didn't test it but I don't have objections to moving
in this direction. Diff looks ok too.

-ml

> 
> Index: acpithinkpad.c
> ===================================================================
> RCS file: /home/cvs/src/sys/dev/acpi/acpithinkpad.c,v
> retrieving revision 1.49
> diff -u -p -r1.49 acpithinkpad.c
> --- acpithinkpad.c    16 Dec 2015 15:43:14 -0000      1.49
> +++ acpithinkpad.c    16 Dec 2015 18:00:03 -0000
> @@ -122,6 +122,8 @@ struct acpithinkpad_softc {
>       uint64_t                 sc_thinklight;
>       const char              *sc_thinklight_get;
>       const char              *sc_thinklight_set;
> +
> +     uint64_t                 sc_brightness;
>  };
>  
>  extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
> @@ -141,13 +143,19 @@ int     thinkpad_brightness_down(struct acpi
>  int  thinkpad_adaptive_change(struct acpithinkpad_softc *);
>  int  thinkpad_activate(struct device *, int);
>  
> -/* wskbd hook functions */
> +/* wscons hook functions */
>  void thinkpad_get_thinklight(struct acpithinkpad_softc *);
>  void thinkpad_set_thinklight(void *, int);
>  int  thinkpad_get_backlight(struct wskbd_backlight *);
>  int  thinkpad_set_backlight(struct wskbd_backlight *);
>  extern int (*wskbd_get_backlight)(struct wskbd_backlight *);
>  extern int (*wskbd_set_backlight)(struct wskbd_backlight *);
> +void thinkpad_get_brightness(struct acpithinkpad_softc *);
> +void thinkpad_set_brightness(void *, int);
> +int  thinkpad_get_param(struct wsdisplay_param *);
> +int  thinkpad_set_param(struct wsdisplay_param *);
> +extern int (*ws_get_param)(struct wsdisplay_param *);
> +extern int (*ws_set_param)(struct wsdisplay_param *);
>  
>  void    thinkpad_sensor_attach(struct acpithinkpad_softc *sc);
>  void    thinkpad_sensor_refresh(void *);
> @@ -267,6 +275,12 @@ thinkpad_attach(struct device *parent, s
>               wskbd_set_backlight = thinkpad_set_backlight;
>       }
>  
> +     if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "PBLG",
> +         0, NULL, &sc->sc_brightness) == 0) {
> +             ws_get_param = thinkpad_get_param;
> +             ws_set_param = thinkpad_set_param;
> +     }
> +
>       /* Run thinkpad_hotkey on button presses */
>       aml_register_notify(sc->sc_devnode, aa->aaa_dev,
>           thinkpad_hotkey, sc, ACPIDEV_POLL);
> @@ -391,6 +405,9 @@ thinkpad_hotkey(struct aml_node *node, i
>                       thinkpad_adaptive_change(sc);
>                       handled = 1;
>                       break;
> +             case THINKPAD_BACKLIGHT_CHANGED:
> +                     thinkpad_get_brightness(sc);
> +                     break;
>               case THINKPAD_ADAPTIVE_BACK:
>               case THINKPAD_ADAPTIVE_GESTURES:
>               case THINKPAD_ADAPTIVE_REFRESH:
> @@ -398,7 +415,6 @@ thinkpad_hotkey(struct aml_node *node, i
>               case THINKPAD_ADAPTIVE_SNIP:
>               case THINKPAD_ADAPTIVE_TAB:
>               case THINKPAD_ADAPTIVE_VOICE:
> -             case THINKPAD_BACKLIGHT_CHANGED:
>               case THINKPAD_KEYLIGHT_CHANGED:
>               case THINKPAD_BRIGHTNESS_CHANGED:
>               case THINKPAD_BUTTON_BATTERY_INFO:
> @@ -630,4 +646,63 @@ thinkpad_set_backlight(struct wskbd_back
>       acpi_addtask(sc->sc_acpi, thinkpad_set_thinklight, sc, 0);
>       acpi_wakeup(sc->sc_acpi);
>       return 0;
> +}
> +
> +void
> +thinkpad_get_brightness(struct acpithinkpad_softc *sc)
> +{
> +     aml_evalinteger(sc->sc_acpi, sc->sc_devnode,
> +         "PBLG", 0, NULL, &sc->sc_brightness);
> +}
> +
> +void
> +thinkpad_set_brightness(void *arg0, int arg1)
> +{
> +     struct acpithinkpad_softc *sc = arg0;
> +     struct aml_value arg;
> +
> +     memset(&arg, 0, sizeof(arg));
> +     arg.type = AML_OBJTYPE_INTEGER;
> +     arg.v_integer = sc->sc_brightness & 0xff;
> +     aml_evalname(sc->sc_acpi, sc->sc_devnode,
> +         "PBLS", 1, &arg, NULL);
> +}
> +
> +int
> +thinkpad_get_param(struct wsdisplay_param *dp)
> +{
> +     struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
> +
> +     if (sc == NULL)
> +             return -1;
> +
> +     dp->min = 0;
> +     dp->max = (sc->sc_brightness >> 8) & 0xff;
> +     dp->curval = sc->sc_brightness & 0xff;
> +     return 0;
> +}
> +
> +int
> +thinkpad_set_param(struct wsdisplay_param *dp)
> +{
> +     struct acpithinkpad_softc *sc = acpithinkpad_cd.cd_devs[0];
> +     int maxval = (sc->sc_brightness >> 8) & 0xff;
> +
> +     if (sc == NULL)
> +             return -1;
> +
> +     switch (dp->param) {
> +     case WSDISPLAYIO_PARAM_BRIGHTNESS:
> +             if (dp->curval < 0)
> +                     dp->curval = 0;
> +             if (dp->curval > maxval)
> +                     dp->curval = maxval;
> +             sc->sc_brightness &= ~0xff;
> +             sc->sc_brightness |= dp->curval;
> +             acpi_addtask(sc->sc_acpi, thinkpad_set_brightness, sc, 0);
> +             acpi_wakeup(sc->sc_acpi);
> +             return 0;
> +     default:
> +             return -1;
> +     }
>  }
> 

Reply via email to