evga-icx/evga-card.c
2025-01-19 23:27:43 -08:00

170 lines
4.3 KiB
C

#include <stdio.h>
#include <string.h>
#include <dirent.h>
#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);
}