Asus F3Jp fan control on Linux

Alexander Breckel, last update on 2008/09/08

I'm a more or less proud owner of an Asus F3Jp notebook, running a dualboot setup with Archlinux and Windows XP. Unfortunately on Linux the CPU fan is constantly running and over time the fan noise became so annoying that I tried to fix the problem. Here's a summary of what I did.

Caution: PLEASE do not try any of this at home without being FULLY aware of the consequences. I'm writing this solely for your information and I cannot be held responsible for ANY damage this probably will do to your notebook, your family or your country.

My setup consists of an Asus F3Jp running an up-to-date Archlinux 2008.06 with the version 2.6.26 of the Linux kernel. The CPU fan is constantly running; not on full speed, but still pretty loud. I tried to run lm_sensors using this manual, but `sensors` only reported the following:

~$ sensors
acpitz-virtual-0
Adapter: Virtual device
temp1:       +54.0°C  (crit = +105.0°C)

coretemp-isa-0000
Adapter: ISA adapter
Core 0:      +59.0°C  (high = +100.0°C, crit = +100.0°C)

coretemp-isa-0001
Adapter: ISA adapter
Core 1:      +59.0°C  (high = +100.0°C, crit = +100.0°C)

No fans are detected, because /proc/acpi/fan/ is empty. Normally there should be a subdirectory for each fan containing state information like RPM. This list indicates, that an "ACPI fan" should report the PnP Device ID PNP0C0B, but /sys/bus/acpi/devices/PNP0C0B:0x does not exist. So the problem is, that the CPU fan is either not ACPI compliant at all or just badly configured. I updated the BIOS to the current version 209 without noticing any changes. Interestingly on Windows XP SP2 the fan can be throttled with the Software Notebook Hardware Control (NHC) using its ACPI Control System. So it is possible to control the fan via ACPI, but somehow something on Linux prevents this from happening.

So lets take a look at how NHC manages to control the fan. Fortunately the relevant source code is available if you download and install the software. If you open up %INSTALLDIR%\acpi\ASUSTeK.cs, there is a beautiful piece of information I'll copy in here. Please contact me if you want this removed from here.

8333  // Fan control for Asus F3JP
8334  // User class by Martin Nössing
8335  //
8336  // The Fan speed will be controlled by the _SB.PCI0.SBRG.EC0.WMFN register in the Embedded Controller.
8337  // WMFN is a 8 bit register. The MSB (Bit 7) control the method of fan control:
8338  //  manual = 0, automatic (default)= 1
8339  // The next 4 Bit (Bit 6 - 2) sets the fan speed (only when Bit 7 is 0):
8340  //  value 0x0 to 0x5: fan is off
8341  //  from value 0x5 to 0xF: fan speeds in ascending order
8342  //  The only problem is that a maximum fan speed set in WMFN(0xF) is not the realy maximum speed of the fan. In automatic mode,
8343  //  the fan can drive the motor more faster on higher tempertures!
[...]
8353  //****NOTE!!:IF YOU TURN YOUR FAN OFF MANUALLY, OVERHEATING MAY OCCUR.!!****

In 2004 Alex Williamson wrote a Linux kernel patch that made ACPI objects and methods accessible in /sys/firmware/acpi/namespace/ACPI, but with Linux 2.6.21 the ACPI namespace was removed. If your kernel version is lower than that, you could try the approach described in here in some weird language. I found no way to get raw access to ACPI without modifying the kernel, which I really want to avoid. But if we cannot work with ACPI, maybe we could work like ACPI and emulate what it would have done if we had somehow modified _SB.PCI0.SBRG.EC0.WMFN.

