#include #include #include #include #include #include #include "icx3.h" /* 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) { char data[I2C_SMBUS_BLOCK_MAX] = {}; int fd, read_result; 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++) { 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) { close(fd); return; } fan_status = (struct icx3_fan_control*) &data; printf("%s: %d RPM (%d/%d%%, %s)\n", icx3_fan_names[i], fan_status->rpm_status, fan_status->duty_status, fan_status->duty, 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; 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; } 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; short cur_data; for (int i=0; idata[2*i+1] << 8) | (short)(temp_sensors->data[2*i]); /* temp is reported in tenths of deg C */ cur_temp = (float)cur_data/10; printf("%s %.1f C\n", icx3_temp_sensor_names[i], cur_temp); } }