Added display of fan status and temperature sensors.

This commit is contained in:
moosecrap 2025-01-29 05:35:31 -08:00
parent 23a734cf0a
commit bcd4457c2f
6 changed files with 264 additions and 195 deletions

View File

@ -1,18 +1,22 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <dirent.h> #include <dirent.h>
#include <stdlib.h>
#include "evga-card.h" #include "evga-card.h"
#include "icx3.h" #include "icx3.h"
/* Search all i2c device files for ones are on a PCI device of a supported GPU, /* Search all i2c device files for ones are on a PCI device of a supported GPU,
and respond with the correct iCX3 version information */ and respond with the correct iCX3 version information */
int find_evga_gpu_i2cs(struct card_info **infos, int max_gpus) int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus)
{ {
char i2c_devices_path[NAME_MAX]; char i2c_devices_path[NAME_MAX];
char device_path[NAME_MAX]; char device_path[NAME_MAX];
char dev_file[NAME_MAX];
FILE *test_fd; FILE *test_fd;
DIR *dir;
struct dirent *ent;
int num_gpus = 0; int num_gpus = 0;
unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0; unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0;
@ -38,114 +42,46 @@ int find_evga_gpu_i2cs(struct card_info **infos, int max_gpus)
strcat(device_path, ent->d_name); strcat(device_path, ent->d_name);
/* Read the PCI info for the underlying device */ /* Read the PCI info for the underlying device */
pci_vendor = read_pci_id(device_path, "/vendor"); pci_vendor = read_pci_id(device_path, "/device/vendor");
pci_device = read_pci_id(device_path, "/device"); pci_device = read_pci_id(device_path, "/device/device");
pci_subsystem_vendor = read_pci_id(device_path, "/subsystem_vendor"); pci_subsystem_vendor = read_pci_id(device_path, "/device/subsystem_vendor");
pci_subsystem_device = read_pci_id(device_path, "/subsystem_device"); pci_subsystem_device = read_pci_id(device_path, "/device/subsystem_device");
/* See if it's a matching device for a supported EVGA card */ /* See if it's a matching device for a supported EVGA card */
for (int i = 0, i < (sizeof(evga_pci_ids) / sizeof(struct gpu_pci_info)), i++) { for (int i = 0; i < (sizeof(evga_pci_ids) / sizeof(struct gpu_pci_info)); i++) {
if (pci_vendor == evga_pci_ids[i]->vendor_id && if (pci_vendor == evga_pci_ids[i].vendor_id &&
pci_device == evga_pci_ids[i]->device_id && pci_device == evga_pci_ids[i].device_id &&
pci_subsystem_vendor == evga_pci_ids[i]->subvendor_id && pci_subsystem_vendor == evga_pci_ids[i].subvendor_id &&
pci_subsystem_device == evga_pci_ids[i]->subdevice_id) { pci_subsystem_device == evga_pci_ids[i].subdevice_id) {
/* Matched all PCI IDs, check for good firmware read */ /* Matched all PCI IDs, check for good firmware read */
strcpy(device_path, "/dev/"); strcpy(dev_file, "/dev/");
strcat(device_path, ent->d_name); strcat(dev_file, ent->d_name);
if (check_for_icx3(device_path)) { if (check_for_icx3(dev_file)) {
/* Write our card info into the provided struct array */ /* Write our card info into the provided struct array */
card_info[num_gpus]->card_name = &evga_pci_ids[i]->card_name; infos[num_gpus].card_name = evga_pci_ids[i].card_name;
card_info[num_gpus]->pci_id infos[num_gpus].pci_id = read_nvidia_pci_address(device_path);
card_info[num_gpus]->i2c_dev_path = calloc(strlen(device_path) + 1, sizeof(char)); infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char));
strcpy(card_info[num_gpus]->i2c_dev_path, device_path); strcpy(infos[num_gpus].i2c_dev_path, dev_file);
num_gpus++;
break; break;
} }
} }
} }
strcat(device_string, "/name"); if (num_gpus == max_gpus)
break;
if(strncmp(ent->d_name, "i2c-", 4) == 0)
{
strcpy(device_string, i2c_devices_path);
strcat(device_string, ent->d_name);
strcat(device_string, "/name");
test_fd = fopen(device_string, O_RDONLY);
if(test_fd)
{
memset(device_string, 0x00, sizeof(device_string));
if(read(test_fd, device_string, sizeof(device_string)) < 0)
{
printf("Failed to read i2c device name\n");
return -1;
}
device_string[strlen(device_string) - 1] = 0x00;
close(test_fd);
// Clear PCI Information
pci_vendor = 0;
pci_device = 0;
pci_subsystem_vendor = 0;
pci_subsystem_device = 0;
port_id = 0;
// Get port ID for NVidia GPUs
sscanf(device_string, "NVIDIA i2c adapter %hu at", &port_id);
// Get device path
strcpy(path, i2c_devices_path);
strcat(path, ent->d_name);
if(ent->d_type == DT_LNK)
{
ptr = realpath(path, NULL);
if(ptr == NULL)
continue;
strcpy(path, ptr);
strcat(path, "/..");
free(ptr);
}
else
{
strcat(path, "/device");
}
ptr = path + strlen(path);
if (pci_vendor == NVIDIA_VEN && pci_subsystem_vendor == EVGA_SUB_VEN) {
strcpy(device_string, "/dev/");
strcat(device_string, ent->d_name);
test_fd = open(device_string, O_RDWR);
if (test_fd < 0)
{
printf("Failed to open device file %s, are you root or have permissions for i2c?\n", device_string);
return -1;
} else {
} else {
printf("Bad FW version read %s\n", device_string);
}
}
}
}
}
}
} }
return num_gpus;
} }
/* Read a 16-bit unsigned int from a pci id file */
unsigned short read_pci_id(char *device_path, char *field) unsigned short read_pci_id(char *device_path, char *field)
{ {
char *buf[16]; char buf[16];
char file_path[NAME_MAX]; char file_path[NAME_MAX];
strcpy(file_path, device_path); strcpy(file_path, device_path);
@ -166,4 +102,23 @@ unsigned short read_pci_id(char *device_path, char *field)
return (unsigned short)strtoul(buf, NULL, 16); return (unsigned short)strtoul(buf, NULL, 16);
} }
char *read_nvidia_pci_address(char *device_path)
{
char file_path[NAME_MAX];
char *ret = calloc(16 + 1, sizeof(char)); /* assuming pci ids could look as large as 00000000:0C:00.0 */
strcpy(file_path, device_path);
strcat(file_path, "/name");
FILE *fp = fopen(file_path, "r");
if (fp == NULL)
return NULL;
fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret);
fclose(fp);
return ret;
}

