XPG SSD working on Linux - DO NOT USE IF YOU DON'T HAVE XPG S40G AS /dev/nvme0!

This commit is contained in:
Adam Honse
2021-11-16 19:44:13 -06:00
parent 571e4f4d38
commit 5196ff7772
11 changed files with 1186 additions and 6 deletions

View File

@@ -0,0 +1,501 @@
/*-------------------------------------------------------------------*\
| XPGSpectrixS40GController.cpp |
| |
| Driver for XPG's Spectrix S40G NVMe |
| |
| NicolasNewman 25th Mar 2021 |
| |
\*-------------------------------------------------------------------*/
#include "XPGSpectrixS40GController.h"
#include <malloc.h>
#include <cstring>
#include "LogManager.h"
/*-----------------------------------------*\
| AsusAuraSMBusController.cpp |
| |
| Driver for ASUS Aura RGB lighting |
| controller |
| |
| Adam Honse (CalcProgrammer1) 8/19/2018 |
\*-----------------------------------------*/
#include <cstring>
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);
// }
}

View File

@@ -0,0 +1,174 @@
/*-------------------------------------------------------------------*\
| XPGSpectrixS40GController.h |
| |
| Driver for XPG's Spectrix S40G NVMe |
| |
| NicolasNewman 25th Mar 2021 |
| |
\*-------------------------------------------------------------------*/
#include "RGBController.h"
#include <vector>
#include <hidapi/hidapi.h>
#include <stdint.h>
#pragma once
#define XPG_SPECTRIX_LED_COUNT ( 8 )
#ifdef _WIN32
#include <windows.h>
#include <fileapi.h>
#else
#endif
/*-----------------------------------------*\
| AsusAuraSMBusController.h |
| |
| Definitions and types for ASUS Aura RGB |
| lighting controller |
| |
| Adam Honse (CalcProgrammer1) 8/19/2018 |
\*-----------------------------------------*/
#include <string>
#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;
};

View File

@@ -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 <vector>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <sys/ioctl.h>
void DetectSpectrixS40GControllers(std::vector<RGBController*>& 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);

View File

@@ -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<int> 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();
}

View File

@@ -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;
};

View File

@@ -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")) {