The Notebook Review forums were hosted by TechTarget, who shut down them down on January 31, 2022. This static read-only archive was pulled by NBR forum users between January 20 and January 31, 2022, in an effort to make sure that the valuable technical information that had been posted on the forums is preserved. For current discussions, many NBR forum users moved over to NotebookTalk.net after the shutdown.
Problems? See this thread at archive.org.

    Fan Control on Asus Prime UX31/UX31A/UX32A/UX32VD

    Discussion in 'Asus' started by prikolchik, Jan 24, 2013.

  1. prikolchik

    prikolchik Notebook Evangelist

    Reputations:
    259
    Messages:
    362
    Likes Received:
    3
    Trophy Points:
    30
    I have figured out how to control the fan speed on UX31 UX31A UX32A UX32VD and possibly many other ASUS laptops.

    I don't have a program that would control the fan speed, but hopefully one of you can develop one now that the fan control functions are known! It is fairly trivial to do on Linux, you can modify asus-laptop.c kernel module using something like that, but you would need to make adaptations for the newer kernels. On Windows, I wouldn't even know where to start, to be honest!

    The basic idea is to use ACPI call methods to set the fan speed. All the fan control methods can be fround in the DSDT table for these laptops (see DSDT for UX32VD)

    There are TWO fans that can be controlled.
    Fan1 - is CPU fan
    Fan2 - is GPU fan (exists on models with dedicated GPU)

    WARNING: Everything is not properly tested and you might end up completely turning off the fans! In the worst case, do a complete Shutdown of your computer to reset the fan values.

    Tools you need
    You will need work with ACPI (call methods, read variables) and tools to read/set values on the Embedded Controller.

    For ACPI, I am not sure what would work on Windows, but for Linux you can use acpi_call kernel module

    For reading/writing to the EmbeddedController you can use RWEverything on Windows and acer_ec.pl on Linux.

    FAN CONTROL
    The fan logic is not in the ACPI, but it is most likely in the Embedded Controller firmware (unconfirmed). Nevertheless, there exist functions in ACPI that let you control the speed of the fan(s) and read their speed as long as the fan(s) are in AUTOMATIC mode. If the fan is not in automatic mode, the speed reporting is NOT supported!

    Once again, you can only see the speed of the fan if it is in automatic fan speed mode (default). You cannot see speed of the fan in manual fan speed mode (user changed using SFNV).

    General: Differences in laptop models
    Some laptops have only one fan (ex. UX31) vs. others have two (ex. UX32VD). If your laptop has only one fan, then controlling the 2nd fan will have no effect.

    There are TWO fans that can be controlled.
    Fan1 - CPU fan
    Fan2 - GPU fan (exists on models with dedicated GPU, such as UX32VD)

    Fan speed
    Please note: speed will not be reported if the fan is in set to MANUAL speed mode using SFNV.

    Read fan speed in RPM.
    Arg0:
    0 - for Fan1
    1 - for Fan2
    Code:
    \_SB.PCI0.LPCB.EC0.TACH Arg0
    Code:
    Method (TACH, 1, Serialized)
    {
        Name (_T_0, Zero)
        If (ECAV ())
        {
            While (One)
            {
                Store (Arg0, _T_0)
                If (LEqual (_T_0, Zero))
                {
                    Store (TAH0, Local0)
                    Break
                }
                Else
                {
                    If (LEqual (_T_0, One))
                    {
                        Store (TAH1, Local0)
                        Break
                    }
                    Else
                    {
                        Return (Ones)
                    }
                }
    
                Break
            }
    
            Multiply (Local0, 0x02, Local0)
            If (LNotEqual (Local0, Zero))
            {
                Divide (0x0041CDB4, Local0, Local1, Local0)
                Return (Local0)
            }
            Else
            {
                Return (Ones)
            }
        }
        Else
        {
            Return (Ones)
        }
    }
    
    Read fan speed in 100s of RPM
    Arg0:
    0 - for Fan1
    1 - for Fan2
    This method is more generic and cleaner, but more "expensive" as it has to interact with SystemIO
    Code:
    \_TZ.RFAN
    Code:
    Method (RFAN, 1, NotSerialized)
    {
        If (\_SB.PCI0.LPCB.EC0.ECAV ())
        {
            Store (\_SB.PCI0.LPCB.EC0.ST83 (Arg0), Local0) // Gets the fan speed. 0x0 - OFF,  0x5a, 0x62, 0x79, 0xFF-reporting disabled?
            If (LEqual (Local0, 0xFF))
            {
                Return (Local0)
            }
    
            Store (\_SB.PCI0.LPCB.EC0.TACH (Arg0), Local0)
            Divide (Local0, 0x64, Local1, Local0)
            Add (Local0, One, Local0)
            If (LLessEqual (Local0, 0x3C))
            {
                Store (Local0, FANS)
            }
            Else
            {
                Store (FANS, Local0)
            }
        }
        Else
        {
            Store (Zero, Local0)
        }
    
        Return (Local0)
    }
    
    Read fan speed in some units (to convert to RPM see the TACH method above for the formula).
    Code:
    \_SB.PCI0.LPCB.EC0.TAH0  //for Fan1
    \_SB.PCI0.LPCB.EC0.TAH1  // for Fan2
    
    Can also be read directly from the Embedded Controller at 0x93 for Fan1 and 0x95 for Fan2
    NOTE: The fan speed is in 16-bit, not 8-bit so need to take into acount the next byte.
    Code:
        OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF)
        Field (ECOR, ByteAcc, Lock, Preserve)
        {
             .......
             Offset (0x93),
             TAH0,   16, // Fan0 Tachometer
             TAH1,   16, // Fan1 Tachometer
             TSTP,   8,  // some sort of Fan control. 0x1 if fan(s) on, 0x0 if fan(s) off, maybe other values...
             .......
        }
    

    Fan maximum speed
    The MAXIMUM_ALLOWED fan speed can be anywhere from 0x00 (0 in decimal) to 0xFF (255 in decimal). Which is from OFF to MAX_POSSIBLE.

    By default, the MAXIMUM_ALLOWED fan speed is set to 0xFF. This setting affects the fan speed both in manual and in automatic fan speed mode. You can change the MAXIMUM_ALLOWED fan speed to any level you want. Here is how

    Set the Quiet Mode: limits the fan speed(s) to the given value: 0x00 (OFF) to 0xFF (MAX). Default is 0xFF

    The "hacky" method:
    Code:
    \_SB.PCI0.LPCB.EC0.ST98 Arg0
    Where Arg0:
    0x00 (OFF) ot 0xFF (MAX) - MAXIMUM_ALLOWED fan speed.

    This is not the best way to do this, however.

    The clean method (how it should be done, ideally):
    First write the fan speed value to:
    Code:
    \_SB.QFAN // some place in SystemMemory
    And then call:
    Code:
    \_SB.ATKD.QMOD Arg0
    Where Arg0:
    0 - just returns
    1 - sets quiet mode to QFAN value
    2 - sets quiet mode to 0xFF (that's the default value)
    Code:
        Method (QMOD, 1, NotSerialized)
        {
            If (LEqual (Arg0, Zero))
            {
                Return (One)
            }
    
            If (LEqual (Arg0, One))
            {
                ^^PCI0.LPCB.EC0.ST98 (QFAN)
            }
    
            If (LEqual (Arg0, 0x02))
            {
                ^^PCI0.LPCB.EC0.ST98 (0xFF)
            }
    
            Return (One)
        }
    


    Fan speed MANUAL
    WARNING: When fan speed is set to custom value, the fan is not properly powered down when in Standby (you can hear high pitch sound coming from the fan), therefore you must set it back to AUTO before going into Standby and the resume the manual values after.

    Set custom fan speeds
    Code:
    \_SB.PCI0.LPCB.EC0.SFNV Arg0 Arg1
    Arg0: 0 - to reset fan(s) back to AUTO control (will only work if you previously called it with Arg0=1, or Arg0=2)
    1 - fan1
    2 - fan2
    Arg1
    if Arg0 == 0, then set this one to 0 too.
    otherwise, it is fan speed from 0x00 (OFF) to 0xFF (MAX)
    For example:
    Code:
    \_SB.PCI0.LPCB.EC0.SFNV 1 0x7D //set Fan1 speed to 0x7D (125)
    \_SB.PCI0.LPCB.EC0.SFNV 2 0x00 //set Fan1 speed to 0x00 (0)
    \_SB.PCI0.LPCB.EC0.SFNV 0 0   //reset fans back to Automatic fan control
    Code:
    Name (DECF, Zero) // stores which fans were set to manual control, for later resetting back to auto
    Method (SFNV, 2, Serialized)
    {
        If (LEqual (Arg0, Zero))
        {
            If (And (DECF, One)) // reset Fan1 back to Auto speed control
            {
                Store (RRAM (0x0521), Local0)
                Or (Local0, 0x80, Local0)
                WRAM (0x0521, Local0) // 0x8d auto ON/OFF
            }
    
            If (And (DECF, 0x02)) // reset Fan2 back to Auto speed control
            {
                Store (RRAM (0x0522), Local0)
                Or (Local0, 0x80, Local0)
                WRAM (0x0522, Local0) // 0x8e auto ON/OFF
            }
    
            Store (Zero, DECF)
            Return (Zero)
        }
    
        If (LEqual (Arg0, One)) // set fan speed manually for Fan1
        {
            Store (RRAM (0x0521), Local0)
            And (Local0, 0x7F, Local0)
            WRAM (0x0521, Local0) // 0xd manually set
            Or (DECF, One, DECF)
            ST84 (Zero, Arg1)
            Return (Zero)
        }
    
        If (LEqual (Arg0, 0x02)) // set fan speed manually for Fan2
        {
            Store (RRAM (0x0522), Local0)
            And (Local0, 0x7F, Local0)
            WRAM (0x0522, Local0) // 0xe manually set
            Or (DECF, 0x02, DECF)
            ST84 (One, Arg1)
            Return (Zero)
        }
    
        Return (Zero)
    }
    Ideally, it is better to use \_SB.ATKD.SFNS as it is a more generic implementation (could work for other Asus laptops without having to change anything), but it requires ACPI memory allocation to pass it the arguments which is, in some cases, non-trivial.

    Additionally, I found in a config file of NoteBook FanControl that TSTP (Embedded Controller byte 0x97) is some sort of a manual fan control byte. It goes from 0 (MIN) to 8 (MAX) and is 9 (RESET/AUTO). I have not tested it, but throwing it out there in case anyone wants to have a look at it.


    Reset fan speed back to AUTO
    First, reset the MAXIMUM_ALLOWED fan speed:
    Code:
    \_SB.ATKD.QMOD 0x02
    And then reset the fans back to auto mode
    Code:
    \_SB.PCI0.LPCB.EC0.SFNV 0 0


    TEMPERATURE
    CPU temperature
    Can be read via ACPI in degrees Celsius:
    Code:
    \_SB.PCI0.LPCB.EC0.ECPU
    Code:
    IndexField (BRAI, BRAD, ByteAcc, NoLock, Preserve)
    {
        .....
        Offset (0x98),
        ECPU,   8, // CPU Current temerature
        ECRT,   8, // CPU Critical Temperature (Tj Max)
        EPSV,   8, // CPU Passive Cooling Temperature
        .....
    }
    
    OR (better, because more generic and clean)
    Code:
    \_TZ.RTMP
    Code:
    Method (RTMP, 0, NotSerialized)
    {
        If (\_SB.PCI0.LPCB.EC0.ECAV ())
        {
            Store (\_SB.PCI0.LPCB.EC0.ECPU, Local0)
            If (LLess (Local0, 0x80))
            {
                Store (Local0, LTMP)
            }
        }
    
        Return (LTMP)
    }
    
    You can also read directly from the Embedded Controller at the offset of 0xA0 or 0xA6 (maybe this one is Intel GPU?) (can view with RWEverything on Windows and acer_ec.pl on Linux)

    GPU (Intel) Temperature
    Same as CPU temperature as Intel GPU is located on the CPU die.

    GPU (Nvidia) Temperature (only on laptops with Nvidia GPU) (such as UX32VD)
    When GPU is in off state, the temperatute reported is 0C, otherwise you get actual temperature +/-1C of what you would get in Nvidia Control Panel.
    Can be read via ACPI in degrees Celsius:
    Code:
    \_SB.PCI0.LPCB.EC0.TH1R
    Code:
        OperationRegion (ECOR, EmbeddedControl, Zero, 0xFF)
        Field (ECOR, ByteAcc, Lock, Preserve)
        {
             .......
            Offset (0xA0),
            ECPU,   8, // CPU Current temerature
            ECRT,   8, // CPU Critical Temperature (Tj Max)
            EPSV,   8, // CPU Passive Cooling Temperature
            EACT,   8, // CPU Active Cooling Temperature?
            TH1R,   8, // Nvidia GPU temperature1
            TH1L,   8, // Nvidia GPU temperature2
            TH0R,   8, // CPU temperature? Intel GPU temperature?
            TH0L,   8, // always 0, so no idea what this is (shows temperature on older asus laptop)
            .........
         }
    
    You can also read directly from the Embedded Controller at the offset of 0xA4 (can view with RWEverything on Windows and acer_ec.pl on Linux)
    There is also THR1L ( 0xA5) which is somehow related, but I am not sure what it is.

    You may also want to check out my other post right here: http://forum.notebookreview.com/asus/687758-asus-ux32a-fan-goes-off-off-21.html#post9073025
     
  2. Thomas2111

    Thomas2111 Newbie

    Reputations:
    0
    Messages:
    6
    Likes Received:
    0
    Trophy Points:
    5
    Hello, thank you for your work !
    we are curently working on installing MAC OSX 10.8 on Zenbookks prime on this thread : Zenbook Prime fixes, mods, tweaks, etc - OSx86 10.8 (Mountain Lion) - InsanelyMac Forum
    One of our lastest ideas was to controll the fan speed cleverly, like on windows when the fans stops when the processors and GPU don't need
    I'm hopping you know where put your methods in ours DSDT.aml, that controls the ACPI, and if they need to be called etc, a little how to patch would be great!
    Thanks in advance and excuse my low english level.
     
  3. prikolchik

    prikolchik Notebook Evangelist

    Reputations:
    259
    Messages:
    362
    Likes Received:
    3
    Trophy Points:
    30
    Getting the fan speed in RPM

    If you do not know what hexadecimal number is and what a byte is then please read: Hexadecimal - Wikipedia, the free encyclopedia (understand what it is and how to convert to dec->hex and hex->dec) Byte - Wikipedia, the free encyclopedia (understand the definition)

    You can read Fan1 and Fan2 speeds in the EC memory using RWEverything on Windows or acer_ec.pl on Linux. The fan speed is reported in some units (whatever they are) and can be converted to RPM using a certain formula. The fan speed is reported as 2-byte value.
    Code:
    0x93 - Fan1: 1st byte of the speed
    0x94 - Fan1: 2nd byte of the speed
    0x95 - Fan2: 1st byte of the speed
    0x96 - Fan2: 2nd byte of the speed
    Here is the output of acer_ec.pl on my computer (UX32VD):
    Code:
          00  01  02  03  04  05  06  07  |  08  09  0A  0B  0C  0D  0E  0F
          __  __  __  __  __  __  __  __  |  __  __  __  __  __  __  __  __
    00 |  0A  80  01  --  --  --  --  --  |  --  --  B7  B8  B7  B8  B7  B8 
    10 |  B7  B8  05  --  05  --  --  19  |  --  --  17  21  55  58  33  32 
    20 |  2D  36  35  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    30 |  --  --  --  --  --  --  --  --  |  --  --  --  --  07  --  --  -- 
    40 |  --  --  --  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    50 |  --  --  --  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    60 |  --  --  --  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    70 |  --  --  --  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    80 |  03  10  --  --  --  80  --  0A  |  --  --  --  --  --  --  --  -- 
    90 |  --  --  --  40  03  64  03  02  |  --  --  --  --  --  --  --  -- 
    A0 |  37  6C  6E  69  --  --  37  --  |  01  --  --  --  --  --  --  -- 
    B0 |  63  --  7E  20  E7  18  44  19  |  01  60  E0  --  --  --  EB  0B 
    C0 |  --  --  D0  20  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    D0 |  --  --  --  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    E0 |  --  --  --  --  --  --  --  --  |  --  --  --  --  --  --  --  -- 
    F0 |  78  19  E8  1C  D0  20  C0  --  |  --  --  --  --  --  --  --  --  
    As you can see, the fan1 speed is reported as 0x40 0x03 and fan2 speed is 0x64 0x03. Now, due to how it works on the hardware level, you actually need to flip the values to get the fan speed, so 0x40 0x03 should actually be 0x03 0x40 and combining the two bytes together to get a 2-byte value: 0x340. So, the fan speed, in terms of registers, should be this:
    Code:
    Fan1: [0x94][0x93], which in my case is: 0x94->0x03, 0x93->0x40, so fan speed: 0x340
    Fan2: [0x96][0x95], which in my case is: 0x96->0x03, 0x95->0x64, so fan speed: 0x364
    Now, we know the fan speed in "some units" and to convert it to RPM we use the following formula (it was in DSDT table in TACH method, see http://forum.notebookreview.com/asus/705656-fan-control-asus-prime-ux31-ux31a-ux32a-ux32vd.html):
    Code:
    0x0041CDB4 / (SPEED * 0x2)
    Which is the same as:
    4312500 / (SPEED * 2)
    So lets calculate the speed of our fans in RPM:
    Code:
    Fan1 - CPU: 0x0041CDB4 / (0x340 * 0x2) = 0xa1f which is in decimal: 2591 RPM
    Fan2 - GPU: 0x0041CDB4 / (0x364 * 0x2) = 0x9b4 which is in decimal: 2484 RPM
    And that's how you get the fan speed ;)
     
  4. cybtrash

    cybtrash Newbie

    Reputations:
    0
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    5
    Hi there,

    today I found your thread. Is there any progress on this topic?
    I googled a lot but it seems you are the only one currently working on this topic (on Linux)?

    It would be a good start if one could increase the "FAN GOES ON" temperature from ~50°C to 65°C. This would avoid that disturbing fan on off on off.
    Would it be complicated to achieve this?
     
  5. prikolchik

    prikolchik Notebook Evangelist

    Reputations:
    259
    Messages:
    362
    Likes Received:
    3
    Trophy Points:
    30
    There is no progress. Everything that is known to me is listed in this thread and in this post. My original plan was to create a linux kernel fan control module, but it turned out to be not as trivial as I thought. It would require a few days to develop and would involve a lot of reading time which I didn't have. You can find source code for working example modules that could be modified for our purpose, such as asus-laptop and asus-wmi. I even came up with a design that conforms to lm-sensor standards, however, I never implemented it.

    For a while I used acpi_call kernel module to directly issue ACPI calls to change the fan speed, but that had it's own drawbacks.

    Then a fellow forum user found the tools that could be used to extract and modify BIOS. I tried to find the Embedded Controller firmware (the chip that controls the fans) in the BIOS file, but I was not successful. I was planning to extract it, decompile it, fix the fan table in the firmware and then flash the new firmware. Since I wasn't able to find EC firmware, I had nothing to modify. And even if I had managed to modify it, I still don't know if there is a way to flash the modified firmware back to EC. There is a linux application superiotools (part of coreboot) that can read/write Embedded Controller firmware, however it did not support the chip on Zenbooks as there was no readily available documentation for it.

    Eventually, the fan stopped bothering me and it wasn't worth the effort to make a fan control application. Now that you brought it up, it is starting to bother me again... :rolleyes:

    It could probably be a day of work for someone who knows how to write proper kernel modules and another few days to test it and iron out the possible bugs. I have found all the required Zenbook fan control info and have listed it in this thread. Someone must actually sit down and do it. From my research, I discovered that the fans on all ASUS laptops are controlled in similar manner, so instead of writing a kernel module just for the Zenbook it may be possible to write one that works for all (or most?) ASUS laptops with very minor modifications. However, it seems like there isn't a developer who's willing to spend the time to actually do it.
     
  6. cybtrash

    cybtrash Newbie

    Reputations:
    0
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    5
    Thank you for your detailed answer. I have tried / compiled your peace of code ( fancntrl.c: Asus UX32VD fan control proof of concept - Pastebin.com)
    It does really work on my UX31A Prime, I can control the fan. So as you stated it seems to work generally on all ASUS netbooks.

    Sadly I can only handle some python/batch scripts, but I am not into deep C/C++ or else I would try it on my own :(

    Just imagine, you could eternize your name in the linux kernel code... :D I am sure a there are a lot of Zenbook Linux users out there who would really appreciate your work.

    edit: I just realized how wonderful it is to work with a silent environment. NBFC works so great under windows, I really hope someone will help us out here for Linux :/
     
  7. prikolchik

    prikolchik Notebook Evangelist

    Reputations:
    259
    Messages:
    362
    Likes Received:
    3
    Trophy Points:
    30
    That code is very unsafe (not thread-safe, it uses system I/O to access non-ACPI accessible EC memory while ACPI could be using System I/O at the same time) and should not be used other than to prove that it can work. You could still potentially use it, if you can lock the appropriate Mutex'es in DSDT table, but if you had access to ACPI you could just call the methods directly.
    I am fine with C and C++, however I don't know all the standards and which documentation to follow.
    Sounds very... intriguing. Maybe I should actually do it... I am too lazy, though.
    I don't know if you realise, but the way NBFC works is by writing to user-accessible ACPI Embedded Controller memory. It is entirely possible for you to write a SIMPLE bash/python script (which you say you can handle ;p) to behave exactly like NBFC does. You can use acer_ec.pl script (Google it) to write to EC memory, but you might want to write your own script for doing this (so that you don't have to constantly ask for access to EC, etc). If you look at the configuration file for NBFC for UX31A, you will see:
    HTML:
    <?xml version="1.0"?>
    <FanControlConfig xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <UniqueId>Asus Zenbook UX31A</UniqueId>
      <NotebookModel>UX31A</NotebookModel>
        <ReadRegister>151</ReadRegister>
      <WriteRegister>151</WriteRegister>
      <MinSpeedValue>0</MinSpeedValue>
      <MaxSpeedValue>8</MaxSpeedValue>
      <FanSpeedResetValue>9</FanSpeedResetValue>
      <ReadWriteWords>false</ReadWriteWords>
      <EcPollInterval>300</EcPollInterval>
      <AdjustFanControlMode>false</AdjustFanControlMode>
      <EcConfigurationRegister>0</EcConfigurationRegister>
      <ManualControlModeValue>0</ManualControlModeValue>
      <AutoControlModeValue>0</AutoControlModeValue>
      <FakeTemperature>false</FakeTemperature>
      <TemperatureRegister>0</TemperatureRegister>
      <ThermalZoneRegister>0</ThermalZoneRegister>
      <FakeTemperatureValue>0</FakeTemperatureValue>
      <TemperatureResetValue>0</TemperatureResetValue>
      <ThermalZonesIndices>
        <int>1</int>
      </ThermalZonesIndices>
      <TemperatureThresholds>
        <TemperatureThreshold>
          <UpThreshold>0</UpThreshold>
          <DownThreshold>0</DownThreshold>
          <FanSpeed>0</FanSpeed>
        </TemperatureThreshold>
        <TemperatureThreshold>
          <UpThreshold>65</UpThreshold>
          <DownThreshold>58</DownThreshold>
          <FanSpeed>22.5</FanSpeed>
        </TemperatureThreshold>
        <TemperatureThreshold>
          <UpThreshold>67</UpThreshold>
          <DownThreshold>61</DownThreshold>
          <FanSpeed>40</FanSpeed>
        </TemperatureThreshold>
        <TemperatureThreshold>
          <UpThreshold>69</UpThreshold>
          <DownThreshold>64</DownThreshold>
          <FanSpeed>65</FanSpeed>
        </TemperatureThreshold>
        <TemperatureThreshold>
          <UpThreshold>71</UpThreshold>
          <DownThreshold>67</DownThreshold>
          <FanSpeed>102.38095238095238</FanSpeed>
        </TemperatureThreshold>
      </TemperatureThresholds>
      <RegisterWriteRequests>
        <RegisterWriteRequest>
          <WriteMode>Set</WriteMode>
          <Register>160</Register>
          <Value>45</Value>
        </RegisterWriteRequest>
        <RegisterWriteRequest>
          <WriteMode>Set</WriteMode>
          <Register>166</Register>
          <Value>45</Value>
        </RegisterWriteRequest>
      </RegisterWriteRequests>
    </FanControlConfig>
    Here it says:
    1. The program reads/writes fan speed to EC register 151 or 0x97.
    2. The minimum fan speed is 0 and max is 8. This is what it writes to that 0x97 register.
    3. The fan speed reset value is 9. This is what you write to register 0x97 if you want to turn auto fan control back on (such as at program exit, at termination, etc).
    4. The program polls the value of the temperature every 300ms.
    5. Temperature is received from the Thermal Zone 1. Which you can get on Linux by reading /sys/devices/virtual/thermal/thermal_zone0/temp (which is preferred) or by accessing EC register 0xA0 (not advised).
    6. The temperature thresholds are such:
    Code:
    Fan on:   0 C, speed down:  0 C speed: 0 %
    Fan on: 65 C, speed down: 58 C speed: 22.5 %
    Fan on: 67 C, speed down: 61 C speed: 40%
    Fan on: 69 C, speed down: 64 C speed: 65 %
    Fan on: 71 C, speed down: 67 C speed: 102 % (uhhh. what?)
    7. Before setting the fan speed in register 0x97 (or you have to do that every polling interval? Not too sure), you need to do:
    Write CPU temperature of 45 to EC 160 or 0xA0
    Write CPU temperature of 45 to EC 166 or 0xA6
    (As far as I know this is done to prevent computer from controlling the fan speeds automatically based on that temperature)

    So, it is possible to write a relatively small script to do the NBFC behaviour on Linux and make it behave like it does on Windows. You may ask: "Why haven't you done this prikolchik if you are so clever?" Well, the reason why I didn't do this is because it is a very hacky and "unsafe" way and consumes a lot (relatively speaking, it is not really noticeable to the user) of CPU time (due to interrupts when writing to EC memory). I don't think it is a solution worth implementing, but it certainly works on Windows and it should definitely work on Linux.

    Anyway, give it a try, experiment. Make use of acer_ec.pl script to play around with EC memory and see what you can come up with.

    ALSO, if you want to go a different route... You can make a simple bash/python script that reads the ThermalZone CPU temperature as described above (in Step 5), but it controls the fan using the appropriate ACPI call methods (SFNV, ST98 as described in first post of this thread) via acpi_call kernel module. It should be fairly trivial to implement, even easier than doing all that Embedded Controller stuff like NBFC does it. For example:
    Code:
    #!/bin/bash
    # make sure to run this with root permissions
    # assuming that you have acpi_call kernel module loaded
    # executes `\_SB.PCI0.LPCB.EC0.ST98 0x45' ACPI call to limit the maximum fan speed to 0x45 (with 0xFF being the maximum).
    # the script prints the return of the called function, which in this case is 0 for success and anything else is failure
    
    ACPI_CALL=/proc/acpi/call
    command='_SB.PCI0.LPCB.EC0.ST98 0x45'
    
    echo -E '\'"$command" > "${ACPI_CALL}"; echo $(cat "${ACPI_CALL}")
    
     
  8. cybtrash

    cybtrash Newbie

    Reputations:
    0
    Messages:
    3
    Likes Received:
    0
    Trophy Points:
    5
    WOW! Thank you, this was a REALLY helpful answer. I will definitely try both of your suggested ways regulating the fan and post my solution if it works.

    No, I don't believe you. Just look at your long, well written answers here, they prove the opposite :)
     
  9. prikolchik

    prikolchik Notebook Evangelist

    Reputations:
    259
    Messages:
    362
    Likes Received:
    3
    Trophy Points:
    30
    Personally, I would avoid the first method as it is more error-prone and more of a hack. 2nd method is a much better and easier. You should be able to find a working bash/python script that runs in a loop and controls the fans and just modify it to call the appropriate ACPI functions.
    Writing documentation and results of experiments is a lot more fun than coding :D And it is a lot easier to be the guy-who-figured-out-fan-control than the guy-who-made-fan-control-work. It is like all I do is some investigation and documentation and I get most of the credit! It is a no-brainer ;)
     
  10. felipec

    felipec Newbie

    Reputations:
    0
    Messages:
    1
    Likes Received:
    0
    Trophy Points:
    5
  11. pitchshifter

    pitchshifter Notebook Enthusiast

    Reputations:
    0
    Messages:
    12
    Likes Received:
    0
    Trophy Points:
    5
    Is there any further progress on this, anyone? This only happens to me when I have my external monitor plugged in (why? I don't know, I also lose DVORAK keyboard layout and all default shortcuts if I boot up with it plugged in as well...ah Linux..) but in any case it is annoying as hell. I have to switch back to Windows until this is fixed. I'd gladly put in money towards a fix!

    It's also not just an issue with needing to mod the BIOS - in Windows, even without NBFC installed, when it goes over the ~48 degree threshold, it turns on and off the fan at a low speed. In Ubuntu, once it goes over it turns it on max. There is no in between speeds, so as a result the problem is far worse in Linux.

    Even there was a fix for Ubuntu so that the fan came on at the BIOS set shelves (which are too low but still not totally on/totally off), this would still be far better...
     
  12. pitchshifter

    pitchshifter Notebook Enthusiast

    Reputations:
    0
    Messages:
    12
    Likes Received:
    0
    Trophy Points:
    5
    Furthermore, there was a bios update 219 for the UX31A with changelog (updated thermal policy) that appears to have fixed the fan speed, if that helps to provide a basis for comparison....
     
  13. daringer

    daringer Newbie

    Reputations:
    0
    Messages:
    1
    Likes Received:
    0
    Trophy Points:
    5
    Kinda late to the game, but with useful information ( https://github.com/daringer/asus-fan ) ... forked the good work from "felipec" and pushed it a little more, means there is:

    - support for the second fan inside the nvidia zenbooks
    - fix for "not showing fan speed while in manual mode"
    - fix for "crazy up/down/up/down" spin behavior
    (looks like my acpi data was not entirely correct, the module sets the most obvious/useful fan settings on load)
    - support for all zenbooks listed on the wikipedia zenbook page
    (if you wanna try another model, just mail me)
    - if there are two fans (e.g., ux32vd) both may be controlled separately, and both show up as "cooling_deviceX"
    - I managed to even set the max speed for each one, but thermal_cooling_device_* only provides "cur_state" and "max_state", which means, I can access it from inside but right now there is no way to use this feature from inside the userland...

    https://github.com/daringer/asus-fan