#include #include #include #include "evga-card.h" #include "icx3.h" /* Search all i2c device files for ones are on a PCI device of a supported GPU, and respond with the correct iCX3 version information */ int find_evga_gpu_i2cs(struct card_info **infos, int max_gpus) { char i2c_devices_path[NAME_MAX]; char device_path[NAME_MAX]; FILE *test_fd; int num_gpus = 0; unsigned short pci_vendor, pci_device, pci_subsystem_vendor, pci_subsystem_device = 0; /* Start looking for I2C adapters in /sys/bus/i2c/devices/ */ strcpy(i2c_devices_path, "/sys/bus/i2c/devices/"); dir = opendir(i2c_devices_path); /* make sure we can open the i2c device */ if(dir == NULL) { return -1; } /* loop over all i2c devices */ while((ent = readdir(dir)) != NULL) { /* Don't check any non-i2c devices */ if(strncmp(ent->d_name, "i2c-", 4) != 0) continue; strcpy(device_path, i2c_devices_path); strcat(device_path, ent->d_name); /* Read the PCI info for the underlying device */ pci_vendor = read_pci_id(device_path, "/vendor"); pci_device = read_pci_id(device_path, "/device"); pci_subsystem_vendor = read_pci_id(device_path, "/subsystem_vendor"); pci_subsystem_device = read_pci_id(device_path, "/subsystem_device"); /* 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++) { if (pci_vendor == evga_pci_ids[i]->vendor_id && pci_device == evga_pci_ids[i]->device_id && pci_subsystem_vendor == evga_pci_ids[i]->subvendor_id && pci_subsystem_device == evga_pci_ids[i]->subdevice_id) { /* Matched all PCI IDs, check for good firmware read */ strcpy(device_path, "/dev/"); strcat(device_path, ent->d_name); if (check_for_icx3(device_path)) { /* Write our card info into the provided struct array */ card_info[num_gpus]->card_name = &evga_pci_ids[i]->card_name; card_info[num_gpus]->pci_id card_info[num_gpus]->i2c_dev_path = calloc(strlen(device_path) + 1, sizeof(char)); strcpy(card_info[num_gpus]->i2c_dev_path, device_path); break; } } } strcat(device_string, "/name"); 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); } } } } } } } } unsigned short read_pci_id(char *device_path, char *field) { char *buf[16]; char file_path[NAME_MAX]; strcpy(file_path, device_path); strcat(file_path, field); FILE *fp = fopen(file_path, "r"); if (fp == NULL) return 0; if (fgets(buf, sizeof(buf), fp) == NULL) { fclose(fp); return 0; } fclose(fp); return (unsigned short)strtoul(buf, NULL, 16); }