So lets take a short look at what ACPI is and does. For deeper knowledge consider reading Wikipedia and some parts of the ACPI Specification, especially chapter 17 on ASL. The Advanced Configuration and Power Interface provides important information about your hardware and callable methods to control it. Altough it is technically capable of saving the human race, it is widely used to toggle suspend and monitor your battery status. The most interesting part for now is the Differentiated System Description Table (DSDT). Among other things it contains the definition of _SB.PCI0.SBRG.EC0.WMFN. The DSDT can be accessed at /proc/acpi/dsdt, but unfortunately it has to be disassembled first to be human readable. You probably need to install the Intel ACPI Source Language Compiler, which is part of the ACPICA release. On Archlinux the package community/iasl provides everything you need.

~$ sudo cp /proc/acpi/dsdt dsdt
~$ iasl -d dsdt

Intel ACPI Component Architecture
AML Disassembler version 20080729 [Aug 21 2008]
Copyright (C) 2000 - 2008 Intel Corporation
Supports ACPI Specification Revision 3.0a

Loading Acpi table from file dsdt
Acpi table [DSDT] successfully installed and loaded
Pass 1 parse of [DSDT]
Pass 2 parse of [DSDT]
Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)
............................................................
Parsing completed
Disassembly completed, written to "dsdt.dsl"

Now the file dsdt.dsl contains some code in ASL. I'll copy the relevant parts of my DSDT, but please keep in mind this is highly hardware- and BIOS-specific, so your version may very well differ from mine:

4521  Mutex (ASIO, 0x00)
[...]
5884  OperationRegion (KAID, SystemIO, 0x025C, 0x01)
5885  Field (KAID, ByteAcc, NoLock, Preserve)
5886  {
5887      AEID,   8
5888  }
5889
5890  OperationRegion (KAIC, SystemIO, 0x025D, 0x01)
5891  Field (KAIC, ByteAcc, NoLock, Preserve)
5892  {
5893      AEIC,   8
5894  }
5895
5896  Method (WEIE, 0, Serialized)
5897  {
5898      Store (0x4000, Local0)
5899      And (AEIC, 0x02, Local1)
5900      While (LAnd (LNotEqual (Local0, Zero), LEqual (Local1, 0x02)))
5901      {
5902          And (AEIC, 0x02, Local1)
5903          Decrement (Local0)
5904      }
5905  }
[...]
5982  Method (WMFN, 1, Serialized)
5983  {
5984      If (LEqual (Acquire (ASIO, 0xFFFF), 0x00))
5985      {
5986          WEIE ()
5987          Store (0x98, AEIC)
5988          WEIE ()
5989          Store (Arg0, AEID)
5990          WEIE ()
5991          Release (ASIO)
5992      }
5993  }

AEID and AEIC are the IO ports 0x025C and 0x025D. 'D' and 'C' sound much like Data and Control registers. WEIE is a method that waits for the seconds bit of AEIC to clear, probably some 'ready' status indicator. And WMFN is a method with one argument, that at first writes the byte 0x98 to the IO port AEIC (maybe a 'set fan speed' command) and then the argument to AEID. If you are looking for some mysterious ACPI magic ... there is none. All this code does can easily be achieved with a userspace C program like this:

Caution: Please do not execute this code, especially on anything else than an Asus F3Jp. It works for me, but probably won't work for you. It may even destroy your notebook as you can easily disable your CPU fan with this!

#include <stdio.h> // printf
#include <stdlib.h> // atoi
#include <stdint.h> // uint8_t, uint16_t
#include <string.h> // strcmp
#include <sys/io.h> // inb, outb

// IO ports
const uint16_t AEIC = 0x025D; // command register
const uint16_t AEID = 0x025C; // data register

// waits for the status bit to clear, max 0x4000 tries
void WEIE() {
	uint16_t Local0 = 0x4000;
	uint8_t Local1 = inb(AEIC) & 0x02;
	while(Local0 != 0 && Local1 == 0x02) {
		Local1 = inb(AEIC) & 0x02;
		Local0--;
	}
}

// sets the fan speed
void WMFN(uint8_t Arg0) {
	WEIE();
	outb(0x98, AEIC);
	WEIE();
	outb(Arg0, AEID);
	WEIE();
}

