diff --git a/Controllers/ENESMBusController/ENESMBusController.cpp b/Controllers/ENESMBusController/ENESMBusController.cpp index 13052521..05f2f86c 100644 --- a/Controllers/ENESMBusController/ENESMBusController.cpp +++ b/Controllers/ENESMBusController/ENESMBusController.cpp @@ -258,40 +258,65 @@ void ENESMBusController::SaveMode() ENERegisterWrite(ENE_REG_APPLY, ENE_SAVE_VAL); } -void ENESMBusController::SetAllColorsDirect(unsigned char red, unsigned char green, unsigned char blue) +void ENESMBusController::SetAllColorsDirect(RGBColor* colors) { - unsigned char* colors = new unsigned char[led_count * 3]; + 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) + for(unsigned int i = 0; i < (led_count * 3); i += 3) { - colors[i + 0] = red; - colors[i + 1] = blue; - colors[i + 2] = green; + color_buf[i + 0] = RGBGetRValue(colors[i / 3]); + color_buf[i + 1] = RGBGetBValue(colors[i / 3]); + color_buf[i + 2] = RGBGetGValue(colors[i / 3]); } - ENERegisterWriteBlock(direct_reg, colors, led_count * 3); - - delete[] colors; -} - -void ENESMBusController::SetAllColorsEffect(unsigned char red, unsigned char green, unsigned char blue) -{ - unsigned char* colors = new unsigned char[led_count * 3]; - - for (unsigned int i = 0; i < (led_count * 3); i += 3) + while(bytes_sent < (led_count * 3)) { - colors[i + 0] = red; - colors[i + 1] = blue; - colors[i + 2] = green; + unsigned 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; } - ENERegisterWriteBlock(effect_reg, colors, led_count * 3); - - ENERegisterWrite(ENE_REG_APPLY, ENE_APPLY_VAL); - - delete[] colors; + 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)) + { + unsigned 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; + } + + delete color_buf; +} + + void ENESMBusController::SetDirect(unsigned char direct) { ENERegisterWrite(ENE_REG_DIRECT, direct); diff --git a/Controllers/ENESMBusController/ENESMBusController.h b/Controllers/ENESMBusController/ENESMBusController.h index e8540053..3c272401 100644 --- a/Controllers/ENESMBusController/ENESMBusController.h +++ b/Controllers/ENESMBusController/ENESMBusController.h @@ -12,6 +12,7 @@ #include #include "ENESMBusInterface.h" +#include "RGBController.h" #pragma once @@ -111,8 +112,8 @@ public: unsigned char GetLEDGreenEffect(unsigned int led); unsigned char GetLEDBlueEffect(unsigned int led); void SaveMode(); - void SetAllColorsDirect(unsigned char red, unsigned char green, unsigned char blue); - void SetAllColorsEffect(unsigned char red, unsigned char green, unsigned char blue); + void SetAllColorsDirect(RGBColor* colors); + void SetAllColorsEffect(RGBColor* colors); void SetDirect(unsigned char direct); void SetLEDColorDirect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue); void SetLEDColorEffect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue); diff --git a/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp b/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp index f1ad8122..1793df63 100644 --- a/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp +++ b/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp @@ -1,6 +1,7 @@ #include "Detector.h" #include "ENESMBusController.h" #include "ENESMBusInterface_i2c_smbus.h" +#include "ENESMBusInterface_SpectrixS40G.h" #include "LogManager.h" #include "RGBController.h" #include "RGBController_ENESMBus.h" @@ -365,4 +366,4 @@ void DetectENESMBusGPUControllers(std::vector &busses) REGISTER_I2C_DETECTOR("ENE SMBus DRAM", DetectENESMBusDRAMControllers); REGISTER_I2C_DETECTOR("ASUS Aura SMBus Motherboard", DetectENESMBusMotherboardControllers); -REGISTER_I2C_DETECTOR("ASUS Aura GPU (ENE)", DetectENESMBusGPUControllers); +REGISTER_I2C_DETECTOR("ASUS Aura GPU (ENE)", DetectENESMBusGPUControllers); \ No newline at end of file diff --git a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface.h b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface.h index bbdc8f49..f3b18b18 100644 --- a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface.h +++ b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface.h @@ -17,6 +17,7 @@ class ENESMBusInterface { public: virtual std::string GetLocation() = 0; + virtual int GetMaxBlock() = 0; virtual unsigned char ENERegisterRead(ene_dev_id dev, ene_register reg) = 0; virtual void ENERegisterWrite(ene_dev_id dev, ene_register reg, unsigned char val) = 0; virtual void ENERegisterWriteBlock(ene_dev_id dev, ene_register reg, unsigned char * data, unsigned char sz) = 0; diff --git a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.cpp b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.cpp new file mode 100644 index 00000000..6b4b91ff --- /dev/null +++ b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.cpp @@ -0,0 +1,200 @@ +/*-----------------------------------------*\ +| ENESMBusInterface_SpectrixS40G.cpp | +| | +| Code for ENE XPG Spectrix S40G NVMe | +| interface | +| | +| Adam Honse (CalcProgrammer1) 11/21/2021 | +\*-----------------------------------------*/ + +#include "ENESMBusInterface_SpectrixS40G.h" +#include +#include + +/*---------------------------------------------------------------------*\ +| Functions for submitting NVME admin passthrough command taken from | +| libnvme: https://github.com/linux-nvme/libnvme | +\*---------------------------------------------------------------------*/ + +#define NVME_IOCTL_ADMIN_CMD _IOWR('N', 0x41, struct nvme_passthru_cmd) + +struct nvme_passthru_cmd +{ + uint8_t opcode; + uint8_t flags; + uint16_t rsvd1; + uint32_t nsid; + uint32_t cdw2; + uint32_t cdw3; + uint64_t metadata; + uint64_t addr; + uint32_t metadata_len; + uint32_t data_len; + uint32_t cdw10; + uint32_t cdw11; + uint32_t cdw12; + uint32_t cdw13; + uint32_t cdw14; + uint32_t cdw15; + uint32_t timeout_ms; + uint32_t result; +}; + +static int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, + struct nvme_passthru_cmd *cmd, uint32_t *result) +{ + int err = ioctl(fd, ioctl_cmd, cmd); + + if (err >= 0 && result) + *result = cmd->result; + return err; +} + +static int nvme_passthru(int fd, unsigned long ioctl_cmd, uint8_t opcode, + uint8_t flags, uint16_t rsvd, uint32_t nsid, uint32_t cdw2, + uint32_t cdw3, uint32_t cdw10, uint32_t cdw11, uint32_t cdw12, + uint32_t cdw13, uint32_t cdw14, uint32_t cdw15, uint32_t data_len, + void *data, uint32_t metadata_len, void *metadata, + uint32_t timeout_ms, uint32_t *result) +{ + struct nvme_passthru_cmd cmd = { + .opcode = opcode, + .flags = flags, + .rsvd1 = rsvd, + .nsid = nsid, + .cdw2 = cdw2, + .cdw3 = cdw3, + .metadata = (uint64_t)(uintptr_t)metadata, + .addr = (uint64_t)(uintptr_t)data, + .metadata_len = metadata_len, + .data_len = data_len, + .cdw10 = cdw10, + .cdw11 = cdw11, + .cdw12 = cdw12, + .cdw13 = cdw13, + .cdw14 = cdw14, + .cdw15 = cdw15, + .timeout_ms = timeout_ms, + }; + + return nvme_submit_passthru(fd, ioctl_cmd, &cmd, result); +} + +int nvme_admin_passthru(int fd, uint8_t opcode, uint8_t flags, uint16_t rsvd, + uint32_t nsid, uint32_t cdw2, uint32_t cdw3, uint32_t cdw10, + uint32_t cdw11, uint32_t cdw12, uint32_t cdw13, uint32_t cdw14, + uint32_t cdw15, uint32_t data_len, void *data, + uint32_t metadata_len, void *metadata, uint32_t timeout_ms, + uint32_t *result) +{ + return nvme_passthru(fd, NVME_IOCTL_ADMIN_CMD, opcode, flags, rsvd, + nsid, cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, + cdw14, cdw15, data_len, data, metadata_len, + metadata, timeout_ms, result); +} + +/*---------------------------------------------------------------------*\ +| ENESMBusInterface_SpectrixS40G implementation | +\*---------------------------------------------------------------------*/ + +ENESMBusInterface_SpectrixS40G::ENESMBusInterface_SpectrixS40G(int fd) +{ + this->nvme_fd = fd; +} + +std::string ENESMBusInterface_SpectrixS40G::GetLocation() +{ + return("NVMe: "); +} + +int ENESMBusInterface_SpectrixS40G::GetMaxBlock() +{ + return(24); +} + +unsigned char ENESMBusInterface_SpectrixS40G::ENERegisterRead(ene_dev_id dev, ene_register reg) +{ + struct nvme_passthru_cmd cfg; + + memset(&cfg, 0, sizeof(nvme_passthru_cmd)); + + unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + cfg.opcode = 0xFA; + cfg.cdw12 = (corrected_reg << 16) | (dev << 1); + cfg.cdw13 = 0x81100001; + cfg.data_len = 1; + + unsigned char data[1]; + unsigned char metadata[1]; + unsigned int result; + + /*-----------------------------------------------------------------------------*\ + | Send the command to the device | + \*-----------------------------------------------------------------------------*/ + nvme_admin_passthru(nvme_fd, cfg.opcode, cfg.flags, cfg.rsvd1, + cfg.nsid, cfg.cdw2, cfg.cdw3, cfg.cdw10, + cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, + cfg.cdw15, cfg.data_len, data, cfg.metadata_len, + metadata, cfg.timeout_ms, &result); + + return(data[0]); +} + +void ENESMBusInterface_SpectrixS40G::ENERegisterWrite(ene_dev_id dev, ene_register reg, unsigned char val) +{ + struct nvme_passthru_cmd cfg; + + memset(&cfg, 0, sizeof(nvme_passthru_cmd)); + + unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + cfg.opcode = 0xFB; + cfg.cdw12 = (corrected_reg << 16) | (dev << 1); + cfg.cdw13 = 0x01100001; + cfg.data_len = 1; + + unsigned char data[1]; + + data[0] = val; + + unsigned char metadata[1]; + unsigned int result; + + /*-----------------------------------------------------------------------------*\ + | Send the command to the device | + \*-----------------------------------------------------------------------------*/ + nvme_admin_passthru(nvme_fd, cfg.opcode, cfg.flags, cfg.rsvd1, + cfg.nsid, cfg.cdw2, cfg.cdw3, cfg.cdw10, + cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, + cfg.cdw15, cfg.data_len, data, cfg.metadata_len, + metadata, cfg.timeout_ms, &result); + +} + +void ENESMBusInterface_SpectrixS40G::ENERegisterWriteBlock(ene_dev_id dev, ene_register reg, unsigned char * data, unsigned char sz) +{ + struct nvme_passthru_cmd cfg; + + memset(&cfg, 0, sizeof(nvme_passthru_cmd)); + + unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + cfg.opcode = 0xFB; + cfg.cdw12 = (corrected_reg << 16) | (dev << 1); + cfg.cdw13 = 0x03100000 | sz; + cfg.data_len = sz; + + unsigned char metadata[1]; + unsigned int result; + + /*-----------------------------------------------------------------------------*\ + | Send the command to the device | + \*-----------------------------------------------------------------------------*/ + nvme_admin_passthru(nvme_fd, cfg.opcode, cfg.flags, cfg.rsvd1, + cfg.nsid, cfg.cdw2, cfg.cdw3, cfg.cdw10, + cfg.cdw11, cfg.cdw12, cfg.cdw13, cfg.cdw14, + cfg.cdw15, cfg.data_len, data, cfg.metadata_len, + metadata, cfg.timeout_ms, &result); + +} \ No newline at end of file diff --git a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.h b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.h new file mode 100644 index 00000000..74a65dbe --- /dev/null +++ b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.h @@ -0,0 +1,27 @@ +/*-----------------------------------------*\ +| ENESMBusInterface_SpectrixS40G.h | +| | +| Definitions and types for ENE XPG | +| Spectrix S40G NVMe interface | +| | +| Adam Honse (CalcProgrammer1) 11/21/2021 | +\*-----------------------------------------*/ + +#include "ENESMBusInterface.h" + +#pragma once + +class ENESMBusInterface_SpectrixS40G : public ENESMBusInterface +{ +public: + ENESMBusInterface_SpectrixS40G(int fd); + + std::string GetLocation(); + int GetMaxBlock(); + unsigned char ENERegisterRead(ene_dev_id dev, ene_register reg); + void ENERegisterWrite(ene_dev_id dev, ene_register reg, unsigned char val); + void ENERegisterWriteBlock(ene_dev_id dev, ene_register reg, unsigned char * data, unsigned char sz); + +private: + int nvme_fd; +}; \ No newline at end of file diff --git a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.cpp b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.cpp index db81db8b..77989518 100644 --- a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.cpp +++ b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.cpp @@ -19,6 +19,11 @@ std::string ENESMBusInterface_i2c_smbus::GetLocation() return("I2C: " + return_string); } +int ENESMBusInterface_i2c_smbus::GetMaxBlock() +{ + return(3); +} + unsigned char ENESMBusInterface_i2c_smbus::ENERegisterRead(ene_dev_id dev, ene_register reg) { //Write ENE register diff --git a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.h b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.h index cf2cd40d..f34c2982 100644 --- a/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.h +++ b/Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_i2c_smbus.h @@ -18,7 +18,7 @@ public: ENESMBusInterface_i2c_smbus(i2c_smbus_interface* bus); std::string GetLocation(); - + int GetMaxBlock(); unsigned char ENERegisterRead(ene_dev_id dev, ene_register reg); void ENERegisterWrite(ene_dev_id dev, ene_register reg, unsigned char val); void ENERegisterWriteBlock(ene_dev_id dev, ene_register reg, unsigned char * data, unsigned char sz); diff --git a/Controllers/ENESMBusController/RGBController_ENESMBus.cpp b/Controllers/ENESMBusController/RGBController_ENESMBus.cpp index 2a8ad42d..e68d3cf3 100644 --- a/Controllers/ENESMBusController/RGBController_ENESMBus.cpp +++ b/Controllers/ENESMBusController/RGBController_ENESMBus.cpp @@ -233,21 +233,15 @@ int RGBController_ENESMBus::GetDeviceMode() void RGBController_ENESMBus::DeviceUpdateLEDs() { - for(std::size_t led = 0; led < colors.size(); led++) + if(GetMode() == 0) { - unsigned char red = RGBGetRValue(colors[led]); - unsigned char grn = RGBGetGValue(colors[led]); - unsigned char blu = RGBGetBValue(colors[led]); - - if(GetMode() == 0) - { - controller->SetLEDColorDirect(led, red, grn, blu); - } - else - { - controller->SetLEDColorEffect(led, red, grn, blu); - } + controller->SetAllColorsDirect(&colors[0]); } + else + { + controller->SetAllColorsEffect(&colors[0]); + } + } void RGBController_ENESMBus::UpdateZoneLEDs(int zone) diff --git a/Controllers/ENESMBusController/XPGSpectrixS40GDetect.cpp b/Controllers/ENESMBusController/XPGSpectrixS40GDetect.cpp new file mode 100644 index 00000000..979f4852 --- /dev/null +++ b/Controllers/ENESMBusController/XPGSpectrixS40GDetect.cpp @@ -0,0 +1,81 @@ +#include "Detector.h" +#include "ENESMBusController.h" +#include "ENESMBusInterface_SpectrixS40G.h" +#include "LogManager.h" +#include "RGBController.h" +#include "RGBController_ENESMBus.h" +#include +#include +#include + +#include +#include +#include + +/******************************************************************************************\ +* * +* DetectSpectrixS40GControllers * +* * +* Detects ENE SMBus controllers on XPG Spectrix S40G NVMe devices * +* * +\******************************************************************************************/ + +void DetectSpectrixS40GControllers(std::vector& rgb_controllers) +{ + /*---------------------------------------------------------------------*\ + | Search for /dev/nvmeX nodes with model matching "XPG SPECTRIX S40G" | + \*---------------------------------------------------------------------*/ + unsigned int nvme_idx = 0; + + while(1) + { + /*-------------------------------------------------*\ + | Create the nvme class model path | + \*-------------------------------------------------*/ + char nvme_dev_buf[1024]; + + snprintf(nvme_dev_buf, 1024, "/sys/class/nvme/nvme%d/model", nvme_idx); + + /*-------------------------------------------------*\ + | Open the input event path to get the name | + \*-------------------------------------------------*/ + int nvme_model_fd = open(nvme_dev_buf, O_RDONLY|O_NONBLOCK); + + if(nvme_model_fd < 0) + { + break; + } + + memset(nvme_dev_buf, 0, 1024); + read(nvme_model_fd, nvme_dev_buf, 1024); + close(nvme_model_fd); + + LOG_DEBUG("[XPG Spectrix S40G] Probing %d, model: %s", nvme_idx, nvme_dev_buf); + + /*-------------------------------------------------*\ + | Check if this NVMe device is a SPECTRIX S40G | + \*-------------------------------------------------*/ + if(strncmp(nvme_dev_buf, "XPG SPECTRIX S40G", 17) == 0) + { + snprintf(nvme_dev_buf, 1024, "/dev/nvme%d", nvme_idx); + + int nvme_fd = open(nvme_dev_buf, O_RDWR); + + if(nvme_fd > 0) + { + ENESMBusInterface_SpectrixS40G* interface = new ENESMBusInterface_SpectrixS40G(nvme_fd); + ENESMBusController* controller = new ENESMBusController(interface, 0x67); + RGBController_ENESMBus* rgb_controller = new RGBController_ENESMBus(controller); + + rgb_controller->name = "XPG Spectrix S40G"; + rgb_controller->type = DEVICE_TYPE_STORAGE; + + rgb_controllers.push_back(rgb_controller); + } + } + + nvme_idx++; + } +} /* DetectSpectrixS40GControllers() */ + +REGISTER_DETECTOR( "XPG Spectrix S40G", DetectSpectrixS40GControllers); \ No newline at end of file diff --git a/OpenRGB.pro b/OpenRGB.pro index 259858f5..f3389348 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -1145,6 +1145,7 @@ unix:!macx { HEADERS += \ i2c_smbus/i2c_smbus_linux.h \ AutoStart/AutoStart-Linux.h \ + Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.h \ Controllers/FaustusController/RGBController_Faustus.h \ Controllers/LinuxLEDController/LinuxLEDController.h \ Controllers/LinuxLEDController/RGBController_LinuxLED.h \ @@ -1189,6 +1190,8 @@ unix:!macx { i2c_smbus/i2c_smbus_linux.cpp \ serial_port/find_usb_serial_port_linux.cpp \ AutoStart/AutoStart-Linux.cpp \ + Controllers/ENESMBusController/XPGSpectrixS40GDetect.cpp \ + Controllers/ENESMBusController/ENESMBusInterface/ENESMBusInterface_SpectrixS40G.cpp \ Controllers/FaustusController/RGBController_Faustus.cpp \ Controllers/LinuxLEDController/LinuxLEDController.cpp \ Controllers/LinuxLEDController/LinuxLEDControllerDetect.cpp \