22 #include <linux/module.h>
23 #include <linux/types.h>
28 #include <linux/capability.h>
32 #include <asm/uaccess.h>
37 #define I8K_VERSION "1.14 21/02/2005"
39 #define I8K_SMM_FN_STATUS 0x0025
40 #define I8K_SMM_POWER_STATUS 0x0069
41 #define I8K_SMM_SET_FAN 0x01a3
42 #define I8K_SMM_GET_FAN 0x00a3
43 #define I8K_SMM_GET_SPEED 0x02a3
44 #define I8K_SMM_GET_TEMP 0x10a3
45 #define I8K_SMM_GET_DELL_SIG1 0xfea3
46 #define I8K_SMM_GET_DELL_SIG2 0xffa3
47 #define I8K_SMM_BIOS_VERSION 0x00a6
49 #define I8K_FAN_MULT 30
50 #define I8K_MAX_TEMP 127
52 #define I8K_FN_NONE 0x00
53 #define I8K_FN_UP 0x01
54 #define I8K_FN_DOWN 0x02
55 #define I8K_FN_MUTE 0x04
56 #define I8K_FN_MASK 0x07
57 #define I8K_FN_SHIFT 8
59 #define I8K_POWER_AC 0x05
60 #define I8K_POWER_BATTERY 0x01
62 #define I8K_TEMPERATURE_BUG 1
65 static char bios_version[4];
66 static struct device *i8k_hwmon_dev;
76 static bool ignore_dmi;
78 MODULE_PARM_DESC(ignore_dmi,
"Continue probing hardware even if DMI data does not match");
80 static bool restricted;
82 MODULE_PARM_DESC(restricted,
"Allow fan control if SYS_ADMIN capability set");
84 static bool power_status;
93 static long i8k_ioctl(
struct file *,
unsigned int,
unsigned long);
101 .unlocked_ioctl = i8k_ioctl,
113 static inline const char *i8k_get_dmi_data(
int field)
117 return dmi_data && *dmi_data ? dmi_data :
"?";
128 #if defined(CONFIG_X86_64)
129 asm volatile(
"pushq %%rax\n\t"
130 "movl 0(%%rax),%%edx\n\t"
132 "movl 4(%%rax),%%ebx\n\t"
133 "movl 8(%%rax),%%ecx\n\t"
134 "movl 12(%%rax),%%edx\n\t"
135 "movl 16(%%rax),%%esi\n\t"
136 "movl 20(%%rax),%%edi\n\t"
140 "xchgq %%rax,(%%rsp)\n\t"
141 "movl %%ebx,4(%%rax)\n\t"
142 "movl %%ecx,8(%%rax)\n\t"
143 "movl %%edx,12(%%rax)\n\t"
144 "movl %%esi,16(%%rax)\n\t"
145 "movl %%edi,20(%%rax)\n\t"
147 "movl %%edx,0(%%rax)\n\t"
153 :
"%ebx",
"%ecx",
"%edx",
"%esi",
"%edi",
"memory");
155 asm volatile(
"pushl %%eax\n\t"
156 "movl 0(%%eax),%%edx\n\t"
158 "movl 4(%%eax),%%ebx\n\t"
159 "movl 8(%%eax),%%ecx\n\t"
160 "movl 12(%%eax),%%edx\n\t"
161 "movl 16(%%eax),%%esi\n\t"
162 "movl 20(%%eax),%%edi\n\t"
166 "xchgl %%eax,(%%esp)\n\t"
167 "movl %%ebx,4(%%eax)\n\t"
168 "movl %%ecx,8(%%eax)\n\t"
169 "movl %%edx,12(%%eax)\n\t"
170 "movl %%esi,16(%%eax)\n\t"
171 "movl %%edi,20(%%eax)\n\t"
173 "movl %%edx,0(%%eax)\n\t"
179 :
"%ebx",
"%ecx",
"%edx",
"%esi",
"%edi",
"memory");
181 if (rc != 0 || (regs->
eax & 0xffff) == 0xffff || regs->
eax == eax)
191 static int i8k_get_bios_version(
void)
195 return i8k_smm(®s) ? : regs.
eax;
201 static int i8k_get_fn_status(
void)
206 if ((rc = i8k_smm(®s)) < 0)
224 static int i8k_get_power_status(
void)
229 if ((rc = i8k_smm(®s)) < 0)
238 static int i8k_get_fan_status(
int fan)
242 regs.ebx = fan & 0xff;
243 return i8k_smm(®s) ? : regs.
eax & 0xff;
249 static int i8k_get_fan_speed(
int fan)
253 regs.ebx = fan & 0xff;
254 return i8k_smm(®s) ? : (regs.
eax & 0xffff) * fan_mult;
260 static int i8k_set_fan(
int fan,
int speed)
265 regs.ebx = (fan & 0xff) | (speed << 8);
267 return i8k_smm(®s) ? : i8k_get_fan_status(fan);
273 static int i8k_get_temp(
int sensor)
279 #ifdef I8K_TEMPERATURE_BUG
282 regs.ebx = sensor & 0xff;
283 if ((rc = i8k_smm(®s)) < 0)
286 temp = regs.
eax & 0xff;
288 #ifdef I8K_TEMPERATURE_BUG
307 static int i8k_get_dell_signature(
int req_fn)
312 if ((rc = i8k_smm(®s)) < 0)
315 return regs.
eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
319 i8k_ioctl_unlocked(
struct file *
fp,
unsigned int cmd,
unsigned long arg)
323 unsigned char buff[16];
331 val = i8k_get_bios_version();
340 val = i8k_get_fn_status();
344 val = i8k_get_power_status();
348 val = i8k_get_temp(0);
355 val = i8k_get_fan_speed(val);
362 val = i8k_get_fan_status(val);
375 val = i8k_set_fan(val, speed);
406 static long i8k_ioctl(
struct file *fp,
unsigned int cmd,
unsigned long arg)
411 ret = i8k_ioctl_unlocked(fp, cmd, arg);
423 int left_fan, right_fan, left_speed, right_speed;
425 cpu_temp = i8k_get_temp(0);
430 fn_key = i8k_get_fn_status();
432 ac_power = i8k_get_power_status();
450 return seq_printf(seq,
"%s %s %s %d %d %d %d %d %d %d\n",
455 left_fan, right_fan, left_speed, right_speed,
475 cpu_temp = i8k_get_temp(0);
478 return sprintf(buf,
"%d\n", cpu_temp * 1000);
488 fan_speed = i8k_get_fan_speed(index);
491 return sprintf(buf,
"%d\n", fan_speed);
498 static const char *labels[4] = {
506 return sprintf(buf,
"%s\n", labels[index]);
519 static void i8k_hwmon_remove_files(
struct device *dev)
530 static int __init i8k_init_hwmon(
void)
535 if (IS_ERR(i8k_hwmon_dev)) {
536 err = PTR_ERR(i8k_hwmon_dev);
537 i8k_hwmon_dev =
NULL;
544 &sensor_dev_attr_name.dev_attr);
546 goto exit_unregister;
549 err = i8k_get_temp(0);
552 "Not creating temperature attributes (%d)\n", err);
556 goto exit_remove_files;
558 &sensor_dev_attr_temp1_label.dev_attr);
560 goto exit_remove_files;
567 "Not creating %s fan attributes (%d)\n",
"left", err);
570 &sensor_dev_attr_fan1_input.dev_attr);
572 goto exit_remove_files;
574 &sensor_dev_attr_fan1_label.dev_attr);
576 goto exit_remove_files;
583 "Not creating %s fan attributes (%d)\n",
"right", err);
586 &sensor_dev_attr_fan2_input.dev_attr);
588 goto exit_remove_files;
590 &sensor_dev_attr_fan2_label.dev_attr);
592 goto exit_remove_files;
598 i8k_hwmon_remove_files(i8k_hwmon_dev);
604 static void __exit i8k_exit_hwmon(
void)
606 i8k_hwmon_remove_files(i8k_hwmon_dev);
612 .ident =
"Dell Inspiron",
619 .ident =
"Dell Latitude",
626 .ident =
"Dell Inspiron 2",
633 .ident =
"Dell Latitude 2",
640 .ident =
"Dell Inspiron 3",
647 .ident =
"Dell Inspiron 3",
654 .ident =
"Dell Precision",
661 .ident =
"Dell Vostro",
673 static int __init i8k_probe(
void)
682 if (!ignore_dmi && !
force)
707 version = i8k_get_bios_version();
711 buff[0] = (version >> 16) & 0xff;
712 buff[1] = (version >> 8) & 0xff;
719 strlcpy(bios_version, buff,
sizeof(bios_version));
724 if (
strncmp(buff, bios_version,
sizeof(bios_version)) != 0)
732 static int __init i8k_init(
void)
742 proc_i8k = proc_create(
"i8k", 0,
NULL, &i8k_fops);
746 err = i8k_init_hwmon();
748 goto exit_remove_proc;
761 static void __exit i8k_exit(
void)