int main(int argc, char ** argv) {
	if(argc != 2) {
		printf("usage: %s speed\n", argv[0]);
		printf("speed: `auto' or a value between 1 and 15\n");
		printf("keep in mind that `auto' will be even faster than 15!\n");
		return 1;
	}

	uint8_t speed = 0xFF;
	if(strcmp(argv[1], "auto") == 0)
		printf("setting speed to 'auto'\n");
	else {
		int arg = atoi(argv[1]);
		if(arg < 1 || arg > 15) {
			printf("Error: the speed %d is not possible\n", arg);
			return 1;
		}
		printf("setting speed to %d\n", arg);
		speed = (arg << 3) | 0x07;
	}

	if(ioperm(AEID, 1, 1)) {
		printf("Error: could not gain access to IO port AEID (0x025C)\n");
		return 1;
	}

	if(ioperm(AEIC, 1, 1)) {
		printf("Error: could not gain access to IO port AEIC (0x025D)\n");
		return 1;
	}

	WMFN(speed);

	printf("done.\n");
	return 0;
}

The next step could be to write a script that polls the CPU temperature and sets the fan speed appropriatly. I still don't know how to read the fan RPM, so a customized DSDT to allow lm_sensors to manage the fan is still far away.

#!/bin/sh

OLD_SPEED="0"
OLD_TEMP="0"

setSpeed () {
	if [ "$1" != "$OLD_SPEED" ]; then
		echo "new speed   $1"
		OLD_SPEED="$1"
		./fan "$1" > /dev/null
	fi
}

while [ 1 ]; do
	TEMP=`cat /proc/acpi/thermal_zone/THRM/temperature | awk '{print $2}'`
	if [ "$TEMP" != "$OLD_TEMP" ]; then
		echo "temperature $TEMP C"
		OLD_TEMP="$TEMP"
	fi

	if [ $TEMP -gt 65 ]; then
		setSpeed auto
	elif [ $TEMP -gt 60 ]; then
		setSpeed 13
	elif [ $TEMP -gt 55 ]; then
		setSpeed 11
	elif [ $TEMP -gt 50 ]; then
		setSpeed 9
	else
		setSpeed 1
	fi

	sleep 2
done



Comments

2013/09/16 - 10:02
alex
Your trick works great!
But how can i go back to system speed control?
2013/05/19 - 08:34
Pierre
Allows a much more quiet F8Va ! Thanks ! :)

here is my script using "sensors" :


#/bin/sh
/etc/setspeed 15
while [ 1 ] ; do
TEMP=`sensors |grep temp1 | awk '{print $2}' |sed 's/....$//'`
if [ "$TEMP" -gt 78 ] ;
then
/etc/setspeed auto
fi
if [ "$TEMP" -lt 65 ] ;
then
/etc/setspeed 15
fi
sleep 4
done
2013/04/21 - 13:12
Anonymous
Ul30VT -> Working :D
2013/04/09 - 21:16
Anonymous
asus u35jc - working.
2013/02/25 - 23:01
Thomas Oster
Damn! It works also on my Asus Pro 50SR Notebook. Exactly the same registers etc. Please digg deeper into that and try to make it work with lm_sensors... so you can maybe get your name into the linux-sources.
2012/12/03 - 16:18
Tomaš
Hallo,
ich habe ein Asus A6 (z92t) Bei diesem habe ich das gleiche Problem. Kannst Du mir bitte irgendwie helfen? Die Lüftung macht mich wahnsinnig.
Wie kann ich mit Dir in Kontakt treten?

Besten Gruß
Tomaš
2012/10/05 - 13:59
pulse
thank you very much for this article. works great for asus f8sa :)
2012/05/30 - 19:57
GaRUi
Fix for reading TEMP. When the temperature is 100 it will say 10 and close the fan. Critical Problem !!!
in Ubuntu 12.04 LTS use,

