Example: Packard Bell EasyNote TK85

Analyzing the DSDT DSL

By looking at the DSL file, we find the methods we are interested in:

        Mutex (FAMX, 0x00)
        Method (FANG, 1, NotSerialized)
        {
            Acquire (FAMX, 0xFFFF)
            ERIB = Arg0
            Local0 = ERBD /* \_SB_.PCI0.LPCB.EC0_.ERBD */
            Release (FAMX)
            Return (Local0)
        }

        Method (FANW, 2, NotSerialized)
        {
            Acquire (FAMX, 0xFFFF)
            ERIB = Arg0
            ERBD = Arg1
            Release (FAMX)
            Return (Arg1)
        }

Finding the Arguments for the Read/Write Method

We have the methods FANG and FANW. The first method takes one argument, while the second takes two. We need to figure out which value we have to pass for reading or writing the fan speed.

We make sure that the fan is stopped or at least at minimum speed.

We make a dump of all possible arguments to the FANG method:

for i in $(seq 0 65535); do
  printf "$i: "
  sudo ec_probe acpi_call '\_SB.PCI0.LPCB.EC0.FANG' $i
done > dump_lowfan

We make sure that the fan is at the highest speed by using stress

stress -c 8

Wait until the fan spins up ...

We make a dump again:

for i in $(seq 0 65535); do
  printf "$i: "
  sudo ec_probe acpi_call '\_SB.PCI0.LPCB.EC0.FANG' $i
done > dump_highfan

Both files should look like this:

0: 0xf0
1: 0xf0
2: 0xf0
3: 0xf0
4: 0xf0
5: 0xf0
6: 0xf0
7: 0xf0
8: 0xf0
[...]

We extract a list of arguments that changed in the two dumps:

diff dump_lowfan dump_highfan | grep -Eo '[0-9]+:' | tr -d ':' | sort -un > dump_diff

We call the FANW method for each value in the diff:

for i in $(cat dump_diff); do
  echo "Value $i (press enter)"
  read
  sudo ec_probe acpi_call '\_SB.PCI0.LPCB.EC0.FANW' $i 0xFF
done > dump_highfan

We observe that the value 33026 changes the fan speed.

Result:

Writing the Configuration File

Because the ACPI firmware overrides the fan speed, we set EcPollInterval to 500 milliseconds to maintain control.

See the configuration file on GitHub