Added fan control for Nvidia GPUs based on a patch by Christian Valli?res.
authormoel.mich
Thu, 07 Jul 2011 21:53:09 +0000
changeset 30965a1ae21325d
parent 308 d882720734bf
child 310 7fe8c37b1b84
Added fan control for Nvidia GPUs based on a patch by Christian Valli?res.
Hardware/Nvidia/NVAPI.cs
Hardware/Nvidia/NvidiaGPU.cs
     1.1 --- a/Hardware/Nvidia/NVAPI.cs	Thu Jul 07 20:41:09 2011 +0000
     1.2 +++ b/Hardware/Nvidia/NVAPI.cs	Thu Jul 07 21:53:09 2011 +0000
     1.3 @@ -16,10 +16,11 @@
     1.4  
     1.5    The Initial Developer of the Original Code is 
     1.6    Michael Möller <m.moeller@gmx.ch>.
     1.7 -  Portions created by the Initial Developer are Copyright (C) 2009-2010
     1.8 +  Portions created by the Initial Developer are Copyright (C) 2009-2011
     1.9    the Initial Developer. All Rights Reserved.
    1.10  
    1.11    Contributor(s):
    1.12 +  Christian Vallières
    1.13  
    1.14    Alternatively, the contents of this file may be used under the terms of
    1.15    either the GNU General Public License Version 2 or later (the "GPL"), or
    1.16 @@ -97,17 +98,17 @@
    1.17  
    1.18    internal enum NvThermalController {
    1.19      NONE = 0,
    1.20 -    GPU_INTERNAL,  
    1.21 +    GPU_INTERNAL,
    1.22      ADM1032,
    1.23 -    MAX6649,       
    1.24 -    MAX1617,      
    1.25 -    LM99,      
    1.26 -    LM89,         
    1.27 -    LM64,         
    1.28 +    MAX6649,
    1.29 +    MAX1617,
    1.30 +    LM99,
    1.31 +    LM89,
    1.32 +    LM64,
    1.33      ADT7473,
    1.34      SBMAX6649,
    1.35 -    VBIOSEVT,  
    1.36 -    OS,    
    1.37 +    VBIOSEVT,
    1.38 +    OS,
    1.39      UNKNOWN = -1,
    1.40    }
    1.41  
    1.42 @@ -127,14 +128,14 @@
    1.43      public uint DefaultMinTemp;
    1.44      public uint DefaultMaxTemp;
    1.45      public uint CurrentTemp;
    1.46 -    public NvThermalTarget Target;     
    1.47 +    public NvThermalTarget Target;
    1.48    }
    1.49  
    1.50    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    1.51    internal struct NvGPUThermalSettings {
    1.52      public uint Version;
    1.53      public uint Count;
    1.54 -    [MarshalAs(UnmanagedType.ByValArray, 
    1.55 +    [MarshalAs(UnmanagedType.ByValArray,
    1.56        SizeConst = NVAPI.MAX_THERMAL_SENSORS_PER_GPU)]
    1.57      public NvSensor[] Sensor;
    1.58    }
    1.59 @@ -202,9 +203,22 @@
    1.60    }
    1.61  
    1.62    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    1.63 +  internal struct NvLevel {
    1.64 +    public int Level;
    1.65 +    public int Policy;
    1.66 +  }
    1.67 +
    1.68 +  [StructLayout(LayoutKind.Sequential, Pack = 8)]
    1.69 +  internal struct NvGPUCoolerLevels {
    1.70 +    public uint Version;
    1.71 +    [MarshalAs(UnmanagedType.ByValArray, SizeConst = NVAPI.MAX_COOLER_PER_GPU)]
    1.72 +    public NvLevel[] Levels;
    1.73 +  }
    1.74 +
    1.75 +  [StructLayout(LayoutKind.Sequential, Pack = 8)]
    1.76    internal struct NvMemoryInfo {
    1.77      public uint Version;
    1.78 -    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 
    1.79 +    [MarshalAs(UnmanagedType.ByValArray, SizeConst =
    1.80        NVAPI.MAX_MEMORY_VALUES_PER_GPU)]
    1.81      public uint[] Values;
    1.82    }
    1.83 @@ -225,7 +239,7 @@
    1.84      public const int MAX_PHYSICAL_GPUS = 64;
    1.85      public const int SHORT_STRING_MAX = 64;
    1.86  
    1.87 -    public const int MAX_THERMAL_SENSORS_PER_GPU = 3;    
    1.88 +    public const int MAX_THERMAL_SENSORS_PER_GPU = 3;
    1.89      public const int MAX_CLOCKS_PER_GPU = 0x120;
    1.90      public const int MAX_PSTATES_PER_GPU = 8;
    1.91      public const int MAX_USAGES_PER_GPU = 33;
    1.92 @@ -242,23 +256,25 @@
    1.93        Marshal.SizeOf(typeof(NvUsages)) | 0x10000;
    1.94      public static readonly uint GPU_COOLER_SETTINGS_VER = (uint)
    1.95        Marshal.SizeOf(typeof(NvGPUCoolerSettings)) | 0x20000;
    1.96 -    public static readonly uint GPU_MEMORY_INFO_VER = (uint) 
    1.97 +    public static readonly uint GPU_MEMORY_INFO_VER = (uint)
    1.98        Marshal.SizeOf(typeof(NvMemoryInfo)) | 0x20000;
    1.99      public static readonly uint DISPLAY_DRIVER_VERSION_VER = (uint)
   1.100        Marshal.SizeOf(typeof(NvDisplayDriverVersion)) | 0x10000;
   1.101 -      
   1.102 +    public static readonly uint GPU_COOLER_LEVELS_VER = (uint)
   1.103 +      Marshal.SizeOf(typeof(NvGPUCoolerLevels)) | 0x10000;
   1.104 +
   1.105      private delegate IntPtr nvapi_QueryInterfaceDelegate(uint id);
   1.106      private delegate NvStatus NvAPI_InitializeDelegate();
   1.107      private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(
   1.108        NvPhysicalGpuHandle gpuHandle, StringBuilder name);
   1.109  
   1.110      public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(
   1.111 -      NvPhysicalGpuHandle gpuHandle, int sensorIndex, 
   1.112 +      NvPhysicalGpuHandle gpuHandle, int sensorIndex,
   1.113        ref NvGPUThermalSettings nvGPUThermalSettings);
   1.114      public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum,
   1.115        ref NvDisplayHandle displayHandle);
   1.116      public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(
   1.117 -      NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, 
   1.118 +      NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles,
   1.119        out uint gpuCount);
   1.120      public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate(
   1.121        [Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount);
   1.122 @@ -273,6 +289,9 @@
   1.123      public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(
   1.124        NvPhysicalGpuHandle gpuHandle, int coolerIndex,
   1.125        ref NvGPUCoolerSettings nvGPUCoolerSettings);
   1.126 +    public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(
   1.127 +      NvPhysicalGpuHandle gpuHandle, int coolerIndex,
   1.128 +      ref NvGPUCoolerLevels NvGPUCoolerLevels);
   1.129      public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(
   1.130        NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo);
   1.131      public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(
   1.132 @@ -284,12 +303,12 @@
   1.133      private static readonly bool available;
   1.134      private static readonly nvapi_QueryInterfaceDelegate nvapi_QueryInterface;
   1.135      private static readonly NvAPI_InitializeDelegate NvAPI_Initialize;
   1.136 -    private static readonly NvAPI_GPU_GetFullNameDelegate 
   1.137 +    private static readonly NvAPI_GPU_GetFullNameDelegate
   1.138        _NvAPI_GPU_GetFullName;
   1.139      private static readonly NvAPI_GetInterfaceVersionStringDelegate
   1.140        _NvAPI_GetInterfaceVersionString;
   1.141  
   1.142 -    public static readonly NvAPI_GPU_GetThermalSettingsDelegate 
   1.143 +    public static readonly NvAPI_GPU_GetThermalSettingsDelegate
   1.144        NvAPI_GPU_GetThermalSettings;
   1.145      public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate
   1.146        NvAPI_EnumNvidiaDisplayHandle;
   1.147 @@ -307,6 +326,8 @@
   1.148        NvAPI_GPU_GetUsages;
   1.149      public static readonly NvAPI_GPU_GetCoolerSettingsDelegate
   1.150        NvAPI_GPU_GetCoolerSettings;
   1.151 +    public static readonly NvAPI_GPU_SetCoolerLevelsDelegate
   1.152 +      NvAPI_GPU_SetCoolerLevels;
   1.153      public static readonly NvAPI_GPU_GetMemoryInfoDelegate
   1.154        NvAPI_GPU_GetMemoryInfo;
   1.155      public static readonly NvAPI_GetDisplayDriverVersionDelegate
   1.156 @@ -345,9 +366,8 @@
   1.157        }
   1.158      }
   1.159  
   1.160 -    private static void GetDelegate<T>(uint id, out T newDelegate) 
   1.161 -      where T : class 
   1.162 -    {
   1.163 +    private static void GetDelegate<T>(uint id, out T newDelegate)
   1.164 +      where T : class {
   1.165        IntPtr ptr = nvapi_QueryInterface(id);
   1.166        if (ptr != IntPtr.Zero) {
   1.167          newDelegate =
   1.168 @@ -357,7 +377,7 @@
   1.169        }
   1.170      }
   1.171  
   1.172 -    static NVAPI() { 
   1.173 +    static NVAPI() {
   1.174        DllImportAttribute attribute = new DllImportAttribute(GetDllName());
   1.175        attribute.CallingConvention = CallingConvention.Cdecl;
   1.176        attribute.PreserveSig = true;
   1.177 @@ -382,6 +402,7 @@
   1.178          GetDelegate(0x60DED2ED, out NvAPI_GPU_GetPStates);
   1.179          GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages);
   1.180          GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings);
   1.181 +        GetDelegate(0x891FA0AE, out NvAPI_GPU_SetCoolerLevels);
   1.182          GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo);
   1.183          GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion);
   1.184          GetDelegate(0x01053FA5, out _NvAPI_GetInterfaceVersionString);
     2.1 --- a/Hardware/Nvidia/NvidiaGPU.cs	Thu Jul 07 20:41:09 2011 +0000
     2.2 +++ b/Hardware/Nvidia/NvidiaGPU.cs	Thu Jul 07 21:53:09 2011 +0000
     2.3 @@ -20,6 +20,7 @@
     2.4    the Initial Developer. All Rights Reserved.
     2.5  
     2.6    Contributor(s):
     2.7 +  Christian Vallières
     2.8  
     2.9    Alternatively, the contents of this file may be used under the terms of
    2.10    either the GNU General Public License Version 2 or later (the "GPL"), or
    2.11 @@ -52,12 +53,15 @@
    2.12      private readonly Sensor[] loads;
    2.13      private readonly Sensor control;
    2.14      private readonly Sensor memoryLoad;
    2.15 +    private readonly Control fanControl;
    2.16  
    2.17 -    public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle, 
    2.18 -      NvDisplayHandle? displayHandle, ISettings settings) 
    2.19 -      : base(GetName(handle), new Identifier("nvidiagpu", 
    2.20 -          adapterIndex.ToString(CultureInfo.InvariantCulture)), settings)
    2.21 -    {
    2.22 +    private bool restoreDefaultFanSpeedRequired;
    2.23 +    private NvLevel initialFanSpeedValue;
    2.24 +
    2.25 +    public NvidiaGPU(int adapterIndex, NvPhysicalGpuHandle handle,
    2.26 +      NvDisplayHandle? displayHandle, ISettings settings)
    2.27 +      : base(GetName(handle), new Identifier("nvidiagpu",
    2.28 +          adapterIndex.ToString(CultureInfo.InvariantCulture)), settings) {
    2.29        this.adapterIndex = adapterIndex;
    2.30        this.handle = handle;
    2.31        this.displayHandle = displayHandle;
    2.32 @@ -103,6 +107,18 @@
    2.33        memoryLoad = new Sensor("GPU Memory", 3, SensorType.Load, this, settings);
    2.34  
    2.35        control = new Sensor("GPU Fan", 0, SensorType.Control, this, settings);
    2.36 +
    2.37 +      NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
    2.38 +      if (coolerSettings.Count > 0) {
    2.39 +        fanControl = new Control(control, settings,
    2.40 +          coolerSettings.Cooler[0].DefaultMin, 
    2.41 +          coolerSettings.Cooler[0].DefaultMax);
    2.42 +        fanControl.ControlModeChanged += ControlModeChanged;
    2.43 +        fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged;
    2.44 +        ControlModeChanged(fanControl);
    2.45 +        control.Control = fanControl;
    2.46 +      }
    2.47 +      Update();
    2.48      }
    2.49  
    2.50      private static string GetName(NvPhysicalGpuHandle handle) {
    2.51 @@ -123,12 +139,26 @@
    2.52        settings.Version = NVAPI.GPU_THERMAL_SETTINGS_VER;
    2.53        settings.Count = NVAPI.MAX_THERMAL_SENSORS_PER_GPU;
    2.54        settings.Sensor = new NvSensor[NVAPI.MAX_THERMAL_SENSORS_PER_GPU];
    2.55 -      if (NVAPI.NvAPI_GPU_GetThermalSettings != null &&
    2.56 +      if (!(NVAPI.NvAPI_GPU_GetThermalSettings != null &&
    2.57          NVAPI.NvAPI_GPU_GetThermalSettings(handle, (int)NvThermalTarget.ALL,
    2.58 -        ref settings) != NvStatus.OK) {
    2.59 -        settings.Count = 0;        
    2.60 +          ref settings) == NvStatus.OK)) 
    2.61 +      {
    2.62 +        settings.Count = 0;
    2.63 +      }       
    2.64 +      return settings;    
    2.65 +    }
    2.66 +
    2.67 +    private NvGPUCoolerSettings GetCoolerSettings() {
    2.68 +      NvGPUCoolerSettings settings = new NvGPUCoolerSettings();
    2.69 +      settings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
    2.70 +      settings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
    2.71 +      if (!(NVAPI.NvAPI_GPU_GetCoolerSettings != null &&
    2.72 +        NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, 
    2.73 +          ref settings) == NvStatus.OK)) 
    2.74 +      {
    2.75 +        settings.Count = 0;
    2.76        }
    2.77 -      return settings;
    2.78 +      return settings;  
    2.79      }
    2.80  
    2.81      private uint[] GetClocks() {
    2.82 @@ -144,7 +174,7 @@
    2.83  
    2.84      public override void Update() {
    2.85        NvGPUThermalSettings settings = GetThermalSettings();
    2.86 -      foreach (Sensor sensor in temperatures) 
    2.87 +      foreach (Sensor sensor in temperatures)
    2.88          sensor.Value = settings.Sensor[sensor.Index].CurrentTemp;
    2.89  
    2.90        if (fan != null) {
    2.91 @@ -167,7 +197,7 @@
    2.92        NvPStates states = new NvPStates();
    2.93        states.Version = NVAPI.GPU_PSTATES_VER;
    2.94        states.PStates = new NvPState[NVAPI.MAX_PSTATES_PER_GPU];
    2.95 -      if (NVAPI.NvAPI_GPU_GetPStates != null && 
    2.96 +      if (NVAPI.NvAPI_GPU_GetPStates != null &&
    2.97          NVAPI.NvAPI_GPU_GetPStates(handle, ref states) == NvStatus.OK) {
    2.98          for (int i = 0; i < 3; i++)
    2.99            if (states.PStates[i].Present) {
   2.100 @@ -188,12 +218,9 @@
   2.101          }
   2.102        }
   2.103  
   2.104 -      NvGPUCoolerSettings coolerSettings = new NvGPUCoolerSettings();
   2.105 -      coolerSettings.Version = NVAPI.GPU_COOLER_SETTINGS_VER;
   2.106 -      coolerSettings.Cooler = new NvCooler[NVAPI.MAX_COOLER_PER_GPU];
   2.107 -      if (NVAPI.NvAPI_GPU_GetCoolerSettings != null && 
   2.108 -        NVAPI.NvAPI_GPU_GetCoolerSettings(handle, 0, ref coolerSettings) ==
   2.109 -        NvStatus.OK && coolerSettings.Count > 0) {
   2.110 +
   2.111 +      NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
   2.112 +      if (coolerSettings.Count > 0) {
   2.113          control.Value = coolerSettings.Cooler[0].CurrentLevel;
   2.114          ActivateSensor(control);
   2.115        }
   2.116 @@ -202,9 +229,8 @@
   2.117        memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
   2.118        memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
   2.119        if (NVAPI.NvAPI_GPU_GetMemoryInfo != null && displayHandle.HasValue &&
   2.120 -        NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) == 
   2.121 -        NvStatus.OK) 
   2.122 -      {
   2.123 +        NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, ref memoryInfo) ==
   2.124 +        NvStatus.OK) {
   2.125          uint totalMemory = memoryInfo.Values[0];
   2.126          uint freeMemory = memoryInfo.Values[4];
   2.127          float usedMemory = Math.Max(totalMemory - freeMemory, 0);
   2.128 @@ -221,9 +247,8 @@
   2.129  
   2.130        r.AppendFormat("Name: {0}{1}", name, Environment.NewLine);
   2.131        r.AppendFormat("Index: {0}{1}", adapterIndex, Environment.NewLine);
   2.132 -      
   2.133 -      if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) 
   2.134 -      {
   2.135 +
   2.136 +      if (displayHandle.HasValue && NVAPI.NvAPI_GetDisplayDriverVersion != null) {
   2.137          NvDisplayDriverVersion driverVersion = new NvDisplayDriverVersion();
   2.138          driverVersion.Version = NVAPI.DISPLAY_DRIVER_VERSION_VER;
   2.139          if (NVAPI.NvAPI_GetDisplayDriverVersion(displayHandle.Value,
   2.140 @@ -231,7 +256,7 @@
   2.141            r.Append("Driver Version: ");
   2.142            r.Append(driverVersion.DriverVersion / 100);
   2.143            r.Append(".");
   2.144 -          r.Append((driverVersion.DriverVersion % 100).ToString("00", 
   2.145 +          r.Append((driverVersion.DriverVersion % 100).ToString("00",
   2.146              CultureInfo.InvariantCulture));
   2.147            r.AppendLine();
   2.148            r.Append("Driver Branch: ");
   2.149 @@ -269,7 +294,7 @@
   2.150            r.AppendLine(status.ToString());
   2.151          }
   2.152          r.AppendLine();
   2.153 -      }      
   2.154 +      }
   2.155  
   2.156        if (NVAPI.NvAPI_GPU_GetAllClocks != null) {
   2.157          NvClocks allClocks = new NvClocks();
   2.158 @@ -290,10 +315,10 @@
   2.159            r.AppendLine(status.ToString());
   2.160          }
   2.161          r.AppendLine();
   2.162 -      }         
   2.163 -           
   2.164 +      }
   2.165 +
   2.166        if (NVAPI.NvAPI_GPU_GetTachReading != null) {
   2.167 -        int tachValue; 
   2.168 +        int tachValue;
   2.169          NvStatus status = NVAPI.NvAPI_GPU_GetTachReading(handle, out tachValue);
   2.170  
   2.171          r.AppendLine("Tachometer");
   2.172 @@ -332,7 +357,7 @@
   2.173          usages.Version = NVAPI.GPU_USAGES_VER;
   2.174          usages.Usage = new uint[NVAPI.MAX_USAGES_PER_GPU];
   2.175          NvStatus status = NVAPI.NvAPI_GPU_GetUsages(handle, ref usages);
   2.176 -     
   2.177 +
   2.178          r.AppendLine("Usages");
   2.179          r.AppendLine();
   2.180          if (status == NvStatus.OK) {
   2.181 @@ -394,7 +419,7 @@
   2.182          NvMemoryInfo memoryInfo = new NvMemoryInfo();
   2.183          memoryInfo.Version = NVAPI.GPU_MEMORY_INFO_VER;
   2.184          memoryInfo.Values = new uint[NVAPI.MAX_MEMORY_VALUES_PER_GPU];
   2.185 -        NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value, 
   2.186 +        NvStatus status = NVAPI.NvAPI_GPU_GetMemoryInfo(displayHandle.Value,
   2.187            ref memoryInfo);
   2.188  
   2.189          r.AppendLine("Memory Info");
   2.190 @@ -412,5 +437,45 @@
   2.191  
   2.192        return r.ToString();
   2.193      }
   2.194 +
   2.195 +    private void SoftwareControlValueChanged(IControl control) {
   2.196 +      SaveDefaultFanSpeed();
   2.197 +      NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
   2.198 +      coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
   2.199 +      coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
   2.200 +      coolerLevels.Levels[0].Level = (int)control.SoftwareValue;
   2.201 +      coolerLevels.Levels[0].Policy = 1;
   2.202 +      NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
   2.203 +    }
   2.204 +
   2.205 +    private void SaveDefaultFanSpeed() {
   2.206 +      if (!restoreDefaultFanSpeedRequired) {
   2.207 +        NvGPUCoolerSettings coolerSettings = GetCoolerSettings();
   2.208 +        if (coolerSettings.Count > 0) {
   2.209 +          restoreDefaultFanSpeedRequired = true;
   2.210 +          initialFanSpeedValue.Level = coolerSettings.Cooler[0].CurrentLevel;
   2.211 +          initialFanSpeedValue.Policy = coolerSettings.Cooler[0].CurrentPolicy;
   2.212 +        }
   2.213 +      }
   2.214 +    }
   2.215 +
   2.216 +    private void ControlModeChanged(IControl control) {
   2.217 +      if (control.ControlMode == ControlMode.Default) {
   2.218 +        RestoreDefaultFanSpeed();
   2.219 +      } else {
   2.220 +        SoftwareControlValueChanged(control);
   2.221 +      }
   2.222 +    }
   2.223 +
   2.224 +    private void RestoreDefaultFanSpeed() {
   2.225 +      if (restoreDefaultFanSpeedRequired) {
   2.226 +        NvGPUCoolerLevels coolerLevels = new NvGPUCoolerLevels();
   2.227 +        coolerLevels.Version = NVAPI.GPU_COOLER_LEVELS_VER;
   2.228 +        coolerLevels.Levels = new NvLevel[NVAPI.MAX_COOLER_PER_GPU];
   2.229 +        coolerLevels.Levels[0] = initialFanSpeedValue;
   2.230 +        NVAPI.NvAPI_GPU_SetCoolerLevels(handle, 0, ref coolerLevels);
   2.231 +        restoreDefaultFanSpeedRequired = false;
   2.232 +      }
   2.233 +    }
   2.234    }
   2.235  }