From 9a970c095551bc563c6cc93c8c5860c7ce1e374e Mon Sep 17 00:00:00 2001 From: jsteube Date: Sat, 18 Jun 2016 10:59:58 +0200 Subject: [PATCH] Added support for XNVCTRL on Linux to add support for --gpu-temp-retain for NVidia GPU --- docs/changes.txt | 1 + include/common.h | 2 + include/ext_xnvctrl.h | 92 ++++++++++++++++++++++++ include/shared.h | 2 + include/types.h | 8 ++- src/Makefile | 9 +-- src/ext_xnvctrl.c | 162 ++++++++++++++++++++++++++++++++++++++++++ src/hashcat.c | 92 +++++++++++++++++++----- src/shared.c | 22 +++++- 9 files changed, 365 insertions(+), 25 deletions(-) create mode 100644 include/ext_xnvctrl.h create mode 100644 src/ext_xnvctrl.c diff --git a/docs/changes.txt b/docs/changes.txt index 068593abf..a842ae111 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -137,3 +137,4 @@ It combines all features of all hashcat projects in one project. - Disabled retain support by default, you can reactive it using --gpu-temp-retain - Completely get rid of HAVE_ADL, HAVE_NVML and HAVE_NVAPI in sources - Replaced NVAPI with NVML on windows +- Added support for XNVCTRL on Linux to add support for --gpu-temp-retain for NVidia GPU diff --git a/include/common.h b/include/common.h index 52562cbab..be7ea98f2 100644 --- a/include/common.h +++ b/include/common.h @@ -56,6 +56,7 @@ typedef void *OCL_LIB; typedef void *ADL_LIB; typedef void *NVAPI_LIB; typedef void *NVML_LIB; +typedef void *XNVCTRL_LIB; #ifdef OSX #define __stdcall #endif @@ -90,6 +91,7 @@ typedef HINSTANCE OCL_LIB; typedef HINSTANCE ADL_LIB; typedef HINSTANCE NVAPI_LIB; typedef HINSTANCE NVML_LIB; +typedef HINSTANCE XNVCTRL_LIB; #endif #define mkdir(name,mode) mkdir (name) diff --git a/include/ext_xnvctrl.h b/include/ext_xnvctrl.h new file mode 100644 index 000000000..f608555d1 --- /dev/null +++ b/include/ext_xnvctrl.h @@ -0,0 +1,92 @@ +/** + * Authors.....: Jens Steube + * License.....: MIT + */ + +#ifndef EXT_XNVCTRL_H +#define EXT_XNVCTRL_H + +#if defined(HAVE_HWMON) + +#include + +/** + * Stuff from X11/Xlib.h + */ + +typedef void *(*XOPENDISPLAY) (char *); +typedef int (*XCLOSEDISPLAY) (void *); + +/** + * Declarations from NVCtrl.h + */ + +#define NV_CTRL_TARGET_TYPE_GPU 1 +#define NV_CTRL_TARGET_TYPE_COOLER 5 /* e.g., fan */ + +#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL 319 /* RW-G */ +#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL_FALSE 0 +#define NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE 1 + +#define NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL 417 /* R--C */ +#define NV_CTRL_THERMAL_COOLER_LEVEL 320 /* RW-C */ + +/* + * NV_CTRL_GPU_CORE_THRESHOLD reflects the temperature at which the + * GPU is throttled to prevent overheating. + */ + +#define NV_CTRL_GPU_CORE_THRESHOLD 61 /* R--G */ + +/** + * hashcat stuff from here + */ + +typedef int HM_ADAPTER_XNVCTRL; + +#include + +#if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +#define XNVCTRL_API_CALL __stdcall +#else +#define XNVCTRL_API_CALL +#endif + +typedef int (*XNVCTRL_API_CALL XNVCTRLQUERYTARGETATTRIBUTE) (void *, int, int, unsigned int, unsigned int, int *); +typedef void (*XNVCTRL_API_CALL XNVCTRLSETTARGETATTRIBUTE) (void *, int, int, unsigned int, unsigned int, int); + +typedef struct +{ + void *dpy; + + XNVCTRL_LIB lib_x11; + XNVCTRL_LIB lib_xnvctrl; + + XOPENDISPLAY XOpenDisplay; + XCLOSEDISPLAY XCloseDisplay; + + XNVCTRLQUERYTARGETATTRIBUTE XNVCTRLQueryTargetAttribute; + XNVCTRLSETTARGETATTRIBUTE XNVCTRLSetTargetAttribute; + +} hm_xnvctrl_lib_t; + +#define XNVCTRL_PTR hm_xnvctrl_lib_t + +int xnvctrl_init (XNVCTRL_PTR *xnvctrl); +void xnvctrl_close (XNVCTRL_PTR *xnvctrl); + +int hm_XNVCTRL_XOpenDisplay (XNVCTRL_PTR *xnvctrl); +void hm_XNVCTRL_XCloseDisplay (XNVCTRL_PTR *xnvctrl); + +int get_core_threshold (XNVCTRL_PTR *xnvctrl, int gpu, int *val); + +int get_fan_control (XNVCTRL_PTR *xnvctrl, int gpu, int *val); +int set_fan_control (XNVCTRL_PTR *xnvctrl, int gpu, int val); + +int get_fan_speed_current (XNVCTRL_PTR *xnvctrl, int gpu, int *val); +int get_fan_speed_target (XNVCTRL_PTR *xnvctrl, int gpu, int *val); +int set_fan_speed_target (XNVCTRL_PTR *xnvctrl, int gpu, int val); + +#endif // HAVE_HWMON + +#endif // EXT_XNVCTRL_H diff --git a/include/shared.h b/include/shared.h index 020311719..34824d366 100644 --- a/include/shared.h +++ b/include/shared.h @@ -117,6 +117,7 @@ static inline int CPU_ISSET (int num, cpu_set_t *cs) { return (cs->count & (1 < #include "ext_ADL.h" #include "ext_nvapi.h" #include "ext_nvml.h" +#include "ext_xnvctrl.h" /** * shared stuff @@ -1464,6 +1465,7 @@ int hm_get_memoryspeed_with_device_id (const uint device_id); int hm_get_corespeed_with_device_id (const uint device_id); int hm_get_throttle_with_device_id (const uint device_id); int hm_set_fanspeed_with_device_id_adl (const uint device_id, const int fanspeed, const int fanpolicy); +int hm_set_fanspeed_with_device_id_xnvctrl (const uint device_id, const int fanspeed); void hm_device_val_to_str (char *target_buf, int max_buf_size, char *suffix, int value); #endif // HAVE_HWMON diff --git a/include/types.h b/include/types.h index c8f8bf6f9..85783472c 100644 --- a/include/types.h +++ b/include/types.h @@ -1099,9 +1099,10 @@ typedef struct __hc_device_param hc_device_param_t; #ifdef HAVE_HWMON typedef struct { - HM_ADAPTER_ADL adl; - HM_ADAPTER_NVML nvml; - HM_ADAPTER_NVAPI nvapi; + HM_ADAPTER_ADL adl; + HM_ADAPTER_NVML nvml; + HM_ADAPTER_NVAPI nvapi; + HM_ADAPTER_XNVCTRL xnvctrl; int od_version; @@ -1177,6 +1178,7 @@ typedef struct void *hm_adl; void *hm_nvml; void *hm_nvapi; + void *hm_xnvctrl; hm_attrs_t hm_device[DEVICES_MAX]; #endif diff --git a/src/Makefile b/src/Makefile index 182bdfad3..cab2bebf6 100644 --- a/src/Makefile +++ b/src/Makefile @@ -156,17 +156,18 @@ ifeq ($(UNAME),Linux) NATIVE_OBJS += obj/ext_ADL.NATIVE.o NATIVE_OBJS += obj/ext_nvapi.NATIVE.o NATIVE_OBJS += obj/ext_nvml.NATIVE.o +NATIVE_OBJS += obj/ext_xnvctrl.NATIVE.o endif -LINUX_32_OBJS := obj/ext_OpenCL.LINUX.32.o obj/shared.LINUX.32.o obj/rp_kernel_on_cpu.LINUX.32.o obj/ext_ADL.LINUX.32.o obj/ext_nvml.LINUX.32.o obj/ext_nvapi.LINUX.32.o -LINUX_64_OBJS := obj/ext_OpenCL.LINUX.64.o obj/shared.LINUX.64.o obj/rp_kernel_on_cpu.LINUX.64.o obj/ext_ADL.LINUX.64.o obj/ext_nvml.LINUX.64.o obj/ext_nvapi.LINUX.64.o +LINUX_32_OBJS := obj/ext_OpenCL.LINUX.32.o obj/shared.LINUX.32.o obj/rp_kernel_on_cpu.LINUX.32.o obj/ext_ADL.LINUX.32.o obj/ext_nvml.LINUX.32.o obj/ext_nvapi.LINUX.32.o obj/ext_xnvctrl.LINUX.32.o +LINUX_64_OBJS := obj/ext_OpenCL.LINUX.64.o obj/shared.LINUX.64.o obj/rp_kernel_on_cpu.LINUX.64.o obj/ext_ADL.LINUX.64.o obj/ext_nvml.LINUX.64.o obj/ext_nvapi.LINUX.64.o obj/ext_xnvctrl.LINUX.64.o ## may need to adjust according to your mingw distribution CRT_GLOB_32 := /usr/i686-w64-mingw32/lib/CRT_glob.o CRT_GLOB_64 := /usr/x86_64-w64-mingw32/lib/CRT_glob.o -WIN_32_OBJS := obj/ext_OpenCL.WIN.32.o obj/shared.WIN.32.o obj/rp_kernel_on_cpu.WIN.32.o obj/ext_ADL.WIN.32.o obj/ext_nvml.WIN.32.o obj/ext_nvapi.WIN.32.o $(CRT_GLOB_32) -WIN_64_OBJS := obj/ext_OpenCL.WIN.64.o obj/shared.WIN.64.o obj/rp_kernel_on_cpu.WIN.64.o obj/ext_ADL.WIN.64.o obj/ext_nvml.WIN.64.o obj/ext_nvapi.WIN.64.o $(CRT_GLOB_64) +WIN_32_OBJS := obj/ext_OpenCL.WIN.32.o obj/shared.WIN.32.o obj/rp_kernel_on_cpu.WIN.32.o obj/ext_ADL.WIN.32.o obj/ext_nvml.WIN.32.o obj/ext_nvapi.WIN.32.o obj/ext_xnvctrl.WIN.32.o $(CRT_GLOB_32) +WIN_64_OBJS := obj/ext_OpenCL.WIN.64.o obj/shared.WIN.64.o obj/rp_kernel_on_cpu.WIN.64.o obj/ext_ADL.WIN.64.o obj/ext_nvml.WIN.64.o obj/ext_nvapi.WIN.64.o obj/ext_xnvctrl.WIN.64.o $(CRT_GLOB_64) ## ## Targets: Global diff --git a/src/ext_xnvctrl.c b/src/ext_xnvctrl.c new file mode 100644 index 000000000..7c97e792a --- /dev/null +++ b/src/ext_xnvctrl.c @@ -0,0 +1,162 @@ +/** + * Authors.....: Jens Steube + * License.....: MIT + */ + +#include + +int xnvctrl_init (XNVCTRL_PTR *xnvctrl) +{ + if (!xnvctrl) return (-1); + + memset (xnvctrl, 0, sizeof (XNVCTRL_PTR)); + + #ifdef _WIN + + // unsupport platform? + return (-1); + + #elif _POSIX + + xnvctrl->lib_x11 = dlopen ("libX11.so", RTLD_LAZY); + + if (xnvctrl->lib_x11 == NULL) + { + if (data.quiet == 0) log_info ("WARNING: load X11 library failed, proceed without X11 HWMon enabled."); + + return -1; + } + + xnvctrl->lib_xnvctrl = dlopen ("libXNVCtrl.so", RTLD_LAZY); + + if (xnvctrl->lib_xnvctrl == NULL) + { + xnvctrl->lib_xnvctrl = dlopen ("libXNVCtrl.so.0", RTLD_LAZY); + + if (xnvctrl->lib_xnvctrl == NULL) + { + if (data.quiet == 0) log_info ("WARNING: load XNVCTRL library failed, proceed without XNVCTRL HWMon enabled."); + + return -1; + } + } + + xnvctrl->XOpenDisplay = dlsym (xnvctrl->lib_x11, "XOpenDisplay"); + xnvctrl->XCloseDisplay = dlsym (xnvctrl->lib_x11, "XCloseDisplay"); + + xnvctrl->XNVCTRLQueryTargetAttribute = dlsym (xnvctrl->lib_xnvctrl, "XNVCTRLQueryTargetAttribute"); + xnvctrl->XNVCTRLSetTargetAttribute = dlsym (xnvctrl->lib_xnvctrl, "XNVCTRLSetTargetAttribute"); + + #endif + + // not using HC_LOAD_FUNC() here, because we're using 2 libraries and therefore have 2 different variable names for them + + return 0; +} + +void xnvctrl_close (XNVCTRL_PTR *xnvctrl) +{ + if (xnvctrl) + { + #if _POSIX + + if (xnvctrl->lib_x11) + { + dlclose (xnvctrl->lib_x11); + } + + if (xnvctrl->lib_xnvctrl) + { + dlclose (xnvctrl->lib_xnvctrl); + } + + #endif + + myfree (xnvctrl); + } +} + +int hm_XNVCTRL_XOpenDisplay (XNVCTRL_PTR *xnvctrl) +{ + void *dpy = xnvctrl->XOpenDisplay (NULL); + + if (dpy == NULL) + { + return -1; + } + + xnvctrl->dpy = dpy; + + return 0; +} + +void hm_XNVCTRL_XCloseDisplay (XNVCTRL_PTR *xnvctrl) +{ + xnvctrl->XCloseDisplay (xnvctrl->dpy); +} + +int get_fan_control (XNVCTRL_PTR *xnvctrl, int gpu, int *val) +{ + int rc = xnvctrl->XNVCTRLQueryTargetAttribute (xnvctrl->dpy, NV_CTRL_TARGET_TYPE_GPU, gpu, 0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL, val); + + if (!rc) return -1; + + return 0; +} + +int set_fan_control (XNVCTRL_PTR *xnvctrl, int gpu, int val) +{ + xnvctrl->XNVCTRLSetTargetAttribute (xnvctrl->dpy, NV_CTRL_TARGET_TYPE_GPU, gpu, 0, NV_CTRL_GPU_COOLER_MANUAL_CONTROL, val); + + int cur; + + int rc = get_fan_control (xnvctrl, gpu, &cur); + + if (rc == -1) return -1; + + if (cur != val) return -1; + + return 0; +} + +int get_core_threshold (XNVCTRL_PTR *xnvctrl, int gpu, int *val) +{ + int rc = xnvctrl->XNVCTRLQueryTargetAttribute (xnvctrl->dpy, NV_CTRL_TARGET_TYPE_GPU, gpu, 0, NV_CTRL_GPU_CORE_THRESHOLD, val); + + if (!rc) return -1; + + return 0; +} + +int get_fan_speed_current (XNVCTRL_PTR *xnvctrl, int gpu, int *val) +{ + int rc = xnvctrl->XNVCTRLQueryTargetAttribute (xnvctrl->dpy, NV_CTRL_TARGET_TYPE_COOLER, gpu, 0, NV_CTRL_THERMAL_COOLER_CURRENT_LEVEL, val); + + if (!rc) return -1; + + return 0; +} + +int get_fan_speed_target (XNVCTRL_PTR *xnvctrl, int gpu, int *val) +{ + int rc = xnvctrl->XNVCTRLQueryTargetAttribute (xnvctrl->dpy, NV_CTRL_TARGET_TYPE_COOLER, gpu, 0, NV_CTRL_THERMAL_COOLER_LEVEL, val); + + if (!rc) return -1; + + return 0; +} + +int set_fan_speed_target (XNVCTRL_PTR *xnvctrl, int gpu, int val) +{ + xnvctrl->XNVCTRLSetTargetAttribute (xnvctrl->dpy, NV_CTRL_TARGET_TYPE_COOLER, gpu, 0, NV_CTRL_THERMAL_COOLER_LEVEL, val); + + int cur; + + int rc = get_fan_speed_target (xnvctrl, gpu, &cur); + + if (rc == -1) return -1; + + if (cur != val) return -1; + + return 0; +} diff --git a/src/hashcat.c b/src/hashcat.c index 0619fce48..dec206573 100644 --- a/src/hashcat.c +++ b/src/hashcat.c @@ -4235,7 +4235,9 @@ static void *thread_monitor (void *p) } else if (device_param->device_vendor_id == VENDOR_ID_NV) { - + #ifdef _POSIX + hm_set_fanspeed_with_device_id_xnvctrl (device_id, fan_speed_new); + #endif } fan_speed_chgd[device_id] = 1; @@ -13651,9 +13653,10 @@ int main (int argc, char **argv) * OpenCL devices: simply push all devices from all platforms into the same device array */ - int need_adl = 0; - int need_nvapi = 0; - int need_nvml = 0; + int need_adl = 0; + int need_nvapi = 0; + int need_nvml = 0; + int need_xnvctrl = 0; hc_device_param_t *devices_param = (hc_device_param_t *) mycalloc (DEVICES_MAX, sizeof (hc_device_param_t)); @@ -14063,6 +14066,10 @@ int main (int argc, char **argv) { need_nvml = 1; + #ifdef _POSIX + need_xnvctrl = 1; + #endif + #ifdef _WIN need_nvapi = 1; #endif @@ -14363,19 +14370,22 @@ int main (int argc, char **argv) */ #ifdef HAVE_HWMON - hm_attrs_t hm_adapters_adl[DEVICES_MAX] = { { 0 } }; - hm_attrs_t hm_adapters_nvapi[DEVICES_MAX] = { { 0 } }; - hm_attrs_t hm_adapters_nvml[DEVICES_MAX] = { { 0 } }; + hm_attrs_t hm_adapters_adl[DEVICES_MAX] = { { 0 } }; + hm_attrs_t hm_adapters_nvapi[DEVICES_MAX] = { { 0 } }; + hm_attrs_t hm_adapters_nvml[DEVICES_MAX] = { { 0 } }; + hm_attrs_t hm_adapters_xnvctrl[DEVICES_MAX] = { { 0 } }; if (gpu_temp_disable == 0) { - ADL_PTR *adl = (ADL_PTR *) mymalloc (sizeof (ADL_PTR)); - NVAPI_PTR *nvapi = (NVAPI_PTR *) mymalloc (sizeof (NVAPI_PTR)); - NVML_PTR *nvml = (NVML_PTR *) mymalloc (sizeof (NVML_PTR)); + ADL_PTR *adl = (ADL_PTR *) mymalloc (sizeof (ADL_PTR)); + NVAPI_PTR *nvapi = (NVAPI_PTR *) mymalloc (sizeof (NVAPI_PTR)); + NVML_PTR *nvml = (NVML_PTR *) mymalloc (sizeof (NVML_PTR)); + XNVCTRL_PTR *xnvctrl = (XNVCTRL_PTR *) mymalloc (sizeof (XNVCTRL_PTR)); - data.hm_adl = NULL; - data.hm_nvapi = NULL; - data.hm_nvml = NULL; + data.hm_adl = NULL; + data.hm_nvapi = NULL; + data.hm_nvml = NULL; + data.hm_xnvctrl = NULL; if ((need_nvml == 1) && (nvml_init (nvml) == 0)) { @@ -14432,6 +14442,30 @@ int main (int argc, char **argv) } } + if ((need_xnvctrl == 1) && (xnvctrl_init (xnvctrl) == 0)) + { + data.hm_xnvctrl = xnvctrl; + } + + if (data.hm_xnvctrl) + { + if (hm_XNVCTRL_XOpenDisplay (data.hm_xnvctrl) == 0) + { + for (uint device_id = 0; device_id < data.devices_cnt; device_id++) + { + hc_device_param_t *device_param = &data.devices_param[device_id]; + + if ((device_param->device_type & CL_DEVICE_TYPE_GPU) == 0) continue; + + hm_adapters_xnvctrl[device_id].xnvctrl = device_id; + + int speed = 0; + + if (get_fan_speed_current (data.hm_xnvctrl, device_id, &speed) == 0) hm_adapters_xnvctrl[device_id].fan_get_supported = 1; + } + } + } + if ((need_adl == 1) && (adl_init (adl) == 0)) { data.hm_adl = adl; @@ -14478,7 +14512,7 @@ int main (int argc, char **argv) } } - if (data.hm_adl == NULL && data.hm_nvml == NULL) + if (data.hm_adl == NULL && data.hm_nvml == NULL && data.hm_xnvctrl) { gpu_temp_disable = 1; } @@ -14567,7 +14601,7 @@ int main (int argc, char **argv) */ #ifdef HAVE_HWMON - if (gpu_temp_disable == 0 && data.hm_adl == NULL && data.hm_nvml == NULL) + if (gpu_temp_disable == 0 && data.hm_adl == NULL && data.hm_nvml == NULL && data.hm_xnvctrl == NULL) { log_info ("Watchdog: Hardware Monitoring Interface not found on your system"); } @@ -14617,6 +14651,7 @@ int main (int argc, char **argv) data.hm_device[device_id].adl = hm_adapters_adl[platform_devices_id].adl; data.hm_device[device_id].nvapi = 0; data.hm_device[device_id].nvml = 0; + data.hm_device[device_id].xnvctrl = 0; data.hm_device[device_id].od_version = hm_adapters_adl[platform_devices_id].od_version; data.hm_device[device_id].fan_get_supported = hm_adapters_adl[platform_devices_id].fan_get_supported; data.hm_device[device_id].fan_set_supported = hm_adapters_adl[platform_devices_id].fan_set_supported; @@ -14627,6 +14662,7 @@ int main (int argc, char **argv) data.hm_device[device_id].adl = 0; data.hm_device[device_id].nvapi = hm_adapters_nvapi[platform_devices_id].nvapi; data.hm_device[device_id].nvml = hm_adapters_nvml[platform_devices_id].nvml; + data.hm_device[device_id].xnvctrl = hm_adapters_xnvctrl[platform_devices_id].xnvctrl; data.hm_device[device_id].od_version = 0; data.hm_device[device_id].fan_get_supported = hm_adapters_nvml[platform_devices_id].fan_get_supported; data.hm_device[device_id].fan_set_supported = 0; @@ -16144,7 +16180,9 @@ int main (int argc, char **argv) } else if (device_param->device_vendor_id == VENDOR_ID_NV) { - + #ifdef _POSIX + rc = hm_set_fanspeed_with_device_id_xnvctrl (device_id, fanspeed); + #endif } if (rc == 0) @@ -18344,7 +18382,9 @@ int main (int argc, char **argv) } else if (device_param->device_vendor_id == VENDOR_ID_NV) { - + #ifdef _POSIX + rc = set_fan_control (data.hm_xnvctrl, data.hm_device[device_id].xnvctrl, NV_CTRL_GPU_COOLER_MANUAL_CONTROL_FALSE); + #endif } if (rc == -1) log_info ("WARNING: Failed to restore default fan speed and policy for device #%", device_id + 1); @@ -18442,6 +18482,24 @@ int main (int argc, char **argv) data.hm_nvml = NULL; } + if (data.hm_nvapi) + { + hm_NvAPI_Unload (data.hm_nvapi); + + nvapi_close (data.hm_nvapi); + + data.hm_nvapi = NULL; + } + + if (data.hm_xnvctrl) + { + hm_XNVCTRL_XCloseDisplay (data.hm_xnvctrl); + + xnvctrl_close (data.hm_xnvctrl); + + data.hm_xnvctrl = NULL; + } + if (data.hm_adl) { hm_ADL_Main_Control_Destroy (data.hm_adl); diff --git a/src/shared.c b/src/shared.c index ac9921670..43aded474 100644 --- a/src/shared.c +++ b/src/shared.c @@ -3195,7 +3195,12 @@ int hm_get_fanpolicy_with_device_id (const uint device_id) if (data.devices_param[device_id].device_vendor_id == VENDOR_ID_NV) { #if defined(LINUX) - return 0; + if (data.hm_xnvctrl) + { + if (set_fan_control (data.hm_xnvctrl, data.hm_device[device_id].xnvctrl, NV_CTRL_GPU_COOLER_MANUAL_CONTROL_TRUE) != 0) return -1; + + return 1; + } #endif #if defined(WIN) @@ -3404,6 +3409,21 @@ int hm_get_throttle_with_device_id (const uint device_id) return -1; } +int hm_set_fanspeed_with_device_id_xnvctrl (const uint device_id, const int fanspeed) +{ + if (data.hm_device[device_id].fan_set_supported == 1) + { + if (data.hm_xnvctrl) + { + if (set_fan_speed_target (data.hm_xnvctrl, data.hm_device[device_id].xnvctrl, fanspeed) != 0) return -1; + + return 0; + } + } + + return -1; +} + int hm_set_fanspeed_with_device_id_adl (const uint device_id, const int fanspeed, const int fanpolicy) { if (data.hm_device[device_id].fan_set_supported == 1)