View File

@ -1,3 +1,5 @@
#pragma once
#define NVIDIA_VEN 0x10DE #define NVIDIA_VEN 0x10DE
#define NVIDIA_RTX3060_DEV 0x2503 #define NVIDIA_RTX3060_DEV 0x2503
@ -80,16 +82,11 @@
#define EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV 0x4983 #define EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV 0x4983
#define EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV 0x4985 #define EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV 0x4985
#define MAX_GPUS 16 struct card_info {
int find_evga_gpu_i2cs(struct card_info **infos, int max_gpus);
unsigned short read_pci_id(char *path);
struct card_info (
char *card_name; char *card_name;
char *pci_id; char *pci_id;
char *i2c_dev_path; char *i2c_dev_path;
); };
struct gpu_pci_info { struct gpu_pci_info {
char *card_name; char *card_name;
@ -99,7 +96,7 @@ struct gpu_pci_info {
unsigned short subdevice_id; unsigned short subdevice_id;
}; };
struct gpu_pci_info evga_pci_ids[] = static struct gpu_pci_info evga_pci_ids[] =
{ {
{"EVGA GeForce RTX 3060 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_GAMING_SUB_DEV }, {"EVGA GeForce RTX 3060 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3060 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_ULTRA_SUB_DEV }, {"EVGA GeForce RTX 3060 Ti FTW3 Ultra" , NVIDIA_VEN, NVIDIA_RTX3060TI_DEV, EVGA_SUB_VEN, EVGA_RTX3060TI_FTW3_ULTRA_SUB_DEV },
@ -157,5 +154,9 @@ struct gpu_pci_info evga_pci_ids[] =
{"EVGA GeForce RTX 3090 K|NGP|N Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_KINGPIN_HC_SUB_DEV }, {"EVGA GeForce RTX 3090 K|NGP|N Hydro Copper" , NVIDIA_VEN, NVIDIA_RTX3090_DEV, EVGA_SUB_VEN, EVGA_RTX3090_KINGPIN_HC_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Black Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_BLACK_SUB_DEV }, {"EVGA GeForce RTX 3090 Ti FTW3 Black Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_BLACK_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV }, {"EVGA GeForce RTX 3090 Ti FTW3 Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_GAMING_SUB_DEV },
{"EVGA GeForce RTX 3090 Ti FTW3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV }, {"EVGA GeForce RTX 3090 Ti FTW3 Ultra Gaming" , NVIDIA_VEN, NVIDIA_RTX3090TI_DEV, EVGA_SUB_VEN, EVGA_RTX3090TI_FTW3_ULTRA_GAMING_SUB_DEV }
} };
int find_evga_gpu_i2cs(struct card_info *infos, int max_gpus);
unsigned short read_pci_id(char *device_path, char *field);
char *read_nvidia_pci_address(char *device_path);

View File

@ -5,17 +5,32 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include "icx3.h" #include "icx3.h"
#include "nvidia_pci.h" #include "evga-card.h"
#define MAX_GPUS 16
int main (int argc, char **argv) int main (int argc, char **argv)
{ {
int *gpus[MAX_GPUS]; struct card_info gpus[MAX_GPUS];
if (find_evga_gpu_i2c(gpus) == -1) { int num_gpus;
num_gpus = find_evga_gpu_i2cs(gpus, MAX_GPUS);
if (num_gpus == -1) {
printf("Error scanning I2C devices\n");
return -1;
} else if (num_gpus == 0) {
printf("No supported GPUs found.\nAre you root or do you have udev access to i2c devices?\nDo you need to run `modprobe i2c-dev`?\n");
return -1; return -1;
} }
for (int i = 0; i < num_gpus; i++){
printf("#%d: %s (%s) @ %s\n", i, gpus[i].card_name, gpus[i].i2c_dev_path, gpus[i].pci_id);
print_icx3_fans(gpus[i].i2c_dev_path);
print_icx3_temps(gpus[i].i2c_dev_path);
printf("\n");
} }
} }

183
icx3.c
View File

@ -1,72 +1,163 @@
#include <linux/i2c-dev.h> #include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <i2c/smbus.h> #include <i2c/smbus.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include "icx3.h" #include "icx3.h"
void *print_icx3_temp(int fp) /* Check an I2C device file for an ICX3 controller, returns the product id, or ICX3_PRODUCT_NONE on bad read. */
enum icx3_product_id check_for_icx3(char *i2c_dev_path)
{ {
int read_result; char data[I2C_SMBUS_BLOCK_MAX] = {};
char buff[1024]; int fd, read_result;
struct icx3_fancontrol *fanstatus; struct icx3_info *temp_info;
fd = open(i2c_dev_path, O_RDONLY);
if (!fd)
return ICX3_PRODUCT_NONE;
if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) {
close(fd);
return ICX3_PRODUCT_NONE;
}
read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_READINFORMATION, ICX3_READINFORMATION_SIZE, data);
close(fd);
if (read_result == ICX3_READINFORMATION_SIZE) {
temp_info = (struct icx3_info*)&data;
if (temp_info->slave_address == ICX3_I2C_ADDR)
return temp_info->product_id;
}
return ICX3_PRODUCT_NONE;
}
void print_icx3_fans(char *i2c_dev_path)
{
char data[I2C_SMBUS_BLOCK_MAX] = {};
int fd, read_result;
struct icx3_fan_control *fan_status;
/* First thing is to check for the product ID to figure out how many fans we have */
int fans_avail[ICX3_MAX_FANS] = {0};
int product_id = check_for_icx3(i2c_dev_path);
/* From ICX3TotalFanCtrl.cs */
switch(product_id) {
case ICX3_PRODUCT_E221_E222_XC3:
case ICX3_PRODUCT_E229_XC3:
case ICX3_PRODUCT_E222_XC3_LPC54113:
case ICX3_PRODUCT_E229_XC3_LPC54113:
case ICX3_PRODUCT_E221_XC3_STM32L431:
case ICX3_PRODUCT_E229_E237_XC3_STM32L431:
/* XC3, default plus fan 3 */
fans_avail[0] = 1;
fans_avail[1] = 1;
fans_avail[2] = 1;
break;
case ICX3_PRODUCT_E227_E228_FTW3:
case ICX3_PRODUCT_E230_FTW3:
case ICX3_PRODUCT_E227_E228_FTW3_LPC54113:
case ICX3_PRODUCT_E230_FTW3_LPC54113:
case ICX3_PRODUCT_E230_E238_FTW3_STM32L431:
case ICX3_PRODUCT_E250_FTW3:
/* FTW3, default plus fan 3 and external fan */
fans_avail[0] = 1;
fans_avail[1] = 1;
fans_avail[2] = 1;
fans_avail[3] = 1;
break;
case ICX3_PRODUCT_E223_KINGPIN_HYBRID:
case ICX3_PRODUCT_E227_E228_FTW3_HYBRID:
case ICX3_PRODUCT_E251_KINGPIN_HYBRID:
case ICX3_PRODUCT_E227_E228_FTW3_HYBRID_LPC54113:
case ICX3_PRODUCT_E250_FTW3_HYBRID:
/* KINGPIN, default and external */
fans_avail[0] = 1;
fans_avail[1] = 1;
fans_avail[3] = 1;
break;
case ICX3_PRODUCT_E227_E228_FTW3_HC:
case ICX3_PRODUCT_E223_KINGPIN_HC:
case ICX3_PRODUCT_E251_KINGPIN_HC:
/* External fan only */
fans_avail[3] = 1;
break;
default:
fans_avail[0] = 1;
fans_avail[1] = 1;
break;
case ICX3_PRODUCT_E221_E222_XC3_HC:
/* Not sure what this case is for */
break;
}
fd = open(i2c_dev_path, O_RDONLY);
/* Error silently here because we should have already checked we can read the i2c in check_for_icx3() */
if (!fd)
return;
if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) {
close(fd);
return;
}
for (int i=0; i < ICX3_MAX_FANS; i++) { for (int i=0; i < ICX3_MAX_FANS; i++) {
read_result = i2c_smbus_read_i2c_block_data(fp, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, buff); if (!fans_avail[i])
continue;
read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_FANCONTROL + i, ICX3_FANCONTROL_SIZE, data);
if (read_result != ICX3_FANCONTROL_SIZE) { if (read_result != ICX3_FANCONTROL_SIZE) {
return 0; close(fd);
return;
} }
fanstatus = (struct icx3_fancontrol*) &buff; fan_status = (struct icx3_fan_control*) &data;
printf("%s: %d RPM (%d/%d%%, %s)\n", printf("%s: %d RPM (%d/%d%%, %s)\n",
icx3_fan_names[i], icx3_fan_names[i],
fanstatus->rpm_status, fan_status->rpm_status,
fanstatus->duty_status, fan_status->duty_status,
fanstatus->duty, fan_status->duty,
icx3_fan_mode_names[fanstatus->fanmode] icx3_fan_mode_names[fan_status->fanmode]
); );
} }
}
void print_icx3_temps(char *i2c_dev_path)
{
char data[I2C_SMBUS_BLOCK_MAX] = {};
int fd, read_result;
struct icx3_temp_sensors *temp_sensors;
struct icx3_tempsensors *tempsensors; fd = open(i2c_dev_path, O_RDONLY);
read_result = i2c_smbus_read_i2c_block_data(fp, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, buff);
if (read_result != ICX3_TEMPSENSOR_SIZE) { /* Error silently here because we should have already checked we can read the i2c in check_for_icx3() */
return 0; if (!fd)
return;
if (ioctl(fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) {
close(fd);
return;
} }
tempsensors = (struct icx3_tempsensors*) &buff;
read_result = i2c_smbus_read_i2c_block_data(fd, ICX3_REG_TEMPSENSOR, ICX3_TEMPSENSOR_SIZE, data);
if (read_result != ICX3_TEMPSENSOR_SIZE) {
close(fd);
return;
}
temp_sensors = (struct icx3_temp_sensors*) &data;
float cur_temp; float cur_temp;
short cur_data; short cur_data;
for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) { for (int i=0; i<ICX3_NUM_TEMP_SENSORS; i++) {
cur_data = (short)(tempsensors->data[2*i+1] << 8) | (short)(tempsensors->data[2*i]); /* endian swap */
cur_data = (short)(temp_sensors->data[2*i+1] << 8) | (short)(temp_sensors->data[2*i]);
/* temp is reported in tenths of deg C */
cur_temp = (float)cur_data/10; cur_temp = (float)cur_data/10;
printf("%s %.1f C\n", printf("%s %.1f C\n",
icx3_temp_sensor_names[i], icx3_temp_sensor_names[i],
cur_temp); cur_temp);
} }
} }
/* Check an I2C device file for an ICX3 controller, returs the product id. */
enum icx3_product_id check_for_icx3(char *i2c_dev_path)
{
char data[I2C_SMBUS_BLOCK_MAX] = {};
int test_fd, read_result;
struct icx3_info *temp_info;
test_fd = fopen(i2c_dev_path, O_RDONLY);
if (!test_fd)
return ICX3_NONE;
if (ioctl(test_fd, I2C_SLAVE, ICX3_I2C_ADDR) < 0) {
close(test_fd);
return ICX3_NONE;
}
read_result = i2c_smbus_read_i2c_block_data(test_fd, ICX3_REG_READINFORMATION, ICX3_READINFORMATION_SIZE, buff);
if (read_result == ICX3_READINFORMATION_SIZE) {
temp_info = (struct *icx3_info)&buff;
if (temp_info->slave_address == ICX3_I2C_ADDR)
return temp_info->product_id;
}
return ICX3_NONE;
}

