aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--drivers/char/i8k.c162
2 files changed, 163 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 880fcb6c86f4..dcf25b71f6d7 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -917,6 +917,7 @@ config TOSHIBA
917 917
918config I8K 918config I8K
919 tristate "Dell laptop support" 919 tristate "Dell laptop support"
920 select HWMON
920 ---help--- 921 ---help---
921 This adds a driver to safely access the System Management Mode 922 This adds a driver to safely access the System Management Mode
922 of the CPU on the Dell Inspiron 8000. The System Management Mode 923 of the CPU on the Dell Inspiron 8000. The System Management Mode
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index ee017166545e..6e40072fbf67 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -5,6 +5,9 @@
5 * 5 *
6 * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> 6 * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org>
7 * 7 *
8 * Hwmon integration:
9 * Copyright (C) 2011 Jean Delvare <khali@linux-fr.org>
10 *
8 * This program is free software; you can redistribute it and/or modify it 11 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the 12 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any 13 * Free Software Foundation; either version 2, or (at your option) any
@@ -24,6 +27,8 @@
24#include <linux/dmi.h> 27#include <linux/dmi.h>
25#include <linux/capability.h> 28#include <linux/capability.h>
26#include <linux/mutex.h> 29#include <linux/mutex.h>
30#include <linux/hwmon.h>
31#include <linux/hwmon-sysfs.h>
27#include <asm/uaccess.h> 32#include <asm/uaccess.h>
28#include <asm/io.h> 33#include <asm/io.h>
29 34
@@ -58,6 +63,7 @@
58 63
59static DEFINE_MUTEX(i8k_mutex); 64static DEFINE_MUTEX(i8k_mutex);
60static char bios_version[4]; 65static char bios_version[4];
66static struct device *i8k_hwmon_dev;
61 67
62MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); 68MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
63MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); 69MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -455,6 +461,152 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
455 return single_open(file, i8k_proc_show, NULL); 461 return single_open(file, i8k_proc_show, NULL);
456} 462}
457 463
464
465/*
466 * Hwmon interface
467 */
468
469static ssize_t i8k_hwmon_show_temp(struct device *dev,
470 struct device_attribute *devattr,
471 char *buf)
472{
473 int cpu_temp;
474
475 cpu_temp = i8k_get_temp(0);
476 if (cpu_temp < 0)
477 return cpu_temp;
478 return sprintf(buf, "%d\n", cpu_temp * 1000);
479}
480
481static ssize_t i8k_hwmon_show_fan(struct device *dev,
482 struct device_attribute *devattr,
483 char *buf)
484{
485 int index = to_sensor_dev_attr(devattr)->index;
486 int fan_speed;
487
488 fan_speed = i8k_get_fan_speed(index);
489 if (fan_speed < 0)
490 return fan_speed;
491 return sprintf(buf, "%d\n", fan_speed);
492}
493
494static ssize_t i8k_hwmon_show_label(struct device *dev,
495 struct device_attribute *devattr,
496 char *buf)
497{
498 static const char *labels[4] = {
499 "i8k",
500 "CPU",
501 "Left Fan",
502 "Right Fan",
503 };
504 int index = to_sensor_dev_attr(devattr)->index;
505
506 return sprintf(buf, "%s\n", labels[index]);
507}
508
509static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL);
510static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
511 I8K_FAN_LEFT);
512static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
513 I8K_FAN_RIGHT);
514static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
515static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
516static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
517static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3);
518
519static void i8k_hwmon_remove_files(struct device *dev)
520{
521 device_remove_file(dev, &dev_attr_temp1_input);
522 device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr);
523 device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr);
524 device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr);
525 device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr);
526 device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr);
527 device_remove_file(dev, &sensor_dev_attr_name.dev_attr);
528}
529
530static int __init i8k_init_hwmon(void)
531{
532 int err;
533
534 i8k_hwmon_dev = hwmon_device_register(NULL);
535 if (IS_ERR(i8k_hwmon_dev)) {
536 err = PTR_ERR(i8k_hwmon_dev);
537 i8k_hwmon_dev = NULL;
538 printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err);
539 return err;
540 }
541
542 /* Required name attribute */
543 err = device_create_file(i8k_hwmon_dev,
544 &sensor_dev_attr_name.dev_attr);
545 if (err)
546 goto exit_unregister;
547
548 /* CPU temperature attributes, if temperature reading is OK */
549 err = i8k_get_temp(0);
550 if (err < 0) {
551 dev_dbg(i8k_hwmon_dev,
552 "Not creating temperature attributes (%d)\n", err);
553 } else {
554 err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input);
555 if (err)
556 goto exit_remove_files;
557 err = device_create_file(i8k_hwmon_dev,
558 &sensor_dev_attr_temp1_label.dev_attr);
559 if (err)
560 goto exit_remove_files;
561 }
562
563 /* Left fan attributes, if left fan is present */
564 err = i8k_get_fan_status(I8K_FAN_LEFT);
565 if (err < 0) {
566 dev_dbg(i8k_hwmon_dev,
567 "Not creating %s fan attributes (%d)\n", "left", err);
568 } else {
569 err = device_create_file(i8k_hwmon_dev,
570 &sensor_dev_attr_fan1_input.dev_attr);
571 if (err)
572 goto exit_remove_files;
573 err = device_create_file(i8k_hwmon_dev,
574 &sensor_dev_attr_fan1_label.dev_attr);
575 if (err)
576 goto exit_remove_files;
577 }
578
579 /* Right fan attributes, if right fan is present */
580 err = i8k_get_fan_status(I8K_FAN_RIGHT);
581 if (err < 0) {
582 dev_dbg(i8k_hwmon_dev,
583 "Not creating %s fan attributes (%d)\n", "right", err);
584 } else {
585 err = device_create_file(i8k_hwmon_dev,
586 &sensor_dev_attr_fan2_input.dev_attr);
587 if (err)
588 goto exit_remove_files;
589 err = device_create_file(i8k_hwmon_dev,
590 &sensor_dev_attr_fan2_label.dev_attr);
591 if (err)
592 goto exit_remove_files;
593 }
594
595 return 0;
596
597 exit_remove_files:
598 i8k_hwmon_remove_files(i8k_hwmon_dev);
599 exit_unregister:
600 hwmon_device_unregister(i8k_hwmon_dev);
601 return err;
602}
603
604static void __exit i8k_exit_hwmon(void)
605{
606 i8k_hwmon_remove_files(i8k_hwmon_dev);
607 hwmon_device_unregister(i8k_hwmon_dev);
608}
609
458static struct dmi_system_id __initdata i8k_dmi_table[] = { 610static struct dmi_system_id __initdata i8k_dmi_table[] = {
459 { 611 {
460 .ident = "Dell Inspiron", 612 .ident = "Dell Inspiron",
@@ -580,6 +732,7 @@ static int __init i8k_probe(void)
580static int __init i8k_init(void) 732static int __init i8k_init(void)
581{ 733{
582 struct proc_dir_entry *proc_i8k; 734 struct proc_dir_entry *proc_i8k;
735 int err;
583 736
584 /* Are we running on an supported laptop? */ 737 /* Are we running on an supported laptop? */
585 if (i8k_probe()) 738 if (i8k_probe())
@@ -590,15 +743,24 @@ static int __init i8k_init(void)
590 if (!proc_i8k) 743 if (!proc_i8k)
591 return -ENOENT; 744 return -ENOENT;
592 745
746 err = i8k_init_hwmon();
747 if (err)
748 goto exit_remove_proc;
749
593 printk(KERN_INFO 750 printk(KERN_INFO
594 "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", 751 "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
595 I8K_VERSION); 752 I8K_VERSION);
596 753
597 return 0; 754 return 0;
755
756 exit_remove_proc:
757 remove_proc_entry("i8k", NULL);
758 return err;
598} 759}
599 760
600static void __exit i8k_exit(void) 761static void __exit i8k_exit(void)
601{ 762{
763 i8k_exit_hwmon();
602 remove_proc_entry("i8k", NULL); 764 remove_proc_entry("i8k", NULL);
603} 765}
604 766