commit 464b9451cef19673dcc19e4e8f0e61085933bf32 Author: Lukas Stancik Date: Sat Dec 26 19:28:14 2020 +0000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42ecb9f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.cache.mk \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bc86eb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,190 @@ + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7f4f4d5 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +obj-m := asus_u36sd_fan.o + +KVER ?= $(shell uname -r) +KDIR ?= /lib/modules/$(KVER)/build + +default: + $(MAKE) -C $(KDIR) M=$(CURDIR) modules + +install: + $(MAKE) -C $(KDIR) M=$(CURDIR) modules_install + +load: + -/sbin/rmmod asus_u36sd_fan + /sbin/insmod asus_u36sd_fan.ko + +clean: + $(MAKE) -C $(KDIR) M=$(CURDIR) clean + +dkms-add: + /usr/sbin/dkms add $(CURDIR) + +dkms-build: + /usr/sbin/dkms build asus_u36sd_fan/0.1 + +dkms-remove: + /usr/sbin/dkms remove asus_u36sd_fan/0.1 --all + diff --git a/asus_u36sd_fan.c b/asus_u36sd_fan.c new file mode 100644 index 0000000..7ba06eb --- /dev/null +++ b/asus_u36sd_fan.c @@ -0,0 +1,337 @@ +/* + * asus_u36sd_fan.c - ASUS U36SD Fan Control driver using ACPI calls + * + * + * Copyright (C) 2013 Lukas Stancik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * The development page for this driver is located at + * + * Based upon asus_fan.c by Giulio Piemontese + * http://github.com/gpiemont/asusfan/ + * + * Previusly (by Dmitry Ursegov) + * http://code.google.com/p/asusfan/ + * + */ + +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Lukas Stancik"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ASUS U36SD Fan Control"); + +#ifndef ASUSFAN_VERBOSE +#define ASUSFAN_VERBOSE 0 +#endif + +#ifndef ASUSFAN_STABLE_RANGE +#define ASUSFAN_STABLE_RANGE 1 +#endif + +#ifndef ASUSFAN_TEMP_NUM_SAMPLES +#define ASUSFAN_TEMP_NUM_SAMPLES 5 +#endif + +MODULE_PARM_DESC(verbose, "Enable Speed changing/temperature status messages (0-2)"); +int asusfan_verbose = ASUSFAN_VERBOSE; +module_param_named(verbose, asusfan_verbose, int, 0600); + +MODULE_PARM_DESC(current_zone, "Current thermal zone"); +int asusfan_curr_zone = -1; +module_param_named(current_zone, asusfan_curr_zone, int, 0444); + +MODULE_PARM_DESC(previous_zone, "Previous thermal zone"); +int asusfan_prev_zone = -1; +module_param_named(previous_zone, asusfan_prev_zone, int, 0444); + +MODULE_PARM_DESC(current_speed, "Current fan speed"); +int asusfan_curr_speed = -1; +module_param_named(current_speed, asusfan_curr_speed, int, 0444); + +MODULE_PARM_DESC(target_speed, "Manually set target fan speed (Dangerous!)"); +int asusfan_target_speed = -1; +module_param_named(target_speed, asusfan_target_speed, int, 0600); + +MODULE_PARM_DESC(max_speed, "Maximum supported speed"); +int asusfan_max_speed = 255; +module_param_named(max_speed, asusfan_max_speed, int, 0400); + +MODULE_PARM_DESC(min_speed, "Minumum supported speed"); +int asusfan_min_speed = 0; +module_param_named(min_speed, asusfan_min_speed, int, 0400); + +MODULE_PARM_DESC(current_temp, "Current temperature value (°C)"); +int asusfan_curr_temp = -1; +module_param_named(current_temp, asusfan_curr_temp, int, 0444); + +MODULE_PARM_DESC(max_temp, "Maximum temperature value (°C) that can be evaluated"); +int asusfan_max_temp = 110; +module_param_named(max_temp, asusfan_max_temp, int, 0444); + +MODULE_PARM_DESC(min_temp, "Minimum temperature value (°C) that can be evaluated"); +int asusfan_min_temp = 0; +module_param_named(min_temp, asusfan_min_temp, int, 0444); + +MODULE_PARM_DESC(temp_stable_range, "Within this range (+/-) temperature is considered stable"); +int asusfan_stable_range = ASUSFAN_STABLE_RANGE; +module_param_named(temp_stable_range, asusfan_stable_range, int, 0600); + +MODULE_PARM_DESC(temp_num_samples, "Number of samples to establish the temperature behaviour"); +int asusfan_num_samples = 0; +module_param_named(temp_num_samples, asusfan_num_samples, int, 0600); + +/* + * We took a pre-defined number of samples of temperature from the acpi, + * then we try to guess the ongoing curve. This is done in a separated thread. + */ + +unsigned int fan_sample = 0; + +char fan_num_samples = ASUSFAN_TEMP_NUM_SAMPLES; +char samples[ASUSFAN_TEMP_NUM_SAMPLES] ; + +#define MONITOR_FREQ 1 + +/* + * When the temperature goes down to a low zone it is better to stay at + * a high speed some degrees more to reduce fan speed switching + */ + +#define NUM_ZONES 9 +#define TMP_DIFF 3 + +#define TIMER_FREQ 10 /* seconds */ + +struct tmp_zone { + int tmp; /* °C */ + int speed; /* 80-255 (0 - fan is disabled) */ + unsigned int sleep; /* Sleep for sleep seconds more at tmp temperature */ +}; + +int asusfan_current_zone = -1; + +typedef enum status { + stable, + ascending, + descending +} status_t; + +status_t __thermal_status = stable; + +const char * const status_name[3] = { + "stable", + "ascending", + "descending" +}; + +MODULE_PARM_DESC(temp_status, "Current temperature status"); +char * asusfan_temp_status = ""; +module_param_named(temp_status, asusfan_temp_status, charp, 0444); + +static struct tmp_zone zone[NUM_ZONES] = { { 45, 0,1 }, + { 50, 80,1 }, + { 55, 100,1 }, + { 60, 110,1 }, + { 65, 130,1 }, + { 70, 140,2 }, + { 85, 160,3 }, + { 100,190,5 }, + { 105,210,7 }}; + +static void timer_handler(struct work_struct *work); +static void temp_status_timer(struct work_struct *work); + +static DECLARE_DELAYED_WORK(ws, timer_handler); +static DECLARE_DELAYED_WORK(wst, temp_status_timer); + +static struct workqueue_struct *wqs; +static struct workqueue_struct *wqst; + +static int get_zone_temp(void) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + int tmp; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + //Get current temperature + status = acpi_evaluate_object(NULL, "\\_TZ.THRM._TMP", + NULL, &output); + if (status != AE_OK) printk("_TZ.THRM._TMP error\n"); + tmp = (int)((out_obj.integer.value-2732))/10; + + if((tmp > asusfan_max_temp ) || (tmp < asusfan_min_temp)) + return -1; + + if(asusfan_curr_temp != tmp) + asusfan_curr_temp = tmp; + + return tmp; +} + +static void set_fan_speed(int speed) +{ + struct acpi_object_list params; + union acpi_object in_objs[2]; + acpi_status status; + + //Set fan speed + params.count = ARRAY_SIZE(in_objs); + params.pointer = &(*in_objs); + in_objs[0].type = ACPI_TYPE_INTEGER; + in_objs[0].integer.value = 1; + in_objs[1].type = ACPI_TYPE_INTEGER; + in_objs[1].integer.value = speed; + if(asusfan_verbose) + printk("ACPI called (_SB.PCI0.SBRG.EC0.SFNV 1 %d)\n", speed); + status = acpi_evaluate_object(NULL, "\\_SB.PCI0.SBRG.EC0.SFNV", + ¶ms, NULL); + if (status != AE_OK) printk("ASUS Fan ACPI call (_SB.PCI0.SBRG.EC0.SFNV 1 %d) error\n", speed); +} + +static void timer_handler(struct work_struct *work) +{ + static int prev_zone = 0; + int curr_zone = 0; + int tmp; + + tmp = get_zone_temp(); + + if (unlikely(tmp == -1)) + return; + + if(tmp >= zone[NUM_ZONES-1].tmp) + goto out; + + //Set fan speed and save previous zone + for(curr_zone=0; curr_zone<(NUM_ZONES-1); curr_zone++) + if(tmp < zone[curr_zone].tmp) + break; + + if(unlikely(curr_zone < prev_zone && + tmp > zone[curr_zone].tmp - TMP_DIFF )) { + set_fan_speed(zone[prev_zone].speed); + asusfan_curr_speed = zone[prev_zone].speed; + if (asusfan_verbose > 0) + printk("ASUS Fan: tmp = %d, curr zone %d, prev zone %d, speed set to %d\n", + tmp, curr_zone, prev_zone, zone[prev_zone].speed); + } + else { + set_fan_speed(zone[curr_zone].speed); + asusfan_curr_speed = zone[curr_zone].speed; + prev_zone = curr_zone; + if (asusfan_verbose > 0) + printk("asus_fan: tmp = %d, curr zone %d, prev zone %d, speed set to %d\n", + tmp, curr_zone, prev_zone, zone[curr_zone].speed); + } + +out: + + queue_delayed_work(wqs, &ws, (TIMER_FREQ + zone[curr_zone].sleep) * HZ); +} + +static void temp_status_timer(struct work_struct *work) +{ + int i = 0; + int diff = 0; + + samples[0] = get_zone_temp(); + + /* "Parabolic" tolerance curve */ + + if ((fan_sample % ASUSFAN_TEMP_NUM_SAMPLES) == 0) + { + diff = (samples[0] - samples[fan_num_samples - 1]); + + if(asusfan_verbose > 1) + printk("sample[0] = %d , sample[%d] = %d, diff = %d\n", samples[0], fan_num_samples - 1, samples[fan_num_samples-1], diff); + + if((diff <= asusfan_stable_range) && ( diff >= -asusfan_stable_range)) + { + __thermal_status = stable; + asusfan_temp_status = status_name[0]; + } + else if(diff > asusfan_stable_range ) + { + __thermal_status = ascending; + asusfan_temp_status = status_name[1]; + } + else if(diff < -asusfan_stable_range ) + { + __thermal_status = descending; + asusfan_temp_status = status_name[2]; + } + if(asusfan_verbose > 1) + printk("sample[0] = %d ", samples[0]); + + while(++i < fan_num_samples) { + samples[fan_num_samples - i] = samples[fan_num_samples - i -1]; + if(asusfan_verbose > 1) + printk("sample[%d] = %d ", i, samples[i]); + } + if(asusfan_verbose > 1) + printk("\n"); + } + + queue_delayed_work(wqst, &wst, MONITOR_FREQ * HZ); +} + +static int asus_fan_init(void) +{ + + memset(&samples, 0, fan_num_samples); + + //Workqueue settings + wqs = create_singlethread_workqueue("tmp"); + queue_delayed_work(wqs, &ws, HZ); + + wqst = create_singlethread_workqueue("sampler"); + queue_delayed_work(wqst, &wst, HZ); + + printk("ASUS U36SD Fan Control version 0.9\n"); + + return 0; +} + +static void asus_fan_exit(void) +{ + set_fan_speed(-1); + + cancel_delayed_work(&ws); + flush_workqueue(wqs); + destroy_workqueue(wqs); + + cancel_delayed_work(&wst); + flush_workqueue(wqst); + destroy_workqueue(wqst); + + printk("ASUS U36SD Fan Control driver unloaded\n"); +} + + +module_init(asus_fan_init); +module_exit(asus_fan_exit); + diff --git a/dkms.conf b/dkms.conf new file mode 100644 index 0000000..3f0d598 --- /dev/null +++ b/dkms.conf @@ -0,0 +1,7 @@ +PACKAGE_NAME=asus_u36sd_fan +PACKAGE_VERSION=0.1 +CLEAN="make clean" +BUILT_MODULE_NAME[0]=asus_u36sd_fan +DEST_MODULE_LOCATION[0]=/extra +MAKE[0]="make KVER=${kernelver} KDIR=/lib/modules/${kernelver}/build" +AUTOINSTALL="yes" \ No newline at end of file