Skip to content

Instantly share code, notes, and snippets.

@daringer
Forked from felipec/asus_fan.c
Last active August 29, 2015 14:01
Show Gist options
  • Save daringer/721e2cea17b570512097 to your computer and use it in GitHub Desktop.
Save daringer/721e2cea17b570512097 to your computer and use it in GitHub Desktop.
OLD/DEPRECATED/OBSOLETE/DONOTUSE: ASUS Fan control linux kernel module - NOW HERE: https://github.com/daringer/asus-fan
/**
* ASUS Zenbook Fan control module, verified with:
* - UX32VD Zenbook
* - ....
*
* Just 'make' and copy the fan.ko file to /lib/modules/`uname -r`/...
* If the modules loads succesfully it will bring up a "thermal_cooling_device"
* like /sys/devices/virtual/thermal/cooling_deviceX/ mostly providing
* cur_state / max_state
*
* PLEASE USE WITH CAUTION, you can easily overheat your machine with a wrong
* manually set fan speed...
*
**/
#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 <[email protected]>");
MODULE_AUTHOR("Markus Meissner <[email protected]>");
MODULE_DESCRIPTION("ASUS fan driver");
MODULE_LICENSE("GPL");
static struct thermal_cooling_device *cdev;
static int last_state;
static bool is_manual;
static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state);
static int fan_set_auto(struct thermal_cooling_device *cdev);
static int fan_set(struct thermal_cooling_device *cdev, int fan, int speed);
static int fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state);
static void __exit fan_exit(void);
static int __init fan_init(void);
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;
// fan does not report during manual speed setting - so fake it!
if (is_manual) {
*state = last_state;
return 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)
{
last_state = state;
// setting fan to automatic, if cur_state is set to (0x0100) 256
if(state == 256) {
is_manual = false;
return fan_set_auto(cdev);
} else {
is_manual = true;
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);
last_state = -1;
is_manual = false;
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);
#!/bin/bash
startpath="/sys/devices/virtual/thermal/"
path=$(grep -r Fan ${startpath}/cooling_device*/type 2> /dev/null | \
cut -d ":" -f 1 | xargs dirname)
if [[ "$1" = "" ]]; then
echo "Usage: $0 <action>"
exit;
fi
if [[ "$1" = "max" || "$1" = "full" || "$1" = "get_max" ]]; then
cat ${path}/max_state
elif [[ "$1" = "cur" || "$1" = "get" || "$1" = "current" ]]; then
cat ${path}/cur_state
elif [[ "$1" = "set" && "$2" != "" ]]; then
echo $2 > ${path}/cur_state
echo "Set to 256 to reactivate automatic regulation!"
fi
obj-m := asus_fan.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
install:
# just copy the .ko file anywhere below:
# /lib/modules/$(uname -r)/
#
# finally add it to some on-boot-load-mechanism
# the module will _not_ automatically load.
@Venemo
Copy link

Venemo commented Jun 30, 2014

You forgot a semicolon at the end of line 101. (The compiler complains)

@Fenisu
Copy link

Fenisu commented Jul 2, 2014

It also complains that the makefile file name is written in lowercase instead of lowercase with a capital M. It should be "Makefile".

And I can't get it to work on Ubuntu 14.04, it loads, but nothing happens. No new "thermal_cooling_device" appears in /sys/devices/virtual/thermal/cooling_deviceX/, I had and still have 7 different, all having cur_state at 0, and won't change if I try.

@Venemo
Copy link

Venemo commented Jul 12, 2014

@Fenisu works fine for me on Fedora 20 and kernel 3.15.3

@daringer
Copy link
Author

daringer commented Aug 3, 2014

@Venemo thanks, yes missed that for some reason!? but updated and pushed it for the sake of completeness - and yes still works fine here on Arch with 3.15.6 ....

Although the location/number of the cooling_device changes from boot to boot, so I would suggest to either avoid rebooting or setup a oneshot-systemd service to link it to a known place on each reboot?

Anyone ever had the automatic regulator go above 40% fan speed? Lately my Zenbook feels hotter as usual, but the fan does not even think about going faster^^

@daringer
Copy link
Author

daringer commented Aug 4, 2014

Haha, it started bugging me already.... uploaded minimal bash-script to get around this...

@Agyar
Copy link

Agyar commented Oct 8, 2014

Does it still work for you ? I have issues with it on Archlinux (updated 3.16.4.1). It doesn't do anything but it used to work... Asking since the state of my fans is pretty crazy right now: full speed anytime with no correlation to temperature !

@daringer
Copy link
Author

Just now upgraded to 3.16.4-1-ck on an Arch System, still works - more or less. Mine does the opposite, never going above 40% even if the cpu reaches 85° or more ... Should maybe first go for a inner-cleanup - Although, did you rebuild the modules? does the script find the path? Can you set the fan-speed over console, by yourself using echo? Additionally, the user might not have the permission to write to /sys/....../cooling_device5/ .

@daringer
Copy link
Author

@Venemo
Copy link

Venemo commented Nov 8, 2014

@daringer Thanks for the update. Your stuff works wonderfully on Fedora 21 with kernel 3.17.2! :)

@daringer
Copy link
Author

daringer commented Dec 1, 2014

wohooo, I've made something useful :D the recent version adds support for the second fan for the dedicated gfx if there is one ... As there are new Zenbooks announced, which seem to use a similar/identical interface, I'll try to (somehow) push it towards mainstream - but haven't done this before, lets see how far I get before I'll start to cry the first time ;DDD

edit: and stop writing here, fill the issues in https://github.com/daringer/asus-fan with stuff you need ...

@MrAmbiG
Copy link

MrAmbiG commented Mar 8, 2015

how to use all this ?!
made 3 files in a directory and ran make install and it gave me error
makefile:6: *** missing separator. Stop.
i guess i will stop using gnu linux os since hardware manufacturers use gnu linux for themselves to boot a cd or in their hardware tools but dont want to support it.

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