Commit 949a9d70 authored by Jean Delvare's avatar Jean Delvare Committed by Jean Delvare

i8k: Integrate with the hwmon subsystem

Let i8k create an hwmon class device so that libsensors will expose
the CPU temperature and fan speeds to monitoring applications.
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Acked-by: default avatarGuenter Roeck <guenter.roeck@ericsson.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Massimo Dal Zotto <dz@debian.org>
parent 9c084dae
...@@ -917,6 +917,7 @@ config TOSHIBA ...@@ -917,6 +917,7 @@ config TOSHIBA
config I8K config I8K
tristate "Dell laptop support" tristate "Dell laptop support"
select HWMON
---help--- ---help---
This adds a driver to safely access the System Management Mode This adds a driver to safely access the System Management Mode
of the CPU on the Dell Inspiron 8000. The System Management Mode of the CPU on the Dell Inspiron 8000. The System Management Mode
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
* *
* Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org> * Copyright (C) 2001 Massimo Dal Zotto <dz@debian.org>
* *
* Hwmon integration:
* Copyright (C) 2011 Jean Delvare <khali@linux-fr.org>
*
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any * Free Software Foundation; either version 2, or (at your option) any
...@@ -24,6 +27,8 @@ ...@@ -24,6 +27,8 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -58,6 +63,7 @@ ...@@ -58,6 +63,7 @@
static DEFINE_MUTEX(i8k_mutex); static DEFINE_MUTEX(i8k_mutex);
static char bios_version[4]; static char bios_version[4];
static struct device *i8k_hwmon_dev;
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); MODULE_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,6 +461,152 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
return single_open(file, i8k_proc_show, NULL); return single_open(file, i8k_proc_show, NULL);
} }
/*
* Hwmon interface
*/
static ssize_t i8k_hwmon_show_temp(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
int cpu_temp;
cpu_temp = i8k_get_temp(0);
if (cpu_temp < 0)
return cpu_temp;
return sprintf(buf, "%d\n", cpu_temp * 1000);
}
static ssize_t i8k_hwmon_show_fan(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
int index = to_sensor_dev_attr(devattr)->index;
int fan_speed;
fan_speed = i8k_get_fan_speed(index);
if (fan_speed < 0)
return fan_speed;
return sprintf(buf, "%d\n", fan_speed);
}
static ssize_t i8k_hwmon_show_label(struct device *dev,
struct device_attribute *devattr,
char *buf)
{
static const char *labels[4] = {
"i8k",
"CPU",
"Left Fan",
"Right Fan",
};
int index = to_sensor_dev_attr(devattr)->index;
return sprintf(buf, "%s\n", labels[index]);
}
static DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL);
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
I8K_FAN_LEFT);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
I8K_FAN_RIGHT);
static SENSOR_DEVICE_ATTR(name, S_IRUGO, i8k_hwmon_show_label, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1);
static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2);
static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 3);
static void i8k_hwmon_remove_files(struct device *dev)
{
device_remove_file(dev, &dev_attr_temp1_input);
device_remove_file(dev, &sensor_dev_attr_fan1_input.dev_attr);
device_remove_file(dev, &sensor_dev_attr_fan2_input.dev_attr);
device_remove_file(dev, &sensor_dev_attr_temp1_label.dev_attr);
device_remove_file(dev, &sensor_dev_attr_fan1_label.dev_attr);
device_remove_file(dev, &sensor_dev_attr_fan2_label.dev_attr);
device_remove_file(dev, &sensor_dev_attr_name.dev_attr);
}
static int __init i8k_init_hwmon(void)
{
int err;
i8k_hwmon_dev = hwmon_device_register(NULL);
if (IS_ERR(i8k_hwmon_dev)) {
err = PTR_ERR(i8k_hwmon_dev);
i8k_hwmon_dev = NULL;
printk(KERN_ERR "i8k: hwmon registration failed (%d)\n", err);
return err;
}
/* Required name attribute */
err = device_create_file(i8k_hwmon_dev,
&sensor_dev_attr_name.dev_attr);
if (err)
goto exit_unregister;
/* CPU temperature attributes, if temperature reading is OK */
err = i8k_get_temp(0);
if (err < 0) {
dev_dbg(i8k_hwmon_dev,
"Not creating temperature attributes (%d)\n", err);
} else {
err = device_create_file(i8k_hwmon_dev, &dev_attr_temp1_input);
if (err)
goto exit_remove_files;
err = device_create_file(i8k_hwmon_dev,
&sensor_dev_attr_temp1_label.dev_attr);
if (err)
goto exit_remove_files;
}
/* Left fan attributes, if left fan is present */
err = i8k_get_fan_status(I8K_FAN_LEFT);
if (err < 0) {
dev_dbg(i8k_hwmon_dev,
"Not creating %s fan attributes (%d)\n", "left", err);
} else {
err = device_create_file(i8k_hwmon_dev,
&sensor_dev_attr_fan1_input.dev_attr);
if (err)
goto exit_remove_files;
err = device_create_file(i8k_hwmon_dev,
&sensor_dev_attr_fan1_label.dev_attr);
if (err)
goto exit_remove_files;
}
/* Right fan attributes, if right fan is present */
err = i8k_get_fan_status(I8K_FAN_RIGHT);
if (err < 0) {
dev_dbg(i8k_hwmon_dev,
"Not creating %s fan attributes (%d)\n", "right", err);
} else {
err = device_create_file(i8k_hwmon_dev,
&sensor_dev_attr_fan2_input.dev_attr);
if (err)
goto exit_remove_files;
err = device_create_file(i8k_hwmon_dev,
&sensor_dev_attr_fan2_label.dev_attr);
if (err)
goto exit_remove_files;
}
return 0;
exit_remove_files:
i8k_hwmon_remove_files(i8k_hwmon_dev);
exit_unregister:
hwmon_device_unregister(i8k_hwmon_dev);
return err;
}
static void __exit i8k_exit_hwmon(void)
{
i8k_hwmon_remove_files(i8k_hwmon_dev);
hwmon_device_unregister(i8k_hwmon_dev);
}
static struct dmi_system_id __initdata i8k_dmi_table[] = { static struct dmi_system_id __initdata i8k_dmi_table[] = {
{ {
.ident = "Dell Inspiron", .ident = "Dell Inspiron",
...@@ -580,6 +732,7 @@ static int __init i8k_probe(void) ...@@ -580,6 +732,7 @@ static int __init i8k_probe(void)
static int __init i8k_init(void) static int __init i8k_init(void)
{ {
struct proc_dir_entry *proc_i8k; struct proc_dir_entry *proc_i8k;
int err;
/* Are we running on an supported laptop? */ /* Are we running on an supported laptop? */
if (i8k_probe()) if (i8k_probe())
...@@ -590,15 +743,24 @@ static int __init i8k_init(void) ...@@ -590,15 +743,24 @@ static int __init i8k_init(void)
if (!proc_i8k) if (!proc_i8k)
return -ENOENT; return -ENOENT;
err = i8k_init_hwmon();
if (err)
goto exit_remove_proc;
printk(KERN_INFO printk(KERN_INFO
"Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
I8K_VERSION); I8K_VERSION);
return 0; return 0;
exit_remove_proc:
remove_proc_entry("i8k", NULL);
return err;
} }
static void __exit i8k_exit(void) static void __exit i8k_exit(void)
{ {
i8k_exit_hwmon();
remove_proc_entry("i8k", NULL); remove_proc_entry("i8k", NULL);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment