#include #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, int i2c_bus) { char i2c_devices_path[NAME_MAX]; char device_path[NAME_MAX]; char dev_file[NAME_MAX]; char *pci_addr; FILE *test_fd; DIR *dir; struct dirent *ent; int num_gpus = 0; int current_i2c_bus = -1; 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; /* Only probe the specific device given (if provided) */ if (i2c_bus >= 0) { sscanf(ent->d_name, "i2c-%i", ¤t_i2c_bus); if (current_i2c_bus != i2c_bus) continue; } strcpy(device_path, i2c_devices_path); strcat(device_path, ent->d_name); /* Only check Nvidia devices */ pci_addr = read_nvidia_pci_address(device_path); if (pci_addr == NULL) continue; /* Read the PCI info for the underlying device */ pci_vendor = read_pci_id(device_path, "/device/vendor"); pci_device = read_pci_id(device_path, "/device/device"); pci_subsystem_vendor = read_pci_id(device_path, "/device/subsystem_vendor"); pci_subsystem_device = read_pci_id(device_path, "/device/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(dev_file, "/dev/"); strcat(dev_file, ent->d_name); infos[num_gpus].i2c_dev_path = dev_file; if (icx3_init(&infos[num_gpus]) > 0) { /* Write our card info into the provided struct array */ infos[num_gpus].card_name = evga_pci_ids[i].card_name; infos[num_gpus].pci_id = pci_addr; infos[num_gpus].pci_device_id = pci_device; infos[num_gpus].i2c_dev_path = calloc(strlen(dev_file) + 1, sizeof(char)); strcpy(infos[num_gpus].i2c_dev_path, dev_file); num_gpus++; break; } } } if (num_gpus == max_gpus) break; } return num_gpus; } /* Read a 16-bit unsigned int from a pci id file */ 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); } 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) { free(ret); return NULL; } fscanf(fp, "NVIDIA i2c adapter %*u at %16s", ret); fclose(fp); if (strlen(ret) == 0) { free(ret); return NULL; } return ret; }