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:
- \_SB.PCI0.LPCB.EC0.FANG 33026 is the ReadAcpiMethod
- \_SB.PCI0.LPCB.EC0.FANW 33026 $ is the WriteAcpiMethod
Writing the Configuration File
- \_SB.PCI0.LPCB.EC0.FANG 33026 is the ReadAcpiMethod
- \_SB.PCI0.LPCB.EC0.FANW 33026 $ is the WriteAcpiMethod
- \_SB.PCI0.LPCB.EC0.FANW 33026 0xFF is the ResetAcpiMethod
- 0 is the MinSpeedValue
- 255 is the MaxSpeedValue
Because the ACPI firmware overrides the fan speed, we set EcPollInterval to 500 milliseconds to maintain control.
See the configuration file on GitHub