Thursday, June 20, 2013

ACPI Brightness Control (3) - Hotkeys in Ubuntu Linux

In ACPI Brightness Control (1) - Control Methods and ACPI Brightness Control (2) - Hotkeys, we understand how ACPI designs brightness from BIOS's perspectives. In this blog, we will see them in action using Ubuntu as an example.

Brightness Sysfs Nodes in Linux Kernel

When booting up, Linux's ACPI VGA driver (drivers/acpi/video.c) enumerates ACPI AML (DSDT and SSDT) to look for output devices that support brightness control. Once identified, it creates sysfs nodes in /sys/class/backlight/acpi_video0. If more than one output device is found, it creates acpi_video1 and so on.

FIgure 1 - Sysfs Nodes for Brightness
Figure 1 shows files in acpi_video0 directory. Three files are particularly important:

  • actual_brightness - implements _BQC
  • brightness - implements _BCM, and also record current brightness level
  • max_brightness - implements _BCL and converts it to number of levels
For example, the _BCL in this Thinkpad reports 16 brightness levels with Ubuntu 12.04, and therefore "cat max_brightness" returns 15. Current brightness can be read by executing "cat actual_brightness" or "cat brightness". In most cases, both max_brightness and brightness return the same value (this should not be surprising) - they are only different if something breaks in kernel or BIOS - such as _BQC does not change with _BCM.

To change brightness level, one writes a value to brightness, ranged from 0 to max_brightness. In this system, it is from 0 to 15. ACPI VGA driver will convert it to the actual value in _BCL and write to _BCM. 

Hotkey Implementation in Ubuntu Linux

Figure 2 - Overall Process for Brightness Hotkeys
Figure 2 is an expansion of ACPI Brightness Control (2) - Hotkeys. It shows that many tasks are done even with a single hotkey press, and it also shows separation between OS and BIOS is clear - the clean interface makes hotkey development easy and that's exactly what ACPI is for. Let's add more details to OS level as it is in Figure 3.

Figure 3 - Brightness and Desktop Daemon
Ubuntu ships with gnome-setting-daemon (GSD) that listens to keycode events. ACPI VGA driver converts ACPI notification events to keycodes, and GSD changes brightness via sysfs nodes according. GSD is also responsible for reading brightness levels from sysfs nodes to show OSD for users and to create slider for changing brightness. It is also worthy noting that ACPI VGA driver can also calls _BCM to change brightness without interacting with GSD, but no OSD may be shown.

As GSD is designed to listen to keycode, System vendor may design BIOS to generate other none-standard ACPI events, such as WMI events, as long as there is a kernel driver to do the conversion; however, this is not a suggested.

PS. Please note keycodes are not the same as KBC's scancode.

Debugging Brightness (Hotkey) Failures

From Figure 3, it becomes obvious brightness hotkeys can fail for two primary reasons:
  1. BIOS does not generate events
  2. _BCM fails to change brightness
In Linux, it is easy to verify whether ACPI VGA events and keycodes are generated:
  • Run "acpi_listen" to show ACPI standard events
  • Run "sudo showkey" to show keycodes
One can trigger writes to _BCM as in "Brightness Sysfs Nodes in Linux Kernel", if brightness is changed but LCD panel is not, BIOS did not implement _BCM correctly (or graphics drivers do not respond requests from BIOS in some cases).

No comments:

Post a Comment