i8k: Convert to use pr_ functions instead of printk
[deliverable/linux.git] / drivers / char / i8k.c
CommitLineData
1da177e4
LT
1/*
2 * i8k.c -- Linux driver for accessing the SMM BIOS on Dell laptops.
3 * See http://www.debian.org/~dz/i8k/ for more information
4 * and for latest version of this driver.
5 *
6 * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org>
7 *
949a9d70
JD
8 * Hwmon integration:
9 * Copyright (C) 2011 Jean Delvare <khali@linux-fr.org>
10 *
1da177e4
LT
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2, or (at your option) any
14 * later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 */
21
60e71aaf
GR
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
1da177e4
LT
24#include <linux/module.h>
25#include <linux/types.h>
26#include <linux/init.h>
27#include <linux/proc_fs.h>
352f8f8b 28#include <linux/seq_file.h>
e70c9d5e 29#include <linux/dmi.h>
7e80d0d0 30#include <linux/capability.h>
613655fa 31#include <linux/mutex.h>
949a9d70
JD
32#include <linux/hwmon.h>
33#include <linux/hwmon-sysfs.h>
1da177e4
LT
34#include <asm/uaccess.h>
35#include <asm/io.h>
36
37#include <linux/i8k.h>
38
352f8f8b 39#define I8K_VERSION "1.14 21/02/2005"
1da177e4
LT
40
41#define I8K_SMM_FN_STATUS 0x0025
42#define I8K_SMM_POWER_STATUS 0x0069
43#define I8K_SMM_SET_FAN 0x01a3
44#define I8K_SMM_GET_FAN 0x00a3
45#define I8K_SMM_GET_SPEED 0x02a3
46#define I8K_SMM_GET_TEMP 0x10a3
7e0fa31d
DT
47#define I8K_SMM_GET_DELL_SIG1 0xfea3
48#define I8K_SMM_GET_DELL_SIG2 0xffa3
1da177e4
LT
49#define I8K_SMM_BIOS_VERSION 0x00a6
50
51#define I8K_FAN_MULT 30
52#define I8K_MAX_TEMP 127
53
54#define I8K_FN_NONE 0x00
55#define I8K_FN_UP 0x01
56#define I8K_FN_DOWN 0x02
57#define I8K_FN_MUTE 0x04
58#define I8K_FN_MASK 0x07
59#define I8K_FN_SHIFT 8
60
61#define I8K_POWER_AC 0x05
62#define I8K_POWER_BATTERY 0x01
63
64#define I8K_TEMPERATURE_BUG 1
65
613655fa 66static DEFINE_MUTEX(i8k_mutex);
e70c9d5e 67static char bios_version[4];
949a9d70 68static struct device *i8k_hwmon_dev;
1da177e4
LT
69
70MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
71MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
72MODULE_LICENSE("GPL");
73
90ab5ee9 74static bool force;
1da177e4
LT
75module_param(force, bool, 0);
76MODULE_PARM_DESC(force, "Force loading without checking for supported models");
77
90ab5ee9 78static bool ignore_dmi;
e70c9d5e
DT
79module_param(ignore_dmi, bool, 0);
80MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
81
90ab5ee9 82static bool restricted;
1da177e4
LT
83module_param(restricted, bool, 0);
84MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
85
90ab5ee9 86static bool power_status;
1da177e4
LT
87module_param(power_status, bool, 0600);
88MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
89
4ed99a27
JE
90static int fan_mult = I8K_FAN_MULT;
91module_param(fan_mult, int, 0);
92MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
93
352f8f8b 94static int i8k_open_fs(struct inode *inode, struct file *file);
d79b6f4d 95static long i8k_ioctl(struct file *, unsigned int, unsigned long);
1da177e4 96
62322d25 97static const struct file_operations i8k_fops = {
1b502217 98 .owner = THIS_MODULE,
352f8f8b
DT
99 .open = i8k_open_fs,
100 .read = seq_read,
101 .llseek = seq_lseek,
102 .release = single_release,
d79b6f4d 103 .unlocked_ioctl = i8k_ioctl,
1da177e4
LT
104};
105
8378b924 106struct smm_regs {
dec63ec3
DT
107 unsigned int eax;
108 unsigned int ebx __attribute__ ((packed));
109 unsigned int ecx __attribute__ ((packed));
110 unsigned int edx __attribute__ ((packed));
111 unsigned int esi __attribute__ ((packed));
112 unsigned int edi __attribute__ ((packed));
8378b924 113};
1da177e4 114
1855256c 115static inline const char *i8k_get_dmi_data(int field)
e70c9d5e 116{
1855256c 117 const char *dmi_data = dmi_get_system_info(field);
4f005551
DT
118
119 return dmi_data && *dmi_data ? dmi_data : "?";
e70c9d5e 120}
1da177e4
LT
121
122/*
123 * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
124 */
8378b924 125static int i8k_smm(struct smm_regs *regs)
1da177e4 126{
dec63ec3
DT
127 int rc;
128 int eax = regs->eax;
129
fe04f22f 130#if defined(CONFIG_X86_64)
22d3243d 131 asm volatile("pushq %%rax\n\t"
fe04f22f
BS
132 "movl 0(%%rax),%%edx\n\t"
133 "pushq %%rdx\n\t"
134 "movl 4(%%rax),%%ebx\n\t"
135 "movl 8(%%rax),%%ecx\n\t"
136 "movl 12(%%rax),%%edx\n\t"
137 "movl 16(%%rax),%%esi\n\t"
138 "movl 20(%%rax),%%edi\n\t"
139 "popq %%rax\n\t"
140 "out %%al,$0xb2\n\t"
141 "out %%al,$0x84\n\t"
142 "xchgq %%rax,(%%rsp)\n\t"
143 "movl %%ebx,4(%%rax)\n\t"
144 "movl %%ecx,8(%%rax)\n\t"
145 "movl %%edx,12(%%rax)\n\t"
146 "movl %%esi,16(%%rax)\n\t"
147 "movl %%edi,20(%%rax)\n\t"
148 "popq %%rdx\n\t"
149 "movl %%edx,0(%%rax)\n\t"
bc1f419c
LT
150 "pushfq\n\t"
151 "popq %%rax\n\t"
fe04f22f 152 "andl $1,%%eax\n"
22d3243d 153 :"=a"(rc)
fe04f22f
BS
154 : "a"(regs)
155 : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
156#else
22d3243d 157 asm volatile("pushl %%eax\n\t"
dec63ec3
DT
158 "movl 0(%%eax),%%edx\n\t"
159 "push %%edx\n\t"
160 "movl 4(%%eax),%%ebx\n\t"
161 "movl 8(%%eax),%%ecx\n\t"
162 "movl 12(%%eax),%%edx\n\t"
163 "movl 16(%%eax),%%esi\n\t"
164 "movl 20(%%eax),%%edi\n\t"
165 "popl %%eax\n\t"
166 "out %%al,$0xb2\n\t"
167 "out %%al,$0x84\n\t"
168 "xchgl %%eax,(%%esp)\n\t"
169 "movl %%ebx,4(%%eax)\n\t"
170 "movl %%ecx,8(%%eax)\n\t"
171 "movl %%edx,12(%%eax)\n\t"
172 "movl %%esi,16(%%eax)\n\t"
173 "movl %%edi,20(%%eax)\n\t"
174 "popl %%edx\n\t"
175 "movl %%edx,0(%%eax)\n\t"
176 "lahf\n\t"
177 "shrl $8,%%eax\n\t"
6b4e81db 178 "andl $1,%%eax\n"
22d3243d 179 :"=a"(rc)
dec63ec3
DT
180 : "a"(regs)
181 : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
fe04f22f 182#endif
8378b924 183 if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
dec63ec3 184 return -EINVAL;
dec63ec3
DT
185
186 return 0;
1da177e4
LT
187}
188
189/*
190 * Read the bios version. Return the version as an integer corresponding
191 * to the ascii value, for example "A17" is returned as 0x00413137.
192 */
193static int i8k_get_bios_version(void)
194{
8378b924 195 struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, };
1da177e4 196
8378b924 197 return i8k_smm(&regs) ? : regs.eax;
1da177e4
LT
198}
199
1da177e4
LT
200/*
201 * Read the Fn key status.
202 */
203static int i8k_get_fn_status(void)
204{
8378b924 205 struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };
dec63ec3
DT
206 int rc;
207
8378b924 208 if ((rc = i8k_smm(&regs)) < 0)
dec63ec3 209 return rc;
dec63ec3
DT
210
211 switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
212 case I8K_FN_UP:
213 return I8K_VOL_UP;
214 case I8K_FN_DOWN:
215 return I8K_VOL_DOWN;
216 case I8K_FN_MUTE:
217 return I8K_VOL_MUTE;
218 default:
219 return 0;
220 }
1da177e4
LT
221}
222
223/*
224 * Read the power status.
225 */
226static int i8k_get_power_status(void)
227{
8378b924 228 struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };
dec63ec3
DT
229 int rc;
230
8378b924 231 if ((rc = i8k_smm(&regs)) < 0)
dec63ec3 232 return rc;
dec63ec3 233
8378b924 234 return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;
1da177e4
LT
235}
236
237/*
238 * Read the fan status.
239 */
240static int i8k_get_fan_status(int fan)
241{
8378b924 242 struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
1da177e4 243
dec63ec3 244 regs.ebx = fan & 0xff;
8378b924 245 return i8k_smm(&regs) ? : regs.eax & 0xff;
1da177e4
LT
246}
247
248/*
249 * Read the fan speed in RPM.
250 */
251static int i8k_get_fan_speed(int fan)
252{
8378b924 253 struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
1da177e4 254
dec63ec3 255 regs.ebx = fan & 0xff;
4ed99a27 256 return i8k_smm(&regs) ? : (regs.eax & 0xffff) * fan_mult;
1da177e4
LT
257}
258
259/*
260 * Set the fan speed (off, low, high). Returns the new fan status.
261 */
262static int i8k_set_fan(int fan, int speed)
263{
8378b924 264 struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
1da177e4 265
dec63ec3 266 speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
dec63ec3 267 regs.ebx = (fan & 0xff) | (speed << 8);
1da177e4 268
8378b924 269 return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
1da177e4
LT
270}
271
272/*
273 * Read the cpu temperature.
274 */
7e0fa31d 275static int i8k_get_temp(int sensor)
1da177e4 276{
8378b924 277 struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
dec63ec3
DT
278 int rc;
279 int temp;
1da177e4
LT
280
281#ifdef I8K_TEMPERATURE_BUG
8378b924 282 static int prev;
1da177e4 283#endif
7e0fa31d 284 regs.ebx = sensor & 0xff;
8378b924 285 if ((rc = i8k_smm(&regs)) < 0)
dec63ec3 286 return rc;
8378b924 287
dec63ec3 288 temp = regs.eax & 0xff;
1da177e4
LT
289
290#ifdef I8K_TEMPERATURE_BUG
dec63ec3
DT
291 /*
292 * Sometimes the temperature sensor returns 0x99, which is out of range.
293 * In this case we return (once) the previous cached value. For example:
294 # 1003655137 00000058 00005a4b
295 # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
296 # 1003655139 00000054 00005c52
297 */
298 if (temp > I8K_MAX_TEMP) {
299 temp = prev;
300 prev = I8K_MAX_TEMP;
301 } else {
302 prev = temp;
303 }
1da177e4
LT
304#endif
305
dec63ec3 306 return temp;
1da177e4
LT
307}
308
7e0fa31d 309static int i8k_get_dell_signature(int req_fn)
1da177e4 310{
7e0fa31d 311 struct smm_regs regs = { .eax = req_fn, };
dec63ec3 312 int rc;
1da177e4 313
8378b924 314 if ((rc = i8k_smm(&regs)) < 0)
dec63ec3 315 return rc;
1da177e4 316
8378b924 317 return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
1da177e4
LT
318}
319
d79b6f4d
FW
320static int
321i8k_ioctl_unlocked(struct file *fp, unsigned int cmd, unsigned long arg)
1da177e4 322{
e70c9d5e 323 int val = 0;
dec63ec3
DT
324 int speed;
325 unsigned char buff[16];
326 int __user *argp = (int __user *)arg;
327
328 if (!argp)
329 return -EINVAL;
330
331 switch (cmd) {
332 case I8K_BIOS_VERSION:
333 val = i8k_get_bios_version();
334 break;
335
336 case I8K_MACHINE_ID:
337 memset(buff, 0, 16);
e70c9d5e 338 strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff));
dec63ec3
DT
339 break;
340
341 case I8K_FN_STATUS:
342 val = i8k_get_fn_status();
343 break;
344
345 case I8K_POWER_STATUS:
346 val = i8k_get_power_status();
347 break;
348
349 case I8K_GET_TEMP:
7e0fa31d 350 val = i8k_get_temp(0);
dec63ec3
DT
351 break;
352
353 case I8K_GET_SPEED:
8378b924 354 if (copy_from_user(&val, argp, sizeof(int)))
dec63ec3 355 return -EFAULT;
8378b924 356
dec63ec3
DT
357 val = i8k_get_fan_speed(val);
358 break;
1da177e4 359
dec63ec3 360 case I8K_GET_FAN:
8378b924 361 if (copy_from_user(&val, argp, sizeof(int)))
dec63ec3 362 return -EFAULT;
8378b924 363
dec63ec3
DT
364 val = i8k_get_fan_status(val);
365 break;
1da177e4 366
dec63ec3 367 case I8K_SET_FAN:
8378b924 368 if (restricted && !capable(CAP_SYS_ADMIN))
dec63ec3 369 return -EPERM;
8378b924
DT
370
371 if (copy_from_user(&val, argp, sizeof(int)))
dec63ec3 372 return -EFAULT;
8378b924
DT
373
374 if (copy_from_user(&speed, argp + 1, sizeof(int)))
dec63ec3 375 return -EFAULT;
8378b924 376
dec63ec3
DT
377 val = i8k_set_fan(val, speed);
378 break;
1da177e4 379
dec63ec3
DT
380 default:
381 return -EINVAL;
1da177e4 382 }
1da177e4 383
8378b924 384 if (val < 0)
dec63ec3 385 return val;
1da177e4 386
dec63ec3
DT
387 switch (cmd) {
388 case I8K_BIOS_VERSION:
8378b924 389 if (copy_to_user(argp, &val, 4))
dec63ec3 390 return -EFAULT;
8378b924 391
dec63ec3
DT
392 break;
393 case I8K_MACHINE_ID:
8378b924 394 if (copy_to_user(argp, buff, 16))
dec63ec3 395 return -EFAULT;
8378b924 396
dec63ec3
DT
397 break;
398 default:
8378b924 399 if (copy_to_user(argp, &val, sizeof(int)))
dec63ec3 400 return -EFAULT;
8378b924 401
dec63ec3 402 break;
1da177e4 403 }
1da177e4 404
dec63ec3 405 return 0;
1da177e4
LT
406}
407
d79b6f4d
FW
408static long i8k_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
409{
410 long ret;
411
613655fa 412 mutex_lock(&i8k_mutex);
d79b6f4d 413 ret = i8k_ioctl_unlocked(fp, cmd, arg);
613655fa 414 mutex_unlock(&i8k_mutex);
d79b6f4d
FW
415
416 return ret;
417}
418
1da177e4
LT
419/*
420 * Print the information for /proc/i8k.
421 */
352f8f8b 422static int i8k_proc_show(struct seq_file *seq, void *offset)
1da177e4 423{
352f8f8b 424 int fn_key, cpu_temp, ac_power;
dec63ec3
DT
425 int left_fan, right_fan, left_speed, right_speed;
426
96de0e25
JE
427 cpu_temp = i8k_get_temp(0); /* 11100 µs */
428 left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
429 right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
430 left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
431 right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
432 fn_key = i8k_get_fn_status(); /* 750 µs */
8378b924 433 if (power_status)
96de0e25 434 ac_power = i8k_get_power_status(); /* 14700 µs */
8378b924 435 else
dec63ec3 436 ac_power = -1;
dec63ec3
DT
437
438 /*
439 * Info:
440 *
441 * 1) Format version (this will change if format changes)
442 * 2) BIOS version
443 * 3) BIOS machine ID
444 * 4) Cpu temperature
445 * 5) Left fan status
446 * 6) Right fan status
447 * 7) Left fan speed
448 * 8) Right fan speed
449 * 9) AC power
450 * 10) Fn Key status
451 */
352f8f8b
DT
452 return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
453 I8K_PROC_FMT,
454 bios_version,
4f005551 455 i8k_get_dmi_data(DMI_PRODUCT_SERIAL),
352f8f8b
DT
456 cpu_temp,
457 left_fan, right_fan, left_speed, right_speed,
458 ac_power, fn_key);
1da177e4
LT
459}
460
352f8f8b 461static int i8k_open_fs(struct inode *inode, struct file *file)
1da177e4 462{
352f8f8b 463 return single_open(file, i8k_proc_show, NULL);
1da177e4
LT
464}
465
949a9d70
JD
466
467/*
468 * Hwmon interface
469 */
470
471static ssize_t i8k_hwmon_show_temp(struct device *dev,
472 struct device_attribute *devattr,
473 char *buf)
474{
475 int cpu_temp;
476
477 cpu_temp = i8k_get_temp(0);
478 if (cpu_temp < 0)
479 return cpu_temp;
480 return sprintf(buf, "%d\n", cpu_temp * 1000);
481}
482
483static ssize_t i8k_hwmon_show_fan(struct device *dev,
484 struct device_attribute *devattr,
485 char *buf)
486{
487 int index = to_sensor_dev_attr(devattr)->index;
488 int fan_speed;
489
490 fan_speed = i8k_get_fan_speed(index);
491 if (fan_speed < 0)
492 return fan_speed;
493 return sprintf(buf, "%d\n", fan_speed);
494}
495
496static ssize_t i8k_hwmon_show_label(struct device *dev,
497 struct device_attribute *devattr,
498 char *buf)
499{
500 static const char *labels[4] = {
501 "i8k",
502 "CPU",
503 "Left Fan",
504 "Right Fan",
505 };
506 int index = to_sensor_dev_attr(devattr)->index;
507
508 return sprintf(buf, "%s\n", labels[index]);
509}
510
511static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL);
512static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
513 I8K_FAN_LEFT);
514static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
515 I8K_FAN_RIGHT);
516static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
517static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
518static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
519static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3);
520
521static void i8k_hwmon_remove_files(struct device *dev)
522{
523 device_remove_file(dev, &dev_attr_temp1_input);
524 device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr);
525 device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr);
526 device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr);
527 device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr);
528 device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr);
529 device_remove_file(dev, &sensor_dev_attr_name.dev_attr);
530}
531
532static int __init i8k_init_hwmon(void)
533{
534 int err;
535
536 i8k_hwmon_dev = hwmon_device_register(NULL);
537 if (IS_ERR(i8k_hwmon_dev)) {
538 err = PTR_ERR(i8k_hwmon_dev);
539 i8k_hwmon_dev = NULL;
60e71aaf 540 pr_err("hwmon registration failed (%d)\n", err);
949a9d70
JD
541 return err;
542 }
543
544 /* Required name attribute */
545 err = device_create_file(i8k_hwmon_dev,
546 &sensor_dev_attr_name.dev_attr);
547 if (err)
548 goto exit_unregister;
549
550 /* CPU temperature attributes, if temperature reading is OK */
551 err = i8k_get_temp(0);
552 if (err < 0) {
553 dev_dbg(i8k_hwmon_dev,
554 "Not creating temperature attributes (%d)\n", err);
555 } else {
556 err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input);
557 if (err)
558 goto exit_remove_files;
559 err = device_create_file(i8k_hwmon_dev,
560 &sensor_dev_attr_temp1_label.dev_attr);
561 if (err)
562 goto exit_remove_files;
563 }
564
565 /* Left fan attributes, if left fan is present */
566 err = i8k_get_fan_status(I8K_FAN_LEFT);
567 if (err < 0) {
568 dev_dbg(i8k_hwmon_dev,
569 "Not creating %s fan attributes (%d)\n", "left", err);
570 } else {
571 err = device_create_file(i8k_hwmon_dev,
572 &sensor_dev_attr_fan1_input.dev_attr);
573 if (err)
574 goto exit_remove_files;
575 err = device_create_file(i8k_hwmon_dev,
576 &sensor_dev_attr_fan1_label.dev_attr);
577 if (err)
578 goto exit_remove_files;
579 }
580
581 /* Right fan attributes, if right fan is present */
582 err = i8k_get_fan_status(I8K_FAN_RIGHT);
583 if (err < 0) {
584 dev_dbg(i8k_hwmon_dev,
585 "Not creating %s fan attributes (%d)\n", "right", err);
586 } else {
587 err = device_create_file(i8k_hwmon_dev,
588 &sensor_dev_attr_fan2_input.dev_attr);
589 if (err)
590 goto exit_remove_files;
591 err = device_create_file(i8k_hwmon_dev,
592 &sensor_dev_attr_fan2_label.dev_attr);
593 if (err)
594 goto exit_remove_files;
595 }
596
597 return 0;
598
599 exit_remove_files:
600 i8k_hwmon_remove_files(i8k_hwmon_dev);
601 exit_unregister:
602 hwmon_device_unregister(i8k_hwmon_dev);
603 return err;
604}
605
606static void __exit i8k_exit_hwmon(void)
607{
608 i8k_hwmon_remove_files(i8k_hwmon_dev);
609 hwmon_device_unregister(i8k_hwmon_dev);
610}
611
e70c9d5e
DT
612static struct dmi_system_id __initdata i8k_dmi_table[] = {
613 {
614 .ident = "Dell Inspiron",
615 .matches = {
616 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
617 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
618 },
619 },
620 {
621 .ident = "Dell Latitude",
622 .matches = {
623 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
624 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
625 },
626 },
7e0fa31d
DT
627 {
628 .ident = "Dell Inspiron 2",
629 .matches = {
630 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
631 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
632 },
633 },
634 {
635 .ident = "Dell Latitude 2",
636 .matches = {
637 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
638 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
639 },
640 },
a9000d03
NW
641 { /* UK Inspiron 6400 */
642 .ident = "Dell Inspiron 3",
643 .matches = {
644 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
645 DMI_MATCH(DMI_PRODUCT_NAME, "MM061"),
646 },
647 },
48103c52
FS
648 {
649 .ident = "Dell Inspiron 3",
650 .matches = {
651 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
652 DMI_MATCH(DMI_PRODUCT_NAME, "MP061"),
653 },
654 },
7ab21a86
AS
655 {
656 .ident = "Dell Precision",
657 .matches = {
658 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
659 DMI_MATCH(DMI_PRODUCT_NAME, "Precision"),
660 },
661 },
bef2a508
FH
662 {
663 .ident = "Dell Vostro",
664 .matches = {
665 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
666 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro"),
667 },
668 },
9aa5b018
AC
669 {
670 .ident = "Dell XPS421",
671 .matches = {
672 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
673 DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
674 },
675 },
bef2a508 676 { }
e70c9d5e 677};
1da177e4
LT
678
679/*
680 * Probe for the presence of a supported laptop.
681 */
682static int __init i8k_probe(void)
683{
dec63ec3
DT
684 char buff[4];
685 int version;
dec63ec3 686
1da177e4 687 /*
dec63ec3 688 * Get DMI information
1da177e4 689 */
e70c9d5e
DT
690 if (!dmi_check_system(i8k_dmi_table)) {
691 if (!ignore_dmi && !force)
692 return -ENODEV;
693
60e71aaf
GR
694 pr_info("not running on a supported Dell system.\n");
695 pr_info("vendor=%s, model=%s, version=%s\n",
e70c9d5e
DT
696 i8k_get_dmi_data(DMI_SYS_VENDOR),
697 i8k_get_dmi_data(DMI_PRODUCT_NAME),
698 i8k_get_dmi_data(DMI_BIOS_VERSION));
1da177e4 699 }
dec63ec3 700
e70c9d5e
DT
701 strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version));
702
1da177e4 703 /*
dec63ec3 704 * Get SMM Dell signature
1da177e4 705 */
7e0fa31d
DT
706 if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&
707 i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {
60e71aaf 708 pr_err("unable to get SMM Dell signature\n");
e70c9d5e
DT
709 if (!force)
710 return -ENODEV;
1da177e4 711 }
1da177e4 712
dec63ec3
DT
713 /*
714 * Get SMM BIOS version.
715 */
716 version = i8k_get_bios_version();
717 if (version <= 0) {
60e71aaf 718 pr_warn("unable to get SMM BIOS version\n");
dec63ec3 719 } else {
dec63ec3
DT
720 buff[0] = (version >> 16) & 0xff;
721 buff[1] = (version >> 8) & 0xff;
722 buff[2] = (version) & 0xff;
723 buff[3] = '\0';
724 /*
725 * If DMI BIOS version is unknown use SMM BIOS version.
726 */
e70c9d5e
DT
727 if (!dmi_get_system_info(DMI_BIOS_VERSION))
728 strlcpy(bios_version, buff, sizeof(bios_version));
729
dec63ec3
DT
730 /*
731 * Check if the two versions match.
732 */
e70c9d5e 733 if (strncmp(buff, bios_version, sizeof(bios_version)) != 0)
60e71aaf 734 pr_warn("BIOS version mismatch: %s != %s\n",
e70c9d5e 735 buff, bios_version);
dec63ec3 736 }
1da177e4 737
dec63ec3 738 return 0;
1da177e4
LT
739}
740
8378b924 741static int __init i8k_init(void)
1da177e4 742{
dec63ec3 743 struct proc_dir_entry *proc_i8k;
949a9d70 744 int err;
dec63ec3
DT
745
746 /* Are we running on an supported laptop? */
e70c9d5e 747 if (i8k_probe())
dec63ec3 748 return -ENODEV;
dec63ec3
DT
749
750 /* Register the proc entry */
1b502217 751 proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops);
352f8f8b 752 if (!proc_i8k)
dec63ec3 753 return -ENOENT;
352f8f8b 754
949a9d70
JD
755 err = i8k_init_hwmon();
756 if (err)
757 goto exit_remove_proc;
758
60e71aaf
GR
759 pr_info("Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
760 I8K_VERSION);
dec63ec3
DT
761
762 return 0;
949a9d70
JD
763
764 exit_remove_proc:
765 remove_proc_entry("i8k", NULL);
766 return err;
1da177e4
LT
767}
768
8378b924 769static void __exit i8k_exit(void)
1da177e4 770{
949a9d70 771 i8k_exit_hwmon();
dec63ec3 772 remove_proc_entry("i8k", NULL);
1da177e4 773}
1da177e4 774
8378b924
DT
775module_init(i8k_init);
776module_exit(i8k_exit);
This page took 0.729949 seconds and 5 git commands to generate.