/*---------------------------------------------------------*\ | ENESMBusController.cpp | | | | Driver for ENE SMBus devices | | | | Adam Honse (CalcProgrammer1) 19 Aug 2018 | | | | This file is part of the OpenRGB project | | SPDX-License-Identifier: GPL-2.0-or-later | \*---------------------------------------------------------*/ #include #include "ENESMBusController.h" #include "LogManager.h" static const char* ene_channels[] = /* ENE channel strings */ { "Audio", "Backplate", "Back I/O", "Center", "Center", "DRAM", "PCIe", "RGB Header", "RGB Header 2", "RGB Header", "SSD", "Unknown", }; ENESMBusController::ENESMBusController(ENESMBusInterface* interface, ene_dev_id dev, std::string dev_name, device_type dev_type) { this->interface = interface; this->dev = dev; this->name = dev_name; this->type = dev_type; supports_mode_14 = false; if(interface->GetInterfaceType() != ENE_INTERFACE_TYPE_ROG_ARION) { UpdateDeviceName(); /*-------------------------------------------------*\ | Read the device configuration table | \*-------------------------------------------------*/ for(int i = 0; i < 64; i++) { config_table[i] = ENERegisterRead(ENE_REG_CONFIG_TABLE + i); } /*-------------------------------------------------*\ | If this is running with TRACE or higher loglevel | | then dump the entire Feature list to log | \*-------------------------------------------------*/ if(LogManager::get()->getLoglevel() >= LL_TRACE) { LOG_TRACE("[ENE SMBus] ENE config table for 0x%02X:", dev); LOG_TRACE(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", config_table[0], config_table[1], config_table[2], config_table[3], config_table[4], config_table[5], config_table[6], config_table[7], config_table[8], config_table[9], config_table[10], config_table[11], config_table[12], config_table[13], config_table[14], config_table[15]); LOG_TRACE(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", config_table[16], config_table[17], config_table[18], config_table[19], config_table[20], config_table[21], config_table[22], config_table[23], config_table[24], config_table[25], config_table[26], config_table[27], config_table[28], config_table[29], config_table[30], config_table[31]); LOG_TRACE(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", config_table[32], config_table[33], config_table[34], config_table[35], config_table[36], config_table[37], config_table[38], config_table[39], config_table[40], config_table[41], config_table[42], config_table[43], config_table[44], config_table[45], config_table[46], config_table[47]); LOG_TRACE(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", config_table[48], config_table[49], config_table[50], config_table[51], config_table[52], config_table[53], config_table[54], config_table[55], config_table[56], config_table[57], config_table[58], config_table[59], config_table[60], config_table[61], config_table[62], config_table[63]); } } else { LOG_TRACE("[ENE SMBus] ROG STRIX ARION detected, filling in hard coded config table entries.", dev); memset(config_table, 0, sizeof(config_table)); config_table[ENE_CONFIG_LED_COUNT] = 4; config_table[0x03] = 4; strcpy(device_version, "ROG STRIX ARION"); } /*-----------------------------------------------------*\ | Read LED count from configuration table | \*-----------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT]; /*-----------------------------------------------------*\ | LED-0116 - First generation motherboard controller | \*-----------------------------------------------------*/ if(strcmp(device_version, "LED-0116") == 0) { direct_reg = ENE_REG_COLORS_DIRECT; effect_reg = ENE_REG_COLORS_EFFECT; channel_cfg = ENE_CONFIG_CHANNEL_V1; } /*-----------------------------------------------------*\ | DIMM_LED-0102 - First generation DRAM controller | | (Trident Z RGB) | \*-----------------------------------------------------*/ else if(strcmp(device_version, "DIMM_LED-0102") == 0) { direct_reg = ENE_REG_COLORS_DIRECT; effect_reg = ENE_REG_COLORS_EFFECT; channel_cfg = ENE_CONFIG_CHANNEL_V1; } /*-----------------------------------------------------*\ | AUDA0-E6K5-0101 - Second generation DRAM controller | | (Geil Super Luce) | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUDA0-E6K5-0101") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V1; /*-------------------------------------------------*\ | Check for Mode 14 support, only known to exist on | | modules where the DRAM 3 zone ID exists | \*-------------------------------------------------*/ for(std::size_t cfg_zone_idx = 0; cfg_zone_idx < ENE_NUM_ZONES; cfg_zone_idx++) { if(config_table[channel_cfg + cfg_zone_idx] == (unsigned char)ENE_LED_CHANNEL_DRAM_3) { supports_mode_14 = true; break; } } } /*-----------------------------------------------------*\ | AUMA0-E6K5-0106 - Second generation motherboard | | controller | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-0106") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; } /*-----------------------------------------------------*\ | AUMA0-E6K5-0105 - Second generation motherboard | | controller | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-0105") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; } /*-----------------------------------------------------*\ | AUMA0-E6K5-0104 - Second generation motherboard | | controller | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-0104") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; } /*-----------------------------------------------------*\ | AUMA0-E8K4-0101 - First generation motherboard | | controller | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E8K4-0101") == 0) { direct_reg = ENE_REG_COLORS_DIRECT; effect_reg = ENE_REG_COLORS_EFFECT; channel_cfg = ENE_CONFIG_CHANNEL_V1; } /*-----------------------------------------------------*\ | AUMA0-E6K5-0107 - Second generation GPU controller | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-0107") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; /*-------------------------------------------------*\ | Read LED count from configuration table | \*-------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT_0107]; } /*-----------------------------------------------------*\ | AUMA0-E6K5-1110 - Third generation GPU controller? | | found an ASUS ROG Strix 4080 OC, seems to be equal to | | AUMA0-E6K5-0107 | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-1110") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; /*-------------------------------------------------*\ | Read LED count from configuration table | \*-------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT_1110]; } /*-----------------------------------------------------*\ | AUMA0-E6K5-1111 - Fourth generation GPU controller? | | found on ASUS ROG Strix 4090 OC EVA-02 Edition, seems | | to be equal to AUMA0-E6K5-0107 | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-1111") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; /*-------------------------------------------------*\ | Read LED count from configuration table | \*-------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT_0107]; } /*-----------------------------------------------------*\ | AUMA0-E6K5-1107 - Second generation GPU controller | | Found on ASUS TUF 4070 TI OC, seems to be equal to | | AUMA0-E6K5-0107 | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-1107") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; /*-------------------------------------------------*\ | Read LED count from configuration table | \*-------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT_0107]; } /*-----------------------------------------------------*\ | AUMA0-E6K5-0008 | | Found on ASUS STRIX 4070 Super OC | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-0008") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V1; /*-------------------------------------------------*\ | Read LED count from configuration table | \*-------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT_0107]; } /*-----------------------------------------------------*\ | AUMA0-E6K5-1113 | | Found on ASUS ASTRAL 5080 OC | \*-----------------------------------------------------*/ else if(strcmp(device_version, "AUMA0-E6K5-1113") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; /*-------------------------------------------------*\ | Read LED count from configuration table | \*-------------------------------------------------*/ led_count = config_table[ENE_CONFIG_LED_COUNT_0107]; } /*-----------------------------------------------------*\ | ROG ARION - ASUS ROG Arion external SSD enclosure | | This device does not support ENE read, so we fake the | | device name string if the interface is ROG Arion type.| | It uses second generation registers. | \*-----------------------------------------------------*/ else if(strcmp(device_version, "ROG STRIX ARION") == 0) { direct_reg = ENE_REG_COLORS_DIRECT_V2; effect_reg = ENE_REG_COLORS_EFFECT_V2; channel_cfg = ENE_CONFIG_CHANNEL_V2; } /*-----------------------------------------------------*\ | Assume first generation controller if string does not | | match | \*-----------------------------------------------------*/ else { direct_reg = ENE_REG_COLORS_DIRECT; effect_reg = ENE_REG_COLORS_EFFECT; channel_cfg = ENE_CONFIG_CHANNEL_V1; } } ENESMBusController::~ENESMBusController() { delete interface; } std::string ENESMBusController::GetLocation() { std::string return_string = interface->GetLocation(); char addr[5]; snprintf(addr, 5, "0x%02X", dev); return_string.append(", address "); return_string.append(addr); return(return_string); } std::string ENESMBusController::GetName() { return(name); } std::string ENESMBusController::GetVersion() { return(device_version); } device_type ENESMBusController::GetType() { return(type); } const char * ENESMBusController::GetChannelName(unsigned int cfg_zone) { LOG_TRACE("[%s] Config table for zone %02d: %02d", device_version, cfg_zone, config_table[channel_cfg + cfg_zone]); if(interface->GetInterfaceType() == ENE_INTERFACE_TYPE_ROG_ARION) { return(ene_channels[10]); } else { switch(config_table[channel_cfg + cfg_zone]) { case (unsigned char)ENE_LED_CHANNEL_AUDIO: return(ene_channels[0]); break; case (unsigned char)ENE_LED_CHANNEL_BACKPLATE: return(ene_channels[1]); break; case (unsigned char)ENE_LED_CHANNEL_BACK_IO: return(ene_channels[2]); break; case (unsigned char)ENE_LED_CHANNEL_CENTER: return(ene_channels[3]); break; case (unsigned char)ENE_LED_CHANNEL_CENTER_START: return(ene_channels[4]); break; case (unsigned char)ENE_LED_CHANNEL_DRAM: case (unsigned char)ENE_LED_CHANNEL_DRAM_2: case (unsigned char)ENE_LED_CHANNEL_DRAM_3: return(ene_channels[5]); break; case (unsigned char)ENE_LED_CHANNEL_PCIE: return(ene_channels[6]); break; case (unsigned char)ENE_LED_CHANNEL_RGB_HEADER: return(ene_channels[7]); break; case (unsigned char)ENE_LED_CHANNEL_RGB_HEADER_2: return(ene_channels[8]); break; case (unsigned char)ENE_LED_CHANNEL_RGB_HEADER_3: return(ene_channels[9]); break; default: return(ene_channels[11]); break; } } } unsigned int ENESMBusController::GetLEDCount(unsigned int cfg_zone) { LOG_TRACE("[%s] LED Count for zone %02d: %02d", device_version, cfg_zone, config_table[0x03 + cfg_zone]); return(config_table[0x03 + cfg_zone]); } unsigned char ENESMBusController::GetLEDRed(unsigned int led) { return(ENERegisterRead(direct_reg + ( 3 * led ))); } unsigned char ENESMBusController::GetLEDGreen(unsigned int led) { return(ENERegisterRead(direct_reg + ( 3 * led ) + 2)); } unsigned char ENESMBusController::GetLEDBlue(unsigned int led) { return(ENERegisterRead(direct_reg + ( 3 * led ) + 1)); } unsigned char ENESMBusController::GetLEDRedEffect(unsigned int led) { return(ENERegisterRead(effect_reg + ( 3 * led ))); } unsigned char ENESMBusController::GetLEDGreenEffect(unsigned int led) { return(ENERegisterRead(effect_reg + ( 3 * led ) + 2)); } unsigned char ENESMBusController::GetLEDBlueEffect(unsigned int led) { return(ENERegisterRead(effect_reg + ( 3 * led ) + 1)); } void ENESMBusController::SaveMode() { ENERegisterWrite(ENE_REG_APPLY, ENE_SAVE_VAL); } void ENESMBusController::SetAllColorsDirect(RGBColor* colors) { unsigned char* color_buf = new unsigned char[led_count * 3]; unsigned int bytes_sent = 0; for(unsigned int i = 0; i < (led_count * 3); i += 3) { color_buf[i + 0] = RGBGetRValue(colors[i / 3]); color_buf[i + 1] = RGBGetBValue(colors[i / 3]); color_buf[i + 2] = RGBGetGValue(colors[i / 3]); } while(bytes_sent < (led_count * 3)) { int bytes_to_send = (led_count * 3) - bytes_sent; if(bytes_to_send > interface->GetMaxBlock()) { bytes_to_send = interface->GetMaxBlock(); } ENERegisterWriteBlock(direct_reg + bytes_sent, &color_buf[bytes_sent], bytes_to_send); bytes_sent += bytes_to_send; } delete[] color_buf; } void ENESMBusController::SetAllColorsEffect(RGBColor* colors) { unsigned char* color_buf = new unsigned char[led_count * 3]; unsigned int bytes_sent = 0; for(unsigned int i = 0; i < (led_count * 3); i += 3) { color_buf[i + 0] = RGBGetRValue(colors[i / 3]); color_buf[i + 1] = RGBGetBValue(colors[i / 3]); color_buf[i + 2] = RGBGetGValue(colors[i / 3]); } while(bytes_sent < (led_count * 3)) { int bytes_to_send = (led_count * 3) - bytes_sent; if(bytes_to_send > interface->GetMaxBlock()) { bytes_to_send = interface->GetMaxBlock(); } ENERegisterWriteBlock(effect_reg + bytes_sent, &color_buf[bytes_sent], bytes_to_send); bytes_sent += bytes_to_send; } ENERegisterWrite(ENE_REG_APPLY, ENE_APPLY_VAL); delete[] color_buf; } void ENESMBusController::SetDirect(unsigned char direct) { ENERegisterWrite(ENE_REG_DIRECT, direct); ENERegisterWrite(ENE_REG_APPLY, ENE_APPLY_VAL); } void ENESMBusController::SetLEDColorDirect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) { unsigned char colors[3] = { red, blue, green }; ENERegisterWriteBlock(direct_reg + ( 3 * led ), colors, 3); } void ENESMBusController::SetLEDColorEffect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) { unsigned char colors[3] = { red, blue, green }; ENERegisterWriteBlock(effect_reg + (3 * led), colors, 3); ENERegisterWrite(ENE_REG_APPLY, ENE_APPLY_VAL); } void ENESMBusController::SetMode(unsigned char mode, unsigned char speed, unsigned char direction) { ENERegisterWrite(ENE_REG_MODE, mode); ENERegisterWrite(ENE_REG_SPEED, speed); ENERegisterWrite(ENE_REG_DIRECTION, direction); ENERegisterWrite(ENE_REG_APPLY, ENE_APPLY_VAL); } bool ENESMBusController::SupportsMode14() { return(supports_mode_14); } void ENESMBusController::UpdateDeviceName() { for (int i = 0; i < 16; i++) { device_version[i] = ENERegisterRead(ENE_REG_DEVICE_NAME + i); } } unsigned char ENESMBusController::ENERegisterRead(ene_register reg) { return(interface->ENERegisterRead(dev, reg)); } void ENESMBusController::ENERegisterWrite(ene_register reg, unsigned char val) { interface->ENERegisterWrite(dev, reg, val); } void ENESMBusController::ENERegisterWriteBlock(ene_register reg, unsigned char * data, unsigned char sz) { interface->ENERegisterWriteBlock(dev, reg, data, sz); }