aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/i8k.c
diff options
context:
space:
mode:
authorPali Rohár <pali.rohar@gmail.com>2015-01-12 08:32:05 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-25 12:17:59 -0500
commitf989e55452c74b4f7b22c889b8ec9f1192aaeec4 (patch)
tree5e0fea244bf5e28774d1682a723b0fa6d878787d /drivers/char/i8k.c
parent1a131ca1de7a84cf3827c418ee5971b493c6f23f (diff)
i8k: Add support for fan labels
This patch adds labels support for fans if SMM function with EAX register 0x03a3 reports it. This information was taken from DOS binary NBSVC.MDM. Additionally this patch change detection of fan presece. Instead reading fan status now detection is based on new label SMM function. Dell DOS binary NBSVC.MDM is doing similar checks, so we should do that too. This patch also remove I8K_FAN_LEFT and I8K_FAN_RIGHT usage from hwmon driver part because that names does not make sense anymore. So numeric constants are used instead. Original /proc/i8k ioctl part was not changed for compatibility reasons. Signed-off-by: Pali Rohár <pali.rohar@gmail.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/char/i8k.c')
-rw-r--r--drivers/char/i8k.c76
1 files changed, 62 insertions, 14 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 09ebe06764e3..24cc4ed9a780 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -43,6 +43,7 @@
43#define I8K_SMM_SET_FAN 0x01a3 43#define I8K_SMM_SET_FAN 0x01a3
44#define I8K_SMM_GET_FAN 0x00a3 44#define I8K_SMM_GET_FAN 0x00a3
45#define I8K_SMM_GET_SPEED 0x02a3 45#define I8K_SMM_GET_SPEED 0x02a3
46#define I8K_SMM_GET_FAN_TYPE 0x03a3
46#define I8K_SMM_GET_NOM_SPEED 0x04a3 47#define I8K_SMM_GET_NOM_SPEED 0x04a3
47#define I8K_SMM_GET_TEMP 0x10a3 48#define I8K_SMM_GET_TEMP 0x10a3
48#define I8K_SMM_GET_TEMP_TYPE 0x11a3 49#define I8K_SMM_GET_TEMP_TYPE 0x11a3
@@ -279,6 +280,17 @@ static int i8k_get_fan_speed(int fan)
279} 280}
280 281
281/* 282/*
283 * Read the fan type.
284 */
285static int i8k_get_fan_type(int fan)
286{
287 struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
288
289 regs.ebx = fan & 0xff;
290 return i8k_smm(&regs) ? : regs.eax & 0xff;
291}
292
293/*
282 * Read the fan nominal rpm for specific fan speed. 294 * Read the fan nominal rpm for specific fan speed.
283 */ 295 */
284static int i8k_get_fan_nominal_speed(int fan, int speed) 296static int i8k_get_fan_nominal_speed(int fan, int speed)
@@ -553,6 +565,37 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev,
553 return sprintf(buf, "%d\n", temp * 1000); 565 return sprintf(buf, "%d\n", temp * 1000);
554} 566}
555 567
568static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
569 struct device_attribute *devattr,
570 char *buf)
571{
572 static const char * const labels[] = {
573 "Processor Fan",
574 "Motherboard Fan",
575 "Video Fan",
576 "Power Supply Fan",
577 "Chipset Fan",
578 "Other Fan",
579 };
580 int index = to_sensor_dev_attr(devattr)->index;
581 bool dock = false;
582 int type;
583
584 type = i8k_get_fan_type(index);
585 if (type < 0)
586 return type;
587
588 if (type & 0x10) {
589 dock = true;
590 type &= 0x0F;
591 }
592
593 if (type >= ARRAY_SIZE(labels))
594 type = (ARRAY_SIZE(labels) - 1);
595
596 return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
597}
598
556static ssize_t i8k_hwmon_show_fan(struct device *dev, 599static ssize_t i8k_hwmon_show_fan(struct device *dev,
557 struct device_attribute *devattr, 600 struct device_attribute *devattr,
558 char *buf) 601 char *buf)
@@ -611,14 +654,17 @@ static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
611static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3); 654static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);
612static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, 655static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
613 3); 656 3);
614static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 657static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);
615 I8K_FAN_LEFT); 658static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
659 0);
616static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, 660static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
617 i8k_hwmon_set_pwm, I8K_FAN_LEFT); 661 i8k_hwmon_set_pwm, 0);
618static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 662static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
619 I8K_FAN_RIGHT); 663 1);
664static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
665 1);
620static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, 666static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
621 i8k_hwmon_set_pwm, I8K_FAN_RIGHT); 667 i8k_hwmon_set_pwm, 1);
622 668
623static struct attribute *i8k_attrs[] = { 669static struct attribute *i8k_attrs[] = {
624 &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ 670 &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */
@@ -630,9 +676,11 @@ static struct attribute *i8k_attrs[] = {
630 &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */ 676 &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */
631 &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */ 677 &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */
632 &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ 678 &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */
633 &sensor_dev_attr_pwm1.dev_attr.attr, /* 9 */ 679 &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */
634 &sensor_dev_attr_fan2_input.dev_attr.attr, /* 10 */ 680 &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */
635 &sensor_dev_attr_pwm2.dev_attr.attr, /* 11 */ 681 &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */
682 &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */
683 &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */
636 NULL 684 NULL
637}; 685};
638 686
@@ -651,10 +699,10 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
651 if (index >= 6 && index <= 7 && 699 if (index >= 6 && index <= 7 &&
652 !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) 700 !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
653 return 0; 701 return 0;
654 if (index >= 8 && index <= 9 && 702 if (index >= 8 && index <= 10 &&
655 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) 703 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
656 return 0; 704 return 0;
657 if (index >= 10 && index <= 11 && 705 if (index >= 11 && index <= 13 &&
658 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) 706 !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
659 return 0; 707 return 0;
660 708
@@ -688,13 +736,13 @@ static int __init i8k_init_hwmon(void)
688 if (err >= 0) 736 if (err >= 0)
689 i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4; 737 i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
690 738
691 /* Left fan attributes, if left fan is present */ 739 /* First fan attributes, if fan type is OK */
692 err = i8k_get_fan_status(I8K_FAN_LEFT); 740 err = i8k_get_fan_type(0);
693 if (err >= 0) 741 if (err >= 0)
694 i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1; 742 i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
695 743
696 /* Right fan attributes, if right fan is present */ 744 /* Second fan attributes, if fan type is OK */
697 err = i8k_get_fan_status(I8K_FAN_RIGHT); 745 err = i8k_get_fan_type(1);
698 if (err >= 0) 746 if (err >= 0)
699 i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2; 747 i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
700 748