I wrote a quick fix patch to handle display brightness issues with AMD Ryzen for my laptop
Background
I recently purchased an ASUS TUF FX505DT "gaming" laptop and installed Manjaro Linux as dual-boot to pre-installed Windows 10. My laptop comes with an AMD Ryzen 3550H with Vega 8 Graphics which is "bleeding-edge" hardware for Linux and bugs were to be expected.
One of such bugs that annoyed me was that my display's brightness settings were being reset to maximum on every reboot. This means, at each startup, I will have to manually dial back the brightness to my comfortable value which would reset again on the next shutdown/reboot. This HAD to be fixed.
Systemd 101:
In modern Linux distributions, we have an init manager called systemd
that takes care of initializing system and user processes so users can get on with watching cat videos on Internet.
According to Wikipedia:
systemd is a software suite that provides an array of system components for Linux operating systems.
And
an init system used to bootstrap user space and manage user processes. It also provides replacements for various daemons and utilities, including device management, login management, network connection management, and event logging.
In simpler terms, it is an "init system" that loads system processes. In Windows land, think of systemd as "a software for loading system stuff like user login screen, Windows desktop that you see after logging in, checking network connectivity, various tray icons and backend daemons, etc. as well as launching all user software in Startup section like CCleaner or Java updater tray icon or Realtek."
Problem:
The problem arises with a recent patch to Linux kernel by AMD. The patch aims to provide precise brightness information to userspace applications (like systemd for instance) but had introduced a bug where it reports current brightness value of display as a 16-bit integer instead of an 8-bit integer.
In Linux, your display brightness is determined by 3 values stored as 8-bit integers - min_brightness
, brightness
(i.e. current brightness) and max_brightness
. According to the spec, brightness
value should always be higher or equal to min_brightness
but lower than max_brightness
.
The recent patch I mentioned earlier introduced a bug where brightness
started being reported as a 16-bit integer without updating min_brightness
and max_brightness
cousins.
For example, if min_brightness
= 0 and max_brightness
= 255, then brightness
value after the said patch started being reported as 10280
which is 16-bit for 40
.
systemd-backlight
has been written to set brightness
to max_brightness
when invalid brightness
value is provided. Do you understand why backlight was reset to maximim now?
You can find more information about my fix for this in my patch.
Theory:
I need to Math.floor
but in C the value of brightness
by checking if its exceeding max_brightness
and dial it back such that min_brightness >= brightness < max_brightness
when necessary.
Code:
I cloned the latest release of systemd
which was v246, as of writing, here and opened the directory in VS Code.
Then, I navigated to src/backlight/backlight.c
, learned they were using pointers to handle code, got nervous, took a deep breath and kept on pushing myself to try and understand the code.
Once that hurdle was crossed, I found clamp_brightness
function which ensures brightness
value is in range of min_brightness >= brightness < max_brightness
. Here, I added the required code to check if brightness
was exceeding max_brightness
(due to it being mistaken for 8-bit integer)
I also found run
function here to handle restoring brightness
value if necessary.
Usage Issues:
The one last thing that gave me trouble was the fact that systemd
codebase was written to be compiled with -shared
such that compiled executable for my patched systemd-backlight
needed .so
files which are DLLs for Linux to be placed in same directory.
My workaround for this was to symlink my patched binary located in my $HOME dir to /usr/lib/systemd/system-backlight` and reboot for changes to take effect. IT WORKED ๐
Conclusion:
I learned so much about systemd and the way it handles system components. I also had to learn C especially performing data type conversions when pointers are involved.
Bonus: Did you know systemd-backlight
was also used to save/restore your keyboard's backlight settings as well?