DSDT editing: Put an end to your ACPI woes

Background:

Ever since I installed Openbox, one of the major frustrations was the fact that it started up with display brightness set at 100%. It wasn’t an issue in either KDE or Windows whose respective power management profiles did the job for me. Since I don’t use any sort of power management program in Openbox, manually setting the brightness to a saner level using brightness keys each time was a pain. For a while, I resorted to an ugly “hack” of sorts : a script that wrote brightness value directly to relevant file in /sys (in my case it is /sys/class/backlight/acpi_video0/brightness). Here is the script:

#! /bin/bash
# The value 15 is obtained from
#`cat /sys/class/backlight/acpi_video0/max_brightness`
function usage()
{
  echo -e "Usage : $0 <value>\n"
  echo -e "<value> is an integer between 1 and 15\n"
}
case $1 in
[1-9]|1[0-5])
  echo $1 > /sys/class/backight/acpi_video0/brightness;
*)
  usage;
esac

I call it an ugly hack because

  1. It requires root access to change brightness
  2. It needs to be set up to execute on start of each DE/WM separately.

I needed a more “universal” and elegant solution than having supuser access just to change brightness.

The dmesg output on my machine contained an error that caught my attention:

[Firmware Bug]: ACPI: No _BQC method, cannot determine initial brightness

Poring through the ACPI Specs (which contains a wealth of information for those willing to sift through all the 700+ pages), I found out that my salvation lay in DSDT editing.

For the unitiated:

ACPI is to laptop users what oxygen is to mankind. BIOS, by itself, provides very basic support for all the hardware typically found inside a laptop. It cannot, for example, handle what happens on opening/closing the laptop lid, plugging in/out the the AC adapter, pressing the brightness keys etc. Sleep and hibernate are two essential features for any laptop user which are too complex for BIOS to handle. All these laptop-specific tasks are instead handled by ACPI. The biggest advantage of ACPI is that it is OS-agnostic. So, ACPI features that work flawlessly on Windows can be almost always expected to work on Linux (the almost part will be explained in a moment).

DSDT is a table that describes the ACPI properties and functions of all your hardware. If certain ACPI feature is missing or functioning improperly on your laptop, you can safely put the blame on a badly coded DSDT. DSDT is written in a language known as ASL (ACPI Source Language) that looks at lot like C. Just like C, it needs to compiled before it can be used by the system. This is where the problem creeps in. ASL compilers are provided by Microsoft and Intel. Like all things Microsoft, their compiler is far too lenient when it comes to ASL syntax compared to Intel’s. Hence, DSDTs compiled using MS compiler are generally buggier and more problematic than Intel-compiled ones. Windows includes all sorts of hacks to mask the ineffectiveness of the MS compiler while Linux typically suffers in some way or the other (laptop not sleeping/hibernating, fan spinning constantly, brightness keys not working etc.).

Lament not, you can extract the DSDT of your system, edit it to fix the errors, and replace the original DSDT with the fixed one to resolve most issues.

Working with the DSDT:

Grab the latest copy of the Intel ASL Compiler from your distro repositories or the source code from here.

Extract the DSDT of your system:

$ sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.aml

Decompile the extracted DSDT:

$ iasl -d dsdt.aml

This will generate a dsdt.dsl file that you can open in any text editor and start editing. But it’s a better idea to recompile the file to see if it produces any errors

iasl -tc dsdt.dsl

On my laptop, it produces following output:

$ iasl -tc dsdt.dsl

Intel ACPI Component ArchitectureASL Optimizing Compiler version 20110112-64 [Jan 20 2011]Copyright (c) 2000 - 2011 Intel Corporationdsdt.dsl 4119: 0x00000000, // LengthError 4122 - ^ Invalid combination of Length and Min/Max fixed flags

dsdt.dsl 4133: 0x00000000, // Length

Error 4122 - ^ Invalid combination of Length and Min/Max fixed flags

dsdt.dsl 8951: Name (_T_1, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_1)

dsdt.dsl 8952: Name (_T_0, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_0)

dsdt.dsl 9009: Name (_T_1, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_1)

dsdt.dsl 9010: Name (_T_0, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_0)

dsdt.dsl 9091: Name (_PLD, Buffer (0x10)

Error 4080 - Invalid object type for reserved name ^ (found BUFFER, requires Package)

dsdt.dsl 9153: Name (_T_1, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_1)

dsdt.dsl 9154: Name (_T_0, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_0)

dsdt.dsl 9211: Name (_T_1, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_1)

dsdt.dsl 9212: Name (_T_0, Zero)

Remark 5111 - Use of compiler reserved name ^ (_T_0)

dsdt.dsl 9288: Name (_PLD, Buffer (0x10)

Error 4080 - Invalid object type for reserved name ^ (found BUFFER, requires Package)

dsdt.dsl 9305: Name (_PLD, Buffer (0x10)

Error 4080 - Invalid object type for reserved name ^ (found BUFFER, requires Package)

dsdt.dsl 10489: Name (_T_2, Zero)

Remark 5111 - ^ Use of compiler reserved name (_T_2)

dsdt.dsl 10490: Name (_T_1, Zero)

Remark 5111 - ^ Use of compiler reserved name (_T_1)

dsdt.dsl 10491: Name (_T_0, Zero)

Remark 5111 - ^ Use of compiler reserved name (_T_0)

ASL Input: dsdt.dsl - 12135 lines, 370000 bytes, 4042 keywords

Compilation complete. 5 Errors, 0 Warnings, 11 Remarks, 10 Optimizations

5 errors and 11 remarks. How you go about resolving these errors if a matter of personal preference. You can search the internet for the error number, which helps most of the time. Or you can actually try learning ASL from the ACPI specs and then get down to the debugging business, like real men do.

Here’s how I fixed my DSDT:

Error 4122: http://www.insanelymac.com/forum/lofiversion/index.php/t189272-100.html

Remark 5111: Replace all instances of _T_# within scope (i.e. within a pair of curly braces) by T_#

Error 4080: Unsolved, but not critical.Apparently, the kernel takes the remedial measure when it encounters this error http://lists.acpica.org/pipermail/devel/2010-July/000164.html

Once the DSDT was clean, it was time to get back to the original problem. As the dmesg output clearly stated, the method _BQC had not been defined in my DSDT at all. Fortunately, it was a simplistic method that merely returned one of the values specified by the _BCL method. I defined it in the Device (LCD) section after the _BCL method:

Method (_BQC, 0, NotSerialized)
{
    Return (0x1E)
}

This corresponded to the brightness level 5 of the “ugly hack” described above. Once finished, it was time to make my laptop use the fixed DSDT instead of the old one. The general steps to do so are explained here. Arch Linux users can follow the ABSmethod to recompile the kernel instead. Note that recompiling the kernel is the only way to do it in Arch, and it can take a good 30-45 mins of fast-scrolling gibberish on the terminal on a decent-spec PC.

Once the “fixed” kernel was compiled and bootable, I had the simplistic pleasure of staring into the LCD screen that didn’t blind me each time it turned on,  and geek’s satisfaction of running a clean DSDT … atleast till the next kernel update!

Advertisements