Open Jackiiiii opened 12 months ago
If you changed line 153, you might need to change line 131 as well, since line 131 would try to search your cpu temp. sensor, I haven't tested this code with with Proxmox yet, but I think I will try it whenever I have the time.
do i need line 131? or can i just mark it out // # something like that?
I think i got everything right, could you maybe explain me what this is for? - >#define CPU_TEMP_CMD_LEN 9
There was a kernal update and i update the lm-sernsors What ever i do this error is not fixable idk what i should do even that i give the direct path still there that error...
But the Watercooler is working fine....
2023-12-12T12:52:37.042999+01:00 kernel: [ 29.398101] Error opening file /sys/class/hwmon/hwmon3/name
2023-12-12T12:52:37.043008+01:00 kernel: [ 29.398135] Error opening file /sys/class/hwmon/hwmon6/name
2023-12-12T12:52:37.090992+01:00 kernel: [ 29.446640] Error opening file /sys/class/hwmon/hwmon3/name
2023-12-12T12:52:37.090996+01:00 kernel: [ 29.446659] Error opening file /sys/class/hwmon/hwmon6/name
2023-12-12T12:52:39.154993+01:00 kernel: [ 31.510077] Error opening file /sys/class/hwmon/hwmon3/name
2023-12-12T12:52:39.155000+01:00 kernel: [ 31.510106] Error opening file /sys/class/hwmon/hwmon6/name
2023-12-12T12:52:39.202992+01:00 kernel: [ 31.558523] Error opening file /sys/class/hwmon/hwmon3/name
2023-12-12T12:52:39.202996+01:00 kernel: [ 31.558542] Error opening file /sys/class/hwmon/hwmon6/name
There was a kernal update and i update the lm-sernsors What ever i do this error is not fixable idk what i should do even that i give the direct path still there that error...
But the Watercooler is working fine....
2023-12-12T12:52:37.042999+01:00 kernel: [ 29.398101] Error opening file /sys/class/hwmon/hwmon3/name 2023-12-12T12:52:37.043008+01:00 kernel: [ 29.398135] Error opening file /sys/class/hwmon/hwmon6/name 2023-12-12T12:52:37.090992+01:00 kernel: [ 29.446640] Error opening file /sys/class/hwmon/hwmon3/name 2023-12-12T12:52:37.090996+01:00 kernel: [ 29.446659] Error opening file /sys/class/hwmon/hwmon6/name 2023-12-12T12:52:39.154993+01:00 kernel: [ 31.510077] Error opening file /sys/class/hwmon/hwmon3/name 2023-12-12T12:52:39.155000+01:00 kernel: [ 31.510106] Error opening file /sys/class/hwmon/hwmon6/name 2023-12-12T12:52:39.202992+01:00 kernel: [ 31.558523] Error opening file /sys/class/hwmon/hwmon3/name 2023-12-12T12:52:39.202996+01:00 kernel: [ 31.558542] Error opening file /sys/class/hwmon/hwmon6/name
May I know your current kernel version? Are you using it in proxmox? I didn't try it on Proxmox yet. I will be testing on Proxmox soon though, please feel free to let me know the Proxmox version you are using so that I can test with it.
Kernel 6.5.11-7-pve
And this is not my cpu temp its something else /sys/class/thermal/thermal_zone%d/temp",priv->cputhermalzoneid); taking temp from /sys/class/hwmon/hwmon5/temp1_input
it was befor on hwmon4 <- now its hwmon5 since the update and i need to edite it allways my self cause it cant fine it by self.
is it because maybe i got just a diffrent cpu, using threadripper 3960x
Kernel 6.5.11-7-pve
And this is not my cpu temp its something else /sys/class/thermal/thermal_zone%d/temp",priv->cputhermalzoneid); taking temp from /sys/class/hwmon/hwmon5/temp1_input
it was befor on hwmon4 <- now its hwmon5 since the update and i need to edite it allways my self cause it cant fine it by self.
is it because maybe i got just a diffrent cpu, using threadripper 3960x
Could you help me to check each of your /sys/class/thermal/thermal_zone?/type, because I don't have a threadripper to test with at the moment, and I would need to know which of the thermal_zone number correspond to your CPU temperature.
For you information, I tested PVE with my i9-13900 CPU and it runs fine, so I think it's because of my code does not recognize your CPU yet, your help to help me identify your CPU would be helpful.
# dir
cooling_device0 cooling_device15 cooling_device21 cooling_device28 cooling_device34 cooling_device40 cooling_device47 thermal_zone1
cooling_device1 cooling_device16 cooling_device22 cooling_device29 cooling_device35 cooling_device41 cooling_device5
cooling_device10 cooling_device17 cooling_device23 cooling_device3 cooling_device36 cooling_device42 cooling_device6
cooling_device11 cooling_device18 cooling_device24 cooling_device30 cooling_device37 cooling_device43 cooling_device7
cooling_device12 cooling_device19 cooling_device25 cooling_device31 cooling_device38 cooling_device44 cooling_device8
cooling_device13 cooling_device2 cooling_device26 cooling_device32 cooling_device39 cooling_device45 cooling_device9
cooling_device14 cooling_device20 cooling_device27 cooling_device33 cooling_device4 cooling_device46 thermal_zone0
its thermal_zone0 and 1 i think but its strangely not the cpu temp.. its says an other temp of an other device. sure, u got discord or something maybe and u wana have a look by your self maybe?
# dir cooling_device0 cooling_device15 cooling_device21 cooling_device28 cooling_device34 cooling_device40 cooling_device47 thermal_zone1 cooling_device1 cooling_device16 cooling_device22 cooling_device29 cooling_device35 cooling_device41 cooling_device5 cooling_device10 cooling_device17 cooling_device23 cooling_device3 cooling_device36 cooling_device42 cooling_device6 cooling_device11 cooling_device18 cooling_device24 cooling_device30 cooling_device37 cooling_device43 cooling_device7 cooling_device12 cooling_device19 cooling_device25 cooling_device31 cooling_device38 cooling_device44 cooling_device8 cooling_device13 cooling_device2 cooling_device26 cooling_device32 cooling_device39 cooling_device45 cooling_device9 cooling_device14 cooling_device20 cooling_device27 cooling_device33 cooling_device4 cooling_device46 thermal_zone0
its thermal_zone0 and 1 i think but its strangely not the cpu temp.. its says an other temp of an other device. sure, u got discord or something maybe and u wana have a look by your self maybe?
could you help to run the following commands and show me the result? cat thermal_zone0/type cat thermal_zone1/type
cat thermal_zone0/type
acpitz
cat thermal_zone1/type
iwlwifi_1
cat thermal_zone0/type acpitz
cat thermal_zone1/type iwlwifi_1
You are right both are not the CPU temp, when you run "sensors" do you see your CPU temperature?
sensors
waterforce-hid-3-1
Adapter: HID adapter
Fan speed: 2046 RPM
Pump speed: 3101 RPM
Coolant temp: +39.0°C
Fan duty: 77.00 uW
Pump duty: 95.00 uW
it8792-isa-0a60
Adapter: ISA adapter
in0: 1.36 V (min = +0.00 V, max = +2.78 V)
in1: 1.51 V (min = +0.00 V, max = +2.78 V)
in2: 992.00 mV (min = +0.00 V, max = +2.78 V)
in3: 283.00 mV (min = +0.00 V, max = +2.78 V)
in4: 1.79 V (min = +0.00 V, max = +2.78 V)
in5: 1.50 V (min = +0.00 V, max = +2.78 V)
in6: 2.78 V (min = +0.00 V, max = +2.78 V) ALARM
3VSB: 3.36 V (min = +0.00 V, max = +5.56 V)
Vbat: 3.21 V
fan1: 0 RPM (min = 0 RPM)
fan2: 0 RPM (min = 0 RPM)
fan3: 0 RPM (min = 0 RPM)
temp1: +48.0°C (low = +127.0°C, high = +127.0°C) sensor = thermistor
temp2: -55.0°C (low = +127.0°C, high = +127.0°C) sensor = thermistor
temp3: +46.0°C (low = +127.0°C, high = +127.0°C) sensor = thermistor
intrusion0: ALARM
nvme-pci-0100
Adapter: PCI adapter
Composite: +47.9°C (low = -5.2°C, high = +83.8°C)
(crit = +87.8°C)
acpitz-acpi-0
Adapter: ACPI interface
temp1: +16.8°C (crit = +20.8°C)
iwlwifi_1-virtual-0
Adapter: Virtual device
temp1: +48.0°C
nouveau-pci-4a00
Adapter: PCI adapter
GPU core: 987.00 mV (min = +0.60 V, max = +1.27 V)
fan1: 0 RPM
temp1: +49.0°C (high = +95.0°C, hyst = +3.0°C)
(crit = +105.0°C, hyst = +5.0°C)
(emerg = +135.0°C, hyst = +5.0°C)
power1: 17.52 W (crit = 177.00 mW)
k10temp-pci-00c3
Adapter: PCI adapter
Tctl: +58.6°C
Tccd1: +48.0°C
Tccd3: +46.8°C
Tccd5: +47.5°C
Tccd7: +43.5°C
nvme-pci-0200
Adapter: PCI adapter
Composite: +49.9°C (low = -5.2°C, high = +83.8°C)
(crit = +87.8°C)
its in - > /sys/class/hwmon/hwmon5/temp1_input But befor update it was in hwmon4 And i have turn of the print cause it trying to search in hwmon1 2 3 4 5 6 and there is nothing.
to get it work even with error i dont this:
sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i);
//cat /sys/class/hwmon/hwmon5/name
for (u8 i=0;i<9;i++) {
sprintf(path_string,"/sys/class/thermal/cooling_device%d/type",i);
//sprintf(path,"/sys/class/thermal/thermal_zone%d/temp",priv->cputhermalzoneid);
sprintf(path,"/sys/class/hwmon/hwmon5/temp1_input",priv->cputhermalzoneid);
its in - > /sys/class/hwmon/hwmon5/temp1_input But befor update it was in hwmon4 And i have turn of the print cause it trying to search in hwmon1 2 3 4 5 6 and there is nothing.
could you help to run the following command? cat /sys/class/hwmon/hwmon5/name
Thats the CPU:
cat /sys/class/hwmon/hwmon5/name
k10temp
/sys/class/hwmon/hwmon5/temp1_input
temp1 is i think
Tctl: +58.6°C
cause checking it show the same temp as sensors command
ls /sys/class/hwmon/hwmon5/
device power temp1_input temp3_input temp5_input temp7_input temp9_input uevent
name subsystem temp1_label temp3_label temp5_label temp7_label temp9_label
It could be that may mainboard handel it otherway.
/sys/class/hwmon/hwmon5/temp1_input
temp1 is i think
Tctl: +58.6°C
cause checking it show the same temp as sensors command
ls /sys/class/hwmon/hwmon5/ device power temp1_input temp3_input temp5_input temp7_input temp9_input uevent name subsystem temp1_label temp3_label temp5_label temp7_label temp9_label
It could be that may mainboard handel it otherway.
seems your CPU temp is in this it8792-isa-0a60? would you be using Gigabyte Motherboard X570 Chipset?
when i turn on prime test for cpu it dont go high the temp in it8792-isa-0a60
the cpu is k10temp-pci-00c3
k10temp-pci-00c3
Adapter: PCI adapter
Tctl: +52.5°C
Tccd1: +51.2°C
Tccd3: +49.0°C
Tccd5: +45.2°C
Tccd7: +42.0°C
Main sensor is Tctl <--
i got gigabyte TRX40-AORUS-XTREME
when i turn on prime test for cpu it dont go high the temp in it8792-isa-0a60
the cpu is k10temp-pci-00c3
k10temp-pci-00c3 Adapter: PCI adapter Tctl: +52.5°C Tccd1: +51.2°C Tccd3: +49.0°C Tccd5: +45.2°C Tccd7: +42.0°C
Main sensor is Tctl <--
i got gigabyte TRX40-AORUS-XTREME
please try to change line to 131: sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i); 110: if (strcmp(temp_string,"k10temp\n")==0) 153: sprintf(path,"/sys/class/hwmon/hwmon%d/temp1_input",priv->cputhermalzoneid);
Not working at all, cooler stuck.
this works but has same errors too and print is off:
/*
* POC code use at your own risk
* modifed based on https://github.com/aleksamagicka/waterforce-hwmon/
*/
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
#include <asm/unaligned.h>
#include <linux/hid.h>
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cpufreq.h>
#include <linux/timer.h>
#include <linux/thermal.h>
#include <linux/kthread.h>
#define USB_VENDOR_ID_GIGABYTE 0x1044
#define USB_PRODUCT_ID_WATERFORCE_1 0x7a4d /* Gigabyte AORUS WATERFORCE X (240, 280, 360) */
#define USB_PRODUCT_ID_WATERFORCE_2 0x7a52 /* Gigabyte AORUS WATERFORCE X 360G */
#define USB_PRODUCT_ID_WATERFORCE_3 0x7a53 /* Gigabyte AORUS WATERFORCE EX 360 */
#define STATUS_VALIDITY 2 /* seconds */
#define MAX_REPORT_LENGTH 6144
#define WATERFORCE_TEMP_SENSOR 0xD
#define WATERFORCE_FAN_SPEED 0x02
#define WATERFORCE_PUMP_SPEED 0x05
#define WATERFORCE_FAN_DUTY 0x08
#define WATERFORCE_PUMP_DUTY 0x09
#define CPU_TEMP_CMD_LEN 9
#define FAN_COLOR_CMD_LEN 5
#define TIMER_WAKEUP_S 2
DECLARE_COMPLETION(status_report_received);
static const u8 get_status_cmd[] = { 0x99, 0xDA };
static const u8 cpu_temp_cmd[] = { 0x99,0xE0,0x00,0x25,0x20,0x05,0x05,0x18,0x30 };
static const u8 fan_color_cmd[] = { 0x99,0xCD,0xFF,0xFF,0xFF };
static const char *const waterforce_temp_label[] = {
"Coolant temp",
};
static const char *const waterforce_speed_label[] = {
"Fan speed",
"Pump speed",
"Fan duty",
"Pump duty"
};
static const char *const waterforce_pwm_label[] = {
"Fan duty",
"Pump duty"
};
static struct timer_list waterforce_timer;
struct hid_device *waterforce_device=NULL;
struct waterforce_data {
struct hid_device *hdev;
struct device *hwmon_dev;
struct mutex buffer_lock; /* For locking access to buffer */
/* Sensor data */
s32 temp_input[1];
u16 speed_input[4]; /* Fan and pump speed in RPM */
u16 duty_input[4]; /* Fan and pump duty in 0-100% */
u8 cpu_temp;
u8 ncore;
u8 nthread;
u8 cpufreqGhz1;
u8 cpufreqGhz2;
u8 fanColorR;
u8 fanColorG;
u8 fanColorB;
u8 *buffer;
u8 cputhermalzoneid;
u8 hwmonid;
bool updating;
unsigned long updated; /* jiffies */
};
static int read_file(char * path,char *buf,int buflen) {
struct file *temp_file;
// Open the temperature file for reading
temp_file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(temp_file)) {
printk(KERN_ERR "Error opening file %s\n", path);
return -ENOENT;
}
// Read the value as a string
memset(buf, 0, buflen);
kernel_read(temp_file, buf, buflen - 1, &temp_file->f_pos);
// Close the temperature file
filp_close(temp_file, NULL);
return 0;
}
static int get_hwmon_id_of_waterforce(struct waterforce_data *priv)
{
char temp_string[20];
char path_string[60];
for (u8 i=0;i<9;i++) {
sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i);
if (read_file(path_string,temp_string,sizeof(temp_string))==0) {
if (strcmp(temp_string,"k10temp\n")==0) {
// printk("HWMon name %s %d\n",temp_string,i);
priv->hwmonid=i;
break;
}
}
}
return 0;
}
static int get_thermal_zone_id_of_cpu(struct waterforce_data *priv)
{
char temp_string[20];
char path_string[60];
for (u8 i=0;i<9;i++) {
sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i);
if (read_file(path_string,temp_string,sizeof(temp_string))==0) {
if (strcmp(temp_string,"x86_pkg_temp\n")==0) {
priv->cputhermalzoneid=i;
// printk("Thermal Zone type %s %d\n",temp_string,i);
break;
}
}
}
return 0;
}
static int get_cpu_temp(struct waterforce_data *priv)
{
int temp_millicelsius;
char temp_string[10];
struct file *temp_file;
char path[60];
sprintf(path,"/sys/class/hwmon/hwmon%d/temp1_input",priv->cputhermalzoneid);
// Open the temperature file for reading
temp_file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(temp_file)) {
printk(KERN_ERR "Error opening temperature file %s\n", path);
return -ENOENT;
}
// Read the temperature value as a string
memset(temp_string, 0, sizeof(temp_string));
kernel_read(temp_file, temp_string, sizeof(temp_string) - 1, &temp_file->f_pos);
// Close the temperature file
filp_close(temp_file, NULL);
// Convert the temperature string to an integer
sscanf(temp_string, "%d", &temp_millicelsius);
priv->cpu_temp=temp_millicelsius/1000;
// Convert the temperature to degrees Celsius and print it
printk(KERN_INFO "CPU temperature: %d.%d C\n", priv->cpu_temp, temp_millicelsius % 1000);
return 0;
}
static int get_cpu_freq(struct waterforce_data *priv)
{
unsigned cpu = cpumask_first(cpu_online_mask);
priv->nthread=nr_cpu_ids;
unsigned maxfreq=0;
while (cpu < nr_cpu_ids) {
// struct cpufreq_policy policy;
// cpufreq_get_policy(&policy,cpu);
unsigned freq=cpufreq_quick_get_max(cpu);
// unsigned freq=policy.cur;
if (freq>maxfreq) { maxfreq=freq; }
// pr_info("CPU: %u, freq: %u kHz\n", cpu, freq);
cpu = cpumask_next(cpu, cpu_online_mask);
}
priv->cpufreqGhz1=maxfreq/1000000;
priv->cpufreqGhz2=(maxfreq%1000000)/100000;
// printk("CPU Max freq: %d.%d",priv->cpufreqGhz1,priv->cpufreqGhz2);
return 0;
}
/*
* Writes the command to the device with the rest of the report (up to 64 bytes) filled
* with zeroes
*/
static int waterforce_write_expanded(struct waterforce_data *priv, const u8 *cmd, int cmd_length)
{
int ret=0;
mutex_lock(&priv->buffer_lock);
if (!priv->updating) {
priv->updating=true;
get_cpu_temp(priv);
get_cpu_freq(priv);
priv->fanColorR=DIV_ROUND_CLOSEST(priv->cpu_temp*256,100);
priv->fanColorG=DIV_ROUND_CLOSEST(priv->speed_input[0]*256,2500);
priv->fanColorB=DIV_ROUND_CLOSEST(priv->speed_input[1]*256,2800);
// printk("Waterforce Color RGB: %d %d %d\n",priv->fanColorR,priv->fanColorG,priv->fanColorB);
memset(priv->buffer, 0x00, MAX_REPORT_LENGTH);
memcpy(priv->buffer, fan_color_cmd, FAN_COLOR_CMD_LEN);
memcpy(&(priv->buffer[2]),&(priv->fanColorR),1);
memcpy(&(priv->buffer[3]),&(priv->fanColorG),1);
memcpy(&(priv->buffer[4]),&(priv->fanColorB),1);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
memset(priv->buffer, 0x00, MAX_REPORT_LENGTH);
memcpy(priv->buffer, cpu_temp_cmd, CPU_TEMP_CMD_LEN);
memcpy(&(priv->buffer[3]),&(priv->cpu_temp),1);
memcpy(&(priv->buffer[4]),&(priv->nthread),1);
memcpy(&(priv->buffer[5]),&(priv->cpufreqGhz1),1);
memcpy(&(priv->buffer[6]),&(priv->cpufreqGhz2),1);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
memset(priv->buffer, 0x00, MAX_REPORT_LENGTH);
memcpy(priv->buffer, cmd, cmd_length);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
}
mutex_unlock(&priv->buffer_lock);
return ret;
}
static int waterforce_get_status(struct waterforce_data *priv)
{
int ret;
reinit_completion(&status_report_received);
/* Send command for getting status */
ret = waterforce_write_expanded(priv, get_status_cmd, 2);
if (ret < 0)
return ret;
if (!wait_for_completion_timeout
(&status_report_received, msecs_to_jiffies(STATUS_VALIDITY * 1000)))
return -ENODATA;
return 0;
}
static umode_t waterforce_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr, int channel)
{
return 0444;
switch (type) {
case hwmon_temp:
case hwmon_fan:
return 0444;
case hwmon_power:
switch (attr) {
case hwmon_pwm_input:
return 0444;
default:
break;
}
break;
default:
break;
}
return 0;
}
static int waterforce_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int ret;
struct waterforce_data *priv = NULL;
if (dev==NULL) { priv=hid_get_drvdata(waterforce_device); }
else { priv=dev_get_drvdata(dev); }
if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ)) {
/* Request status on demand */
ret = waterforce_get_status(priv);
if (ret < 0) {
return -ENODATA;
}
}
switch (type) {
case hwmon_temp:
*val = priv->temp_input[channel];
break;
case hwmon_fan:
*val = priv->speed_input[channel];
break;
case hwmon_power:
*val = priv->duty_input[channel];
break;
switch (attr) {
case hwmon_pwm_input:
*val = DIV_ROUND_CLOSEST(priv->duty_input[channel] * 255, 100);
break;
default:
break;
}
break;
default:
return -EOPNOTSUPP; /* unreachable */
}
return 0;
}
static int waterforce_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
switch (type) {
case hwmon_temp:
*str = waterforce_temp_label[channel];
break;
case hwmon_fan:
*str = waterforce_speed_label[channel];
break;
case hwmon_power:
*str = waterforce_pwm_label[channel];
break;
default:
return -EOPNOTSUPP; /* unreachable */
}
return 0;
}
static const struct hwmon_ops waterforce_hwmon_ops = {
.is_visible = waterforce_is_visible,
.read = waterforce_read,
.read_string = waterforce_read_string,
};
static const struct hwmon_channel_info *waterforce_info[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL
),
HWMON_CHANNEL_INFO(power,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL),
NULL
};
static const struct hwmon_chip_info waterforce_chip_info = {
.ops = &waterforce_hwmon_ops,
.info = waterforce_info,
};
static int waterforce_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
int size)
{
struct waterforce_data *priv = hid_get_drvdata(hdev);
if (data[0] != get_status_cmd[0] || data[1] != get_status_cmd[1]) {
/* Device returned improper data */
hid_err_once(priv->hdev, "firmware or device is possibly damaged\n");
return 0;
}
/* for (int i=0;i<16;i++) {
printk("data[%d]=%d\n",i,data[i]);
} */
priv->temp_input[0] = data[WATERFORCE_TEMP_SENSOR]*1000;
priv->speed_input[0] = get_unaligned_le16(data + WATERFORCE_FAN_SPEED);
priv->speed_input[1] = get_unaligned_le16(data + WATERFORCE_PUMP_SPEED);
priv->speed_input[2] = data[WATERFORCE_FAN_DUTY];
priv->speed_input[3] = data[WATERFORCE_PUMP_DUTY];
priv->duty_input[0] = data[WATERFORCE_FAN_DUTY];
priv->duty_input[1] = data[WATERFORCE_PUMP_DUTY];
complete(&status_report_received);
priv->updated = jiffies;
priv->updating=false;
return 0;
}
static void waterforce_timer_callback(struct timer_list *timer)
{
// printk(KERN_INFO "Timer expired\n");
if (waterforce_device!=NULL) {
struct waterforce_data *priv = hid_get_drvdata(waterforce_device);
if (priv) {
get_thermal_zone_id_of_cpu(priv);
get_hwmon_id_of_waterforce(priv);
char buf[100];
char path[100];
sprintf(path,"/sys/class/hwmon/hwmon%d/fan1_input",priv->hwmonid);
read_file(path,buf,sizeof(buf));
}
}
}
static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct waterforce_data *priv;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->hdev = hdev;
hid_set_drvdata(hdev, priv);
priv->updating=false;
waterforce_device=hdev;
/*
* Initialize ->updated to STATUS_VALIDITY seconds in the past, making
* the initial empty data invalid for waterforce_read without the need for
* a special case there.
*/
priv->updated = jiffies - STATUS_VALIDITY * HZ;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "hid parse failed with %d\n", ret);
return ret;
}
/*
* Enable hidraw so existing user-space tools can continue to work.
*/
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret) {
hid_err(hdev, "hid hw start failed with %d\n", ret);
goto fail_and_stop;
}
ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev, "hid hw open failed with %d\n", ret);
goto fail_and_close;
}
priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL);
if (!priv->buffer) {
ret = -ENOMEM;
goto fail_and_close;
}
mutex_init(&priv->buffer_lock);
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "waterforce",
priv, &waterforce_chip_info, NULL);
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
hid_err(hdev, "hwmon registration failed with %d\n", ret);
goto fail_and_close;
}
get_cpu_freq(priv);
return 0;
fail_and_close:
hid_hw_close(hdev);
fail_and_stop:
hid_hw_stop(hdev);
return ret;
}
static void waterforce_remove(struct hid_device *hdev)
{
struct waterforce_data *priv = hid_get_drvdata(hdev);
hwmon_device_unregister(priv->hwmon_dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id waterforce_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE_3) },
{ }
};
MODULE_DEVICE_TABLE(hid, waterforce_table);
static struct hid_driver waterforce_driver = {
.name = "waterforce",
.id_table = waterforce_table,
.probe = waterforce_probe,
.remove = waterforce_remove,
.raw_event = waterforce_raw_event,
};
static struct task_struct *waterforce_timer_thread;
static int waterforce_thread_fn(void *data)
{
// timer_setup(&waterforce_timer,waterforce_timer_callback,0);
// mod_timer(&waterforce_timer, jiffies + msecs_to_jiffies(TIMER_WAKEUP_MS));
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
// printk("waterforce_thread_fn\n");
waterforce_timer_callback(NULL);
schedule_timeout(HZ*TIMER_WAKEUP_S);
}
return 0;
}
static int __init waterforce_init(void)
{
waterforce_timer_thread = kthread_run(waterforce_thread_fn,NULL,"waterforce_timer_thread");
if (IS_ERR(waterforce_timer_thread)) {
printk(KERN_ERR "Waterforce: Failed to create thread\n");
// del_timer(&waterforce_timer);
return PTR_ERR(waterforce_timer_thread);
}
return hid_register_driver(&waterforce_driver);
}
static void __exit waterforce_exit(void)
{
// del_timer_sync(&waterforce_timer);
// wake_up_process(waterforce_timer_thread);
kthread_stop(waterforce_timer_thread);
hid_unregister_driver(&waterforce_driver);
}
/*
* When compiled into the kernel, initialize after the hid bus.
*/
late_initcall(waterforce_init);
module_exit(waterforce_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hwmon driver for Gigabyte AORUS Waterforce AIO coolers");
sorry my bad, line 110 should be line 135 please try to change line to 131: sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i); 135: if (strcmp(temp_string,"k10temp\n")==0) 153: sprintf(path,"/sys/class/hwmon/hwmon%d/temp1_input",priv->cputhermalzoneid);
i think it work, thanks!!! No error untill now
btw this dont work for me:
sudo make modules_install
sudo depmod
or do i need to restart then?
Only work if i do:
sudo make
sudo make install
sudo depmod
For none reboot then this: ./Makefile
i think it work, thanks!!! No error untill now
btw this dont work for me:
sudo make modules_install sudo depmod
or do i need to restart then?
Only work if i do:
sudo make sudo make install sudo depmod
For none reboot then this: ./Makefile thx, if you do not reboot "make dev" would do
And if i want to install it i dont it right ?
And if i want to install it i dont it right ?
if you want to install it, I think you did right, i just tested on my PVE
make install
depmod
Thanks very much!! 👍
This is not the right place to ask but:
I got a other question, i m using pve as workstation and i m on my windows hole time with it as vm. Do u know something about laytency? i have IRQ balance installed cause i dont wana use cpu pinning, if i use it, i wont be flexibel just creating vm or use more cores if i need, cause i need to then always edite the pinning or SMT affinity. Its total a mess with that and laytency i got. When i start LatencyMon even then my sound start cracking more and often if i test with LatencyMon. Do u know something about it? Already compiled the kernel with 1000hz i think it help with video a bit and now i m working on qemu changes and compiling because some Games not working because anticheat. How i have it right now is perfect for work stuff and gaming but Latency is not great.
Thanks very much!! 👍
This is not the right place to ask but:
I got a other question, i m using pve as workstation and i m on my windows hole time with it as vm. Do u know something about laytency? i have IRQ balance installed cause i dont wana use cpu pinning, if i use it, i wont be flexibel just creating vm or use more cores if i need, cause i need to then always edite the pinning or SMT affinity. Its total a mess with that and laytency i got. When i start LatencyMon even then my sound start cracking more and often if i test with LatencyMon. Do u know something about it? Already compiled the kernel with 1000hz i think it help with video a bit and now i m working on qemu changes and compiling because some Games not working because anticheat. How i have it right now is perfect for work stuff and gaming but Latency is not great.
I am not familiar with latency tuning on QEMU vm at the moment, if I some how get those information in future, I would get back to you. I am also interested to know how to recompile QEMU to fix the anticheat issue, would appreciate if you would put in a few pointers here.
Here we go again after reboot it start posting error but when I run ./Makefile there no error but when I restart errors. Even with make install and the other commands... but this time only hwon3
Cooler is working!
posting
Thanks very much!! 👍
This is not the right place to ask but:
I got a other question, i m using pve as workstation and i m on my windows hole time with it as vm. Do u know something about laytency? i have IRQ balance installed cause i dont wana use cpu pinning, if i use it, i wont be flexibel just creating vm or use more cores if i need, cause i need to then always edite the pinning or SMT affinity. Its total a mess with that and laytency i got. When i start LatencyMon even then my sound start cracking more and often if i test with LatencyMon. Do u know something about it? Already compiled the kernel with 1000hz i think it help with video a bit and now i m working on qemu changes and compiling because some Games not working because anticheat. How i have it right now is perfect for work stuff and gaming but Latency is not great.
I am not familiar with latency tuning on QEMU vm at the moment, if I some how get those information in future, I would get back to you. I am also interested to know how to recompile QEMU to fix the anticheat issue, would appreciate if you would put in a few pointers here.
Thanks😊
Do u know maybe why i m getting again errors? 🥲
I just turn off the print again.
I just turn off the print again.
Could you post the waterforce.c here and let me have a look?
in this code i turn the print off in the line:
if (IS_ERR(temp_file)) {
//printk(KERN_ERR "Error opening file %s\n", path);
return -ENOENT;
}
/*
* POC code use at your own risk
* modifed based on https://github.com/aleksamagicka/waterforce-hwmon/
*/
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
#include <asm/unaligned.h>
#include <linux/hid.h>
#include <linux/hwmon.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cpufreq.h>
#include <linux/timer.h>
#include <linux/thermal.h>
#include <linux/kthread.h>
#define USB_VENDOR_ID_GIGABYTE 0x1044
#define USB_PRODUCT_ID_WATERFORCE_1 0x7a4d /* Gigabyte AORUS WATERFORCE X (240, 280, 360) */
#define USB_PRODUCT_ID_WATERFORCE_2 0x7a52 /* Gigabyte AORUS WATERFORCE X 360G */
#define USB_PRODUCT_ID_WATERFORCE_3 0x7a53 /* Gigabyte AORUS WATERFORCE EX 360 */
#define STATUS_VALIDITY 2 /* seconds */
#define MAX_REPORT_LENGTH 6144
#define WATERFORCE_TEMP_SENSOR 0xD
#define WATERFORCE_FAN_SPEED 0x02
#define WATERFORCE_PUMP_SPEED 0x05
#define WATERFORCE_FAN_DUTY 0x08
#define WATERFORCE_PUMP_DUTY 0x09
#define CPU_TEMP_CMD_LEN 9
#define FAN_COLOR_CMD_LEN 5
#define TIMER_WAKEUP_S 2
DECLARE_COMPLETION(status_report_received);
static const u8 get_status_cmd[] = { 0x99, 0xDA };
static const u8 cpu_temp_cmd[] = { 0x99,0xE0,0x00,0x25,0x20,0x05,0x05,0x18,0x30 };
static const u8 fan_color_cmd[] = { 0x99,0xCD,0xFF,0xFF,0xFF };
static const char *const waterforce_temp_label[] = {
"Coolant temp",
};
static const char *const waterforce_speed_label[] = {
"Fan speed",
"Pump speed",
"Fan duty",
"Pump duty"
};
static const char *const waterforce_pwm_label[] = {
"Fan duty",
"Pump duty"
};
static struct timer_list waterforce_timer;
struct hid_device *waterforce_device=NULL;
struct waterforce_data {
struct hid_device *hdev;
struct device *hwmon_dev;
struct mutex buffer_lock; /* For locking access to buffer */
/* Sensor data */
s32 temp_input[1];
u16 speed_input[4]; /* Fan and pump speed in RPM */
u16 duty_input[4]; /* Fan and pump duty in 0-100% */
u8 cpu_temp;
u8 ncore;
u8 nthread;
u8 cpufreqGhz1;
u8 cpufreqGhz2;
u8 fanColorR;
u8 fanColorG;
u8 fanColorB;
u8 *buffer;
u8 cputhermalzoneid;
u8 hwmonid;
bool updating;
unsigned long updated; /* jiffies */
};
static int read_file(char * path,char *buf,int buflen) {
struct file *temp_file;
// Open the temperature file for reading
temp_file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(temp_file)) {
//printk(KERN_ERR "Error opening file %s\n", path);
return -ENOENT;
}
// Read the value as a string
memset(buf, 0, buflen);
kernel_read(temp_file, buf, buflen - 1, &temp_file->f_pos);
// Close the temperature file
filp_close(temp_file, NULL);
return 0;
}
static int get_hwmon_id_of_waterforce(struct waterforce_data *priv)
{
char temp_string[20];
char path_string[60];
for (u8 i=0;i<9;i++) {
sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i);
if (read_file(path_string,temp_string,sizeof(temp_string))==0) {
if (strcmp(temp_string,"waterforce\n")==0) {
// printk("HWMon name %s %d\n",temp_string,i);
priv->hwmonid=i;
break;
}
}
}
return 0;
}
static int get_thermal_zone_id_of_cpu(struct waterforce_data *priv)
{
char temp_string[20];
char path_string[60];
for (u8 i=0;i<9;i++) {
sprintf(path_string,"/sys/class/hwmon/hwmon%d/name",i);
if (read_file(path_string,temp_string,sizeof(temp_string))==0) {
if (strcmp(temp_string,"k10temp\n")==0) {
priv->cputhermalzoneid=i;
// printk("Thermal Zone type %s %d\n",temp_string,i);
break;
}
}
}
return 0;
}
static int get_cpu_temp(struct waterforce_data *priv)
{
int temp_millicelsius;
char temp_string[10];
struct file *temp_file;
char path[60];
sprintf(path,"/sys/class/hwmon/hwmon%d/temp1_input",priv->cputhermalzoneid);
// Open the temperature file for reading
temp_file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(temp_file)) {
printk(KERN_ERR "Error opening temperature file %s\n", path);
return -ENOENT;
}
// Read the temperature value as a string
memset(temp_string, 0, sizeof(temp_string));
kernel_read(temp_file, temp_string, sizeof(temp_string) - 1, &temp_file->f_pos);
// Close the temperature file
filp_close(temp_file, NULL);
// Convert the temperature string to an integer
sscanf(temp_string, "%d", &temp_millicelsius);
priv->cpu_temp=temp_millicelsius/1000;
// Convert the temperature to degrees Celsius and print it
printk(KERN_INFO "CPU temperature: %d.%d C\n", priv->cpu_temp, temp_millicelsius % 1000);
return 0;
}
static int get_cpu_freq(struct waterforce_data *priv)
{
unsigned cpu = cpumask_first(cpu_online_mask);
priv->nthread=nr_cpu_ids;
unsigned maxfreq=0;
while (cpu < nr_cpu_ids) {
// struct cpufreq_policy policy;
// cpufreq_get_policy(&policy,cpu);
unsigned freq=cpufreq_quick_get_max(cpu);
// unsigned freq=policy.cur;
if (freq>maxfreq) { maxfreq=freq; }
// pr_info("CPU: %u, freq: %u kHz\n", cpu, freq);
cpu = cpumask_next(cpu, cpu_online_mask);
}
priv->cpufreqGhz1=maxfreq/1000000;
priv->cpufreqGhz2=(maxfreq%1000000)/100000;
// printk("CPU Max freq: %d.%d",priv->cpufreqGhz1,priv->cpufreqGhz2);
return 0;
}
/*
* Writes the command to the device with the rest of the report (up to 64 bytes) filled
* with zeroes
*/
static int waterforce_write_expanded(struct waterforce_data *priv, const u8 *cmd, int cmd_length)
{
int ret=0;
mutex_lock(&priv->buffer_lock);
if (!priv->updating) {
priv->updating=true;
get_cpu_temp(priv);
get_cpu_freq(priv);
priv->fanColorR=DIV_ROUND_CLOSEST(priv->cpu_temp*256,100);
priv->fanColorG=DIV_ROUND_CLOSEST(priv->speed_input[0]*256,2500);
priv->fanColorB=DIV_ROUND_CLOSEST(priv->speed_input[1]*256,2800);
// printk("Waterforce Color RGB: %d %d %d\n",priv->fanColorR,priv->fanColorG,priv->fanColorB);
memset(priv->buffer, 0x00, MAX_REPORT_LENGTH);
memcpy(priv->buffer, fan_color_cmd, FAN_COLOR_CMD_LEN);
memcpy(&(priv->buffer[2]),&(priv->fanColorR),1);
memcpy(&(priv->buffer[3]),&(priv->fanColorG),1);
memcpy(&(priv->buffer[4]),&(priv->fanColorB),1);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
memset(priv->buffer, 0x00, MAX_REPORT_LENGTH);
memcpy(priv->buffer, cpu_temp_cmd, CPU_TEMP_CMD_LEN);
memcpy(&(priv->buffer[3]),&(priv->cpu_temp),1);
memcpy(&(priv->buffer[4]),&(priv->nthread),1);
memcpy(&(priv->buffer[5]),&(priv->cpufreqGhz1),1);
memcpy(&(priv->buffer[6]),&(priv->cpufreqGhz2),1);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
memset(priv->buffer, 0x00, MAX_REPORT_LENGTH);
memcpy(priv->buffer, cmd, cmd_length);
ret = hid_hw_output_report(priv->hdev, priv->buffer, MAX_REPORT_LENGTH);
}
mutex_unlock(&priv->buffer_lock);
return ret;
}
static int waterforce_get_status(struct waterforce_data *priv)
{
int ret;
reinit_completion(&status_report_received);
/* Send command for getting status */
ret = waterforce_write_expanded(priv, get_status_cmd, 2);
if (ret < 0)
return ret;
if (!wait_for_completion_timeout
(&status_report_received, msecs_to_jiffies(STATUS_VALIDITY * 1000)))
return -ENODATA;
return 0;
}
static umode_t waterforce_is_visible(const void *data,
enum hwmon_sensor_types type, u32 attr, int channel)
{
return 0444;
switch (type) {
case hwmon_temp:
case hwmon_fan:
return 0444;
case hwmon_power:
switch (attr) {
case hwmon_pwm_input:
return 0444;
default:
break;
}
break;
default:
break;
}
return 0;
}
static int waterforce_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
int ret;
struct waterforce_data *priv = NULL;
if (dev==NULL) { priv=hid_get_drvdata(waterforce_device); }
else { priv=dev_get_drvdata(dev); }
if (time_after(jiffies, priv->updated + STATUS_VALIDITY * HZ)) {
/* Request status on demand */
ret = waterforce_get_status(priv);
if (ret < 0) {
return -ENODATA;
}
}
switch (type) {
case hwmon_temp:
*val = priv->temp_input[channel];
break;
case hwmon_fan:
*val = priv->speed_input[channel];
break;
case hwmon_power:
*val = priv->duty_input[channel];
break;
switch (attr) {
case hwmon_pwm_input:
*val = DIV_ROUND_CLOSEST(priv->duty_input[channel] * 255, 100);
break;
default:
break;
}
break;
default:
return -EOPNOTSUPP; /* unreachable */
}
return 0;
}
static int waterforce_read_string(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
switch (type) {
case hwmon_temp:
*str = waterforce_temp_label[channel];
break;
case hwmon_fan:
*str = waterforce_speed_label[channel];
break;
case hwmon_power:
*str = waterforce_pwm_label[channel];
break;
default:
return -EOPNOTSUPP; /* unreachable */
}
return 0;
}
static const struct hwmon_ops waterforce_hwmon_ops = {
.is_visible = waterforce_is_visible,
.read = waterforce_read,
.read_string = waterforce_read_string,
};
static const struct hwmon_channel_info *waterforce_info[] = {
HWMON_CHANNEL_INFO(temp,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(fan,
HWMON_F_INPUT | HWMON_F_LABEL,
HWMON_F_INPUT | HWMON_F_LABEL
),
HWMON_CHANNEL_INFO(power,
HWMON_P_INPUT | HWMON_P_LABEL,
HWMON_P_INPUT | HWMON_P_LABEL),
NULL
};
static const struct hwmon_chip_info waterforce_chip_info = {
.ops = &waterforce_hwmon_ops,
.info = waterforce_info,
};
static int waterforce_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data,
int size)
{
struct waterforce_data *priv = hid_get_drvdata(hdev);
if (data[0] != get_status_cmd[0] || data[1] != get_status_cmd[1]) {
/* Device returned improper data */
hid_err_once(priv->hdev, "firmware or device is possibly damaged\n");
return 0;
}
/* for (int i=0;i<16;i++) {
printk("data[%d]=%d\n",i,data[i]);
} */
priv->temp_input[0] = data[WATERFORCE_TEMP_SENSOR]*1000;
priv->speed_input[0] = get_unaligned_le16(data + WATERFORCE_FAN_SPEED);
priv->speed_input[1] = get_unaligned_le16(data + WATERFORCE_PUMP_SPEED);
priv->speed_input[2] = data[WATERFORCE_FAN_DUTY];
priv->speed_input[3] = data[WATERFORCE_PUMP_DUTY];
priv->duty_input[0] = data[WATERFORCE_FAN_DUTY];
priv->duty_input[1] = data[WATERFORCE_PUMP_DUTY];
complete(&status_report_received);
priv->updated = jiffies;
priv->updating=false;
return 0;
}
static void waterforce_timer_callback(struct timer_list *timer)
{
// printk(KERN_INFO "Timer expired\n");
if (waterforce_device!=NULL) {
struct waterforce_data *priv = hid_get_drvdata(waterforce_device);
if (priv) {
get_thermal_zone_id_of_cpu(priv);
get_hwmon_id_of_waterforce(priv);
char buf[100];
char path[100];
sprintf(path,"/sys/class/hwmon/hwmon%d/fan1_input",priv->hwmonid);
read_file(path,buf,sizeof(buf));
}
}
}
static int waterforce_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct waterforce_data *priv;
int ret;
priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->hdev = hdev;
hid_set_drvdata(hdev, priv);
priv->updating=false;
waterforce_device=hdev;
/*
* Initialize ->updated to STATUS_VALIDITY seconds in the past, making
* the initial empty data invalid for waterforce_read without the need for
* a special case there.
*/
priv->updated = jiffies - STATUS_VALIDITY * HZ;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "hid parse failed with %d\n", ret);
return ret;
}
/*
* Enable hidraw so existing user-space tools can continue to work.
*/
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret) {
hid_err(hdev, "hid hw start failed with %d\n", ret);
goto fail_and_stop;
}
ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev, "hid hw open failed with %d\n", ret);
goto fail_and_close;
}
priv->buffer = devm_kzalloc(&hdev->dev, MAX_REPORT_LENGTH, GFP_KERNEL);
if (!priv->buffer) {
ret = -ENOMEM;
goto fail_and_close;
}
mutex_init(&priv->buffer_lock);
priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "waterforce",
priv, &waterforce_chip_info, NULL);
if (IS_ERR(priv->hwmon_dev)) {
ret = PTR_ERR(priv->hwmon_dev);
hid_err(hdev, "hwmon registration failed with %d\n", ret);
goto fail_and_close;
}
get_cpu_freq(priv);
return 0;
fail_and_close:
hid_hw_close(hdev);
fail_and_stop:
hid_hw_stop(hdev);
return ret;
}
static void waterforce_remove(struct hid_device *hdev)
{
struct waterforce_data *priv = hid_get_drvdata(hdev);
hwmon_device_unregister(priv->hwmon_dev);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
static const struct hid_device_id waterforce_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GIGABYTE, USB_PRODUCT_ID_WATERFORCE_3) },
{ }
};
MODULE_DEVICE_TABLE(hid, waterforce_table);
static struct hid_driver waterforce_driver = {
.name = "waterforce",
.id_table = waterforce_table,
.probe = waterforce_probe,
.remove = waterforce_remove,
.raw_event = waterforce_raw_event,
};
static struct task_struct *waterforce_timer_thread;
static int waterforce_thread_fn(void *data)
{
// timer_setup(&waterforce_timer,waterforce_timer_callback,0);
// mod_timer(&waterforce_timer, jiffies + msecs_to_jiffies(TIMER_WAKEUP_MS));
while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
// printk("waterforce_thread_fn\n");
waterforce_timer_callback(NULL);
schedule_timeout(HZ*TIMER_WAKEUP_S);
}
return 0;
}
static int __init waterforce_init(void)
{
waterforce_timer_thread = kthread_run(waterforce_thread_fn,NULL,"waterforce_timer_thread");
if (IS_ERR(waterforce_timer_thread)) {
printk(KERN_ERR "Waterforce: Failed to create thread\n");
// del_timer(&waterforce_timer);
return PTR_ERR(waterforce_timer_thread);
}
return hid_register_driver(&waterforce_driver);
}
static void __exit waterforce_exit(void)
{
// del_timer_sync(&waterforce_timer);
// wake_up_process(waterforce_timer_thread);
kthread_stop(waterforce_timer_thread);
hid_unregister_driver(&waterforce_driver);
}
/*
* When compiled into the kernel, initialize after the hid bus.
*/
late_initcall(waterforce_init);
module_exit(waterforce_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Hwmon driver for Gigabyte AORUS Waterforce AIO coolers");
when the error show up, does the "CPU temperature:" also show up as well? could you help to check if the hwmon3/name exists when the error show up?
everything work, display, temp shows, cooler works to and cool the cpu. only thing is, this error is there even it works. And no does not exist:
/sys/class/hwmon# dir
hwmon0 hwmon1 hwmon11 hwmon2 hwmon4 hwmon5 hwmon6 hwmon9
root@gaming:/sys/class/hwmon#
everything work, display, temp shows, cooler works to and cool the cpu. only thing is, this error is there even it works. And no does not exist:
/sys/class/hwmon# dir hwmon0 hwmon1 hwmon11 hwmon2 hwmon4 hwmon5 hwmon6 hwmon9 root@gaming:/sys/class/hwmon#
there seems to be no hwmon3 directory, and since the code currently just iterative from hwmon0 to hwmon9, it would throw error message when the file or the directory is not there, I will see if I can just open directory from within the hwmon directory only. In the mean time you can just comment the Error opening file message.
Ok 👍
Would it not help something like if not exist? just ignore it?
Hello, first of all, thank you very much for your code.
Unfortunately, it didn't work right away...
The line 153 with: sprintf(path, "/sys/class/thermal/thermal_zone%d/temp", priv->cputhermalzoneid); does not match my CPU and system; I am using Proxmox Debian and an AMD Threadripper. I changed line 153 to the path where my system actually shows the value that your code needs. However, I have the problem that your code posts a lot of errors in my console. I have deactivated it in your code, but I would like to know why this is happening and whether it is a serious issue?