TEMP=`cat /sys/devices/virtual/thermal/thermal_zone0/temp | awk '{print $1/1000}'`
instead of
TEMP=`cat /sys/devices/virtual/thermal/thermal_zone0/temp | awk '{printf("%.2s",$1)}'`

2012/05/21 - 18:36
GaRui
I have changed the script a bit. Because inside my laptop there is some dust and temperature is hight at moment. So I have maxed it to 15 which is the maximum possible value for manual mode WMFN(0xF)

while [ 1 ]; do
#TEMP=`cat /proc/acpi/thermal_zone/THRM/temperature | awk '{print $2}'`
TEMP=`cat /sys/devices/virtual/thermal/thermal_zone0/temp | awk '{printf("%.2s",$1)}'`
if [ "$TEMP" != "$OLD_TEMP" ]; then
echo "temperature $TEMP C"
OLD_TEMP="$TEMP"
fi

if [ $TEMP -gt 75 ]; then
setSpeed auto
elif [ $TEMP -gt 70 ]; then
setSpeed 15
elif [ $TEMP -gt 60 ]; then
setSpeed 13
elif [ $TEMP -gt 55 ]; then
setSpeed 11

It is still much silence than auto mode. And temperature is about 74 (step 15) instead of 69 (step auto).
But I need to say my CPU freq is 996MHz Instead of 1992Mhz. (I know I need to clean this fan quickly :) )
It will make my days better since I will open my laptop and clean inside.


Thanks again Alexander Breckel !!!
2012/05/21 - 17:49
GaRUi
Script show like this below but not functioning if you do not run it with root access.
(I have changed upper level to 70 for auto)
./f3jfan-controller
temperature 68 C
new speed 13
temperature 69 C
temperature 73 C
new speed auto
temperature 72 C
temperature 70 C
new speed 13
temperature 69 C
temperature 70 C

> ./f3jfan 9
setting speed to 9
Error: could not gain access to IO port AEID (0x025C)

> sudo ./f3jfan auto
setting speed to 'auto'
done.

(Silencee!)

Maybe you can set a secure bit to f3jp so everyone can run it.


Big Thanks to the Alexander Breckel and Martin Nössing !!!
2012/05/21 - 17:31
GaRui
It is important if someone like ME needs to do it with Ubuntu 12.04 LTS

* Try "/sys/firmware/acpi/tables/DSDT" instead of "/proc/acpi/DSDT" .
* TEMP=`cat /sys/devices/virtual/thermal/thermal_zone0/temp | awk '{printf("%.2s",$1)}'`
instead of TEMP=`cat /proc/acpi/thermal_zone/THRM/temperature | awk '{print $2}'`

2012/01/09 - 15:27
Eugen
Hello,

f3jfan is not working on my Asus F3jp and Ubuntu 11.10.

I got this messages:

During "make":

