diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7a6f096 --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +COMPILER=G++ + +# todo: object files into output path, processing c / c++ files in the same time (?), nested directories for source files (?) +C = c +OUTPUT_PATH = bin/ +SOURCE_PATH = src/ +EXE = bin/mbpfan + +ifeq ($(COMPILER), G++) + ifeq ($(OS),Windows_NT) + OBJ = obj + else + OBJ = o + endif + COPT = -O2 + CCMD = g++ + OBJFLAG = -o + EXEFLAG = -o +# INCLUDES = -I../.includes + INCLUDES = +# LIBS = -lgc + LIBS = -lm +# LIBPATH = -L../gc/.libs + LIBPATH = + CPPFLAGS = $(COPT) -g $(INCLUDES) + LDFLAGS = $(LIBPATH) -g $(LIBS) + DEP = dep +else + OBJ = obj + COPT = /O2 + CCMD = cl + OBJFLAG = /Fo + EXEFLAG = /Fe +# INCLUDES = /I..\\.includes + INCLUDES = +# LIBS = ..\\.libs\\libgc.lib + LIBS = + CPPFLAGS = $(COPT) /DEBUG $(INCLUDES) + LDFLAGS = /DEBUG +endif + +OBJS := $(patsubst %.$(C),%.$(OBJ),$(wildcard $(SOURCE_PATH)*.$(C))) + +%.$(OBJ):%.$(C) + @echo Compiling $(basename $<)... + $(CCMD) -c $(CPPFLAGS) $(CXXFLAGS) $< $(OBJFLAG)$@ + +all: $(OBJS) + @echo Linking... + $(CCMD) $(LDFLAGS) $^ $(LIBS) $(EXEFLAG) $(EXE) + +clean: + rm -rf $(SOURCE_PATH)*.$(OBJ) $(EXE) + +rebuild: clean all +#rebuild is not entirely correct \ No newline at end of file diff --git a/README b/README index a85248e..a8a499e 100644 --- a/README +++ b/README @@ -1,4 +1,23 @@ -This is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module. It includes a PKGBUILD for easy installation in Arch Linux. +This is an enhanced version of rvega's Fan-Control-Daemon , +which itself is an enhanced version of Allan McRae mbpfan + +Fan-Control-Daemon is a daemon that uses input from coretemp module and sets the fan speed using the applesmc module. +This enhanced version assumes any number of processors and fans (max. 10). + + * It only uses the temperatures from the processors as input. + * It requires coretemp and applesmc kernel modules to be loaded. + * It requires root use + + +Compile with +gcc -o mbpfan -lm mbpfan.c + +Run with +sudo ./mbpfan + +Original README below. +-- +It includes a PKGBUILD for easy installation in Arch Linux. Based on: diff --git a/bin/mbpfan b/bin/mbpfan new file mode 100755 index 0000000..cb5a8c2 Binary files /dev/null and b/bin/mbpfan differ diff --git a/mbpfan.c b/mbpfan.c deleted file mode 100644 index 7cf3844..0000000 --- a/mbpfan.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * mbpfan.c - automatically control fan for MacBook Pro - * Copyright (C) 2010 Allan McRae - * Modifications by Rafael Vega - * - * 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 3 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. - * - * 20110811 - v1.1 - * - * Notes: - * Uses only the temperatures from the processors as input. - * Assumes two processors and one fan. - * Requires coretemp and applesmc kernel modules to be loaded. - * - * Tested models: - * MacBook Pro 8.1 13" (Intel i7 - Linux 3.2) - */ - - -#include -#include -#include - -/* lazy min/max... */ -#define min(a,b) a < b ? a : b -#define max(a,b) a > b ? a : b - -/* basic fan speed parameters */ -unsigned short min_fan_speed=2000; -unsigned short max_fan_speed=6200; - -/* temperature thresholds - * low_temp - temperature below which fan speed will be at minimum - * high_temp - fan will increase speed when higher than this temperature - * max_temp - fan will run at full speed above this temperature */ -unsigned short low_temp=63; -unsigned short high_temp=66; -unsigned short max_temp=86; -/* unsigned short low_temp=55; */ -/* unsigned short high_temp=65; */ -/* unsigned short max_temp=80; */ - -/* temperature polling interval */ -unsigned short polling_interval=10; - - -/* Controls the speed of the fan */ -void set_fan_speed(unsigned short speed) -{ - FILE *file; - - file=fopen("/sys/devices/platform/applesmc.768/fan1_min", "w"); - fprintf(file, "%d", speed); - fclose(file); -} - - -/* Takes "manual" control of fan */ -/* void prepare_fan() */ -/* { */ -/* FILE *file; */ -/* */ -/* file=fopen("/sys/devices/platform/applesmc.768/fan1_manual", "w"); */ -/* fprintf(file, "%d", 1); */ -/* fclose(file); */ -/* } */ - - -/* Returns average CPU temp in degrees (ceiling) */ -unsigned short get_temp() -{ - FILE *file; - unsigned short temp; - unsigned int t0, t1; - - file=fopen("/sys/devices/platform/coretemp.0/temp2_input", "r"); - fscanf(file, "%d", &t0); - fclose(file); - - file=fopen("/sys/devices/platform/coretemp.0/temp3_input", "r"); - fscanf(file, "%d", &t1); - fclose(file); - - temp = (unsigned short)(ceil((float)(t0 + t1) / 2000.)); - return temp; -} - - -int main() -{ - unsigned short old_temp, new_temp, fan_speed, steps; - short temp_change; - float step_up, step_down; - - /* prepare_fan(); */ - - /* assume running on boot so set fan speed to minimum */ - new_temp = get_temp(); - fan_speed = 2000; - set_fan_speed(fan_speed); - sleep(polling_interval); - - step_up = (float)(max_fan_speed - min_fan_speed) / - (float)((max_temp - high_temp) * (max_temp - high_temp + 1) / 2); - - step_down = (float)(max_fan_speed - min_fan_speed) / - (float)((max_temp - low_temp) * (max_temp - low_temp + 1) / 2); - - while(1) - { - old_temp = new_temp; - new_temp = get_temp(); - - if(new_temp >= max_temp && fan_speed != max_fan_speed) { - fan_speed = max_fan_speed; - } - - if(new_temp <= low_temp && fan_speed != min_fan_speed) { - fan_speed = min_fan_speed; - } - - temp_change = new_temp - old_temp; - - if(temp_change > 0 && new_temp > high_temp && new_temp < max_temp) { - steps = (new_temp - high_temp) * (new_temp - high_temp + 1) / 2; - fan_speed = max(fan_speed, ceil(min_fan_speed + steps * step_up)); - } - - if(temp_change < 0 && new_temp > low_temp && new_temp < max_temp) { - steps = (max_temp - new_temp) * (max_temp - new_temp + 1) / 2; - fan_speed = min(fan_speed, floor(max_fan_speed - steps * step_down)); - } - - set_fan_speed(fan_speed); - sleep(polling_interval); - } - - return 0; -} diff --git a/mbpfan.rc b/mbpfan.rc-BROKEN similarity index 100% rename from mbpfan.rc rename to mbpfan.rc-BROKEN diff --git a/src/mbpfan.c b/src/mbpfan.c new file mode 100644 index 0000000..5ca8931 --- /dev/null +++ b/src/mbpfan.c @@ -0,0 +1,261 @@ +/** + * mbpfan.c - automatically control fan for MacBook Pro + * Copyright (C) 2010 Allan McRae + * Modifications by Rafael Vega + * Modifications (2012) by Daniel Graziotin + * + * 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 3 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. + * + * 2012-06-09 - v1.2 + * + * Notes: + * Assumes any number of processors and fans (max. 10) + * It Uses only the temperatures from the processors as input. + * Requires coretemp and applesmc kernel modules to be loaded. + * Requires root use + * + * Tested models: + * MacBook Pro 8.1 13" (Intel i7 - Linux 3.2) + * Macbook Pro 6,2 15" (Intel i7 - Linux 3.2) + */ + + +#include +#include +#include +#include +#include +#include "mbpfan.h" + +/* lazy min/max... */ +#define min(a,b) a < b ? a : b +#define max(a,b) a > b ? a : b + +unsigned short min_fan_speed = 2000; +unsigned short max_fan_speed = 6200; + +/* temperature thresholds + * low_temp - temperature below which fan speed will be at minimum + * high_temp - fan will increase speed when higher than this temperature + * max_temp - fan will run at full speed above this temperature */ +unsigned short low_temp = 63; // try ranges 55-63 +unsigned short high_temp = 66; // try ranges 58-66 +unsigned short max_temp = 86; // do not set it > 90 + +unsigned short polling_interval = 7; + + +struct s_sensors { + char* path; + char* fan_path; + unsigned int temperature; + struct s_sensors *next; +}; + +void find_fans(t_sensors* sensors) +{ + t_sensors *tmp = sensors; + + char *path = NULL; + const char *path_begin = "/sys/devices/platform/applesmc.768/fan"; + const char *path_end = "_min"; + int path_size = strlen(path_begin) + strlen(path_end) + 2; + char number[1]; + sprintf(number,"%d",0); + + int counter = 0; + + for(counter = 0; counter<10; counter++) { + path = (char*) malloc(sizeof( char ) * path_size); + path[0] = '\0'; + sprintf(number,"%d",counter); + + strncat( path, path_begin, strlen(path_begin) ); + strncat( path, number, strlen(number) ); + strncat( path, path_end, strlen(path_begin) ); + + FILE *file = fopen(path, "r"); + + if(file != NULL) { + if (tmp->path != NULL) + tmp->fan_path = (char *) malloc(sizeof( char ) * path_size); + strcpy(tmp->fan_path, path); + tmp = tmp->next; + fclose(file); + } + } + + free(path); + path = NULL; +} + + +t_sensors *find_sensors() +{ + + t_sensors *sensors_head = NULL; + t_sensors *s = NULL; + + char *path = NULL; + const char *path_begin = "/sys/devices/platform/coretemp.0/temp"; + const char *path_end = "_input"; + + int path_size = strlen(path_begin) + strlen(path_end) + 2; + char number[1]; + sprintf(number,"%d",0); + + int i = 0; + for(i = 0; i<10; i++) { + path = (char*) malloc(sizeof( char ) * path_size); + + sprintf(number,"%d",i); + path[0] = '\0'; + strncat( path, path_begin, strlen(path_begin) ); + strncat( path, number, strlen(number) ); + strncat( path, path_end, strlen(path_begin) ); + + FILE *file = fopen(path, "r"); + + if(file != NULL) { + s = (t_sensors *) malloc( sizeof( t_sensors ) ); + s->path = (char *) malloc(sizeof( char ) * path_size); + strcpy(s->path, path); + int result = fscanf(file, "%d", &s->temperature); + if (sensors_head == NULL) { + sensors_head = s; + sensors_head->next = NULL; + } else { + t_sensors *tmp = sensors_head; + while (tmp->next != NULL) { + tmp = tmp->next; + } + tmp->next = s; + tmp->next->next = NULL; + } + fclose(file); + } + free(path); + path = NULL; + } + if(sensors_head != NULL) + find_fans(sensors_head); + return sensors_head; +} + +t_sensors *refresh_sensors(t_sensors *sensors) +{ + + t_sensors *tmp = sensors; + + while(tmp != NULL) { + FILE *file = fopen(tmp->path, "r"); + + if(file != NULL) { + int result = fscanf(file, "%d", &tmp->temperature); + fclose(file); + } + + tmp = tmp->next; + } + return sensors; +} + + + +/* Controls the speed of the fan */ +void set_fan_speed(t_sensors* sensors, unsigned short speed) +{ + + t_sensors *tmp = sensors; + + while(tmp != NULL) { + FILE *file = fopen(tmp->path, "rw"); + + if(file != NULL) { + fprintf(file, "%d", speed); + fclose(file); + } + + tmp = tmp->next; + } + +} + + + +/* Returns average CPU temp in degrees (ceiling) */ +unsigned short get_temp(t_sensors* sensors) +{ + sensors = refresh_sensors(sensors); + int sum_temp = 0; + unsigned short temp = 0; + + t_sensors* tmp = sensors; + while(tmp != NULL) { + sum_temp += tmp->temperature; + tmp = tmp->next; + } + temp = (unsigned short)( ceil( (float)( sum_temp ) / 2000. ) ); + return temp; +} + + +int main() +{ + unsigned short old_temp, new_temp, fan_speed, steps; + short temp_change; + float step_up, step_down; + + t_sensors* sensors = find_sensors(); + + new_temp = get_temp(sensors); + fan_speed = 2000; + set_fan_speed(sensors, fan_speed); + sleep(polling_interval); + + step_up = (float)( max_fan_speed - min_fan_speed ) / + (float)( ( max_temp - high_temp ) * ( max_temp - high_temp + 1 ) / 2 ); + + step_down = (float)( max_fan_speed - min_fan_speed ) / + (float)( ( max_temp - low_temp ) * ( max_temp - low_temp + 1 ) / 2 ); + + while(1) { + old_temp = new_temp; + new_temp = get_temp(sensors); + + if(new_temp >= max_temp && fan_speed != max_fan_speed) { + fan_speed = max_fan_speed; + } + + if(new_temp <= low_temp && fan_speed != min_fan_speed) { + fan_speed = min_fan_speed; + } + + temp_change = new_temp - old_temp; + + if(temp_change > 0 && new_temp > high_temp && new_temp < max_temp) { + steps = ( new_temp - high_temp ) * ( new_temp - high_temp + 1 ) / 2; + fan_speed = max( fan_speed, ceil(min_fan_speed + steps * step_up) ); + } + + if(temp_change < 0 && new_temp > low_temp && new_temp < max_temp) { + steps = ( max_temp - new_temp ) * ( max_temp - new_temp + 1 ) / 2; + fan_speed = min( fan_speed, floor(max_fan_speed - steps * step_down) ); + } + + set_fan_speed(sensors, fan_speed); + sleep(polling_interval); + printf("Old Temp %d: New Temp: %d, Fan Speed: %d\n", old_temp, new_temp, fan_speed); + + } + + return 0; +} diff --git a/src/mbpfan.h b/src/mbpfan.h new file mode 100644 index 0000000..33a4a9b --- /dev/null +++ b/src/mbpfan.h @@ -0,0 +1,41 @@ +/** Basic fan speed parameters + */ +extern unsigned short min_fan_speed; +extern unsigned short max_fan_speed; + +/** Temperature Thresholds + * low_temp - temperature below which fan speed will be at minimum + * high_temp - fan will increase speed when higher than this temperature + * max_temp - fan will run at full speed above this temperature */ +extern unsigned short low_temp; +extern unsigned short high_temp; +extern unsigned short max_temp; + + +/** Temperature polling interval + * Default value was 10 (seconds) + */ +extern unsigned short polling_interval; + +/** Represents a Temperature sensor + */ +struct s_sensors; +typedef struct s_sensors t_sensors; + +/** + * Detect the sensors in /sys/devices/platform/coretemp.0/temp + * Return a linked list of t_sensors (first temperature detected) + */ +t_sensors *find_sensors(); + +/** + * Detect the fans in /sys/devices/platform/applesmc.768/ + * Associate each fan to a sensor + */ +void find_fans(t_sensors *sensors); + +/** + * Given a linked list of t_sensors, refresh their detected + * temperature + */ +t_sensors *refresh_sensors(t_sensors *sensors); \ No newline at end of file diff --git a/src/mbpfan.o b/src/mbpfan.o new file mode 100644 index 0000000..da206ee Binary files /dev/null and b/src/mbpfan.o differ