David Schlachter

Adjusting acpi_video brightness increments on FreeBSD

March 12, 2020

On FreeBSD systems using Intel integrated graphics, intel-backlight allows the brightness to be set in nice increments using the incr and decr arguments. Alternatively, the acpi_video kernel module can also control brightness, but changes it by one-percent increments for each press of the brightness up/down Fn keys. My goal was to configure acpi_video to follow the behaviour of intel-backlight.

On my ThinkPad T480 (FreeBSD 12.1-RELEASE), I had previously used acpi_ibm and devd to call intel-backlight when pressing the corresponding Fn keys, without loading acpi_video. Downsides of this approach were that brightness would go to 100% when plugging in the AC adapter, resuming from suspend, or waking the screen from dpms sleep in X11. Alternatively, simply loading the acpi_video module would fix these issues, but brightness control was very slow because of the small adjustment increments.

The source code for intel-backlight shows the increments used by the tool. I created a simple shell script to set the display brightness according to these levels. If called with "1" as the argument, brightness will be increased; if called with "0" as the argument, it will be decreased:

#!/bin/sh
# /usr/local/bin/acpi_brightness_control.sh
CURRENT_LEVEL=$(/sbin/sysctl -n hw.acpi.video.lcd0.brightness)
UP="$1"

if [ "$UP" == 1 ]; then
 for i in 1 2 4 6 9 12 16 20 25 30 36 43 51 60 70 80 90 100; do
  if [ "$CURRENT_LEVEL" -lt "$i" ]; then
   /sbin/sysctl "hw.acpi.video.lcd0.brightness=$i"
   exit
  fi
 done
fi

if [ "$UP" == 0 ]; then
 for i in 100 90 80 70 60 51 43 36 30 25 20 16 12 9 6 4 2 1; do
  if [ "$CURRENT_LEVEL" -gt "$i" ]; then
   /sbin/sysctl "hw.acpi.video.lcd0.brightness=$i"
   exit
  fi
 done
fi

I load acpi_ibm and acpi_video in /boot/loader.conf. On my machine, the brightness Fn keys give event codes 0x10 and 0x11 (can be seen using sudo cat /var/run/devd.pipe). To handle these keys with devd, I set dev.acpi_ibm.0.handlerevents=0x10\ 0x11 in /etc/sysctl.conf.

To handle the brightness keys, I create /etc/devd/acpi_brightness.conf:

# /etc/devd/acpi_brightness.conf
notify 20 {
 match "system" "ACPI";
 match "subsystem" "IBM";
 match "notify" "0x10";
 action "/usr/local/bin/acpi_brightness_control.sh 1";
};
notify 20 {
 match "system" "ACPI";
 match "subsystem" "IBM";
 match "notify" "0x11";
 action "/usr/local/bin/acpi_brightness_control.sh 0";
}

Again, the specific match criteria necessary for the keys on a different machine can be observed by pressing the keys while watching the output of sudo cat /var/run/devd.pipe.

Finally, restart devd (sudo service devd restart) to apply the new rule.

Note also that the default brightness on battery or line power can be set using the hw.acpi.video.lcd0.economy and hw.acpi.video.lcd0.fullpower sysctl variables.

This approach provides all the advantages of intel-backlight using only built-in kernel modules.