├── .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 |
--------------------------------------------------------------------------------