diff --git a/Detector.h b/Detector.h index c01a1bba..d4f667be 100644 --- a/Detector.h +++ b/Detector.h @@ -3,4 +3,5 @@ #include "DeviceDetector.h" #define REGISTER_DETECTOR(func) static DeviceDetector device_detector_obj(func) -#define REGISTER_I2C_DETECTOR(func) static I2CDeviceDetector device_detector_obj(func) \ No newline at end of file +#define REGISTER_I2C_DETECTOR(func) static I2CDeviceDetector device_detector_obj(func) +#define REGISTER_I2C_BUS_DETECTOR(func) static I2CBusDetector device_detector_obj(func) diff --git a/DeviceDetector.h b/DeviceDetector.h index 7d27e1d1..e03cfd5c 100644 --- a/DeviceDetector.h +++ b/DeviceDetector.h @@ -21,4 +21,13 @@ public: { ResourceManager::get()->RegisterI2CDeviceDetector(detector); } -}; \ No newline at end of file +}; + +class I2CBusDetector +{ +public: + I2CBusDetector(I2CBusDetectorFunction detector) + { + ResourceManager::get()->RegisterI2CBusDetector(detector); + } +}; diff --git a/OpenRGB.cpp b/OpenRGB.cpp deleted file mode 100644 index 09c321f1..00000000 --- a/OpenRGB.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/******************************************************************************************\ -* * -* OpenRGB.cpp * -* * -* Functions for communicating with RGBController API devices on Windows and Linux * -* * -\******************************************************************************************/ - -#include "RGBController.h" -#include "i2c_smbus.h" -#include "ResourceManager.h" -#include -#include -#include - -#ifdef WIN32 -#include -#include "i2c_smbus_piix4.h" -#include "i2c_smbus_i801.h" -#include "i2c_smbus_nct6775.h" -#include "i2c_smbus_nvapi.h" -#include "i2c_smbus_amdadl.h" -#include "super_io.h" -#include "wmi.h" -#else /* WIN32 */ - -#include "i2c_smbus_linux.h" -#include -#include -#include -#include - -#endif /* WIN32 */ - - -#ifdef WIN32 -/******************************************************************************************\ -* * -* DetectNuvotonI2CBusses (Windows) * -* * -* Detects available Nuvoton Super IO SMBUS adapters and enumerates * -* i2c_smbus_interface objects for them * -* * -\******************************************************************************************/ - -void DetectNuvotonI2CBusses(std::vector &busses) -{ - i2c_smbus_interface* bus; - int sioaddr = 0x2E; - superio_enter(sioaddr); - - int val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | superio_inb(sioaddr, SIO_REG_DEVID + 1); - - switch (val & SIO_ID_MASK) - { - case SIO_NCT5577_ID: - case SIO_NCT6102_ID: - case SIO_NCT6793_ID: - case SIO_NCT6796_ID: - case SIO_NCT6798_ID: - bus = new i2c_smbus_nct6775(); - - // Set logical device register to get SMBus base address - superio_outb(sioaddr, SIO_REG_LOGDEV, SIO_LOGDEV_SMBUS); - - // Get SMBus base address from configuration register - int smba = (superio_inb(sioaddr, SIO_REG_SMBA) << 8) | superio_inb(sioaddr, SIO_REG_SMBA + 1); - ((i2c_smbus_nct6775*)bus)->nct6775_smba = smba; - - // Set device name string - switch (val & SIO_ID_MASK) - { - case SIO_NCT5577_ID: - sprintf(bus->device_name, "Nuvoton NCT5577D SMBus at %X", smba); - break; - case SIO_NCT6102_ID: - sprintf(bus->device_name, "Nuvoton NCT6102D/NCT6106D SMBus at %X", smba); - break; - case SIO_NCT6793_ID: - sprintf(bus->device_name, "Nuvoton NCT6793D SMBus at %X", smba); - break; - case SIO_NCT6796_ID: - sprintf(bus->device_name, "Nuvoton NCT6796D SMBus at %X", smba); - break; - case SIO_NCT6798_ID: - sprintf(bus->device_name, "Nuvoton NCT6798D SMBus at %X", smba); - break; - } - - busses.push_back(bus); - } - -} /* DetectNuvotonI2CBusses() */ - -/******************************************************************************************\ -* * -* DetectNvAPII2CBusses (Windows) * -* * -* Detects available NVidia NvAPI I2C adapters and enumerates * -* i2c_smbus_interface objects for them. Only enumerates the first bus for each GPU * -* * -\******************************************************************************************/ - -void DetectNvAPII2CBusses(std::vector &busses) -{ - static NV_PHYSICAL_GPU_HANDLE gpu_handles[64]; - static NV_S32 gpu_count = 0; - NV_U32 device_id; - NV_U32 ext_device_id; - NV_STATUS res; - NV_U32 revision_id; - NV_U32 sub_system_id; - - NV_STATUS initialize = NvAPI_Initialize(); - - NvAPI_EnumPhysicalGPUs(gpu_handles, &gpu_count); - - for(NV_S32 gpu_idx = 0; gpu_idx < gpu_count; gpu_idx++) - { - i2c_smbus_nvapi * nvapi_bus = new i2c_smbus_nvapi(gpu_handles[gpu_idx]); - - sprintf(nvapi_bus->device_name, "NVidia NvAPI I2C on GPU %d", gpu_idx); - - res = NvAPI_GPU_GetPCIIdentifiers(gpu_handles[gpu_idx], &device_id, &sub_system_id, &revision_id, &ext_device_id); - - if (res == 0) - { - nvapi_bus->pci_device = device_id >> 16; - nvapi_bus->pci_vendor = device_id & 0xffff; - nvapi_bus->pci_subsystem_device = sub_system_id >> 16; - nvapi_bus->pci_subsystem_vendor = sub_system_id & 0xffff; - nvapi_bus->port_id = 1; - } - - busses.push_back(nvapi_bus); - } -} /* DetectNvAPII2CBusses() */ - -/******************************************************************************************\ -* * -* DetectAMDADLI2CBusses (Windows) * -* * -* Detects available AMD ADL I2C adapters and enumerates * -* i2c_smbus_interface objects for them. Only enumerates Bus Nr 1 * -* * -\******************************************************************************************/ - -void DetectADLI2C(std::vector &busses) -{ - int adl_status; - int gpu_count = 0; - ADL_CONTEXT_HANDLE gpu_handle; - - i2c_smbus_amdadl * adl_bus = new i2c_smbus_amdadl(gpu_handle); - - adl_status = adl_bus->ADL_Initialize(); - - if(0 != adl_status) - { - printf_s("ADL Status %d \n", adl_status); - } - else - { - sprintf(adl_bus->device_name, "AMD ADL I2C on GPU %d", gpu_count); - busses.push_back(adl_bus); - } -} /* DetectAMDADLI2CBusses() */ - -/******************************************************************************************\ -* * -* DetectI2CBusses (Windows) * -* * -* Detects available AMD and Intel SMBUS adapters and enumerates i2c_smbus_interface * -* objects for them * -* * -\******************************************************************************************/ - -void DetectI2CBusses(std::vector &busses) -{ - i2c_smbus_interface * bus; - HRESULT hres; - Wmi wmi; - wmi.init(); - - // Query WMI for Win32_PnPSignedDriver entries with names matching "SMBUS" or "SM BUS" - // These devices may be browsed under Device Manager -> System Devices - std::vector q_res_PnPSignedDriver; - hres = wmi.query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '\%SMBUS\%' OR Description LIKE '\%SM BUS\%'", q_res_PnPSignedDriver); - - if (hres) - { - return; - } - - // For each detected SMBus adapter, try enumerating it as either AMD or Intel - for (QueryObj &i : q_res_PnPSignedDriver) - { - // AMD SMBus controllers do not show any I/O resources allocated in Device Manager - // Analysis of many AMD boards has shown that AMD SMBus controllers have two adapters with fixed I/O spaces at 0x0B00 and 0x0B20 - // AMD SMBus adapters use the PIIX4 driver - if (i["Manufacturer"].find("Advanced Micro Devices, Inc") != std::string::npos) - { - bus = new i2c_smbus_piix4(); - strcpy(bus->device_name, i["Description"].c_str()); - strcat(bus->device_name, " at 0x0B00"); - ((i2c_smbus_piix4 *)bus)->piix4_smba = 0x0B00; - busses.push_back(bus); - - bus = new i2c_smbus_piix4(); - ((i2c_smbus_piix4 *)bus)->piix4_smba = 0x0B20; - strcpy(bus->device_name, i["Description"].c_str()); - strcat(bus->device_name, " at 0x0B20"); - busses.push_back(bus); - } - - // Intel SMBus controllers do show I/O resources in Device Manager - // Analysis of many Intel boards has shown that Intel SMBus adapter I/O space varies between boards - // We can query Win32_PnPAllocatedResource entries and look up the PCI device ID to find the allocated I/O space - // Intel SMBus adapters use the i801 driver - else if ((i["Manufacturer"].find("Intel") != std::string::npos) - || (i["Manufacturer"].find("INTEL") != std::string::npos)) - { - std::string rgx1 = ".+" + q_res_PnPSignedDriver[0]["DeviceID"].substr(4, 33) + ".+"; - - AdditionalFilters filters; - filters.emplace("Dependent", rgx1); - filters.emplace("Antecedent", ".*Port.*"); - - std::vector q_res_PNPAllocatedResource; - hres = wmi.query("SELECT * FROM Win32_PnPAllocatedResource", q_res_PNPAllocatedResource, &filters); - - std::regex rgx2(".*StartingAddress=\"(\\d+)\".*"); - std::smatch matches; - - // Query the StartingAddress for the matching device ID and use it to enumerate the bus - if (std::regex_search(q_res_PNPAllocatedResource[0]["Antecedent"], matches, rgx2)) - { - unsigned int IORangeStart = std::stoi(matches[1].str()); - - bus = new i2c_smbus_i801(); - strcpy(bus->device_name, i["Description"].c_str()); - ((i2c_smbus_i801 *)bus)->i801_smba = IORangeStart; - busses.push_back(bus); - } - } - } - - // Detect Nuvoton Super IO SMBus adapters - DetectNuvotonI2CBusses(busses); - - // Detect NVidia NvAPI I2C adapters - DetectNvAPII2CBusses(busses); - - // Detect AMD ADL I2C adadpters - DetectADLI2C(busses); - -} /* DetectI2CBusses() */ - -#else /* WIN32 */ - -/******************************************************************************************\ -* * -* DetectI2CBusses (Linux) * -* * -* Detects available SMBUS adapters and enumerates i2c_smbus_interface objects for * -* them * -* * -\******************************************************************************************/ - -void DetectI2CBusses(std::vector &busses) -{ - i2c_smbus_linux * bus; - char device_string[1024]; - DIR * dir; - char driver_path[512]; - struct dirent * ent; - int test_fd; - char path[1024]; - char buff[100]; - unsigned short pci_device, pci_vendor, pci_subsystem_device, pci_subsystem_vendor; - unsigned short port_id; - bool info; - - // Start looking for I2C adapters in /sys/bus/i2c/devices/ - strcpy(driver_path, "/sys/bus/i2c/devices/"); - dir = opendir(driver_path); - - if(dir == NULL) - { - return; - } - - // Loop through all entries in i2c-adapter list - ent = readdir(dir); - while(ent != NULL) - { - if(ent->d_type == DT_DIR || ent->d_type == DT_LNK) - { - if(strncmp(ent->d_name, "i2c-", 4) == 0) - { - strcpy(device_string, driver_path); - strcat(device_string, ent->d_name); - strcat(device_string, "/name"); - test_fd = open(device_string, O_RDONLY); - - if(test_fd) - { - memset(device_string, 0x00, sizeof(device_string)); - read(test_fd, device_string, sizeof(device_string)); - device_string[strlen(device_string) - 1] = 0x00; - - close(test_fd); - - // For now, only get PCI information from nVidia GPUs - // PCI IDs are not currently obtained from the Nouveau driver - // and GPUs using PCI IDs for detection will not work with it. - if (sscanf(device_string, "NVIDIA i2c adapter %hu at", &port_id) == 1) - { - info = true; - - // Get PCI Device - snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/device"); - test_fd = open(path, O_RDONLY); - if (test_fd < 0) - { - ent = readdir(dir); - continue; - } - memset(buff, 0x00, sizeof(buff)); - read(test_fd, buff, sizeof(buff)); - buff[strlen(buff) - 1] = 0x00; - pci_device = strtoul(buff, NULL, 16); - close(test_fd); - - // Get PCI Vendor - snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/vendor"); - test_fd = open(path, O_RDONLY); - if (test_fd < 0) - { - ent = readdir(dir); - continue; - } - memset(buff, 0x00, sizeof(buff)); - read(test_fd, buff, sizeof(buff)); - buff[strlen(buff) - 1] = 0x00; - pci_vendor = strtoul(buff, NULL, 16); - close(test_fd); - - // Get PCI Subsystem Device - snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/subsystem_device"); - test_fd = open(path, O_RDONLY); - if (test_fd < 0) - { - ent = readdir(dir); - continue; - } - memset(buff, 0x00, sizeof(buff)); - read(test_fd, buff, sizeof(buff)); - buff[strlen(buff) - 1] = 0x00; - pci_subsystem_device = strtoul(buff, NULL, 16); - close(test_fd); - - // Get PCI Subsystem Vendor - snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/subsystem_vendor"); - test_fd = open(path, O_RDONLY); - if (test_fd < 0) - { - ent = readdir(dir); - continue; - } - memset(buff, 0x00, sizeof(buff)); - read(test_fd, buff, sizeof(buff)); - buff[strlen(buff) - 1] = 0x00; - pci_subsystem_vendor = strtoul(buff, NULL, 16); - close(test_fd); - } - else - { - info = false; - } - - strcpy(device_string, "/dev/"); - strcat(device_string, ent->d_name); - test_fd = open(device_string, O_RDWR); - - if (test_fd < 0) - { - ent = readdir(dir); - continue; - } - - bus = new i2c_smbus_linux(); - strcpy(bus->device_name, device_string); - bus->handle = test_fd; - if (info) { - bus->pci_device = pci_device; - bus->pci_vendor = pci_vendor; - bus->pci_subsystem_device = pci_subsystem_device; - bus->pci_subsystem_vendor = pci_subsystem_vendor; - bus->port_id = port_id; - } - busses.push_back(bus); - } - } - } - ent = readdir(dir); - } - -} /* DetectI2CBusses() */ - -#endif /* WIN32 */ - - -/******************************************************************************************\ -* * -* DetectRGBConrollers * -* * -* Detect and populate RGB Controllers vector * -* * -\******************************************************************************************/ - -void DetectRGBControllers(void) -{ - DetectI2CBusses(ResourceManager::get()->GetI2CBusses()); - - ResourceManager::get()->DetectDevices(); -} /* DetectRGBControllers() */ diff --git a/OpenRGB.pro b/OpenRGB.pro index 309af90d..831082f6 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -229,7 +229,6 @@ SOURCES += \ dependencies/libe131/src/e131.c \ main.cpp \ cli.cpp \ - OpenRGB.cpp \ NetworkClient.cpp \ NetworkServer.cpp \ ProfileManager.cpp \ diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 2c0e9e34..5753eeee 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -48,6 +48,11 @@ std::vector & ResourceManager::GetRGBControllers() return rgb_controllers; } +void ResourceManager::RegisterI2CBusDetector(I2CBusDetectorFunction detector) +{ + i2c_bus_detectors.push_back(detector); +} + void ResourceManager::RegisterI2CDeviceDetector(I2CDeviceDetectorFunction detector) { i2c_device_detectors.push_back(detector); @@ -91,6 +96,14 @@ void ResourceManager::DetectDevicesThreadFunction() { unsigned int prev_count = 0; + /*-------------------------------------------------*\ + | Detect i2c busses | + \*-------------------------------------------------*/ + for(int i2c_bus_detector_idx = 0; i2c_bus_detector_idx < i2c_bus_detectors.size(); i2c_bus_detector_idx++) + { + i2c_bus_detectors[i2c_bus_detector_idx](busses); + } + /*-------------------------------------------------*\ | Detect i2c devices | \*-------------------------------------------------*/ diff --git a/ResourceManager.h b/ResourceManager.h index c9277362..63d469b1 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -8,6 +8,7 @@ #include "i2c_smbus.h" #include "RGBController.h" +typedef std::function&)> I2CBusDetectorFunction; typedef std::function&)> DeviceDetectorFunction; typedef std::function&, std::vector&)> I2CDeviceDetectorFunction; @@ -27,6 +28,7 @@ public: void RegisterRGBController(RGBController *); std::vector & GetRGBControllers(); + void RegisterI2CBusDetector (I2CBusDetectorFunction detector); void RegisterDeviceDetector (DeviceDetectorFunction detector); void RegisterI2CDeviceDetector (I2CDeviceDetectorFunction detector); @@ -44,6 +46,7 @@ private: std::vector busses; std::vector rgb_controllers; std::vector device_detectors; + std::vector i2c_bus_detectors; std::vector i2c_device_detectors; std::thread * DetectDevicesThread; diff --git a/dependencies/dmiinfo.cpp b/dependencies/dmiinfo.cpp index ee65b567..8e210d43 100644 --- a/dependencies/dmiinfo.cpp +++ b/dependencies/dmiinfo.cpp @@ -32,7 +32,7 @@ DMIInfo::DMIInfo() // Query WMI for Win32_PnPSignedDriver entries with names matching "SMBUS" or "SM BUS" // These devices may be browsed under Device Manager -> System Devices std::vector q_res_BaseBoard; - //hres = wmi.query("SELECT * FROM Win32_BaseBoard", q_res_BaseBoard); + hres = wmi.query("SELECT * FROM Win32_BaseBoard", q_res_BaseBoard); if (hres) { diff --git a/i2c_smbus/i2c_smbus_amdadl.cpp b/i2c_smbus/i2c_smbus_amdadl.cpp index b205f77c..e6bd7bf2 100644 --- a/i2c_smbus/i2c_smbus_amdadl.cpp +++ b/i2c_smbus/i2c_smbus_amdadl.cpp @@ -142,3 +142,27 @@ s32 i2c_smbus_amdadl::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int s return (ret); }; +#include "Detector.h" + +void i2c_smbus_amdadl_detect(std::vector &busses) +{ + int adl_status; + int gpu_count = 0; + ADL_CONTEXT_HANDLE gpu_handle; + + i2c_smbus_amdadl * adl_bus = new i2c_smbus_amdadl(gpu_handle); + + adl_status = adl_bus->ADL_Initialize(); + + if(0 != adl_status) + { + printf_s("ADL Status %d \n", adl_status); + } + else + { + sprintf(adl_bus->device_name, "AMD ADL I2C on GPU %d", gpu_count); + busses.push_back(adl_bus); + } +} /* DetectAMDADLI2CBusses() */ + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_amdadl_detect); diff --git a/i2c_smbus/i2c_smbus_i801.cpp b/i2c_smbus/i2c_smbus_i801.cpp index 73c0992d..e2e1763b 100644 --- a/i2c_smbus/i2c_smbus_i801.cpp +++ b/i2c_smbus/i2c_smbus_i801.cpp @@ -482,3 +482,61 @@ s32 i2c_smbus_i801::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int siz { return i801_access(addr, read_write, command, size, data); } + +#include "Detector.h" +#include "wmi.h" + +void i2c_smbus_i801_detect(std::vector &busses) +{ + i2c_smbus_interface * bus; + HRESULT hres; + Wmi wmi; + wmi.init(); + + // Query WMI for Win32_PnPSignedDriver entries with names matching "SMBUS" or "SM BUS" + // These devices may be browsed under Device Manager -> System Devices + std::vector q_res_PnPSignedDriver; + hres = wmi.query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '\%SMBUS\%' OR Description LIKE '\%SM BUS\%'", q_res_PnPSignedDriver); + + if (hres) + { + return; + } + + // For each detected SMBus adapter, try enumerating it as either AMD or Intel + for (QueryObj &i : q_res_PnPSignedDriver) + { + // Intel SMBus controllers do show I/O resources in Device Manager + // Analysis of many Intel boards has shown that Intel SMBus adapter I/O space varies between boards + // We can query Win32_PnPAllocatedResource entries and look up the PCI device ID to find the allocated I/O space + // Intel SMBus adapters use the i801 driver + if ((i["Manufacturer"].find("Intel") != std::string::npos) + || (i["Manufacturer"].find("INTEL") != std::string::npos)) + { + std::string rgx1 = ".+" + q_res_PnPSignedDriver[0]["DeviceID"].substr(4, 33) + ".+"; + + AdditionalFilters filters; + filters.emplace("Dependent", rgx1); + filters.emplace("Antecedent", ".*Port.*"); + + std::vector q_res_PNPAllocatedResource; + hres = wmi.query("SELECT * FROM Win32_PnPAllocatedResource", q_res_PNPAllocatedResource, &filters); + + std::regex rgx2(".*StartingAddress=\"(\\d+)\".*"); + std::smatch matches; + + // Query the StartingAddress for the matching device ID and use it to enumerate the bus + if (std::regex_search(q_res_PNPAllocatedResource[0]["Antecedent"], matches, rgx2)) + { + unsigned int IORangeStart = std::stoi(matches[1].str()); + + bus = new i2c_smbus_i801(); + strcpy(bus->device_name, i["Description"].c_str()); + ((i2c_smbus_i801 *)bus)->i801_smba = IORangeStart; + busses.push_back(bus); + } + } + } +} + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_i801_detect); diff --git a/i2c_smbus/i2c_smbus_linux.cpp b/i2c_smbus/i2c_smbus_linux.cpp index d398f177..6437ce01 100644 --- a/i2c_smbus/i2c_smbus_linux.cpp +++ b/i2c_smbus/i2c_smbus_linux.cpp @@ -27,3 +27,151 @@ s32 i2c_smbus_linux::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int si return ioctl(handle, I2C_SMBUS, &args); } + +#include "Detector.h" +#include +#include +#include +#include + +void i2c_smbus_linux_detect(std::vector &busses) +{ + i2c_smbus_linux * bus; + char device_string[1024]; + DIR * dir; + char driver_path[512]; + struct dirent * ent; + int test_fd; + char path[1024]; + char buff[100]; + unsigned short pci_device, pci_vendor, pci_subsystem_device, pci_subsystem_vendor; + unsigned short port_id; + bool info; + + // Start looking for I2C adapters in /sys/bus/i2c/devices/ + strcpy(driver_path, "/sys/bus/i2c/devices/"); + dir = opendir(driver_path); + + if(dir == NULL) + { + return; + } + + // Loop through all entries in i2c-adapter list + ent = readdir(dir); + while(ent != NULL) + { + if(ent->d_type == DT_DIR || ent->d_type == DT_LNK) + { + if(strncmp(ent->d_name, "i2c-", 4) == 0) + { + strcpy(device_string, driver_path); + strcat(device_string, ent->d_name); + strcat(device_string, "/name"); + test_fd = open(device_string, O_RDONLY); + + if(test_fd) + { + memset(device_string, 0x00, sizeof(device_string)); + read(test_fd, device_string, sizeof(device_string)); + device_string[strlen(device_string) - 1] = 0x00; + + close(test_fd); + + // For now, only get PCI information from nVidia GPUs + // PCI IDs are not currently obtained from the Nouveau driver + // and GPUs using PCI IDs for detection will not work with it. + if (sscanf(device_string, "NVIDIA i2c adapter %hu at", &port_id) == 1) + { + info = true; + + // Get PCI Device + snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/device"); + test_fd = open(path, O_RDONLY); + if (test_fd < 0) + { + ent = readdir(dir); + continue; + } + memset(buff, 0x00, sizeof(buff)); + read(test_fd, buff, sizeof(buff)); + buff[strlen(buff) - 1] = 0x00; + pci_device = strtoul(buff, NULL, 16); + close(test_fd); + + // Get PCI Vendor + snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/vendor"); + test_fd = open(path, O_RDONLY); + if (test_fd < 0) + { + ent = readdir(dir); + continue; + } + memset(buff, 0x00, sizeof(buff)); + read(test_fd, buff, sizeof(buff)); + buff[strlen(buff) - 1] = 0x00; + pci_vendor = strtoul(buff, NULL, 16); + close(test_fd); + + // Get PCI Subsystem Device + snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/subsystem_device"); + test_fd = open(path, O_RDONLY); + if (test_fd < 0) + { + ent = readdir(dir); + continue; + } + memset(buff, 0x00, sizeof(buff)); + read(test_fd, buff, sizeof(buff)); + buff[strlen(buff) - 1] = 0x00; + pci_subsystem_device = strtoul(buff, NULL, 16); + close(test_fd); + + // Get PCI Subsystem Vendor + snprintf(path, sizeof(path), "%s%s%s", driver_path, ent->d_name, "/device/subsystem_vendor"); + test_fd = open(path, O_RDONLY); + if (test_fd < 0) + { + ent = readdir(dir); + continue; + } + memset(buff, 0x00, sizeof(buff)); + read(test_fd, buff, sizeof(buff)); + buff[strlen(buff) - 1] = 0x00; + pci_subsystem_vendor = strtoul(buff, NULL, 16); + close(test_fd); + } + else + { + info = false; + } + + strcpy(device_string, "/dev/"); + strcat(device_string, ent->d_name); + test_fd = open(device_string, O_RDWR); + + if (test_fd < 0) + { + ent = readdir(dir); + continue; + } + + bus = new i2c_smbus_linux(); + strcpy(bus->device_name, device_string); + bus->handle = test_fd; + if (info) { + bus->pci_device = pci_device; + bus->pci_vendor = pci_vendor; + bus->pci_subsystem_device = pci_subsystem_device; + bus->pci_subsystem_vendor = pci_subsystem_vendor; + bus->port_id = port_id; + } + busses.push_back(bus); + } + } + } + ent = readdir(dir); + } +} + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_linux_detect); diff --git a/i2c_smbus/i2c_smbus_nct6775.cpp b/i2c_smbus/i2c_smbus_nct6775.cpp index fff30461..1ca8368a 100644 --- a/i2c_smbus/i2c_smbus_nct6775.cpp +++ b/i2c_smbus/i2c_smbus_nct6775.cpp @@ -187,3 +187,56 @@ s32 i2c_smbus_nct6775::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int { return nct6775_access(addr, read_write, command, size, data); } + +#include "Detector.h" +#include "super_io.h" + +void i2c_smbus_nct6775_detect(std::vector &busses) +{ + i2c_smbus_interface* bus; + int sioaddr = 0x2E; + superio_enter(sioaddr); + + int val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | superio_inb(sioaddr, SIO_REG_DEVID + 1); + + switch (val & SIO_ID_MASK) + { + case SIO_NCT5577_ID: + case SIO_NCT6102_ID: + case SIO_NCT6793_ID: + case SIO_NCT6796_ID: + case SIO_NCT6798_ID: + bus = new i2c_smbus_nct6775(); + + // Set logical device register to get SMBus base address + superio_outb(sioaddr, SIO_REG_LOGDEV, SIO_LOGDEV_SMBUS); + + // Get SMBus base address from configuration register + int smba = (superio_inb(sioaddr, SIO_REG_SMBA) << 8) | superio_inb(sioaddr, SIO_REG_SMBA + 1); + ((i2c_smbus_nct6775*)bus)->nct6775_smba = smba; + + // Set device name string + switch (val & SIO_ID_MASK) + { + case SIO_NCT5577_ID: + sprintf(bus->device_name, "Nuvoton NCT5577D SMBus at %X", smba); + break; + case SIO_NCT6102_ID: + sprintf(bus->device_name, "Nuvoton NCT6102D/NCT6106D SMBus at %X", smba); + break; + case SIO_NCT6793_ID: + sprintf(bus->device_name, "Nuvoton NCT6793D SMBus at %X", smba); + break; + case SIO_NCT6796_ID: + sprintf(bus->device_name, "Nuvoton NCT6796D SMBus at %X", smba); + break; + case SIO_NCT6798_ID: + sprintf(bus->device_name, "Nuvoton NCT6798D SMBus at %X", smba); + break; + } + + busses.push_back(bus); + } +} + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_nct6775_detect); diff --git a/i2c_smbus/i2c_smbus_nvapi.cpp b/i2c_smbus/i2c_smbus_nvapi.cpp index ea119344..ea46a63c 100644 --- a/i2c_smbus/i2c_smbus_nvapi.cpp +++ b/i2c_smbus/i2c_smbus_nvapi.cpp @@ -95,3 +95,42 @@ s32 i2c_smbus_nvapi::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int si return(ret); } + +#include "Detector.h" + +void i2c_smbus_nvapi_detect(std::vector &busses) +{ + static NV_PHYSICAL_GPU_HANDLE gpu_handles[64]; + static NV_S32 gpu_count = 0; + NV_U32 device_id; + NV_U32 ext_device_id; + NV_STATUS res; + NV_U32 revision_id; + NV_U32 sub_system_id; + + NV_STATUS initialize = NvAPI_Initialize(); + + NvAPI_EnumPhysicalGPUs(gpu_handles, &gpu_count); + + for(NV_S32 gpu_idx = 0; gpu_idx < gpu_count; gpu_idx++) + { + i2c_smbus_nvapi * nvapi_bus = new i2c_smbus_nvapi(gpu_handles[gpu_idx]); + + sprintf(nvapi_bus->device_name, "NVidia NvAPI I2C on GPU %d", gpu_idx); + + res = NvAPI_GPU_GetPCIIdentifiers(gpu_handles[gpu_idx], &device_id, &sub_system_id, &revision_id, &ext_device_id); + + if (res == 0) + { + nvapi_bus->pci_device = device_id >> 16; + nvapi_bus->pci_vendor = device_id & 0xffff; + nvapi_bus->pci_subsystem_device = sub_system_id >> 16; + nvapi_bus->pci_subsystem_vendor = sub_system_id & 0xffff; + nvapi_bus->port_id = 1; + } + + busses.push_back(nvapi_bus); + } +} /* DetectNvAPII2CBusses() */ + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_nvapi_detect); diff --git a/i2c_smbus/i2c_smbus_piix4.cpp b/i2c_smbus/i2c_smbus_piix4.cpp index fe201387..31f93444 100644 --- a/i2c_smbus/i2c_smbus_piix4.cpp +++ b/i2c_smbus/i2c_smbus_piix4.cpp @@ -176,3 +176,48 @@ s32 i2c_smbus_piix4::i2c_smbus_xfer(u8 addr, char read_write, u8 command, int si { return piix4_access(addr, read_write, command, size, data); } + +#include "Detector.h" +#include "wmi.h" + +void i2c_smbus_piix4_detect(std::vector &busses) +{ + i2c_smbus_interface * bus; + HRESULT hres; + Wmi wmi; + wmi.init(); + + // Query WMI for Win32_PnPSignedDriver entries with names matching "SMBUS" or "SM BUS" + // These devices may be browsed under Device Manager -> System Devices + std::vector q_res_PnPSignedDriver; + hres = wmi.query("SELECT * FROM Win32_PnPSignedDriver WHERE Description LIKE '\%SMBUS\%' OR Description LIKE '\%SM BUS\%'", q_res_PnPSignedDriver); + + if (hres) + { + return; + } + + // For each detected SMBus adapter, try enumerating it as either AMD or Intel + for (QueryObj &i : q_res_PnPSignedDriver) + { + // AMD SMBus controllers do not show any I/O resources allocated in Device Manager + // Analysis of many AMD boards has shown that AMD SMBus controllers have two adapters with fixed I/O spaces at 0x0B00 and 0x0B20 + // AMD SMBus adapters use the PIIX4 driver + if (i["Manufacturer"].find("Advanced Micro Devices, Inc") != std::string::npos) + { + bus = new i2c_smbus_piix4(); + strcpy(bus->device_name, i["Description"].c_str()); + strcat(bus->device_name, " at 0x0B00"); + ((i2c_smbus_piix4 *)bus)->piix4_smba = 0x0B00; + busses.push_back(bus); + + bus = new i2c_smbus_piix4(); + ((i2c_smbus_piix4 *)bus)->piix4_smba = 0x0B20; + strcpy(bus->device_name, i["Description"].c_str()); + strcat(bus->device_name, " at 0x0B20"); + busses.push_back(bus); + } + } +} + +REGISTER_I2C_BUS_DETECTOR(i2c_smbus_piix4_detect); diff --git a/main.cpp b/main.cpp index 67c2dea8..24ce2142 100644 --- a/main.cpp +++ b/main.cpp @@ -154,7 +154,7 @@ int main(int argc, char* argv[]) if(!AttemptLocalConnection(rgb_controllers)) { - DetectRGBControllers(); + ResourceManager::get()->DetectDevices(); } profile_manager.LoadSizeFromProfile("sizes.ors"); diff --git a/wmi/wmi.cpp b/wmi/wmi.cpp index 4a6a18ec..04365138 100644 --- a/wmi/wmi.cpp +++ b/wmi/wmi.cpp @@ -1,5 +1,8 @@ #include "wmi.h" +IWbemLocator* Wmi::pLoc = nullptr; +IWbemServices* Wmi::pSvc = nullptr; + // Taken from https://stackoverflow.com/questions/215963/ // Convert a wide Unicode string to an UTF8 string std::string utf8_encode(const std::wstring& wstr) @@ -32,22 +35,25 @@ bool isMatch(const std::string& value, const std::regex& re) return std::regex_match(value, re); } -Wmi::Wmi() : pLoc(nullptr), pSvc(nullptr) +Wmi::Wmi() { }; Wmi::~Wmi() { - //pSvc->Release(); - //pLoc->Release(); - CoUninitialize(); + } HRESULT Wmi::init() { HRESULT hres; + if(pLoc != nullptr && pSvc != nullptr) + { + return S_OK; + } + // Initialize COM. ------------------------------------------ hres = CoInitializeEx(0, COINIT_MULTITHREADED); if (FAILED(hres)) diff --git a/wmi/wmi.h b/wmi/wmi.h index cfa9d20a..8565fa3d 100644 --- a/wmi/wmi.h +++ b/wmi/wmi.h @@ -33,6 +33,6 @@ public: const AdditionalFilters* filters = nullptr); private: - IWbemLocator *pLoc = nullptr; - IWbemServices *pSvc= nullptr; + static IWbemLocator *pLoc; + static IWbemServices *pSvc; };