aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2011-05-25 14:43:33 -0400
committerJean Delvare <khali@endymion.delvare>2011-05-25 14:43:33 -0400
commit949a9d70020defd7c241607ab3ed037ea88f551c (patch)
treeb366a24968110e94f0ef753558be3b9d8cbbf7b3 /drivers/char
parent9c084dae5dc7ae0039e330230e70f2a5956e566a (diff)
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: Jean Delvare <khali@linux-fr.org> Acked-by: Guenter 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>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/i8k.c162
1 files changed, 162 insertions, 0 deletions
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