diff options
Diffstat (limited to 'drivers/char/i8k.c')
| -rw-r--r-- | drivers/char/i8k.c | 123 |
1 files changed, 82 insertions, 41 deletions
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 93dcad0c1cbe..65525c7e903c 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c | |||
| @@ -65,6 +65,8 @@ static char bios_version[4]; | |||
| 65 | static struct device *i8k_hwmon_dev; | 65 | static struct device *i8k_hwmon_dev; |
| 66 | static u32 i8k_hwmon_flags; | 66 | static u32 i8k_hwmon_flags; |
| 67 | static int i8k_fan_mult; | 67 | static int i8k_fan_mult; |
| 68 | static int i8k_pwm_mult; | ||
| 69 | static int i8k_fan_max = I8K_FAN_HIGH; | ||
| 68 | 70 | ||
| 69 | #define I8K_HWMON_HAVE_TEMP1 (1 << 0) | 71 | #define I8K_HWMON_HAVE_TEMP1 (1 << 0) |
| 70 | #define I8K_HWMON_HAVE_TEMP2 (1 << 1) | 72 | #define I8K_HWMON_HAVE_TEMP2 (1 << 1) |
| @@ -97,6 +99,10 @@ static int fan_mult = I8K_FAN_MULT; | |||
| 97 | module_param(fan_mult, int, 0); | 99 | module_param(fan_mult, int, 0); |
| 98 | MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); | 100 | MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with"); |
| 99 | 101 | ||
| 102 | static int fan_max = I8K_FAN_HIGH; | ||
| 103 | module_param(fan_max, int, 0); | ||
| 104 | MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed"); | ||
| 105 | |||
| 100 | static int i8k_open_fs(struct inode *inode, struct file *file); | 106 | static int i8k_open_fs(struct inode *inode, struct file *file); |
| 101 | static long i8k_ioctl(struct file *, unsigned int, unsigned long); | 107 | static long i8k_ioctl(struct file *, unsigned int, unsigned long); |
| 102 | 108 | ||
| @@ -276,7 +282,7 @@ static int i8k_set_fan(int fan, int speed) | |||
| 276 | { | 282 | { |
| 277 | struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; | 283 | struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; |
| 278 | 284 | ||
| 279 | speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); | 285 | speed = (speed < 0) ? 0 : ((speed > i8k_fan_max) ? i8k_fan_max : speed); |
| 280 | regs.ebx = (fan & 0xff) | (speed << 8); | 286 | regs.ebx = (fan & 0xff) | (speed << 8); |
| 281 | 287 | ||
| 282 | return i8k_smm(®s) ? : i8k_get_fan_status(fan); | 288 | return i8k_smm(®s) ? : i8k_get_fan_status(fan); |
| @@ -521,7 +527,7 @@ static ssize_t i8k_hwmon_show_pwm(struct device *dev, | |||
| 521 | status = i8k_get_fan_status(index); | 527 | status = i8k_get_fan_status(index); |
| 522 | if (status < 0) | 528 | if (status < 0) |
| 523 | return -EIO; | 529 | return -EIO; |
| 524 | return sprintf(buf, "%d\n", clamp_val(status * 128, 0, 255)); | 530 | return sprintf(buf, "%d\n", clamp_val(status * i8k_pwm_mult, 0, 255)); |
| 525 | } | 531 | } |
| 526 | 532 | ||
| 527 | static ssize_t i8k_hwmon_set_pwm(struct device *dev, | 533 | static ssize_t i8k_hwmon_set_pwm(struct device *dev, |
| @@ -535,7 +541,7 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev, | |||
| 535 | err = kstrtoul(buf, 10, &val); | 541 | err = kstrtoul(buf, 10, &val); |
| 536 | if (err) | 542 | if (err) |
| 537 | return err; | 543 | return err; |
| 538 | val = clamp_val(DIV_ROUND_CLOSEST(val, 128), 0, 2); | 544 | val = clamp_val(DIV_ROUND_CLOSEST(val, i8k_pwm_mult), 0, i8k_fan_max); |
| 539 | 545 | ||
| 540 | mutex_lock(&i8k_mutex); | 546 | mutex_lock(&i8k_mutex); |
| 541 | err = i8k_set_fan(index, val); | 547 | err = i8k_set_fan(index, val); |
| @@ -544,20 +550,6 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev, | |||
| 544 | return err < 0 ? -EIO : count; | 550 | return err < 0 ? -EIO : count; |
| 545 | } | 551 | } |
| 546 | 552 | ||
| 547 | static ssize_t i8k_hwmon_show_label(struct device *dev, | ||
| 548 | struct device_attribute *devattr, | ||
| 549 | char *buf) | ||
| 550 | { | ||
| 551 | static const char *labels[3] = { | ||
| 552 | "CPU", | ||
| 553 | "Left Fan", | ||
| 554 | "Right Fan", | ||
| 555 | }; | ||
| 556 | int index = to_sensor_dev_attr(devattr)->index; | ||
| 557 | |||
| 558 | return sprintf(buf, "%s\n", labels[index]); | ||
| 559 | } | ||
| 560 | |||
| 561 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); | 553 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); |
| 562 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); | 554 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1); |
| 563 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); | 555 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2); |
| @@ -570,41 +562,34 @@ static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, | |||
| 570 | I8K_FAN_RIGHT); | 562 | I8K_FAN_RIGHT); |
| 571 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, | 563 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, |
| 572 | i8k_hwmon_set_pwm, I8K_FAN_RIGHT); | 564 | i8k_hwmon_set_pwm, I8K_FAN_RIGHT); |
| 573 | static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 0); | ||
| 574 | static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_label, NULL, 1); | ||
| 575 | static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_label, NULL, 2); | ||
| 576 | 565 | ||
| 577 | static struct attribute *i8k_attrs[] = { | 566 | static struct attribute *i8k_attrs[] = { |
| 578 | &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ | 567 | &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ |
| 579 | &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */ | 568 | &sensor_dev_attr_temp2_input.dev_attr.attr, /* 1 */ |
| 580 | &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */ | 569 | &sensor_dev_attr_temp3_input.dev_attr.attr, /* 2 */ |
| 581 | &sensor_dev_attr_temp3_input.dev_attr.attr, /* 3 */ | 570 | &sensor_dev_attr_temp4_input.dev_attr.attr, /* 3 */ |
| 582 | &sensor_dev_attr_temp4_input.dev_attr.attr, /* 4 */ | 571 | &sensor_dev_attr_fan1_input.dev_attr.attr, /* 4 */ |
| 583 | &sensor_dev_attr_fan1_input.dev_attr.attr, /* 5 */ | 572 | &sensor_dev_attr_pwm1.dev_attr.attr, /* 5 */ |
| 584 | &sensor_dev_attr_pwm1.dev_attr.attr, /* 6 */ | 573 | &sensor_dev_attr_fan2_input.dev_attr.attr, /* 6 */ |
| 585 | &sensor_dev_attr_fan1_label.dev_attr.attr, /* 7 */ | 574 | &sensor_dev_attr_pwm2.dev_attr.attr, /* 7 */ |
| 586 | &sensor_dev_attr_fan2_input.dev_attr.attr, /* 8 */ | ||
| 587 | &sensor_dev_attr_pwm2.dev_attr.attr, /* 9 */ | ||
| 588 | &sensor_dev_attr_fan2_label.dev_attr.attr, /* 10 */ | ||
| 589 | NULL | 575 | NULL |
| 590 | }; | 576 | }; |
| 591 | 577 | ||
| 592 | static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, | 578 | static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, |
| 593 | int index) | 579 | int index) |
| 594 | { | 580 | { |
| 595 | if ((index == 0 || index == 1) && | 581 | if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) |
| 596 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1)) | ||
| 597 | return 0; | 582 | return 0; |
| 598 | if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) | 583 | if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2)) |
| 599 | return 0; | 584 | return 0; |
| 600 | if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) | 585 | if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3)) |
| 601 | return 0; | 586 | return 0; |
| 602 | if (index == 4 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) | 587 | if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) |
| 603 | return 0; | 588 | return 0; |
| 604 | if (index >= 5 && index <= 7 && | 589 | if (index >= 4 && index <= 5 && |
| 605 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) | 590 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) |
| 606 | return 0; | 591 | return 0; |
| 607 | if (index >= 8 && index <= 10 && | 592 | if (index >= 6 && index <= 7 && |
| 608 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) | 593 | !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) |
| 609 | return 0; | 594 | return 0; |
| 610 | 595 | ||
| @@ -659,6 +644,37 @@ static int __init i8k_init_hwmon(void) | |||
| 659 | return 0; | 644 | return 0; |
| 660 | } | 645 | } |
| 661 | 646 | ||
| 647 | struct i8k_config_data { | ||
| 648 | int fan_mult; | ||
| 649 | int fan_max; | ||
| 650 | }; | ||
| 651 | |||
| 652 | enum i8k_configs { | ||
| 653 | DELL_LATITUDE_D520, | ||
| 654 | DELL_PRECISION_490, | ||
| 655 | DELL_STUDIO, | ||
| 656 | DELL_XPS_M140, | ||
| 657 | }; | ||
| 658 | |||
| 659 | static const struct i8k_config_data i8k_config_data[] = { | ||
| 660 | [DELL_LATITUDE_D520] = { | ||
| 661 | .fan_mult = 1, | ||
| 662 | .fan_max = I8K_FAN_TURBO, | ||
| 663 | }, | ||
| 664 | [DELL_PRECISION_490] = { | ||
| 665 | .fan_mult = 1, | ||
| 666 | .fan_max = I8K_FAN_TURBO, | ||
| 667 | }, | ||
| 668 | [DELL_STUDIO] = { | ||
| 669 | .fan_mult = 1, | ||
| 670 | .fan_max = I8K_FAN_HIGH, | ||
| 671 | }, | ||
| 672 | [DELL_XPS_M140] = { | ||
| 673 | .fan_mult = 1, | ||
| 674 | .fan_max = I8K_FAN_HIGH, | ||
| 675 | }, | ||
| 676 | }; | ||
| 677 | |||
| 662 | static struct dmi_system_id i8k_dmi_table[] __initdata = { | 678 | static struct dmi_system_id i8k_dmi_table[] __initdata = { |
| 663 | { | 679 | { |
| 664 | .ident = "Dell Inspiron", | 680 | .ident = "Dell Inspiron", |
| @@ -682,6 +698,14 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { | |||
| 682 | }, | 698 | }, |
| 683 | }, | 699 | }, |
| 684 | { | 700 | { |
| 701 | .ident = "Dell Latitude D520", | ||
| 702 | .matches = { | ||
| 703 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 704 | DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D520"), | ||
| 705 | }, | ||
| 706 | .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520], | ||
| 707 | }, | ||
| 708 | { | ||
| 685 | .ident = "Dell Latitude 2", | 709 | .ident = "Dell Latitude 2", |
| 686 | .matches = { | 710 | .matches = { |
| 687 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 711 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| @@ -703,6 +727,15 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { | |||
| 703 | }, | 727 | }, |
| 704 | }, | 728 | }, |
| 705 | { | 729 | { |
| 730 | .ident = "Dell Precision 490", | ||
| 731 | .matches = { | ||
| 732 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 733 | DMI_MATCH(DMI_PRODUCT_NAME, | ||
| 734 | "Precision WorkStation 490"), | ||
| 735 | }, | ||
| 736 | .driver_data = (void *)&i8k_config_data[DELL_PRECISION_490], | ||
| 737 | }, | ||
| 738 | { | ||
| 706 | .ident = "Dell Precision", | 739 | .ident = "Dell Precision", |
| 707 | .matches = { | 740 | .matches = { |
| 708 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 741 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| @@ -729,7 +762,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { | |||
| 729 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 762 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 730 | DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), | 763 | DMI_MATCH(DMI_PRODUCT_NAME, "Studio"), |
| 731 | }, | 764 | }, |
| 732 | .driver_data = (void *)1, /* fan multiplier override */ | 765 | .driver_data = (void *)&i8k_config_data[DELL_STUDIO], |
| 733 | }, | 766 | }, |
| 734 | { | 767 | { |
| 735 | .ident = "Dell XPS M140", | 768 | .ident = "Dell XPS M140", |
| @@ -737,7 +770,7 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = { | |||
| 737 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | 770 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), |
| 738 | DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), | 771 | DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"), |
| 739 | }, | 772 | }, |
| 740 | .driver_data = (void *)1, /* fan multiplier override */ | 773 | .driver_data = (void *)&i8k_config_data[DELL_XPS_M140], |
| 741 | }, | 774 | }, |
| 742 | { } | 775 | { } |
| 743 | }; | 776 | }; |
| @@ -777,9 +810,17 @@ static int __init i8k_probe(void) | |||
| 777 | } | 810 | } |
| 778 | 811 | ||
| 779 | i8k_fan_mult = fan_mult; | 812 | i8k_fan_mult = fan_mult; |
| 813 | i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */ | ||
| 780 | id = dmi_first_match(i8k_dmi_table); | 814 | id = dmi_first_match(i8k_dmi_table); |
| 781 | if (id && fan_mult == I8K_FAN_MULT && id->driver_data) | 815 | if (id && id->driver_data) { |
| 782 | i8k_fan_mult = (unsigned long)id->driver_data; | 816 | const struct i8k_config_data *conf = id->driver_data; |
| 817 | |||
| 818 | if (fan_mult == I8K_FAN_MULT && conf->fan_mult) | ||
| 819 | i8k_fan_mult = conf->fan_mult; | ||
| 820 | if (fan_max == I8K_FAN_HIGH && conf->fan_max) | ||
| 821 | i8k_fan_max = conf->fan_max; | ||
| 822 | } | ||
| 823 | i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max); | ||
| 783 | 824 | ||
| 784 | return 0; | 825 | return 0; |
| 785 | } | 826 | } |
