In some cases the ACPI BIOS provides the interfaces required to control the backlight through the generic ACPI interface, but the actual methods are not implemented. So the ACPI driver registers with the hardware and prevents any laptop specific drivers from doing so. In those cases it is possible to prevent the ACPI backlight driver from starting by adding the following line to the kernel boot parameters:
acpi_backlight=vendor
Unfortunately the thinkpad-acpi driver behaves differently, as it does not act on the ACPI driver being active or not, but on the ACPI methods being defined. Thus forcing the vendor specific driver to activate requires an additional:
thinkpad-acpi.brightness_enable=1
You can check to see if your system uses the thinkpad-acpi driver by using the following command:
lsmod | grep thinkpad_acpi
If ACPI can control the brightness but the control is somehow incorrect, you can disable ACPI brightness changes with boot parameteracpi.brightness_switch_enabled=0 (also accessible in /sys/module/video/parameters/brightness_switch_enabled). Note that this does not releaseACPI control as acpi_backlight=vendor does (sometimes acpi=off is suggested but this completely turns off the ACPI subsystem). Changing this attribute merely suppresses events from the video device to be forwarded and therefore to be ignored. Writing values into the kernel interfaces should still work.
To decide whether the missing brightness control is a hotkey, a X driver or a kernel issue, testing the kernel interfaces will give additional information.
This actually is deprecated and would also only be working if the ACPI backlight driver is active. It will be described only for completeness. The ACPI backlight driver also exposes itself through the new sysfs interface.
/proc/acpi/video/ | +-| | | +- | | | | | +- EDID | | +- brightness | | +- state | | +- info | +- ... +- ...
Each discovered graphics card will have one entry and within that each defined output device will have its set of values. The brightness variable contains either "
#> grep -r . /proc/acpi/video/GFX0/DD04/ proc/acpi/video/GFX0/DD04/EDID:/proc/acpi/video/GFX0/DD04/brightness:levels: 20 28 36 44 52 60 68 76 84 92 100 /proc/acpi/video/GFX0/DD04/brightness:current: 100 /proc/acpi/video/GFX0/DD04/state:state: 0x1d /proc/acpi/video/GFX0/DD04/state:query: 0x00 /proc/acpi/video/GFX0/DD04/info:device_id: 0x0410 /proc/acpi/video/GFX0/DD04/info:type: LCD /proc/acpi/video/GFX0/DD04/info:known by bios: yes
So in this case there are 11 possible percentage values which, when written into the brightness file, would change the brightness of the display. Currently it is set to full brightness.
Note that only those discrete percentage values are defined. Writing other values results in an error.
Also note that the effect may not be immediate. When testing this, the laptop I used would take a bit and then gradually fade to the destination brightness.
Contrary to the ACPI interface in /proc, the sysfs interface has only entries when there is an output device that supports backlight control.
/sys/class/backlight/ | +-
The file actual_brightness contains the currently set brightness level. Reading brightness results in the same number. In max_brightness is the maximum number allowed to be written into brightness. While the ACPI /proc interface uses percentage levels, the sysfs interface uses index numbers between 0 and the maximum brightness.
See the kernel documentation of sysfs class backlight interface for the definitive description of the attributes.
#> grep . /sys/class/backlight/acpi_video0/* /sys/class/backlight/acpi_video0/actual_brightness:10 /sys/class/backlight/acpi_video0/bl_power:0 /sys/class/backlight/acpi_video0/brightness:10 /sys/class/backlight/acpi_video0/max_brightness:10
Whenever the kernel interface does not work or is not present at all, it is time to put on the mining helmet and try to make sense of the information stored in the ACPI BIOS which can be obtained following this description. The next challenges will be to find the right section for the graphics device and the display devices defined there.
The ACPI BIOS often contains not only the information for the graphics card used in the one laptop we are looking at, but has entries for every possible variation the vendor had in mind. So before further inspection, we need to find out which definition we have to look at.
If the video device is handled by the ACPI video driver and just the backlight interface is not working, the name of the used graphics device can be obtained by looking at the output of dmesg.
#> dmesg|grep 'ACPI: Video' [ 2.941100] ACPI: Video Device [GFX0] (multi-head: yes rom: no post: no)
So we know we need to look for GFX0 in the DSDT. But if the definition is bad enough to be not detected by the ACPI driver? In that case we might be successful through the backdoor. In other words from the info we got of the PCI bus.
#> lspci |grep VGA 00:02.0 VGA compatible controller: Intel Corporation Mobile 945GME Express Integrated Graphics Controller (rev 03)
So the graphics device is attached as PCI device 2 functional endpoint 0. Let's search for "_ADR.*00020000" in the disassembled DSDT:
Device (GFX0) { Name (_ADR, 0x00020000) ...
So this nicely matches the name we are expecting. If we don't know the name and maybe there are other devices (on another bus) with the same ID. Well there are a few methods that are required for a device to be considered as a video device. The ACPI spec (Appendix B.) requires two methods to be defined at the graphics device level. Actually only one, but there is (as so often room for interpretation). Linux used to require both but this was changed to be ok with one of them.
Essentially one of these two methods must be defined for the graphics device. Otherwise the ACPI driver will not detect it as a valid video device. In which case only the BIOS/laptop vendor can resolve this.
Every output device has to define methods which allow interaction (defined in Appendix B.6 of the ACPI spec). The following methods are related to the brightness control:
Method (_BCL, 0) { // List of supported brightness levels Return (Package(7){ 80, // level when machine has full power 50, // level when machine is on batteries // other supported levels 20, 40, 60, 80, 100 } }
Reading the method definitions requires some knowledge about the ACPI AML language and some persistence on hunting down more or less complex implementations. Some are more obvious than others. There have been cases where percentage values got converted into index values and then (incorrectly) back on query.
Also often the values get stored into a register of the embedded controller which does not necessarily need to have any result on the brightness.