Support AE-5 and AE-5 Plus on Windows
parent
3fb56e610d
commit
db517c01af
@ -0,0 +1,28 @@
|
|||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CreativeSoundBlasterAE5ControllerBase.h |
|
||||||
|
| |
|
||||||
|
| Base interface for Creative SoundBlaster AE-5 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CreativeSoundBlasterAE5ControllerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~CreativeSoundBlasterAE5ControllerBase() = default;
|
||||||
|
|
||||||
|
virtual bool Initialize() = 0;
|
||||||
|
virtual std::string GetDeviceLocation() = 0;
|
||||||
|
virtual std::string GetDeviceName() = 0;
|
||||||
|
virtual unsigned int GetLEDCount() = 0;
|
||||||
|
virtual unsigned int GetExternalLEDCount() = 0;
|
||||||
|
virtual void SetExternalLEDCount(unsigned int count) = 0;
|
||||||
|
|
||||||
|
virtual void SetLEDColors(unsigned char led_count, unsigned char* red_values,
|
||||||
|
unsigned char* green_values, unsigned char* blue_values) = 0;
|
||||||
|
};
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CreativeSoundBlasterAE5ControllerDetect_Windows.cpp |
|
||||||
|
| |
|
||||||
|
| Detector for Creative SoundBlaster AE-5 (Windows) |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "Detector.h"
|
||||||
|
#include "CreativeSoundBlasterAE5Controller_Windows.h"
|
||||||
|
#include "RGBController_CreativeSoundBlasterAE5_Windows.h"
|
||||||
|
#include "LogManager.h"
|
||||||
|
|
||||||
|
void DetectCreativeAE5Device()
|
||||||
|
{
|
||||||
|
LOG_INFO("[Creative SoundBlaster AE-5] Windows detection function called");
|
||||||
|
|
||||||
|
CreativeSoundBlasterAE5Controller_Windows* controller = new CreativeSoundBlasterAE5Controller_Windows();
|
||||||
|
|
||||||
|
if(controller->Initialize())
|
||||||
|
{
|
||||||
|
LOG_INFO("[Creative SoundBlaster AE-5] Device initialized successfully, registering controller");
|
||||||
|
RGBController_CreativeSoundBlasterAE5* rgb_controller = new RGBController_CreativeSoundBlasterAE5(controller);
|
||||||
|
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG_WARNING("[Creative SoundBlaster AE-5] Device initialization failed");
|
||||||
|
delete controller;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_DETECTOR("Creative SoundBlaster AE-5", DetectCreativeAE5Device);
|
||||||
@ -0,0 +1,451 @@
|
|||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CreativeSoundBlasterAE5Controller_Windows.cpp |
|
||||||
|
| |
|
||||||
|
| Driver for Creative SoundBlaster AE-5 (Windows) |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <setupapi.h>
|
||||||
|
#include "CreativeSoundBlasterAE5Controller_Windows.h"
|
||||||
|
#include "LogManager.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Lifecycle |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
CreativeSoundBlasterAE5Controller_Windows::CreativeSoundBlasterAE5Controller_Windows()
|
||||||
|
{
|
||||||
|
name = "Creative SoundBlaster AE-5";
|
||||||
|
location = "";
|
||||||
|
device_found = false;
|
||||||
|
device_handle = INVALID_HANDLE_VALUE;
|
||||||
|
device_opened = false;
|
||||||
|
external_led_count = 0;
|
||||||
|
led_mutex = CreateMutexA(NULL, FALSE, "OpenRGB_AE5_LED_Mutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
CreativeSoundBlasterAE5Controller_Windows::~CreativeSoundBlasterAE5Controller_Windows()
|
||||||
|
{
|
||||||
|
CloseDevice();
|
||||||
|
if(led_mutex != NULL)
|
||||||
|
{
|
||||||
|
CloseHandle(led_mutex);
|
||||||
|
led_mutex = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreativeSoundBlasterAE5Controller_Windows::Initialize()
|
||||||
|
{
|
||||||
|
if(!FindDevice())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdaudio_device_path = FindHDAudioDevicePath();
|
||||||
|
if(hdaudio_device_path.empty())
|
||||||
|
{
|
||||||
|
LOG_WARNING("[%s] Failed to find HDAudio device path", name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpenDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Device Discovery |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
bool CreativeSoundBlasterAE5Controller_Windows::FindDevice()
|
||||||
|
{
|
||||||
|
LOG_DEBUG("[%s] Looking for vendor 0x%04X, device 0x%04X", name.c_str(), AE5_VENDOR_ID, AE5_DEVICE_ID);
|
||||||
|
|
||||||
|
HDEVINFO device_info_set = SetupDiGetClassDevs(
|
||||||
|
NULL, // No class GUID
|
||||||
|
TEXT("PCI"), // Enumerator
|
||||||
|
NULL, // No parent window
|
||||||
|
DIGCF_PRESENT | DIGCF_ALLCLASSES // Only present devices
|
||||||
|
);
|
||||||
|
|
||||||
|
if(device_info_set == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
LOG_ERROR("[%s] SetupDiGetClassDevs failed: %lu", name.c_str(), GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP_DEVINFO_DATA device_info_data;
|
||||||
|
device_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||||
|
|
||||||
|
for(DWORD device_index = 0; SetupDiEnumDeviceInfo(device_info_set, device_index, &device_info_data); device_index++)
|
||||||
|
{
|
||||||
|
TCHAR hardware_id[256];
|
||||||
|
if(!SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_HARDWAREID,
|
||||||
|
NULL, (PBYTE)hardware_id, sizeof(hardware_id), NULL))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hw_id_str(hardware_id);
|
||||||
|
std::transform(hw_id_str.begin(), hw_id_str.end(), hw_id_str.begin(), ::toupper);
|
||||||
|
|
||||||
|
if(hw_id_str.find("PCI\\VEN_1102&DEV_0012") != std::string::npos)
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------*\
|
||||||
|
| Check subsystem ID to determine AE-5 variant |
|
||||||
|
| Format is SUBSYS_{DEVICE_ID}{VENDOR_ID} |
|
||||||
|
\*---------------------------------------------*/
|
||||||
|
|
||||||
|
if(hw_id_str.find("SUBSYS_01911102") != std::string::npos)
|
||||||
|
{
|
||||||
|
name = "Creative SoundBlaster AE-5 Plus";
|
||||||
|
}
|
||||||
|
else if(hw_id_str.find("SUBSYS_00511102") != std::string::npos)
|
||||||
|
{
|
||||||
|
name = "Creative SoundBlaster AE-5";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = "Creative SoundBlaster AE-5";
|
||||||
|
LOG_WARNING("[%s] Unknown subsystem variant found in hardware ID: %s", name.c_str(), hardware_id);
|
||||||
|
LOG_WARNING("[%s] Please report this to @eclipse_sol84 in the OpenRGB Discord!", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("[%s] Found matching device: %s", name.c_str(), hardware_id);
|
||||||
|
|
||||||
|
TCHAR location_info[256];
|
||||||
|
if(SetupDiGetDeviceRegistryProperty(device_info_set, &device_info_data, SPDRP_LOCATION_INFORMATION,
|
||||||
|
NULL, (PBYTE)location_info, sizeof(location_info), NULL))
|
||||||
|
{
|
||||||
|
location = "PCI: " + std::string(location_info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
location = "PCI: " + hw_id_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
device_found = true;
|
||||||
|
SetupDiDestroyDeviceInfoList(device_info_set);
|
||||||
|
|
||||||
|
LOG_INFO("[%s] Device successfully detected at %s", name.c_str(), location.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupDiDestroyDeviceInfoList(device_info_set);
|
||||||
|
LOG_WARNING("[%s] No matching device found", name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CreativeSoundBlasterAE5Controller_Windows::FindHDAudioDevicePath()
|
||||||
|
{
|
||||||
|
LOG_INFO("[%s] Searching for HDAudio device path...", name.c_str());
|
||||||
|
|
||||||
|
HKEY device_classes_key;
|
||||||
|
LONG result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
||||||
|
"SYSTEM\\CurrentControlSet\\Control\\DeviceClasses",
|
||||||
|
0, KEY_READ, &device_classes_key);
|
||||||
|
|
||||||
|
if(result != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
LOG_ERROR("[%s] Failed to open DeviceClasses registry key: %lu", name.c_str(), result);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD guid_index = 0;
|
||||||
|
CHAR guid_name[256];
|
||||||
|
DWORD guid_name_size;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Enumerate all GUID folders in DeviceClasses |
|
||||||
|
| Then enumerate device instances to find VID & PID |
|
||||||
|
| Finally, check if this device has a #GPDHDA subkey |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
guid_name_size = sizeof(guid_name);
|
||||||
|
result = RegEnumKeyExA(device_classes_key, guid_index, guid_name, &guid_name_size,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if(result != ERROR_SUCCESS) break;
|
||||||
|
|
||||||
|
HKEY guid_key;
|
||||||
|
result = RegOpenKeyExA(device_classes_key, guid_name, 0, KEY_READ, &guid_key);
|
||||||
|
if(result != ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
guid_index++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD device_index = 0;
|
||||||
|
CHAR device_name[512];
|
||||||
|
DWORD device_name_size;
|
||||||
|
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
device_name_size = sizeof(device_name);
|
||||||
|
result = RegEnumKeyExA(guid_key, device_index, device_name, &device_name_size,
|
||||||
|
NULL, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if(result != ERROR_SUCCESS) break;
|
||||||
|
|
||||||
|
std::string device_str(device_name);
|
||||||
|
std::transform(device_str.begin(), device_str.end(), device_str.begin(), ::toupper);
|
||||||
|
|
||||||
|
if(device_str.find("VEN_1102&DEV_0011") != std::string::npos)
|
||||||
|
{
|
||||||
|
HKEY device_key;
|
||||||
|
result = RegOpenKeyExA(guid_key, device_name, 0, KEY_READ, &device_key);
|
||||||
|
if(result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
HKEY gpdhda_key;
|
||||||
|
result = RegOpenKeyExA(device_key, "#GPDHDA", 0, KEY_READ, &gpdhda_key);
|
||||||
|
if(result == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
LOG_INFO("[%s] Found HDAudio device interface", name.c_str());
|
||||||
|
RegCloseKey(gpdhda_key);
|
||||||
|
RegCloseKey(device_key);
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Convert registry path format to device path format |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
std::string device_path(device_name);
|
||||||
|
std::transform(device_path.begin(), device_path.end(), device_path.begin(), ::tolower);
|
||||||
|
|
||||||
|
if(device_path.substr(0, 4) == "##?#")
|
||||||
|
{
|
||||||
|
device_path = "\\\\?\\" + device_path.substr(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
device_path += "\\gpdhda";
|
||||||
|
|
||||||
|
RegCloseKey(guid_key);
|
||||||
|
RegCloseKey(device_classes_key);
|
||||||
|
return device_path;
|
||||||
|
}
|
||||||
|
RegCloseKey(device_key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
device_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(guid_key);
|
||||||
|
guid_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(device_classes_key);
|
||||||
|
LOG_WARNING("[%s] No Creative HDAudio device found in registry", name.c_str());
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreativeSoundBlasterAE5Controller_Windows::OpenDevice()
|
||||||
|
{
|
||||||
|
if(hdaudio_device_path.empty())
|
||||||
|
{
|
||||||
|
LOG_ERROR("[%s] No HDAudio device path available", name.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("[%s] Opening device: %s", name.c_str(), hdaudio_device_path.c_str());
|
||||||
|
|
||||||
|
std::wstring wide_path(hdaudio_device_path.begin(), hdaudio_device_path.end());
|
||||||
|
|
||||||
|
device_handle = CreateFileW(
|
||||||
|
wide_path.c_str(),
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
0,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if(device_handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
LOG_ERROR("[%s] Failed to open device: Error %lu", name.c_str(), error);
|
||||||
|
|
||||||
|
if(error == ERROR_PATH_NOT_FOUND) // Error 3
|
||||||
|
{
|
||||||
|
LOG_ERROR("[%s] This device requires Creative's official drivers to be installed for RGB control", name.c_str());
|
||||||
|
LOG_ERROR("[%s] Please install Creative Sound Blaster Command software or drivers from Creative's website", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO("[%s] Device opened successfully", name.c_str());
|
||||||
|
device_opened = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreativeSoundBlasterAE5Controller_Windows::CloseDevice()
|
||||||
|
{
|
||||||
|
if(device_handle != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(device_handle);
|
||||||
|
device_handle = INVALID_HANDLE_VALUE;
|
||||||
|
device_opened = false;
|
||||||
|
LOG_INFO("[%s] Device closed", name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Getters |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
std::string CreativeSoundBlasterAE5Controller_Windows::GetDeviceLocation()
|
||||||
|
{
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CreativeSoundBlasterAE5Controller_Windows::GetDeviceName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CreativeSoundBlasterAE5Controller_Windows::GetLEDCount()
|
||||||
|
{
|
||||||
|
return AE5_INTERNAL_LED_COUNT + external_led_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CreativeSoundBlasterAE5Controller_Windows::GetExternalLEDCount()
|
||||||
|
{
|
||||||
|
return external_led_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreativeSoundBlasterAE5Controller_Windows::SetExternalLEDCount(unsigned int count)
|
||||||
|
{
|
||||||
|
external_led_count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| LED Control |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
void CreativeSoundBlasterAE5Controller_Windows::SetLEDColors(unsigned char led_count, unsigned char* red_values,
|
||||||
|
unsigned char* green_values, unsigned char* blue_values)
|
||||||
|
{
|
||||||
|
if(!device_opened || device_handle == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
LOG_ERROR("[%s] Device not opened, cannot set LED colors", name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(led_count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------*\
|
||||||
|
| Wait for mutex to prevent conflicts with Creative software |
|
||||||
|
\*----------------------------------------------------------*/
|
||||||
|
|
||||||
|
if(led_mutex != NULL)
|
||||||
|
{
|
||||||
|
DWORD wait_result = WaitForSingleObject(led_mutex, 5000); // 5 second timeout
|
||||||
|
if(wait_result != WAIT_OBJECT_0)
|
||||||
|
{
|
||||||
|
LOG_WARNING("[%s] Failed to acquire LED mutex, proceeding anyway", name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------*\
|
||||||
|
| Internal LEDs - Setting LEDs can sometimes |
|
||||||
|
| not change them fully, we send this command twice to ensure |
|
||||||
|
| they fully change colors. It's particularly visable when |
|
||||||
|
| switching to dim colors or turning off the LEDs. |
|
||||||
|
\*---------------------------------------------------------------*/
|
||||||
|
|
||||||
|
if(led_count > 0)
|
||||||
|
{
|
||||||
|
SendLEDCommand(0x03, AE5_INTERNAL_LED_COUNT, red_values, green_values, blue_values);
|
||||||
|
SendLEDCommand(0x03, AE5_INTERNAL_LED_COUNT, red_values, green_values, blue_values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| External LEDs |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
if(led_count > AE5_INTERNAL_LED_COUNT && external_led_count > 0)
|
||||||
|
{
|
||||||
|
SendLEDCommand(0x02, external_led_count, red_values + AE5_INTERNAL_LED_COUNT, green_values + AE5_INTERNAL_LED_COUNT, blue_values + AE5_INTERNAL_LED_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(led_mutex != NULL)
|
||||||
|
{
|
||||||
|
ReleaseMutex(led_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CreativeSoundBlasterAE5Controller_Windows::SendLEDCommand(BYTE command_byte, unsigned int led_count_to_set,
|
||||||
|
unsigned char* red_values, unsigned char* green_values, unsigned char* blue_values)
|
||||||
|
{
|
||||||
|
AE5_LED_Command cmd;
|
||||||
|
memset(&cmd, 0, sizeof(AE5_LED_Command));
|
||||||
|
|
||||||
|
cmd.command = command_byte;
|
||||||
|
cmd.packet_led_count = led_count_to_set;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Calculate data length |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
unsigned int data_length = led_count_to_set * 4;
|
||||||
|
cmd.data_length_low = data_length & 0xFF;
|
||||||
|
cmd.data_length_high = (data_length >> 8) & 0xFF;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Fill LED data |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < led_count_to_set; i++)
|
||||||
|
{
|
||||||
|
unsigned int offset = i * 4;
|
||||||
|
|
||||||
|
if(command_byte == 0x02) // External WS2812B LED Strip
|
||||||
|
{
|
||||||
|
cmd.led_data[offset + 0] = blue_values[i];
|
||||||
|
cmd.led_data[offset + 1] = red_values[i];
|
||||||
|
cmd.led_data[offset + 2] = green_values[i];
|
||||||
|
cmd.led_data[offset + 3] = 0x00;
|
||||||
|
}
|
||||||
|
else // Internal APA102 LED Strip
|
||||||
|
{
|
||||||
|
cmd.led_data[offset + 0] = red_values[i];
|
||||||
|
cmd.led_data[offset + 1] = green_values[i];
|
||||||
|
cmd.led_data[offset + 2] = blue_values[i];
|
||||||
|
cmd.led_data[offset + 3] = 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AE5_LED_Command output_cmd;
|
||||||
|
memset(&output_cmd, 0, sizeof(AE5_LED_Command));
|
||||||
|
DWORD bytes_returned = 0;
|
||||||
|
|
||||||
|
BOOL result = DeviceIoControl(
|
||||||
|
device_handle,
|
||||||
|
0x77772400, // Custom IOCTL command from Creative Lab's drivers
|
||||||
|
&cmd,
|
||||||
|
sizeof(AE5_LED_Command),
|
||||||
|
&output_cmd,
|
||||||
|
sizeof(AE5_LED_Command),
|
||||||
|
&bytes_returned,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!result)
|
||||||
|
{
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
LOG_ERROR("[%s] DeviceIoControl failed: Error %lu", name.c_str(), error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@ -0,0 +1,173 @@
|
|||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| RGBController_CreativeSoundBlasterAE5_Windows.cpp |
|
||||||
|
| |
|
||||||
|
| RGBController for Creative SoundBlaster AE-5 (Windows) |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "RGBController_CreativeSoundBlasterAE5_Windows.h"
|
||||||
|
|
||||||
|
/**------------------------------------------------------------------*\
|
||||||
|
@name Creative Sound Blaster AE-5
|
||||||
|
@category Audio
|
||||||
|
@type PCI
|
||||||
|
@save :x:
|
||||||
|
@direct :white_check_mark:
|
||||||
|
@effects :x:
|
||||||
|
@detectors DetectCreativeAE5Device
|
||||||
|
@comment
|
||||||
|
\*-------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
RGBController_CreativeSoundBlasterAE5::RGBController_CreativeSoundBlasterAE5(CreativeSoundBlasterAE5ControllerBase* controller_ptr)
|
||||||
|
{
|
||||||
|
controller = controller_ptr;
|
||||||
|
|
||||||
|
name = controller->GetDeviceName();
|
||||||
|
vendor = "Creative Labs";
|
||||||
|
type = DEVICE_TYPE_SPEAKER;
|
||||||
|
description = controller->GetDeviceName() + " Device";
|
||||||
|
location = controller->GetDeviceLocation();
|
||||||
|
serial = "";
|
||||||
|
|
||||||
|
mode Direct;
|
||||||
|
Direct.name = "Direct";
|
||||||
|
Direct.value = 0;
|
||||||
|
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
|
||||||
|
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||||
|
modes.push_back(Direct);
|
||||||
|
|
||||||
|
SetupZones();
|
||||||
|
}
|
||||||
|
|
||||||
|
RGBController_CreativeSoundBlasterAE5::~RGBController_CreativeSoundBlasterAE5()
|
||||||
|
{
|
||||||
|
delete controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::SetupZones()
|
||||||
|
{
|
||||||
|
zone internal_zone;
|
||||||
|
internal_zone.name = "Internal";
|
||||||
|
internal_zone.type = ZONE_TYPE_LINEAR;
|
||||||
|
internal_zone.leds_min = 5;
|
||||||
|
internal_zone.leds_max = 5;
|
||||||
|
internal_zone.leds_count = 5;
|
||||||
|
internal_zone.matrix_map = NULL;
|
||||||
|
zones.push_back(internal_zone);
|
||||||
|
|
||||||
|
for(unsigned int led_idx = 0; led_idx < 5; led_idx++)
|
||||||
|
{
|
||||||
|
led new_led;
|
||||||
|
new_led.name = "Internal LED " + std::to_string(led_idx + 1);
|
||||||
|
leds.push_back(new_led);
|
||||||
|
}
|
||||||
|
|
||||||
|
zone external_zone;
|
||||||
|
external_zone.name = "External";
|
||||||
|
external_zone.type = ZONE_TYPE_LINEAR;
|
||||||
|
external_zone.leds_min = 0;
|
||||||
|
external_zone.leds_max = 100;
|
||||||
|
external_zone.leds_count = controller->GetExternalLEDCount();
|
||||||
|
external_zone.matrix_map = NULL;
|
||||||
|
zones.push_back(external_zone);
|
||||||
|
|
||||||
|
for(unsigned int led_idx = 0; led_idx < controller->GetExternalLEDCount(); led_idx++)
|
||||||
|
{
|
||||||
|
led new_led;
|
||||||
|
new_led.name = "External LED " + std::to_string(led_idx + 1);
|
||||||
|
leds.push_back(new_led);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::ResizeZone(int zone, int new_size)
|
||||||
|
{
|
||||||
|
if(zone == 1) // External zone
|
||||||
|
{
|
||||||
|
zones[zone].leds_count = new_size;
|
||||||
|
|
||||||
|
leds.resize(5);
|
||||||
|
|
||||||
|
for(unsigned int led_idx = 0; led_idx < (unsigned int)new_size; led_idx++)
|
||||||
|
{
|
||||||
|
led new_led;
|
||||||
|
new_led.name = "External LED " + std::to_string(led_idx + 1);
|
||||||
|
leds.push_back(new_led);
|
||||||
|
}
|
||||||
|
|
||||||
|
controller->SetExternalLEDCount(new_size);
|
||||||
|
SetupColors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::UpdateLEDRange(unsigned int start_led, unsigned int led_count)
|
||||||
|
{
|
||||||
|
if(led_count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char* red_values = new unsigned char[led_count];
|
||||||
|
unsigned char* green_values = new unsigned char[led_count];
|
||||||
|
unsigned char* blue_values = new unsigned char[led_count];
|
||||||
|
|
||||||
|
for(unsigned int i = 0; i < led_count; i++)
|
||||||
|
{
|
||||||
|
unsigned int led_idx = start_led + i;
|
||||||
|
red_values[i] = RGBGetRValue(colors[led_idx]);
|
||||||
|
green_values[i] = RGBGetGValue(colors[led_idx]);
|
||||||
|
blue_values[i] = RGBGetBValue(colors[led_idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
controller->SetLEDColors(led_count, red_values, green_values, blue_values);
|
||||||
|
|
||||||
|
delete[] red_values;
|
||||||
|
delete[] green_values;
|
||||||
|
delete[] blue_values;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::DeviceUpdateLEDs()
|
||||||
|
{
|
||||||
|
UpdateLEDRange(0, controller->GetLEDCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::UpdateZoneLEDs(int zone)
|
||||||
|
{
|
||||||
|
if(zone >= 0 && zone < (int)zones.size())
|
||||||
|
{
|
||||||
|
unsigned int start_led = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < zone; i++)
|
||||||
|
{
|
||||||
|
start_led += zones[i].leds_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateLEDRange(start_led, zones[zone].leds_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::UpdateSingleLED(int led)
|
||||||
|
{
|
||||||
|
/*-------------------------------------------------------------*\
|
||||||
|
| Find which zone this LED belongs to and update only that zone |
|
||||||
|
\*-------------------------------------------------------------*/
|
||||||
|
|
||||||
|
unsigned int current_led = 0;
|
||||||
|
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
|
||||||
|
{
|
||||||
|
if(led >= (int)current_led && led < (int)(current_led + zones[zone_idx].leds_count))
|
||||||
|
{
|
||||||
|
UpdateLEDRange(current_led, zones[zone_idx].leds_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
current_led += zones[zone_idx].leds_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CreativeSoundBlasterAE5::DeviceUpdateMode()
|
||||||
|
{
|
||||||
|
DeviceUpdateLEDs();
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| RGBController_CreativeSoundBlasterAE5_Windows.h |
|
||||||
|
| |
|
||||||
|
| RGBController for Creative SoundBlaster AE-5 (Windows) |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "RGBController.h"
|
||||||
|
#include "CreativeSoundBlasterAE5ControllerBase.h"
|
||||||
|
|
||||||
|
class RGBController_CreativeSoundBlasterAE5: public RGBController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RGBController_CreativeSoundBlasterAE5(CreativeSoundBlasterAE5ControllerBase* controller_ptr);
|
||||||
|
~RGBController_CreativeSoundBlasterAE5();
|
||||||
|
|
||||||
|
void SetupZones();
|
||||||
|
|
||||||
|
void ResizeZone(int zone, int new_size);
|
||||||
|
|
||||||
|
void DeviceUpdateLEDs();
|
||||||
|
void UpdateZoneLEDs(int zone);
|
||||||
|
void UpdateSingleLED(int led);
|
||||||
|
|
||||||
|
void DeviceUpdateMode();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CreativeSoundBlasterAE5ControllerBase* controller;
|
||||||
|
void UpdateLEDRange(unsigned int start_led, unsigned int led_count);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue