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);
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