gcc -s -O2 -Wall -o f3jfan src/*.c
src/main.c: In function ‘main’:
src/main.c:215:8: warning: ignoring return value of ‘fread’, declared with attribute warn_unused_result [-Wunused-result]

And if try to start f3jfan:

X@Ente-Notebook ~/Downloads/f3jfan-0.1 $ sudo f3jfan &
[1] 2623
X@Ente-Notebook ~/Downloads/f3jfan-0.1 $ Error: could not open `/proc/acpi/thermal_zone/THRM/temperature' for read access

I couldn't solve the problem by myself.

Content of folder /proc/acpi:

dir ac_adapter
dir battery
dir button
file event
file wakeup

But I found some Files with "find /sys/ -name 'therm*'" in

/sys/devices/virtual/thermal/thermal_zone0

There is also a file "temp"

Any hint for solving this Prob?




2011/05/20 - 19:33
johannes
ok! got it! works beautifully on asus f3jc with ubuntu 10.10! thank you! finally, no more ms!
2011/04/24 - 11:34
johannes
sorry, i don't get what i need to do after running
~$ sudo cp /proc/acpi/dsdt dsdt
~$ iasl -d dsdt

what do i do with the file dsdt.dsl?
and what do i do with the code you provided?
could someone please explain step by step?

thank you!!!
2011/01/11 - 11:58
dennis
After installing this my WLAN stopped working. Using the script on Asus F3jp.
2010/09/12 - 14:43
sunab
Works perfectly on asus F3jm. Thanks.
2010/09/12 - 14:43
sunab
Works perfectly on asus F3jm. Thanks.
2010/07/13 - 19:40
dwa
Thanks a million! It works like a charm on a X56Va as well
2010/07/04 - 20:36
jcolt
And then there was... silence... :D

Works on F3JR.
2010/04/04 - 12:31
drejk
my mistake, it works for X59SL :-), but the DSDT disassembly doesn't contain anything similar. weird.
2010/04/04 - 12:28
Drejk
shaorang> how did you make it work with x59sl? Doesn't work for me...
2010/03/20 - 22:55
AdeBe
I can confirm that it works also on Asus F3F.

I was trying for some time to get the same results, the only thing that I had to know was name of apropiate DSDT method.
Now I'm happy :-)

Great work!
2010/03/20 - 22:22
AdeBe
I can confirm that it works also on Asus F3F.

I was trying for some time to get the same results, the only thing that I had to know was name of apropiate DSDT method.
Now I'm happy :-)

Great work!
2010/03/18 - 14:23
Paul85
Hi mates!
I have Asus k40 and a very similar problem, so planning to use this way to fix it. Have just 2 questions:

1) If someone tried it on K series?

2) How to apply this code in Linux, I should compile it then and....? (sorry for programming stupidity:))))

PS. Fedora 12

Thanks in advanced!!!
2010/02/28 - 09:52
shaorang
Hi! Working with a X59SL series!

Thanks a lot!!!
2009/11/07 - 15:04
Grapsus
Working great on ASUS F3T ! My computer was so noisy while running at 55°C. Thank you very much.
2009/11/07 - 04:18
André V.
Wow! I was just scared up with the silence when I executed that! I just thought for a (mili)second that the computer had shut down!
It's working perfectly in my F3Jc. Thanks!
2009/06/06 - 16:14
Alexander Breckel
@Vitaliy, Thanks :-)

@Berion, I have to admin that after getting it to work this way I was too lazy to look further. But if anyone else wants to give it a try, I will happily post / link to the results here. Maybe the lm-sensors guys?
2009/06/05 - 01:24
Berion
Hi, I just wanted to say that your program & script works just fine on my Asus B50A (tried after checking the DSDT of course, where the WMFN-section is the same). Finally I can get rid of that high-pitching noise (at least with low load)! Now if it would somehow be possible to control all this with lm-sensors it would be great, but I guess you haven't gotten any further on that note, right?
2009/06/03 - 08:40
Vitaliy
Alexander, I can confirm it works on Asus F3jC

You saved me :)

It works so nice now.
2009/05/26 - 10:57
Samed
Here's the turkish translation of article: http://eventualis.org/index.php/asus-f3j-serilerinde-fan-kontrolu/
2009/05/26 - 10:27
Alexander Breckel
@mebitek What happened when you compiled the C program and ran it as root? Any warnings at all?
2009/05/25 - 17:13
mebitek
Hi, I have asus F3JA model, and dsdt is the same as yours. but fan speed do not seem to be changed.
I'm available to discuss and help to solve this problem!

thx a lot for your work,
mebitek
2009/05/23 - 19:03
Turgut Kalfaoglu
This is wonderful - suddenly my M51VA is TOTALLY SILENT!!
Thank you!!!
-ttturgut
2009/05/21 - 18:58
Alexander Breckel
I've been getting some mails, so i setup a simple comment system for people to discuss this article.

People told me that these scripts and programs also work on ASUS F6A and Asus B50A, altough I cannot verify this. Asus, feel free to send me Notebooks ;-)


Write a comment