Skip to content

Instantly share code, notes, and snippets.

@felipec
Created August 6, 2013 21:51
Show Gist options
  • Save felipec/6169047 to your computer and use it in GitHub Desktop.
Save felipec/6169047 to your computer and use it in GitHub Desktop.
ASUS fan control
/*
*
* obj-m := fan.o
* KDIR := /lib/modules/$(shell uname -r)/build
* PWD := $(shell pwd)
*
* all:
* $(MAKE) -C $(KDIR) M=$(PWD) modules
*
* clean:
* $(MAKE) -C $(KDIR) M=$(PWD) clean
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
#include <linux/dmi.h>
MODULE_AUTHOR("Felipe Contreras <felipe.contreras@gmail.com>");
MODULE_DESCRIPTION("ASUS fan driver");
MODULE_LICENSE("GPL");
static struct thermal_cooling_device *cdev;
static int fan_get_max_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
*state = 0xff;
return 0;
}
static int fan_get_cur_state(struct thermal_cooling_device *cdev,
unsigned long *state)
{
struct acpi_object_list params;
union acpi_object in_objs[1];
unsigned long long value;
acpi_status r;
params.count = ARRAY_SIZE(in_objs);
params.pointer = in_objs;
in_objs[0].type = ACPI_TYPE_INTEGER;
in_objs[0].integer.value = 0;
r = acpi_evaluate_integer(NULL, "\\_TZ.RFAN", &params, &value);
if (r != AE_OK)
return r;
*state = value;
return 0;
}
static int fan_set(struct thermal_cooling_device *cdev, int fan, int speed)
{
struct acpi_object_list params;
union acpi_object in_objs[2];
unsigned long long value;
params.count = ARRAY_SIZE(in_objs);
params.pointer = in_objs;
in_objs[0].type = ACPI_TYPE_INTEGER;
in_objs[0].integer.value = fan;
in_objs[1].type = ACPI_TYPE_INTEGER;
in_objs[1].integer.value = speed;
return acpi_evaluate_integer(NULL, "\\_SB.PCI0.LPCB.EC0.SFNV", &params, &value);
}
static int fan_set_cur_state(struct thermal_cooling_device *cdev,
unsigned long state)
{
return fan_set(cdev, 1, state);
}
static int fan_set_auto(struct thermal_cooling_device *cdev)
{
return fan_set(cdev, 0, 0);
}
static const struct thermal_cooling_device_ops fan_cooling_ops = {
.get_max_state = fan_get_max_state,
.get_cur_state = fan_get_cur_state,
.set_cur_state = fan_set_cur_state,
};
static int __init fan_init(void)
{
if (strcmp(dmi_get_system_info(DMI_SYS_VENDOR), "ASUSTeK COMPUTER INC."))
return -ENODEV;
cdev = thermal_cooling_device_register("Fan", NULL, &fan_cooling_ops);
if (IS_ERR(cdev))
return PTR_ERR(cdev);
fan_set_auto(cdev);
return 0;
}
static void __exit fan_exit(void)
{
fan_set_auto(cdev);
thermal_cooling_device_unregister(cdev);
}
module_init(fan_init);
module_exit(fan_exit);
@Agyar
Copy link

Agyar commented Aug 12, 2013

Compilation and Modprobe worked for me on my arch, on a 3.9.9-1-ARCH x64. But how to use it ? Can't wait to get it working ! Thank you so much for this code !

Copy link

ghost commented Aug 17, 2013

Hi there! Thank you very much for this!! This fan on-off-on-off is driving me crazy, it forces me sometimes to work with Windows, because there that NotebookFanControl program works perfectly and makes working almost fan/noise-less (CPU temp while working with Office / Browsing web is always around 45-55°C here and normaly the fan turn on at 50°C. NBFC forces the fan to start at 60°C).

Could you please provide some more info about compiling and using this peace of code?

I get the following error under Kubuntu x64 when trying to compile with gcc
asus_fan.c:14:26: fatal error: linux/module.h: No such file or directory
compilation terminated.

Kernels header should be installed here.

@Agyar
Copy link

Agyar commented Aug 27, 2013

you have a makefile at the top of the file .... just create one with those few lines and run make all... you can then insmod the .ko produced... if you get an error like "file exists" you probably already have a module name "fan" running ... rmmod it and re-run insmod.

@Juma7C9
Copy link

Juma7C9 commented Aug 28, 2013

Hi, I compiled and inserted the module too, but I'm stuck there, as the fan isn't seen by 'sensors' program, and there seems to be no way to control it.
What I'm I missing? Do I need to recompile the kernel with the modified asus-laptop.c?
By the way, I'm running Arch Linux on 3.10.9-1 stock kernel.

Thank you.

@Agyar
Copy link

Agyar commented Aug 30, 2013

I do have a "asus" part in sensors when it is modprobed. However, cpu temperature is pretty much all I got. So I still don't have any fan informations...

If you don't have any informations, maybe you do not have acpi stuff installed...

@asuxer: thanks for the lkml link, I hope it will keep going on...

Copy link

ghost commented Oct 12, 2013

OK I give up...

I recompiled the original Ubuntu kernel, but patched it with the diff from here
https://lkml.org/lkml/2013/10/8/800
(http://www.gossamer-threads.com/lists/linux/kernel/1796054)

Reboot, then I re-run sensors-detect, then sudo pwmconfig (from package fancontrol) but still I get
/usr/sbin/pwmconfig: There are no fan-capable sensor modules installed

felipec, please tell us what you did. You say it works perfectly for you?

@nuklea
Copy link

nuklea commented Dec 9, 2013

@asuxer this module don't create /sys/class/hwmon devices. Control your fan with:

$ echo 200 | sudo tee /sys/class/thermal/cooling_deviceN/cur_state

@daringer
Copy link

  • added full Makefile
  • added "hack" to set fan back to automatic without unloading the module

-> forked here: https://gist.github.com/daringer/721e2cea17b570512097

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment