├── .gitignore ├── Makefile ├── README.md └── dell-bios-fan-control.c /.gitignore: -------------------------------------------------------------------------------- 1 | dell-bios-fan-control 2 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | all: dell-bios-fan-control 4 | 5 | dell-bios-fan-control: dell-bios-fan-control.c 6 | $(CC) -o $@ $^ 7 | 8 | clean: 9 | rm -f dell-bios-fan-control 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## dell-bios-fan-control 2 | 3 | #### A user space utility to set control of fans by bios on Dell 9560 Laptops. 4 | 5 | Allows to control the fans by bios or i8kctl utils. 6 | 7 | 8 | 9 | ### Usage 10 | 11 | To enable SMBIOS control: 12 | 13 |
14 | dell-bios-fan-control 1
15 | 
16 | 17 | To disable SMBIOS control: 18 | 19 |
20 | dell-bios-fan-control 0
21 | 
22 | 23 | After disabling SMBIOS control of fans you can set fan speed by i8kctl: 24 | 25 |
26 | i8kctl fan 1 1
27 | 
28 | 29 | 30 | 31 | ### Caveats 32 | 33 | * The BIOS of some newer Dell laptops (9560, ...) 34 | will override the speed you set unless you disable the BIOS control. 35 | 36 | * This tool allows to enable or disable bios control of fans to 37 | use i8kmon instead 38 | 39 | 40 | ### Credits 41 | 42 | * All credits belong to: https://github.com/clopez/dellfan 43 | -------------------------------------------------------------------------------- /dell-bios-fan-control.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dell-bios-fan-control 3 | * user space utility to set control of fans by bios on Dell 9560 Laptops. 4 | * 5 | * SMM Management code from i8k. See file drivers/char/i8k.c at Linux kernel. 6 | * 7 | * Copyright (C) 2001 Massimo Dal Zotto 8 | * Copyright (C) 2014 Carlos Alberto Lopez Perez 9 | * 10 | * This program is free software; you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation; either version 2 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program; if not, see . 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | /* 31 | * 32 | * Most of the code was taken from https://github.com/clopez/dellfan 33 | * 34 | */ 35 | 36 | #define DISABLE_BIOS_METHOD2 0x34a3 37 | #define ENABLE_BIOS_METHOD2 0x35a3 38 | 39 | void init_ioperm(void) 40 | { 41 | if (ioperm(0xb2, 4, 1) || ioperm(0x84, 4, 1)) { 42 | perror("ioperm"); 43 | exit(EXIT_FAILURE); 44 | } 45 | } 46 | 47 | struct smm_regs { 48 | unsigned int eax; 49 | unsigned int ebx __attribute__ ((packed)); 50 | unsigned int ecx __attribute__ ((packed)); 51 | unsigned int edx __attribute__ ((packed)); 52 | unsigned int esi __attribute__ ((packed)); 53 | unsigned int edi __attribute__ ((packed)); 54 | }; 55 | 56 | static int i8k_smm(struct smm_regs *regs) 57 | { 58 | int rc; 59 | int eax = regs->eax; 60 | 61 | 62 | asm volatile("pushq %%rax\n\t" 63 | "movl 0(%%rax),%%edx\n\t" 64 | "pushq %%rdx\n\t" 65 | "movl 4(%%rax),%%ebx\n\t" 66 | "movl 8(%%rax),%%ecx\n\t" 67 | "movl 12(%%rax),%%edx\n\t" 68 | "movl 16(%%rax),%%esi\n\t" 69 | "movl 20(%%rax),%%edi\n\t" 70 | "popq %%rax\n\t" 71 | "out %%al,$0xb2\n\t" 72 | "out %%al,$0x84\n\t" 73 | "xchgq %%rax,(%%rsp)\n\t" 74 | "movl %%ebx,4(%%rax)\n\t" 75 | "movl %%ecx,8(%%rax)\n\t" 76 | "movl %%edx,12(%%rax)\n\t" 77 | "movl %%esi,16(%%rax)\n\t" 78 | "movl %%edi,20(%%rax)\n\t" 79 | "popq %%rdx\n\t" 80 | "movl %%edx,0(%%rax)\n\t" 81 | "pushfq\n\t" 82 | "popq %%rax\n\t" 83 | "andl $1,%%eax\n" 84 | :"=a"(rc) 85 | : "a"(regs) 86 | : "%ebx", "%ecx", "%edx", "%esi", "%edi"); 87 | 88 | if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) 89 | return -1; 90 | 91 | return 0; 92 | } 93 | 94 | 95 | int send(unsigned int cmd, unsigned int arg) { 96 | 97 | struct smm_regs regs = { .eax = cmd, }; 98 | 99 | regs.ebx = arg; 100 | 101 | i8k_smm(®s); 102 | return regs.eax ; 103 | 104 | } 105 | 106 | int main(int argc, char **argv) { 107 | 108 | int enable; 109 | 110 | if (geteuid() != 0) { 111 | printf("need root privileges\n"); 112 | exit(EXIT_FAILURE); 113 | } 114 | 115 | if (argc != 2) { 116 | printf ("Use: %s enable\n", argv[0]); 117 | printf ("\tenable = {0,1}\n"); 118 | exit(EXIT_FAILURE); 119 | } 120 | 121 | init_ioperm(); 122 | 123 | enable = atoi(argv[1]); 124 | if (enable == 1) { 125 | send(ENABLE_BIOS_METHOD2, 0); 126 | printf ("BIOS CONTROL ENABLED\n"); 127 | } 128 | else 129 | if (enable == 0) { 130 | send(DISABLE_BIOS_METHOD2, 0); 131 | printf ("BIOS CONTROL DISABLED\n"); 132 | } 133 | else { 134 | printf ("Use 1 to enable bios control or 0 to disable\n"); 135 | exit(EXIT_FAILURE); 136 | } 137 | 138 | } 139 | --------------------------------------------------------------------------------