/******************************************************************************************\ * * * OpenRGB.cpp * * * * Functions for communicating with RGBController API devices on Windows and Linux * * * \******************************************************************************************/ #include "RGBController.h" #include "i2c_smbus.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 */ std::vector busses; std::vector rgb_controllers; #ifdef WIN32 /******************************************************************************************\ * * * DetectNuvotonI2CBusses (Windows) * * * * Detects available Nuvoton Super IO SMBUS adapters and enumerates * * i2c_smbus_interface objects for them * * * \******************************************************************************************/ void DetectNuvotonI2CBusses() { 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() { static NV_PHYSICAL_GPU_HANDLE gpu_handles[64]; static NV_S32 gpu_count = 0; 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); 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() { 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() { 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(); // Detect NVidia NvAPI I2C adapters DetectNvAPII2CBusses(); // Detect AMD ADL I2C adadpters DetectADLI2C(); } /* DetectI2CBusses() */ #else /* WIN32 */ /******************************************************************************************\ * * * DetectI2CBusses (Linux) * * * * Detects available SMBUS adapters and enumerates i2c_smbus_interface objects for * * them * * * \******************************************************************************************/ void DetectI2CBusses() { i2c_smbus_linux * bus; char device_string[1024]; DIR * dir; char driver_path[512]; struct dirent * ent; int test_fd; // 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); 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; busses.push_back(bus); } } } ent = readdir(dir); } } /* DetectI2CBusses() */ #endif /* WIN32 */ void DetectAuraSMBusControllers(std::vector &busses, std::vector &rgb_controllers); void DetectAuraGPUControllers(std::vector &busses, std::vector &rgb_controllers); void DetectCorsairVengeanceControllers(std::vector &busses, std::vector &rgb_controllers); void DetectCorsairVengeanceProControllers(std::vector &busses, std::vector &rgb_controllers); void DetectCrucialControllers(std::vector &busses, std::vector &rgb_controllers); void DetectHyperXDRAMControllers(std::vector &busses, std::vector &rgb_controllers); void DetectPatriotViperControllers(std::vector &busses, std::vector &rgb_controllers); void DetectPolychromeControllers(std::vector& busses, std::vector& rgb_controllers); void DetectRGBFusionControllers(std::vector& busses, std::vector& rgb_controllers); void DetectRGBFusionGPUControllers(std::vector& busses, std::vector& rgb_controllers); void DetectRGBFusion2SMBusControllers(std::vector& busses, std::vector& rgb_controllers); void DetectRGBFusion2DRAMControllers(std::vector& busses, std::vector& rgb_controllers); void DetectMSIMysticLightControllers(std::vector &rgb_controllers); void DetectMSIRGBControllers(std::vector &rgb_controllers); void DetectAuraUSBControllers(std::vector &rgb_controllers); void DetectAuraCoreControllers(std::vector &rgb_controllers); void DetectLEDStripControllers(std::vector &rgb_controllers); void DetectNZXTHue2Controllers(std::vector &rgb_controllers); void DetectHuePlusControllers(std::vector &rgb_controllers); void DetectOpenRazerControllers(std::vector &rgb_controllers); void DetectE131Controllers(std::vector &rgb_controllers); void DetectAMDWraithPrismControllers(std::vector& rgb_controllers); void DetectCoolerMasterControllers(std::vector& rgb_controllers); void DetectMSI3ZoneControllers(std::vector& rgb_controllers); void DetectPoseidonZRGBControllers(std::vector& rgb_controllers); void DetectCorsairPeripheralControllers(std::vector& rgb_controllers); void DetectCorsairLightingNodeControllers(std::vector &rgb_controllers); void DetectFaustusControllers(std::vector &rgb_controllers); void DetectHyperXKeyboardControllers(std::vector& rgb_controllers); void DetectThermaltakeRiingControllers(std::vector& rgb_controllers); void DetectRGBFusion2USBControllers(std::vector &rgb_controllers); void DetectRedragonControllers(std::vector& rgb_controllers); void DetectLogitechControllers(std::vector& rgb_controllers); void DetectNZXTKrakenControllers(std::vector& rgb_controllers); void DetectSteelSeriesControllers(std::vector& rgb_controllers); void DetectGloriousModelOControllers(std::vector& rgb_controllers); /******************************************************************************************\ * * * DetectRGBConrollers * * * * Detect and populate RGB Controllers vector * * * \******************************************************************************************/ void DetectRGBControllers(void) { DetectI2CBusses(); DetectAuraSMBusControllers(busses, rgb_controllers); DetectAuraGPUControllers(busses, rgb_controllers); DetectCorsairVengeanceControllers(busses, rgb_controllers); DetectCorsairVengeanceProControllers(busses, rgb_controllers); DetectCrucialControllers(busses, rgb_controllers); DetectHyperXDRAMControllers(busses, rgb_controllers); DetectPatriotViperControllers(busses, rgb_controllers); DetectPolychromeControllers(busses, rgb_controllers); DetectRGBFusionGPUControllers(busses, rgb_controllers); //TODO: Implement better detection before enabling these controllers //DetectRGBFusion2SMBusControllers(busses, rgb_controllers); //DetectRGBFusion2DRAMControllers(busses, rgb_controllers); DetectRGBFusionControllers(busses, rgb_controllers); DetectMSIMysticLightControllers(rgb_controllers); DetectMSIRGBControllers(rgb_controllers); DetectAuraUSBControllers(rgb_controllers); DetectAuraCoreControllers(rgb_controllers); DetectLEDStripControllers(rgb_controllers); DetectNZXTHue2Controllers(rgb_controllers); DetectHuePlusControllers(rgb_controllers); DetectAMDWraithPrismControllers(rgb_controllers); DetectCoolerMasterControllers(rgb_controllers); DetectMSI3ZoneControllers(rgb_controllers); DetectPoseidonZRGBControllers(rgb_controllers); DetectHyperXKeyboardControllers(rgb_controllers); DetectCorsairPeripheralControllers(rgb_controllers); DetectCorsairLightingNodeControllers(rgb_controllers); DetectThermaltakeRiingControllers(rgb_controllers); DetectRGBFusion2USBControllers(rgb_controllers); DetectRedragonControllers(rgb_controllers); DetectLogitechControllers(rgb_controllers); DetectNZXTKrakenControllers(rgb_controllers); DetectSteelSeriesControllers(rgb_controllers); DetectGloriousModelOControllers(rgb_controllers); DetectE131Controllers(rgb_controllers); DetectOpenRazerControllers(rgb_controllers); /*-------------------------------------*\ | Windows-only devices | \*-------------------------------------*/ #ifdef WIN32 /*-------------------------------------*\ | Linux-only devices | \*-------------------------------------*/ #else DetectFaustusControllers(rgb_controllers); #endif } /* DetectRGBControllers() */