Analyzing the DSDT DSL
By looking at the DSL file, we find the registers we are interested in:
OperationRegion (ERAM, EmbeddedControl, Zero, 0xFF) Field (ERAM, ByteAcc, Lock, Preserve) { [...] Offset (0xB2), RPM1, 8, RPM2, 8, [...] Offset (0xF4), SFAN, 8, [...] }
Calculating Register Addresses
We calculate the register addresses as follows:
- RPM1 = Offset(0xB2) = 0xB2 = 178
- RPM2 = Offset(0xB2) + (8 / 8) = 0xB3 = 179
- SFAN = Offset(0xF4) = 0xF4 = 244
Finding the WriteRegister
We use the probing tool to find out which register controls the fan:
sudo ec_probe write 244 1
sudo ec_probe write 244 20
sudo ec_probe write 244 50
sudo ec_probe write 244 100
sudo ec_probe write 244 255
sudo ec_probe write 244 0
We see that:
- 1 stops the fan
- 50 starts spinning the fan at minimum speed
- 100 sets the fan to maximum speed
- 0 resets the fan to auto mode
Result:
- SFAN (244) is the WriteRegister
- The value 0 is used as FanSpeedResetValue
- The value 50 is used as MinSpeedValue
- The value 100 is used as MaxSpeedValue
- The value 1, which stops the fan, will be used in FanSpeedPercentageOverrides
Finding the ReadRegister
We found RPM1 and RPM2. One of them might hold the fan speed.
However, probing the registers with
sudo ec_probe read 178
sudo ec_probe read 179
while spinning the fan up and down does not yield values that are continuous or meaningful.
We search for RPM1 and RPM2 in the dsdt.dsl and find this:
Method (FRSP, 0, NotSerialized) { Local2 = Zero If ((\_SB.PCI0.LPCB.EC0.ECOK == One)) { Local0 = \_SB.PCI0.LPCB.EC0.RPM1 Local1 = \_SB.PCI0.LPCB.EC0.RPM2 Local1 <<= 0x08 Local0 |= Local1 If ((Local0 != Zero)) { Divide (0x00075300, Local0, Local0, Local2) } } Return (Local2) }
We see that FRSP is the method that combines the two registers into one, applies a division and returns the value.
Result: \_TZ.TZ01.FRSP is the ReadAcpiMethod.
Finding the Read values
We call the ReadAcpiMethod for each fan state (off, minimum speed, maximum speed):
sudo ec_probe write 244 1
sudo ec_probe acpi_call '\_TZ.TZ01.FRSP'
sudo ec_probe write 244 50
sudo ec_probe acpi_call '\_TZ.TZ01.FRSP'
sudo ec_probe write 244 100
sudo ec_probe acpi_call '\_TZ.TZ01.FRSP'
The output of the ReadAcpiMethod (in decimal) is: 0, ~300, ~1380.
Result:
- 300 is the MinSpeedValueRead
- 1380 is the MaxSpeedValueRead
- 0 is a special value for fan speed 0 and will be used in FanSpeedPercentageOverrides
Writing the Configuration File
For writing the fan speed we have:
- 244 (SFAN) is the WriteRegister
- 50 is the MinSpeedValue
- 100 is the MaxSpeedValue
- 0 is the FanSpeedResetValue
- 1 is a special case. This will be handled by FanSpeedPercentageOverrides
For reading the fan speed we have:
- \_TZ.TZ01.FRSP is the ReadAcpiMethod
- 300 is the MinSpeedValueRead
- 1380 is the MaxSpeedValueRead
- 0 is a special case. This will be handled by FanSpeedPercentageOverrides
Also:
- IndependentReadMinMaxValues is true, since MinSpeedValue/MaxSpeedValue and MinSpeedValueRead/MaxSpeedValueRead are different
See the configuration file on GitHub