diff options
Diffstat (limited to 'drivers/misc/thinkpad_acpi.c')
| -rw-r--r-- | drivers/misc/thinkpad_acpi.c | 326 |
1 files changed, 303 insertions, 23 deletions
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index d5526e882ddd..a4d7ee472396 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
| @@ -2695,6 +2695,7 @@ static enum fan_control_access_mode fan_control_access_mode; | |||
| 2695 | static enum fan_control_commands fan_control_commands; | 2695 | static enum fan_control_commands fan_control_commands; |
| 2696 | 2696 | ||
| 2697 | static u8 fan_control_initial_status; | 2697 | static u8 fan_control_initial_status; |
| 2698 | static u8 fan_control_desired_level; | ||
| 2698 | 2699 | ||
| 2699 | static void fan_watchdog_fire(struct work_struct *ignored); | 2700 | static void fan_watchdog_fire(struct work_struct *ignored); |
| 2700 | static int fan_watchdog_maxinterval; | 2701 | static int fan_watchdog_maxinterval; |
| @@ -2708,8 +2709,222 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */ | |||
| 2708 | "JFNS", /* 770x-JL */ | 2709 | "JFNS", /* 770x-JL */ |
| 2709 | ); /* all others */ | 2710 | ); /* all others */ |
| 2710 | 2711 | ||
| 2712 | /* | ||
| 2713 | * SYSFS fan layout: hwmon compatible (device) | ||
| 2714 | * | ||
| 2715 | * pwm*_enable: | ||
| 2716 | * 0: "disengaged" mode | ||
| 2717 | * 1: manual mode | ||
| 2718 | * 2: native EC "auto" mode (recommended, hardware default) | ||
| 2719 | * | ||
| 2720 | * pwm*: set speed in manual mode, ignored otherwise. | ||
| 2721 | * 0 is level 0; 255 is level 7. Intermediate points done with linear | ||
| 2722 | * interpolation. | ||
| 2723 | * | ||
| 2724 | * fan*_input: tachometer reading, RPM | ||
| 2725 | * | ||
| 2726 | * | ||
| 2727 | * SYSFS fan layout: extensions | ||
| 2728 | * | ||
| 2729 | * fan_watchdog (driver): | ||
| 2730 | * fan watchdog interval in seconds, 0 disables (default), max 120 | ||
| 2731 | */ | ||
| 2732 | |||
| 2733 | /* sysfs fan pwm1_enable ----------------------------------------------- */ | ||
| 2734 | static ssize_t fan_pwm1_enable_show(struct device *dev, | ||
| 2735 | struct device_attribute *attr, | ||
| 2736 | char *buf) | ||
| 2737 | { | ||
| 2738 | int res, mode; | ||
| 2739 | u8 status; | ||
| 2740 | |||
| 2741 | res = fan_get_status_safe(&status); | ||
| 2742 | if (res) | ||
| 2743 | return res; | ||
| 2744 | |||
| 2745 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | ||
| 2746 | if (status != fan_control_initial_status) { | ||
| 2747 | tp_features.fan_ctrl_status_undef = 0; | ||
| 2748 | } else { | ||
| 2749 | /* Return most likely status. In fact, it | ||
| 2750 | * might be the only possible status */ | ||
| 2751 | status = TP_EC_FAN_AUTO; | ||
| 2752 | } | ||
| 2753 | } | ||
| 2754 | |||
| 2755 | if (status & TP_EC_FAN_FULLSPEED) { | ||
| 2756 | mode = 0; | ||
| 2757 | } else if (status & TP_EC_FAN_AUTO) { | ||
| 2758 | mode = 2; | ||
| 2759 | } else | ||
| 2760 | mode = 1; | ||
| 2761 | |||
| 2762 | return snprintf(buf, PAGE_SIZE, "%d\n", mode); | ||
| 2763 | } | ||
| 2764 | |||
| 2765 | static ssize_t fan_pwm1_enable_store(struct device *dev, | ||
| 2766 | struct device_attribute *attr, | ||
| 2767 | const char *buf, size_t count) | ||
| 2768 | { | ||
| 2769 | unsigned long t; | ||
| 2770 | int res, level; | ||
| 2771 | |||
| 2772 | if (parse_strtoul(buf, 2, &t)) | ||
| 2773 | return -EINVAL; | ||
| 2774 | |||
| 2775 | switch (t) { | ||
| 2776 | case 0: | ||
| 2777 | level = TP_EC_FAN_FULLSPEED; | ||
| 2778 | break; | ||
| 2779 | case 1: | ||
| 2780 | level = TPACPI_FAN_LAST_LEVEL; | ||
| 2781 | break; | ||
| 2782 | case 2: | ||
| 2783 | level = TP_EC_FAN_AUTO; | ||
| 2784 | break; | ||
| 2785 | case 3: | ||
| 2786 | /* reserved for software-controlled auto mode */ | ||
| 2787 | return -ENOSYS; | ||
| 2788 | default: | ||
| 2789 | return -EINVAL; | ||
| 2790 | } | ||
| 2791 | |||
| 2792 | res = fan_set_level_safe(level); | ||
| 2793 | if (res < 0) | ||
| 2794 | return res; | ||
| 2795 | |||
| 2796 | fan_watchdog_reset(); | ||
| 2797 | |||
| 2798 | return count; | ||
| 2799 | } | ||
| 2800 | |||
| 2801 | static struct device_attribute dev_attr_fan_pwm1_enable = | ||
| 2802 | __ATTR(pwm1_enable, S_IWUSR | S_IRUGO, | ||
| 2803 | fan_pwm1_enable_show, fan_pwm1_enable_store); | ||
| 2804 | |||
| 2805 | /* sysfs fan pwm1 ------------------------------------------------------ */ | ||
| 2806 | static ssize_t fan_pwm1_show(struct device *dev, | ||
| 2807 | struct device_attribute *attr, | ||
| 2808 | char *buf) | ||
| 2809 | { | ||
| 2810 | int res; | ||
| 2811 | u8 status; | ||
| 2812 | |||
| 2813 | res = fan_get_status_safe(&status); | ||
| 2814 | if (res) | ||
| 2815 | return res; | ||
| 2816 | |||
| 2817 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | ||
| 2818 | if (status != fan_control_initial_status) { | ||
| 2819 | tp_features.fan_ctrl_status_undef = 0; | ||
| 2820 | } else { | ||
| 2821 | status = TP_EC_FAN_AUTO; | ||
| 2822 | } | ||
| 2823 | } | ||
| 2824 | |||
| 2825 | if ((status & | ||
| 2826 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0) | ||
| 2827 | status = fan_control_desired_level; | ||
| 2828 | |||
| 2829 | if (status > 7) | ||
| 2830 | status = 7; | ||
| 2831 | |||
| 2832 | return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7); | ||
| 2833 | } | ||
| 2834 | |||
| 2835 | static ssize_t fan_pwm1_store(struct device *dev, | ||
| 2836 | struct device_attribute *attr, | ||
| 2837 | const char *buf, size_t count) | ||
| 2838 | { | ||
| 2839 | unsigned long s; | ||
| 2840 | int rc; | ||
| 2841 | u8 status, newlevel; | ||
| 2842 | |||
| 2843 | if (parse_strtoul(buf, 255, &s)) | ||
| 2844 | return -EINVAL; | ||
| 2845 | |||
| 2846 | /* scale down from 0-255 to 0-7 */ | ||
| 2847 | newlevel = (s >> 5) & 0x07; | ||
| 2848 | |||
| 2849 | rc = mutex_lock_interruptible(&fan_mutex); | ||
| 2850 | if (rc < 0) | ||
| 2851 | return rc; | ||
| 2852 | |||
| 2853 | rc = fan_get_status(&status); | ||
| 2854 | if (!rc && (status & | ||
| 2855 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { | ||
| 2856 | rc = fan_set_level(newlevel); | ||
| 2857 | if (!rc) | ||
| 2858 | fan_update_desired_level(newlevel); | ||
| 2859 | fan_watchdog_reset(); | ||
| 2860 | } | ||
| 2861 | |||
| 2862 | mutex_unlock(&fan_mutex); | ||
| 2863 | return (rc)? rc : count; | ||
| 2864 | } | ||
| 2865 | |||
| 2866 | static struct device_attribute dev_attr_fan_pwm1 = | ||
| 2867 | __ATTR(pwm1, S_IWUSR | S_IRUGO, | ||
| 2868 | fan_pwm1_show, fan_pwm1_store); | ||
| 2869 | |||
| 2870 | /* sysfs fan fan1_input ------------------------------------------------ */ | ||
| 2871 | static ssize_t fan_fan1_input_show(struct device *dev, | ||
| 2872 | struct device_attribute *attr, | ||
| 2873 | char *buf) | ||
| 2874 | { | ||
| 2875 | int res; | ||
| 2876 | unsigned int speed; | ||
| 2877 | |||
| 2878 | res = fan_get_speed(&speed); | ||
| 2879 | if (res < 0) | ||
| 2880 | return res; | ||
| 2881 | |||
| 2882 | return snprintf(buf, PAGE_SIZE, "%u\n", speed); | ||
| 2883 | } | ||
| 2884 | |||
| 2885 | static struct device_attribute dev_attr_fan_fan1_input = | ||
| 2886 | __ATTR(fan1_input, S_IRUGO, | ||
| 2887 | fan_fan1_input_show, NULL); | ||
| 2888 | |||
| 2889 | /* sysfs fan fan_watchdog (driver) ------------------------------------- */ | ||
| 2890 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | ||
| 2891 | char *buf) | ||
| 2892 | { | ||
| 2893 | return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval); | ||
| 2894 | } | ||
| 2895 | |||
| 2896 | static ssize_t fan_fan_watchdog_store(struct device_driver *drv, | ||
| 2897 | const char *buf, size_t count) | ||
| 2898 | { | ||
| 2899 | unsigned long t; | ||
| 2900 | |||
| 2901 | if (parse_strtoul(buf, 120, &t)) | ||
| 2902 | return -EINVAL; | ||
| 2903 | |||
| 2904 | fan_watchdog_maxinterval = t; | ||
| 2905 | fan_watchdog_reset(); | ||
| 2906 | |||
| 2907 | return count; | ||
| 2908 | } | ||
| 2909 | |||
| 2910 | static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO, | ||
| 2911 | fan_fan_watchdog_show, fan_fan_watchdog_store); | ||
| 2912 | |||
| 2913 | /* --------------------------------------------------------------------- */ | ||
| 2914 | static struct attribute *fan_attributes[] = { | ||
| 2915 | &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr, | ||
| 2916 | &dev_attr_fan_fan1_input.attr, | ||
| 2917 | NULL | ||
| 2918 | }; | ||
| 2919 | |||
| 2920 | static const struct attribute_group fan_attr_group = { | ||
| 2921 | .attrs = fan_attributes, | ||
| 2922 | }; | ||
| 2923 | |||
| 2711 | static int __init fan_init(struct ibm_init_struct *iibm) | 2924 | static int __init fan_init(struct ibm_init_struct *iibm) |
| 2712 | { | 2925 | { |
| 2926 | int rc; | ||
| 2927 | |||
| 2713 | vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); | 2928 | vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); |
| 2714 | 2929 | ||
| 2715 | mutex_init(&fan_mutex); | 2930 | mutex_init(&fan_mutex); |
| @@ -2718,6 +2933,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 2718 | fan_control_commands = 0; | 2933 | fan_control_commands = 0; |
| 2719 | fan_watchdog_maxinterval = 0; | 2934 | fan_watchdog_maxinterval = 0; |
| 2720 | tp_features.fan_ctrl_status_undef = 0; | 2935 | tp_features.fan_ctrl_status_undef = 0; |
| 2936 | fan_control_desired_level = 7; | ||
| 2721 | 2937 | ||
| 2722 | IBM_ACPIHANDLE_INIT(fans); | 2938 | IBM_ACPIHANDLE_INIT(fans); |
| 2723 | IBM_ACPIHANDLE_INIT(gfan); | 2939 | IBM_ACPIHANDLE_INIT(gfan); |
| @@ -2796,9 +3012,36 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 2796 | fan_control_access_mode != TPACPI_FAN_WR_NONE), | 3012 | fan_control_access_mode != TPACPI_FAN_WR_NONE), |
| 2797 | fan_status_access_mode, fan_control_access_mode); | 3013 | fan_status_access_mode, fan_control_access_mode); |
| 2798 | 3014 | ||
| 2799 | return (fan_status_access_mode != TPACPI_FAN_NONE || | 3015 | /* update fan_control_desired_level */ |
| 2800 | fan_control_access_mode != TPACPI_FAN_WR_NONE)? | 3016 | if (fan_status_access_mode != TPACPI_FAN_NONE) |
| 2801 | 0 : 1; | 3017 | fan_get_status_safe(NULL); |
| 3018 | |||
| 3019 | if (fan_status_access_mode != TPACPI_FAN_NONE || | ||
| 3020 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | ||
| 3021 | rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, | ||
| 3022 | &fan_attr_group); | ||
| 3023 | if (!(rc < 0)) | ||
| 3024 | rc = driver_create_file(&tpacpi_pdriver.driver, | ||
| 3025 | &driver_attr_fan_watchdog); | ||
| 3026 | if (rc < 0) | ||
| 3027 | return rc; | ||
| 3028 | return 0; | ||
| 3029 | } else | ||
| 3030 | return 1; | ||
| 3031 | } | ||
| 3032 | |||
| 3033 | /* | ||
| 3034 | * Call with fan_mutex held | ||
| 3035 | */ | ||
| 3036 | static void fan_update_desired_level(u8 status) | ||
| 3037 | { | ||
| 3038 | if ((status & | ||
| 3039 | (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) { | ||
| 3040 | if (status > 7) | ||
| 3041 | fan_control_desired_level = 7; | ||
| 3042 | else | ||
| 3043 | fan_control_desired_level = status; | ||
| 3044 | } | ||
| 2802 | } | 3045 | } |
| 2803 | 3046 | ||
| 2804 | static int fan_get_status(u8 *status) | 3047 | static int fan_get_status(u8 *status) |
| @@ -2837,9 +3080,33 @@ static int fan_get_status(u8 *status) | |||
| 2837 | return 0; | 3080 | return 0; |
| 2838 | } | 3081 | } |
| 2839 | 3082 | ||
| 3083 | static int fan_get_status_safe(u8 *status) | ||
| 3084 | { | ||
| 3085 | int rc; | ||
| 3086 | u8 s; | ||
| 3087 | |||
| 3088 | rc = mutex_lock_interruptible(&fan_mutex); | ||
| 3089 | if (rc < 0) | ||
| 3090 | return rc; | ||
| 3091 | rc = fan_get_status(&s); | ||
| 3092 | if (!rc) | ||
| 3093 | fan_update_desired_level(s); | ||
| 3094 | mutex_unlock(&fan_mutex); | ||
| 3095 | |||
| 3096 | if (status) | ||
| 3097 | *status = s; | ||
| 3098 | |||
| 3099 | return rc; | ||
| 3100 | } | ||
| 3101 | |||
| 2840 | static void fan_exit(void) | 3102 | static void fan_exit(void) |
| 2841 | { | 3103 | { |
| 2842 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); | 3104 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); |
| 3105 | |||
| 3106 | /* FIXME: can we really do this unconditionally? */ | ||
| 3107 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); | ||
| 3108 | driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); | ||
| 3109 | |||
| 2843 | cancel_delayed_work(&fan_watchdog_task); | 3110 | cancel_delayed_work(&fan_watchdog_task); |
| 2844 | flush_scheduled_work(); | 3111 | flush_scheduled_work(); |
| 2845 | } | 3112 | } |
| @@ -2902,17 +3169,10 @@ static void fan_watchdog_reset(void) | |||
| 2902 | 3169 | ||
| 2903 | static int fan_set_level(int level) | 3170 | static int fan_set_level(int level) |
| 2904 | { | 3171 | { |
| 2905 | int res; | ||
| 2906 | |||
| 2907 | switch (fan_control_access_mode) { | 3172 | switch (fan_control_access_mode) { |
| 2908 | case TPACPI_FAN_WR_ACPI_SFAN: | 3173 | case TPACPI_FAN_WR_ACPI_SFAN: |
| 2909 | if (level >= 0 && level <= 7) { | 3174 | if (level >= 0 && level <= 7) { |
| 2910 | res = mutex_lock_interruptible(&fan_mutex); | 3175 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level)) |
| 2911 | if (res < 0) | ||
| 2912 | return res; | ||
| 2913 | res = acpi_evalf(sfan_handle, NULL, NULL, "vd", level); | ||
| 2914 | mutex_unlock(&fan_mutex); | ||
| 2915 | if (!res) | ||
| 2916 | return -EIO; | 3176 | return -EIO; |
| 2917 | } else | 3177 | } else |
| 2918 | return -EINVAL; | 3178 | return -EINVAL; |
| @@ -2925,12 +3185,7 @@ static int fan_set_level(int level) | |||
| 2925 | ((level < 0) || (level > 7))) | 3185 | ((level < 0) || (level > 7))) |
| 2926 | return -EINVAL; | 3186 | return -EINVAL; |
| 2927 | 3187 | ||
| 2928 | res = mutex_lock_interruptible(&fan_mutex); | 3188 | if (!acpi_ec_write(fan_status_offset, level)) |
| 2929 | if (res < 0) | ||
| 2930 | return res; | ||
| 2931 | res = acpi_ec_write(fan_status_offset, level); | ||
| 2932 | mutex_unlock(&fan_mutex); | ||
| 2933 | if (!res) | ||
| 2934 | return -EIO; | 3189 | return -EIO; |
| 2935 | else | 3190 | else |
| 2936 | tp_features.fan_ctrl_status_undef = 0; | 3191 | tp_features.fan_ctrl_status_undef = 0; |
| @@ -2942,6 +3197,25 @@ static int fan_set_level(int level) | |||
| 2942 | return 0; | 3197 | return 0; |
| 2943 | } | 3198 | } |
| 2944 | 3199 | ||
| 3200 | static int fan_set_level_safe(int level) | ||
| 3201 | { | ||
| 3202 | int rc; | ||
| 3203 | |||
| 3204 | rc = mutex_lock_interruptible(&fan_mutex); | ||
| 3205 | if (rc < 0) | ||
| 3206 | return rc; | ||
| 3207 | |||
| 3208 | if (level == TPACPI_FAN_LAST_LEVEL) | ||
| 3209 | level = fan_control_desired_level; | ||
| 3210 | |||
| 3211 | rc = fan_set_level(level); | ||
| 3212 | if (!rc) | ||
| 3213 | fan_update_desired_level(level); | ||
| 3214 | |||
| 3215 | mutex_unlock(&fan_mutex); | ||
| 3216 | return rc; | ||
| 3217 | } | ||
| 3218 | |||
| 2945 | static int fan_set_enable(void) | 3219 | static int fan_set_enable(void) |
| 2946 | { | 3220 | { |
| 2947 | u8 s; | 3221 | u8 s; |
| @@ -3009,19 +3283,24 @@ static int fan_set_disable(void) | |||
| 3009 | case TPACPI_FAN_WR_TPEC: | 3283 | case TPACPI_FAN_WR_TPEC: |
| 3010 | if (!acpi_ec_write(fan_status_offset, 0x00)) | 3284 | if (!acpi_ec_write(fan_status_offset, 0x00)) |
| 3011 | rc = -EIO; | 3285 | rc = -EIO; |
| 3012 | else | 3286 | else { |
| 3287 | fan_control_desired_level = 0; | ||
| 3013 | tp_features.fan_ctrl_status_undef = 0; | 3288 | tp_features.fan_ctrl_status_undef = 0; |
| 3289 | } | ||
| 3014 | break; | 3290 | break; |
| 3015 | 3291 | ||
| 3016 | case TPACPI_FAN_WR_ACPI_SFAN: | 3292 | case TPACPI_FAN_WR_ACPI_SFAN: |
| 3017 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) | 3293 | if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) |
| 3018 | rc = -EIO; | 3294 | rc = -EIO; |
| 3295 | else | ||
| 3296 | fan_control_desired_level = 0; | ||
| 3019 | break; | 3297 | break; |
| 3020 | 3298 | ||
| 3021 | default: | 3299 | default: |
| 3022 | rc = -ENXIO; | 3300 | rc = -ENXIO; |
| 3023 | } | 3301 | } |
| 3024 | 3302 | ||
| 3303 | |||
| 3025 | mutex_unlock(&fan_mutex); | 3304 | mutex_unlock(&fan_mutex); |
| 3026 | return rc; | 3305 | return rc; |
| 3027 | } | 3306 | } |
| @@ -3063,7 +3342,7 @@ static int fan_read(char *p) | |||
| 3063 | switch (fan_status_access_mode) { | 3342 | switch (fan_status_access_mode) { |
| 3064 | case TPACPI_FAN_RD_ACPI_GFAN: | 3343 | case TPACPI_FAN_RD_ACPI_GFAN: |
| 3065 | /* 570, 600e/x, 770e, 770x */ | 3344 | /* 570, 600e/x, 770e, 770x */ |
| 3066 | if ((rc = fan_get_status(&status)) < 0) | 3345 | if ((rc = fan_get_status_safe(&status)) < 0) |
| 3067 | return rc; | 3346 | return rc; |
| 3068 | 3347 | ||
| 3069 | len += sprintf(p + len, "status:\t\t%s\n" | 3348 | len += sprintf(p + len, "status:\t\t%s\n" |
| @@ -3073,7 +3352,7 @@ static int fan_read(char *p) | |||
| 3073 | 3352 | ||
| 3074 | case TPACPI_FAN_RD_TPEC: | 3353 | case TPACPI_FAN_RD_TPEC: |
| 3075 | /* all except 570, 600e/x, 770e, 770x */ | 3354 | /* all except 570, 600e/x, 770e, 770x */ |
| 3076 | if ((rc = fan_get_status(&status)) < 0) | 3355 | if ((rc = fan_get_status_safe(&status)) < 0) |
| 3077 | return rc; | 3356 | return rc; |
| 3078 | 3357 | ||
| 3079 | if (unlikely(tp_features.fan_ctrl_status_undef)) { | 3358 | if (unlikely(tp_features.fan_ctrl_status_undef)) { |
| @@ -3117,7 +3396,7 @@ static int fan_read(char *p) | |||
| 3117 | 3396 | ||
| 3118 | default: | 3397 | default: |
| 3119 | len += sprintf(p + len, " (<level> is 0-7, " | 3398 | len += sprintf(p + len, " (<level> is 0-7, " |
| 3120 | "auto, disengaged)\n"); | 3399 | "auto, disengaged, full-speed)\n"); |
| 3121 | break; | 3400 | break; |
| 3122 | } | 3401 | } |
| 3123 | } | 3402 | } |
| @@ -3140,12 +3419,13 @@ static int fan_write_cmd_level(const char *cmd, int *rc) | |||
| 3140 | 3419 | ||
| 3141 | if (strlencmp(cmd, "level auto") == 0) | 3420 | if (strlencmp(cmd, "level auto") == 0) |
| 3142 | level = TP_EC_FAN_AUTO; | 3421 | level = TP_EC_FAN_AUTO; |
| 3143 | else if (strlencmp(cmd, "level disengaged") == 0) | 3422 | else if ((strlencmp(cmd, "level disengaged") == 0) | |
| 3423 | (strlencmp(cmd, "level full-speed") == 0)) | ||
| 3144 | level = TP_EC_FAN_FULLSPEED; | 3424 | level = TP_EC_FAN_FULLSPEED; |
| 3145 | else if (sscanf(cmd, "level %d", &level) != 1) | 3425 | else if (sscanf(cmd, "level %d", &level) != 1) |
| 3146 | return 0; | 3426 | return 0; |
| 3147 | 3427 | ||
| 3148 | if ((*rc = fan_set_level(level)) == -ENXIO) | 3428 | if ((*rc = fan_set_level_safe(level)) == -ENXIO) |
| 3149 | printk(IBM_ERR "level command accepted for unsupported " | 3429 | printk(IBM_ERR "level command accepted for unsupported " |
| 3150 | "access mode %d", fan_control_access_mode); | 3430 | "access mode %d", fan_control_access_mode); |
| 3151 | 3431 | ||