78
icx3.h
View File

@ -1,3 +1,5 @@
#pragma once
#define ICX3_I2C_ADDR 0x2D #define ICX3_I2C_ADDR 0x2D
#define ICX3_REG_FANCONTROL 80 #define ICX3_REG_FANCONTROL 80
@ -11,8 +13,7 @@
#define ICX3_MAX_FANS 4 #define ICX3_MAX_FANS 4
#define ICX3_NUM_TEMP_SENSORS 9 #define ICX3_NUM_TEMP_SENSORS 9
struct icx3_fan_control {
struct icx3_fancontrol {
unsigned char length; unsigned char length;
unsigned char fanmode; unsigned char fanmode;
unsigned short rpm_offset; unsigned short rpm_offset;
@ -21,12 +22,13 @@ struct icx3_fancontrol {
unsigned short rpm_status; unsigned short rpm_status;
}; };
struct icx3_tempsensors { struct icx3_temp_sensors {
unsigned char length; unsigned char length;
unsigned char data[18]; unsigned char data[18];
}; };
struct icx3_info { struct icx3_info {
unsigned char length;
unsigned char reserved; unsigned char reserved;
unsigned char slave_address; unsigned char slave_address;
unsigned char product_id; unsigned char product_id;
@ -35,45 +37,45 @@ struct icx3_info {
}; };
enum icx3_product_id { enum icx3_product_id {
ICX3_IAP = 160, ICX3_PRODUCT_IAP = 160,
ICX3_E227_E228_FTW3 = 2, ICX3_PRODUCT_E227_E228_FTW3 = 2,
ICX3_E230_FTW3 = 4, ICX3_PRODUCT_E230_FTW3 = 4,
ICX3_E227_E228_FTW3_HYBRID = 8, ICX3_PRODUCT_E227_E228_FTW3_HYBRID = 8,
ICX3_E227_E228_FTW3_HC = 9, ICX3_PRODUCT_E227_E228_FTW3_HC = 9,
ICX3_E221_E222_XC3 = 1, ICX3_PRODUCT_E221_E222_XC3 = 1,
ICX3_E229_XC3 = 5, ICX3_PRODUCT_E229_XC3 = 5,
ICX3_E221_E222_XC3_HYBRID = 6, ICX3_PRODUCT_E221_E222_XC3_HYBRID = 6,
ICX3_E221_E222_XC3_HC = 7, ICX3_PRODUCT_E221_E222_XC3_HC = 7,
ICX3_IAP_KINGPIN = 161, ICX3_PRODUCT_IAP_KINGPIN = 161,
ICX3_E223_KINGPIN_HYBRID = 3, ICX3_PRODUCT_E223_KINGPIN_HYBRID = 3,
ICX3_E223_KINGPIN_HC = 10, ICX3_PRODUCT_E223_KINGPIN_HC = 10,
ICX3_IAP_KINGPIN_E251 = 165, ICX3_PRODUCT_IAP_KINGPIN_E251 = 165,
ICX3_E251_KINGPIN_HYBRID = 19, ICX3_PRODUCT_E251_KINGPIN_HYBRID = 19,
ICX3_E251_KINGPIN_HC = 26, ICX3_PRODUCT_E251_KINGPIN_HC = 26,
ICX3_IAP_LPC5516 = 164, ICX3_PRODUCT_IAP_LPC5516 = 164,
ICX3_E250_FTW3 = 50, ICX3_PRODUCT_E250_FTW3 = 50,
ICX3_E250_FTW3_HYBRID = 56, ICX3_PRODUCT_E250_FTW3_HYBRID = 56,
ICX3_IAP_LPC54113 = 162, ICX3_PRODUCT_IAP_LPC54113 = 162,
ICX3_E227_E228_FTW3_LPC54113 = 18, ICX3_PRODUCT_E227_E228_FTW3_LPC54113 = 18,
ICX3_E227_E228_FTW3_HYBRID_LPC54113 = 24, ICX3_PRODUCT_E227_E228_FTW3_HYBRID_LPC54113 = 24,
ICX3_E230_FTW3_LPC54113 = 20, ICX3_PRODUCT_E230_FTW3_LPC54113 = 20,
ICX3_E222_XC3_LPC54113 = 17, ICX3_PRODUCT_E222_XC3_LPC54113 = 17,
ICX3_E229_XC3_LPC54113 = 21, ICX3_PRODUCT_E229_XC3_LPC54113 = 21,
ICX3_IAP_STM32L431 = 163, ICX3_PRODUCT_IAP_STM32L431 = 163,
ICX3_E230_E238_FTW3_STM32L431 = 36, ICX3_PRODUCT_E230_E238_FTW3_STM32L431 = 36,
ICX3_E221_XC3_STM32L431 = 33, ICX3_PRODUCT_E221_XC3_STM32L431 = 33,
ICX3_E229_E237_XC3_STM32L431 = 37, ICX3_PRODUCT_E229_E237_XC3_STM32L431 = 37,
ICX3_NONE = 0 ICX3_PRODUCT_NONE = 0
} };
const char *icx3_fan_names[] = { static char *icx3_fan_names[] = {
"Fan 1", "Fan 1",
"Fan 2", "Fan 2",
"Fan 3", "Fan 3",
"Ext. fan" "Ext. fan"
}; };
const char *icx3_fan_mode_names[] = { static char *icx3_fan_mode_names[] = {
"Default", "Default",
"Auto", "Auto",
"Manual", "Manual",
@ -82,7 +84,7 @@ const char *icx3_fan_mode_names[] = {
"Mode 3" "Mode 3"
}; };
const char *icx3_temp_sensor_names[] = { static char *icx3_temp_sensor_names[] = {
"GPU2", "GPU2",
"MEM1", "MEM1",
"MEM2", "MEM2",
@ -94,4 +96,6 @@ const char *icx3_temp_sensor_names[] = {
"PWR5", "PWR5",
}; };
enum icx3_product_id check_for_icx3(char *i2c_dev_path); enum icx3_product_id check_for_icx3(char *i2c_dev_path);
void print_icx3_fans(char *i2c_dev_path);
void print_icx3_temps(char *i2c_dev_path);

View File

@ -1,13 +1,16 @@
.PHONY : clean debug .PHONY : clean debug
OBJS = evga-icx.o evga-card.o icx3.o
LDLIBS = -li2c LDLIBS = -li2c
objects = evga-icx.o CFLAGS = -MD
evga-icx : $(objects) evga-icx : $(OBJS)
debug : CFLAGS += -g -O0 debug : CFLAGS += -g -O0
debug : evga-icx debug : evga-icx
clean : clean :
rm evga-icx $(objects) rm evga-icx $(OBJS)
rm *.d
-include $(OBJS:.o=.d)