diff --git a/Controllers/XPGSpectrixS40GController/RGBController_XPGSpectrixS40G.cpp b/Controllers/XPGSpectrixS40GControllerLinux/RGBController_XPGSpectrixS40G.cpp similarity index 100% rename from Controllers/XPGSpectrixS40GController/RGBController_XPGSpectrixS40G.cpp rename to Controllers/XPGSpectrixS40GControllerLinux/RGBController_XPGSpectrixS40G.cpp diff --git a/Controllers/XPGSpectrixS40GController/RGBController_XPGSpectrixS40G.h b/Controllers/XPGSpectrixS40GControllerLinux/RGBController_XPGSpectrixS40G.h similarity index 100% rename from Controllers/XPGSpectrixS40GController/RGBController_XPGSpectrixS40G.h rename to Controllers/XPGSpectrixS40GControllerLinux/RGBController_XPGSpectrixS40G.h diff --git a/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.cpp b/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.cpp new file mode 100644 index 000000000..841550291 --- /dev/null +++ b/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.cpp @@ -0,0 +1,501 @@ +/*-------------------------------------------------------------------*\ +| XPGSpectrixS40GController.cpp | +| | +| Driver for XPG's Spectrix S40G NVMe | +| | +| NicolasNewman 25th Mar 2021 | +| | +\*-------------------------------------------------------------------*/ + +#include "XPGSpectrixS40GController.h" +#include +#include +#include "LogManager.h" + +/*-----------------------------------------*\ +| AsusAuraSMBusController.cpp | +| | +| Driver for ASUS Aura RGB lighting | +| controller | +| | +| Adam Honse (CalcProgrammer1) 8/19/2018 | +\*-----------------------------------------*/ +#include + +static const char* aura_channels[] = /* Aura channel strings */ +{ + "Audio", + "Backplate", + "Back I/O", + "Center", + "Center", + "DRAM", + "PCIe", + "RGB Header", + "RGB Header 2", + "RGB Header", + "Unknown", +}; + +XPGSpectrixS40GController::XPGSpectrixS40GController(int fd, aura_dev_id dev) +{ + nvme_fd = fd; + this->dev = dev; + direct_reg = AURA_REG_COLORS_DIRECT_V2; + effect_reg = AURA_REG_COLORS_EFFECT_V2; + channel_cfg = AURA_CONFIG_CHANNEL_V2; + led_count = 8; +} + +XPGSpectrixS40GController::~XPGSpectrixS40GController() +{ + +} + +std::string XPGSpectrixS40GController::GetDeviceName() +{ + return("SSD"); +} + +std::string XPGSpectrixS40GController::GetDeviceLocation() +{ + return("I2C: SSD"); +} + +unsigned char XPGSpectrixS40GController::GetChannel(unsigned int led) +{ + return(0); +} + +const char * XPGSpectrixS40GController::GetChannelName(unsigned int led) +{ + switch (config_table[channel_cfg + led]) + { + case (unsigned char)AURA_LED_CHANNEL_AUDIO: + return(aura_channels[0]); + break; + + case (unsigned char)AURA_LED_CHANNEL_BACKPLATE: + return(aura_channels[1]); + break; + + case (unsigned char)AURA_LED_CHANNEL_BACK_IO: + return(aura_channels[2]); + break; + + case (unsigned char)AURA_LED_CHANNEL_CENTER: + return(aura_channels[3]); + break; + + case (unsigned char)AURA_LED_CHANNEL_CENTER_START: + return(aura_channels[4]); + break; + + case (unsigned char)AURA_LED_CHANNEL_DRAM: + return(aura_channels[5]); + break; + + case (unsigned char)AURA_LED_CHANNEL_PCIE: + return(aura_channels[6]); + break; + + case (unsigned char)AURA_LED_CHANNEL_RGB_HEADER: + return(aura_channels[7]); + break; + + case (unsigned char)AURA_LED_CHANNEL_RGB_HEADER_2: + return(aura_channels[8]); + break; + + case (unsigned char)AURA_LED_CHANNEL_RGB_HEADER_3: + return(aura_channels[9]); + break; + + default: + return(aura_channels[10]); + break; + } +} + +unsigned int XPGSpectrixS40GController::GetLEDCount() +{ + return(led_count); +} + +unsigned char XPGSpectrixS40GController::GetLEDRed(unsigned int led) +{ + return(AuraRegisterRead(direct_reg + ( 3 * led ))); +} + +unsigned char XPGSpectrixS40GController::GetLEDGreen(unsigned int led) +{ + return(AuraRegisterRead(direct_reg + ( 3 * led ) + 2)); +} + +unsigned char XPGSpectrixS40GController::GetLEDBlue(unsigned int led) +{ + return(AuraRegisterRead(direct_reg + ( 3 * led ) + 1)); +} + +void XPGSpectrixS40GController::SaveMode() +{ + AuraRegisterWrite(AURA_REG_APPLY, AURA_SAVE_VAL); +} + +void XPGSpectrixS40GController::SetAllColorsDirect(RGBColor* colors) +{ + unsigned char* color_buf = new unsigned char[led_count * 3]; + + 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]); + } + + AuraRegisterWriteBlock(direct_reg, color_buf, led_count * 3); + + delete color_buf; +} + +void XPGSpectrixS40GController::SetAllColorsEffect(RGBColor* colors) +{ + unsigned char* color_buf = new unsigned char[led_count * 3]; + + 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]); + } + + AuraRegisterWriteBlock(effect_reg, color_buf, led_count * 3); + + AuraRegisterWrite(AURA_REG_APPLY, AURA_APPLY_VAL); + + delete[] color_buf; +} + +void XPGSpectrixS40GController::SetDirect(unsigned char direct) +{ + AuraRegisterWrite(AURA_REG_DIRECT, direct); + AuraRegisterWrite(AURA_REG_APPLY, AURA_APPLY_VAL); +} + +void XPGSpectrixS40GController::SetLEDColorDirect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned char colors[3] = { red, blue, green }; + + AuraRegisterWriteBlock(direct_reg + ( 3 * led ), colors, 3); +} + +void XPGSpectrixS40GController::SetLEDColorEffect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned char colors[3] = { red, blue, green }; + + AuraRegisterWriteBlock(effect_reg + (3 * led), colors, 3); + + AuraRegisterWrite(AURA_REG_APPLY, AURA_APPLY_VAL); +} + +void XPGSpectrixS40GController::SetMode(unsigned char mode, unsigned char speed, unsigned char direction) +{ + AuraRegisterWrite(AURA_REG_MODE, mode); + AuraRegisterWrite(AURA_REG_SPEED, speed); + AuraRegisterWrite(AURA_REG_DIRECTION, direction); + AuraRegisterWrite(AURA_REG_APPLY, AURA_APPLY_VAL); +} + +void XPGSpectrixS40GController::AuraUpdateDeviceName() +{ + for (int i = 0; i < 16; i++) + { + device_name[i] = AuraRegisterRead(AURA_REG_DEVICE_NAME + i); + } +} + +unsigned char XPGSpectrixS40GController::AuraRegisterRead(aura_register reg) +{ + return(0); +} + +#include "libnvme.h" + +void XPGSpectrixS40GController::AuraRegisterWrite(aura_register reg, unsigned char val) +{ + struct config { + __u8 opcode; + __u8 flags; + __u16 rsvd; + __u32 namespace_id; + __u32 data_len; + __u32 metadata_len; + __u32 timeout; + __u32 cdw2; + __u32 cdw3; + __u32 cdw10; + __u32 cdw11; + __u32 cdw12; + __u32 cdw13; + __u32 cdw14; + __u32 cdw15; + char *input_file; + int raw_binary; + int show_command; + int dry_run; + int read; + int write; + __u8 prefill; + int latency; + }; + + struct config cfg = { + .opcode = 0, + .flags = 0, + .rsvd = 0, + .namespace_id = 0, + .data_len = 0, + .metadata_len = 0, + .timeout = 10, + .cdw2 = 0, + .cdw3 = 0, + .cdw10 = 0, + .cdw11 = 0, + .cdw12 = 0, + .cdw13 = 0, + .cdw14 = 0, + .cdw15 = 0, + .input_file = "", + .prefill = 0, + }; + + unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + cfg.opcode = 0xFB; + cfg.namespace_id = 0x00000031; + cfg.cdw12 = (corrected_reg << 16) | (dev << 1); + cfg.cdw13 = 0x01100001; + cfg.data_len = 1; + cfg.write = true; + + unsigned char data[1]; + + data[0] = val; + + unsigned char metadata[1]; + + unsigned int result; + + nvme_admin_passthru(nvme_fd, cfg.opcode, cfg.flags, cfg.rsvd, + cfg.namespace_id, 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, &result); + + // if(hDevice != INVALID_HANDLE_VALUE) + // { + // /*-----------------------------------------------------------------------------*\ + // | Create buffer to hold STORAGE_PROTOCOL_COMMAND | + // | Size must be enough for the STORAGE_PROTOCOL_COMMAND struct plus the command | + // | data. Subtract sizeof(DWORD) as the Command field in the structure overlaps | + // | the actual command data. | + // \*-----------------------------------------------------------------------------*/ + // unsigned char buffer[sizeof(STORAGE_PROTOCOL_COMMAND) + (sizeof(DWORD) * 34) - sizeof(DWORD)]; + + // /*-----------------------------------------------------------------------------*\ + // | Create STORAGE_PROTOCOL_COMMAND pointer and point it to the buffer | + // \*-----------------------------------------------------------------------------*/ + // PSTORAGE_PROTOCOL_COMMAND command = (PSTORAGE_PROTOCOL_COMMAND)buffer; + + // /*-----------------------------------------------------------------------------*\ + // | Fill in STORAGE_PROTOCOL_COMMAND structure | + // \*-----------------------------------------------------------------------------*/ + // command->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION; + // command->Length = sizeof(STORAGE_PROTOCOL_COMMAND); + // command->ProtocolType = ProtocolTypeNvme; + // command->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST; + // command->ReturnStatus = 0x00000000; + // command->ErrorCode = 0x00000000; + // command->CommandLength = STORAGE_PROTOCOL_COMMAND_LENGTH_NVME; + // command->ErrorInfoLength = 0x00000040; + // command->DataToDeviceTransferLength = 0x00000001; + // command->DataFromDeviceTransferLength = 0x00000000; + // command->TimeOutValue = 0x00000001; + // command->ErrorInfoOffset = 0x00000090; + // command->DataToDeviceBufferOffset = 0x000000D0; + // command->DataFromDeviceBufferOffset = 0x00000000; + // command->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND; + // command->Reserved0 = 0x00000000; + // command->FixedProtocolReturnData = 0x00000000; + // command->Reserved1[0] = 0x00000000; + // command->Reserved1[1] = 0x00000000; + // command->Reserved1[2] = 0x00000000; + + // /*-----------------------------------------------------------------------------*\ + // | Create ENE Register Write command, filling in the appropriate register and | + // | value | + // \*-----------------------------------------------------------------------------*/ + // PNVME_COMMAND CommandValue = (PNVME_COMMAND)command->Command; + + // unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + // CommandValue->CDW0.OPC = 0xFB; + // CommandValue->NSID = 0x00000031; + // CommandValue->u.GENERAL.CDW12 = (corrected_reg << 16) | (dev << 1); + // CommandValue->u.GENERAL.CDW13 = 0x01100001; + + // DWORD ExtraValue[18] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + // 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + + // ExtraValue[16] = val; + + // /*-----------------------------------------------------------------------------*\ + // | Copy the ENE Register Write extra data into the STORAGE_PROTOCOL_COMMAND | + // | buffer | + // \*-----------------------------------------------------------------------------*/ + // memcpy(&command->Command + sizeof(NVME_COMMAND), ExtraValue, sizeof(ExtraValue)); + + // /*-----------------------------------------------------------------------------*\ + // | Send the STORAGE_PROTOCOL_COMMAND to the device | + // \*-----------------------------------------------------------------------------*/ + // DeviceIoControl(hDevice, IOCTL_STORAGE_PROTOCOL_COMMAND, buffer, sizeof(buffer), buffer, sizeof(buffer), 0x0, (LPOVERLAPPED)0x0); + // } +} + +void XPGSpectrixS40GController::AuraRegisterWriteBlock(aura_register reg, unsigned char * data, unsigned char sz) +{ + struct config { + __u8 opcode; + __u8 flags; + __u16 rsvd; + __u32 namespace_id; + __u32 data_len; + __u32 metadata_len; + __u32 timeout; + __u32 cdw2; + __u32 cdw3; + __u32 cdw10; + __u32 cdw11; + __u32 cdw12; + __u32 cdw13; + __u32 cdw14; + __u32 cdw15; + char *input_file; + int raw_binary; + int show_command; + int dry_run; + int read; + int write; + __u8 prefill; + int latency; + }; + + struct config cfg = { + .opcode = 0, + .flags = 0, + .rsvd = 0, + .namespace_id = 0, + .data_len = 0, + .metadata_len = 0, + .timeout = 0, + .cdw2 = 0, + .cdw3 = 0, + .cdw10 = 0, + .cdw11 = 0, + .cdw12 = 0, + .cdw13 = 0, + .cdw14 = 0, + .cdw15 = 0, + .input_file = "", + .prefill = 0, + }; + + unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + cfg.opcode = 0xFB; + cfg.namespace_id = 0x00000031; + cfg.cdw12 = (corrected_reg << 16) | (dev << 1); + cfg.cdw13 = 0x03100000 | sz; + cfg.data_len = sz; + + unsigned char metadata[1]; + + unsigned int result; + + nvme_admin_passthru(nvme_fd, cfg.opcode, cfg.flags, cfg.rsvd, + cfg.namespace_id, 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, &result); + + // if(hDevice != INVALID_HANDLE_VALUE) + // { + // /*-----------------------------------------------------------------------------*\ + // | Create buffer to hold STORAGE_PROTOCOL_COMMAND | + // | Size must be enough for the STORAGE_PROTOCOL_COMMAND struct plus the command | + // | data. Subtract sizeof(DWORD) as the Command field in the structure overlaps | + // | the actual command data. | + // \*-----------------------------------------------------------------------------*/ + // unsigned char buffer[sizeof(STORAGE_PROTOCOL_COMMAND) + (sizeof(DWORD) * 39) - sizeof(DWORD)]; + + // /*-----------------------------------------------------------------------------*\ + // | Create STORAGE_PROTOCOL_COMMAND pointer and point it to the buffer | + // \*-----------------------------------------------------------------------------*/ + // PSTORAGE_PROTOCOL_COMMAND command = (PSTORAGE_PROTOCOL_COMMAND)buffer; + + // /*-----------------------------------------------------------------------------*\ + // | Fill in STORAGE_PROTOCOL_COMMAND structure | + // \*-----------------------------------------------------------------------------*/ + // command->Version = STORAGE_PROTOCOL_STRUCTURE_VERSION; + // command->Length = sizeof(STORAGE_PROTOCOL_COMMAND); + // command->ProtocolType = ProtocolTypeNvme; + // command->Flags = STORAGE_PROTOCOL_COMMAND_FLAG_ADAPTER_REQUEST; + // command->ReturnStatus = 0x00000000; + // command->ErrorCode = 0x00000000; + // command->CommandLength = STORAGE_PROTOCOL_COMMAND_LENGTH_NVME; + // command->ErrorInfoLength = 0x00000040; + // command->DataToDeviceTransferLength = sz; + // command->DataFromDeviceTransferLength = 0x00000000; + // command->TimeOutValue = 0x00000001; + // command->ErrorInfoOffset = 0x00000090; + // command->DataToDeviceBufferOffset = 0x000000D0; + // command->DataFromDeviceBufferOffset = 0x00000000; + // command->CommandSpecific = STORAGE_PROTOCOL_SPECIFIC_NVME_ADMIN_COMMAND; + // command->Reserved0 = 0x00000000; + // command->FixedProtocolReturnData = 0x00000000; + // command->Reserved1[0] = 0x00000000; + // command->Reserved1[1] = 0x00000000; + // command->Reserved1[2] = 0x00000000; + + // /*-----------------------------------------------------------------------------*\ + // | Create ENE Register Write Block command, filling in the appropriate register | + // | and value | + // \*-----------------------------------------------------------------------------*/ + // PNVME_COMMAND CommandValue = (PNVME_COMMAND)command->Command; + + // unsigned short corrected_reg = ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF); + + // CommandValue->CDW0.OPC = 0xFB; + // CommandValue->NSID = 0x00000031; + // CommandValue->u.GENERAL.CDW12 = (corrected_reg << 16) | (dev << 1); + // CommandValue->u.GENERAL.CDW13 = 0x03100000 | sz; + + // DWORD ExtraValue[23] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + // 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + // 0x00000000, 0x00000000, 0x00000000 }; + + // memcpy(&ExtraValue[16], data, sz); + + // /*-----------------------------------------------------------------------------*\ + // | Copy the ENE Register Write Block extra data into the | + // | STORAGE_PROTOCOL_COMMAND buffer | + // \*-----------------------------------------------------------------------------*/ + // memcpy(&command->Command + sizeof(NVME_COMMAND), ExtraValue, sizeof(ExtraValue)); + + // /*-----------------------------------------------------------------------------*\ + // | Send the STORAGE_PROTOCOL_COMMAND to the device | + // \*-----------------------------------------------------------------------------*/ + // DeviceIoControl(hDevice, IOCTL_STORAGE_PROTOCOL_COMMAND, buffer, sizeof(buffer), buffer, sizeof(buffer), 0x0, (LPOVERLAPPED)0x0); + // } +} + diff --git a/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.h b/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.h new file mode 100644 index 000000000..8136431ed --- /dev/null +++ b/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.h @@ -0,0 +1,174 @@ +/*-------------------------------------------------------------------*\ +| XPGSpectrixS40GController.h | +| | +| Driver for XPG's Spectrix S40G NVMe | +| | +| NicolasNewman 25th Mar 2021 | +| | +\*-------------------------------------------------------------------*/ + +#include "RGBController.h" +#include +#include +#include + +#pragma once + +#define XPG_SPECTRIX_LED_COUNT ( 8 ) + +#ifdef _WIN32 + #include + #include +#else + +#endif + +/*-----------------------------------------*\ +| AsusAuraSMBusController.h | +| | +| Definitions and types for ASUS Aura RGB | +| lighting controller | +| | +| Adam Honse (CalcProgrammer1) 8/19/2018 | +\*-----------------------------------------*/ + +#include +#include "i2c_smbus.h" + +#pragma once + +typedef unsigned char aura_dev_id; +typedef unsigned short aura_register; + +#define AURA_APPLY_VAL 0x01 /* Value for Apply Changes Register */ +#define AURA_SAVE_VAL 0xAA /* Value for Save Changes */ + +enum +{ + AURA_REG_DEVICE_NAME = 0x1000, /* Device String 16 bytes */ + AURA_REG_MICRON_CHECK = 0x1030, /* If "Micron" appears here, skip */ + AURA_REG_CONFIG_TABLE = 0x1C00, /* Start of LED configuration bytes */ + AURA_REG_COLORS_DIRECT = 0x8000, /* Colors for Direct Mode 15 bytes */ + AURA_REG_COLORS_EFFECT = 0x8010, /* Colors for Internal Effects 15 bytes */ + AURA_REG_DIRECT = 0x8020, /* "Direct Access" Selection Register */ + AURA_REG_MODE = 0x8021, /* Mode Selection Register */ + AURA_REG_SPEED = 0x8022, /* Speed Control Register */ + AURA_REG_DIRECTION = 0x8023, /* Direction Control Register */ + AURA_REG_APPLY = 0x80A0, /* Apply Changes Register */ + AURA_REG_SLOT_INDEX = 0x80F8, /* Slot Index Register (RAM only) */ + AURA_REG_I2C_ADDRESS = 0x80F9, /* I2C Address Register (RAM only) */ + AURA_REG_COLORS_DIRECT_V2 = 0x8100, /* Direct Colors (v2) 30 bytes */ + AURA_REG_COLORS_EFFECT_V2 = 0x8160, /* Internal Colors (v2) 30 bytes */ +}; + +enum +{ + AURA_MODE_OFF = 0, /* OFF mode */ + AURA_MODE_STATIC = 1, /* Static color mode */ + AURA_MODE_BREATHING = 2, /* Breathing effect mode */ + AURA_MODE_FLASHING = 3, /* Flashing effect mode */ + AURA_MODE_SPECTRUM_CYCLE = 4, /* Spectrum Cycle mode */ + AURA_MODE_RAINBOW = 5, /* Rainbow effect mode */ + AURA_MODE_SPECTRUM_CYCLE_BREATHING = 6, /* Rainbow Breathing effect mode */ + AURA_MODE_CHASE_FADE = 7, /* Chase with Fade effect mode */ + AURA_MODE_SPECTRUM_CYCLE_CHASE_FADE = 8, /* Chase with Fade, Rainbow effect mode */ + AURA_MODE_CHASE = 9, /* Chase effect mode */ + AURA_MODE_SPECTRUM_CYCLE_CHASE = 10, /* Chase with Rainbow effect mode */ + AURA_MODE_SPECTRUM_CYCLE_WAVE = 11, /* Wave effect mode */ + AURA_MODE_CHASE_RAINBOW_PULSE = 12, /* Chase with Rainbow Pulse effect mode*/ + AURA_MODE_RANDOM_FLICKER = 13, /* Random flicker effect mode */ + AURA_NUMBER_MODES /* Number of Aura modes */ +}; + +enum +{ + AURA_SPEED_SLOWEST = 0x04, /* Slowest effect speed */ + AURA_SPEED_SLOW = 0x03, /* Slow effect speed */ + AURA_SPEED_NORMAL = 0x02, /* Normal effect speed */ + AURA_SPEED_FAST = 0x01, /* Fast effect speed */ + AURA_SPEED_FASTEST = 0x00, /* Fastest effect speed */ +}; + +enum +{ + AURA_DIRECTION_FORWARD = 0x0, /* Forward effect direction */ + AURA_DIRECTION_REVERSE = 0x1, /* Reverse effect direction */ +}; + +enum +{ + AURA_LED_CHANNEL_DRAM_2 = 0x05, /* DRAM LED channel */ + AURA_LED_CHANNEL_CENTER_START = 0x82, /* Center zone first LED channel */ + AURA_LED_CHANNEL_CENTER = 0x83, /* Center zone LED channel */ + AURA_LED_CHANNEL_AUDIO = 0x84, /* Audio zone LED channel */ + AURA_LED_CHANNEL_BACK_IO = 0x85, /* Back I/O zone LED channel */ + AURA_LED_CHANNEL_RGB_HEADER = 0x86, /* RGB Header LED channel */ + AURA_LED_CHANNEL_RGB_HEADER_2 = 0x87, /* RGB Header 2 LED channel */ + AURA_LED_CHANNEL_BACKPLATE = 0x88, /* Backplate zone LED channel */ + AURA_LED_CHANNEL_DRAM = 0x8A, /* DRAM LED channel */ + AURA_LED_CHANNEL_PCIE = 0x8B, /* PCIe zone LED channel */ + AURA_LED_CHANNEL_RGB_HEADER_3 = 0x91, /* RGB Header 3 LED channel */ +}; + +enum +{ + AURA_CONFIG_LED_COUNT = 0x02, /* LED Count configuration offset */ + AURA_CONFIG_CHANNEL_V1 = 0x13, /* LED Channel configuration offset */ + AURA_CONFIG_CHANNEL_V2 = 0x1B, /* LED Channel V2 configuration offset */ +}; + +class XPGSpectrixS40GController +{ +public: + XPGSpectrixS40GController(int fd, aura_dev_id dev); + ~XPGSpectrixS40GController(); + +#ifdef _WIN32 + /*-----------------------------------------------------*\ + | Windows specific function that allows the devices | + | handle to be passed from elsewhere once detected | + \*-----------------------------------------------------*/ + int SetHandle(wchar_t dev_name[MAX_PATH]); +#else + +#endif + + std::string GetDeviceName(); + std::string GetDeviceLocation(); + unsigned char GetChannel(unsigned int led); + const char* GetChannelName(unsigned int led); + unsigned int GetLEDCount(); + unsigned char GetLEDRed(unsigned int led); + unsigned char GetLEDGreen(unsigned int led); + unsigned char GetLEDBlue(unsigned int led); + void SaveMode(); + 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); + void SetMode(unsigned char mode, unsigned char speed, unsigned char direction); + + void AuraUpdateDeviceName(); + + unsigned char AuraRegisterRead(aura_register reg); + void AuraRegisterWrite(aura_register reg, unsigned char val); + void AuraRegisterWriteBlock(aura_register reg, unsigned char * data, unsigned char sz); + +private: +#ifdef _WIN32 + HANDLE hDevice; +#else + +#endif + int nvme_fd; + char device_name[16]; + unsigned char config_table[64]; + unsigned int led_count; + aura_register direct_reg; + aura_register effect_reg; + unsigned char channel_cfg; + i2c_smbus_interface * bus; + aura_dev_id dev; + +}; diff --git a/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GControllerDetect.cpp b/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GControllerDetect.cpp new file mode 100644 index 000000000..8ab6f949f --- /dev/null +++ b/Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GControllerDetect.cpp @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------*\ +| XPGSpectrixS40GControllerDetect.cpp | +| | +| Driver for XPG's Spectrix S40G NVMe | +| | +| NicolasNewman 25th Mar 2021 | +| | +\*-------------------------------------------------------------------*/ + +#include "Detector.h" +#include "XPGSpectrixS40GController.h" +#include "RGBController.h" +#include "RGBController_XPGSpectrixS40G.h" +#include + +#include +#include +#include +#include +#include + +void DetectSpectrixS40GControllers(std::vector& rgb_controllers) +{ + XPGSpectrixS40GController* new_xpg_s40g; + RGBController_XPGSpectrixS40G* new_controller; + + int nvme_fd = open("/dev/nvme0", O_RDWR); + + new_xpg_s40g = new XPGSpectrixS40GController(nvme_fd, 0x67); + + new_controller = new RGBController_XPGSpectrixS40G(new_xpg_s40g); + rgb_controllers.push_back(new_controller); + +} /* DetectSpectrixS40GControllers() */ + +REGISTER_DETECTOR("XPG Spectrix S40G NVMe", DetectSpectrixS40GControllers); diff --git a/Controllers/XPGSpectrixS40GControllerWindows/RGBController_XPGSpectrixS40G.cpp b/Controllers/XPGSpectrixS40GControllerWindows/RGBController_XPGSpectrixS40G.cpp new file mode 100644 index 000000000..9e435e009 --- /dev/null +++ b/Controllers/XPGSpectrixS40GControllerWindows/RGBController_XPGSpectrixS40G.cpp @@ -0,0 +1,431 @@ +/*-------------------------------------------------------------------*\ +| RGBController_XPGSpectrixS40G.cpp | +| | +| Driver for XPG's Spectrix S40G NVMe | +| | +| NicolasNewman 25th Mar 2021 | +| | +\*-------------------------------------------------------------------*/ + +#include "RGBController_XPGSpectrixS40G.h" + +int RGBController_XPGSpectrixS40G::GetDeviceMode() +{ + /*-----------------------------------------------------------------*\ + | Determine starting mode by reading the mode and direct registers | + \*-----------------------------------------------------------------*/ + int dev_mode = aura->AuraRegisterRead(AURA_REG_MODE); + int color_mode = MODE_COLORS_PER_LED; + int speed = aura->AuraRegisterRead(AURA_REG_SPEED); + int direction = aura->AuraRegisterRead(AURA_REG_DIRECTION); + + if(aura->AuraRegisterRead(AURA_REG_DIRECT)) + { + dev_mode = 0xFFFF; + } + + switch(dev_mode) + { + case AURA_MODE_OFF: + case AURA_MODE_RAINBOW: + case AURA_MODE_SPECTRUM_CYCLE: + case AURA_MODE_RANDOM_FLICKER: + color_mode = MODE_COLORS_NONE; + break; + + case AURA_MODE_SPECTRUM_CYCLE_CHASE: + dev_mode = AURA_MODE_CHASE; + color_mode = MODE_COLORS_RANDOM; + break; + + case AURA_MODE_SPECTRUM_CYCLE_BREATHING: + dev_mode = AURA_MODE_BREATHING; + color_mode = MODE_COLORS_RANDOM; + break; + + case AURA_MODE_SPECTRUM_CYCLE_CHASE_FADE: + dev_mode = AURA_MODE_CHASE_FADE; + color_mode = MODE_COLORS_RANDOM; + break; + } + + for(std::size_t mode = 0; mode < modes.size(); mode++) + { + if(modes[mode].value == dev_mode) + { + active_mode = mode; + modes[mode].color_mode = color_mode; + + if(modes[mode].flags & MODE_FLAG_HAS_SPEED) + { + modes[mode].speed = speed; + } + + if(modes[mode].flags & MODE_FLAG_HAS_DIRECTION_LR) + { + modes[mode].direction = direction; + } + + break; + } + } + + return(active_mode); +} + +void RGBController_XPGSpectrixS40G::DeviceUpdateLEDs() +{ + if(GetMode() == 0) + { + aura->SetAllColorsDirect(&colors[0]); + } + else + { + aura->SetAllColorsEffect(&colors[0]); + } +} + +void RGBController_XPGSpectrixS40G::UpdateZoneLEDs(int zone) +{ + for (std::size_t led_idx = 0; led_idx < zones[zone].leds_count; led_idx++) + { + int led = zones[zone].leds[led_idx].value; + RGBColor color = colors[led]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + if (GetMode() == 0) + { + aura->SetLEDColorDirect(led, red, grn, blu); + } + else + { + aura->SetLEDColorEffect(led, red, grn, blu); + } + } +} + +void RGBController_XPGSpectrixS40G::UpdateSingleLED(int led) +{ + RGBColor color = colors[led]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + if (GetMode() == 0) + { + aura->SetLEDColorDirect(led, red, grn, blu); + } + else + { + aura->SetLEDColorEffect(led, red, grn, blu); + } +} + +RGBController_XPGSpectrixS40G::RGBController_XPGSpectrixS40G(XPGSpectrixS40GController * aura_ptr) +{ + aura = aura_ptr; + + version = aura->GetDeviceName(); + location = aura->GetDeviceLocation(); + if((version.find("DIMM_LED") != std::string::npos) || (version.find("AUDA") != std::string::npos) ) + { + type = DEVICE_TYPE_DRAM; + name = "ASUS Aura DRAM"; + } + else + { + type = DEVICE_TYPE_MOTHERBOARD; + name = "ASUS Aura Motherboard"; + } + vendor = "ASUS"; + description = "ASUS Aura SMBus Device"; + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0xFFFF; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + mode Off; + Off.name = "Off"; + Off.value = AURA_MODE_OFF; + Off.flags = MODE_FLAG_MANUAL_SAVE; + Off.color_mode = MODE_COLORS_NONE; + modes.push_back(Off); + + mode Static; + Static.name = "Static"; + Static.value = AURA_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE; + Static.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Static); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = AURA_MODE_BREATHING; + Breathing.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE; + Breathing.color_mode = MODE_COLORS_PER_LED; + Breathing.speed_min = AURA_SPEED_SLOWEST; + Breathing.speed_max = AURA_SPEED_FASTEST; + Breathing.speed = AURA_SPEED_NORMAL; + modes.push_back(Breathing); + + mode Flashing; + Flashing.name = "Flashing"; + Flashing.value = AURA_MODE_FLASHING; + Flashing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE; + Flashing.color_mode = MODE_COLORS_PER_LED; + Flashing.speed_min = AURA_SPEED_SLOWEST; + Flashing.speed_max = AURA_SPEED_FASTEST; + Flashing.speed = AURA_SPEED_NORMAL; + modes.push_back(Flashing); + + mode SpectrumCycle; + SpectrumCycle.name = "Spectrum Cycle"; + SpectrumCycle.value = AURA_MODE_SPECTRUM_CYCLE; + SpectrumCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE; + SpectrumCycle.color_mode = MODE_COLORS_NONE; + SpectrumCycle.speed_min = AURA_SPEED_SLOWEST; + SpectrumCycle.speed_max = AURA_SPEED_FASTEST; + SpectrumCycle.speed = AURA_SPEED_NORMAL; + modes.push_back(SpectrumCycle); + + mode Rainbow; + Rainbow.name = "Rainbow"; + Rainbow.value = AURA_MODE_RAINBOW; + Rainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_MANUAL_SAVE; + Rainbow.color_mode = MODE_COLORS_NONE; + Rainbow.speed_min = AURA_SPEED_SLOWEST; + Rainbow.speed_max = AURA_SPEED_FASTEST; + Rainbow.speed = AURA_SPEED_NORMAL; + Rainbow.direction = MODE_DIRECTION_LEFT; + modes.push_back(Rainbow); + + mode ChaseFade; + ChaseFade.name = "Chase Fade"; + ChaseFade.value = AURA_MODE_CHASE_FADE; + ChaseFade.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_MANUAL_SAVE; + ChaseFade.color_mode = MODE_COLORS_PER_LED; + ChaseFade.speed_min = AURA_SPEED_SLOWEST; + ChaseFade.speed_max = AURA_SPEED_FASTEST; + ChaseFade.speed = AURA_SPEED_NORMAL; + ChaseFade.direction = MODE_DIRECTION_LEFT; + modes.push_back(ChaseFade); + + mode Chase; + Chase.name = "Chase"; + Chase.value = AURA_MODE_CHASE; + Chase.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_MANUAL_SAVE; + Chase.color_mode = MODE_COLORS_PER_LED; + Chase.speed_min = AURA_SPEED_SLOWEST; + Chase.speed_max = AURA_SPEED_FASTEST; + Chase.speed = AURA_SPEED_NORMAL; + ChaseFade.direction = MODE_DIRECTION_LEFT; + modes.push_back(Chase); + + mode RandomFlicker; + RandomFlicker.name = "Random Flicker"; + RandomFlicker.value = AURA_MODE_RANDOM_FLICKER; + RandomFlicker.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE; + RandomFlicker.color_mode = MODE_COLORS_NONE; + RandomFlicker.speed_min = AURA_SPEED_SLOWEST; + RandomFlicker.speed_max = AURA_SPEED_FASTEST; + RandomFlicker.speed = AURA_SPEED_NORMAL; + modes.push_back(RandomFlicker); + + SetupZones(); + + /*-------------------------------------------------*\ + | Initialize active mode | + \*-------------------------------------------------*/ + //active_mode = GetDeviceMode(); +} + +RGBController_XPGSpectrixS40G::~RGBController_XPGSpectrixS40G() +{ + delete aura; +} + +void RGBController_XPGSpectrixS40G::SetupZones() +{ + std::vector aura_led_map; + + /*---------------------------------------------------------*\ + | Search through all LEDs and create zones for each channel | + | type | + \*---------------------------------------------------------*/ + for (std::size_t led_idx = 0; led_idx < aura->GetLEDCount(); led_idx++) + { + bool matched = false; + + /*---------------------------------------------------------*\ + | Search through existing zones to make sure we don't | + | create a duplicate zone | + \*---------------------------------------------------------*/ + for (std::size_t existing_zone_idx = 0; existing_zone_idx < zones.size(); existing_zone_idx++) + { + if (aura->GetChannelName(led_idx) == zones[existing_zone_idx].name) + { + matched = true; + } + } + + /*---------------------------------------------------------*\ + | If zone does not already exist, create it | + \*---------------------------------------------------------*/ + if (matched == false) + { + zone* new_zone = new zone(); + + /*---------------------------------------------------------*\ + | Set zone name to channel name | + \*---------------------------------------------------------*/ + new_zone->name = aura->GetChannelName(led_idx); + + new_zone->leds_count = 0; + + /*---------------------------------------------------------*\ + | Find all LEDs with this channel type and add them to zone | + \*---------------------------------------------------------*/ + for (std::size_t zone_led_idx = 0; zone_led_idx < aura->GetLEDCount(); zone_led_idx++) + { + if (aura->GetChannelName(zone_led_idx) == new_zone->name) + { + new_zone->leds_count++; + aura_led_map.push_back(zone_led_idx); + } + } + + /*---------------------------------------------------------*\ + | Aura zones have fixed size, so set min and max to count | + \*---------------------------------------------------------*/ + new_zone->leds_min = new_zone->leds_count; + new_zone->leds_max = new_zone->leds_count; + + /*---------------------------------------------------------*\ + | If this zone has more than one LED, mark it as linear type| + \*---------------------------------------------------------*/ + if(new_zone->leds_count > 1) + { + new_zone->type = ZONE_TYPE_LINEAR; + } + else + { + new_zone->type = ZONE_TYPE_SINGLE; + } + + new_zone->matrix_map = NULL; + + /*---------------------------------------------------------*\ + | Push new zone to zones vector | + \*---------------------------------------------------------*/ + zones.push_back(*new_zone); + } + } + + /*---------------------------------------------------------*\ + | Create LED entries for each zone | + \*---------------------------------------------------------*/ + for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + for(std::size_t led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++) + { + led* new_led = new led(); + + new_led->name = zones[zone_idx].name + " LED "; + new_led->name.append(std::to_string(led_idx + 1)); + + new_led->value = aura_led_map[led_idx]; + + leds.push_back(*new_led); + } + } + + SetupColors(); + + /*---------------------------------------------------------*\ + | Initialize colors for each LED | + \*---------------------------------------------------------*/ + for(std::size_t led_idx = 0; led_idx < leds.size(); led_idx++) + { + unsigned int led = leds[led_idx].value; + unsigned char red = aura->GetLEDRed(led); + unsigned char grn = aura->GetLEDGreen(led); + unsigned char blu = aura->GetLEDBlue(led); + + colors[led_idx] = ToRGBColor(red, grn, blu); + } +} + +void RGBController_XPGSpectrixS40G::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_XPGSpectrixS40G::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_XPGSpectrixS40G::DeviceUpdateMode() +{ + if (modes[active_mode].value == 0xFFFF) + { + aura->SetDirect(true); + } + else + { + int new_mode = modes[active_mode].value; + int new_speed = 0; + int new_direction = 0; + + if(modes[active_mode].color_mode == MODE_COLORS_RANDOM) + { + switch(new_mode) + { + case AURA_MODE_CHASE: + new_mode = AURA_MODE_SPECTRUM_CYCLE_CHASE; + break; + case AURA_MODE_BREATHING: + new_mode = AURA_MODE_SPECTRUM_CYCLE_BREATHING; + break; + case AURA_MODE_CHASE_FADE: + new_mode = AURA_MODE_SPECTRUM_CYCLE_CHASE_FADE; + break; + } + } + + if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED) + { + new_speed = modes[active_mode].speed; + } + + if(modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) + { + switch(modes[active_mode].direction) + { + case MODE_DIRECTION_LEFT: + new_direction = AURA_DIRECTION_FORWARD; + break; + + case MODE_DIRECTION_RIGHT: + new_direction = AURA_DIRECTION_REVERSE; + break; + } + } + + aura->SetMode(new_mode, new_speed, new_direction); + aura->SetDirect(false); + } +} + +void RGBController_XPGSpectrixS40G::DeviceSaveMode() +{ + DeviceUpdateMode(); + aura->SaveMode(); +} \ No newline at end of file diff --git a/Controllers/XPGSpectrixS40GControllerWindows/RGBController_XPGSpectrixS40G.h b/Controllers/XPGSpectrixS40GControllerWindows/RGBController_XPGSpectrixS40G.h new file mode 100644 index 000000000..acf68f2aa --- /dev/null +++ b/Controllers/XPGSpectrixS40GControllerWindows/RGBController_XPGSpectrixS40G.h @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------*\ +| RGBController_XPGSpectrixS40G.h | +| | +| Driver for XPG's Spectrix S40G NVMe | +| | +| NicolasNewman 25th Mar 2021 | +| | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "XPGSpectrixS40GController.h" + +class RGBController_XPGSpectrixS40G : public RGBController +{ +public: + RGBController_XPGSpectrixS40G(XPGSpectrixS40GController* spectrix_ptr); + ~RGBController_XPGSpectrixS40G(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void DeviceUpdateMode(); + void DeviceSaveMode(); + + int GetDeviceMode(); + +private: + XPGSpectrixS40GController* aura; +}; diff --git a/Controllers/XPGSpectrixS40GController/XPGSpectrixS40GController.cpp b/Controllers/XPGSpectrixS40GControllerWindows/XPGSpectrixS40GController.cpp similarity index 100% rename from Controllers/XPGSpectrixS40GController/XPGSpectrixS40GController.cpp rename to Controllers/XPGSpectrixS40GControllerWindows/XPGSpectrixS40GController.cpp diff --git a/Controllers/XPGSpectrixS40GController/XPGSpectrixS40GController.h b/Controllers/XPGSpectrixS40GControllerWindows/XPGSpectrixS40GController.h similarity index 100% rename from Controllers/XPGSpectrixS40GController/XPGSpectrixS40GController.h rename to Controllers/XPGSpectrixS40GControllerWindows/XPGSpectrixS40GController.h diff --git a/Controllers/XPGSpectrixS40GController/XPGSpectrixS40GControllerDetect.cpp b/Controllers/XPGSpectrixS40GControllerWindows/XPGSpectrixS40GControllerDetect.cpp similarity index 100% rename from Controllers/XPGSpectrixS40GController/XPGSpectrixS40GControllerDetect.cpp rename to Controllers/XPGSpectrixS40GControllerWindows/XPGSpectrixS40GControllerDetect.cpp diff --git a/OpenRGB.pro b/OpenRGB.pro index 566fb28fc..98056c1e3 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -142,7 +142,7 @@ INCLUDEPATH += Controllers/ThermaltakePoseidonZRGBController/ \ Controllers/ThermaltakeRiingController/ \ Controllers/WootingKeyboardController/ \ - Controllers/XPGSpectrixS40GController/ \ + Controllers/XPGSpectrixS40GControllerLinux/ \ Controllers/YeelightController/ \ Controllers/ZalmanZSyncController/ \ RGBController/ \ @@ -464,8 +464,8 @@ HEADERS += Controllers/WootingKeyboardController/WootingTwoKeyboardController.h \ Controllers/WootingKeyboardController/RGBController_WootingKeyboard.h \ Controllers/ThermaltakeRiingController/RGBController_ThermaltakeRiingQuad.h \ - Controllers/XPGSpectrixS40GController/XPGSpectrixS40GController.h \ - Controllers/XPGSpectrixS40GController/RGBController_XPGSpectrixS40G.h \ + Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.h \ + Controllers/XPGSpectrixS40GControllerLinux/RGBController_XPGSpectrixS40G.h \ Controllers/YeelightController/YeelightController.h \ Controllers/YeelightController/RGBController_Yeelight.h \ Controllers/ZalmanZSyncController/ZalmanZSyncController.h \ @@ -881,9 +881,9 @@ SOURCES += Controllers/WootingKeyboardController/WootingTwoKeyboardController.cpp \ Controllers/WootingKeyboardController/RGBController_WootingKeyboard.cpp \ Controllers/ThermaltakeRiingController/RGBController_ThermaltakeRiingQuad.cpp \ - Controllers/XPGSpectrixS40GController/XPGSpectrixS40GController.cpp \ - Controllers/XPGSpectrixS40GController/XPGSpectrixS40GControllerDetect.cpp \ - Controllers/XPGSpectrixS40GController/RGBController_XPGSpectrixS40G.cpp \ + Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GController.cpp \ + Controllers/XPGSpectrixS40GControllerLinux/XPGSpectrixS40GControllerDetect.cpp \ + Controllers/XPGSpectrixS40GControllerLinux/RGBController_XPGSpectrixS40G.cpp \ Controllers/YeelightController/YeelightController.cpp \ Controllers/YeelightController/YeelightControllerDetect.cpp \ Controllers/YeelightController/RGBController_Yeelight.cpp \ @@ -1157,6 +1157,7 @@ unix:!macx { -lmbedx509 \ -lmbedtls \ -lmbedcrypto \ + -lnvme \ COMPILER_VERSION = $$system($$QMAKE_CXX " -dumpversion") if (!versionAtLeast(COMPILER_VERSION, "9")) {