diff --git a/Controllers/CoolerMasterController/CMGD160Controller/CMGD160Controller.cpp b/Controllers/CoolerMasterController/CMGD160Controller/CMGD160Controller.cpp new file mode 100644 index 000000000..62e3effd4 --- /dev/null +++ b/Controllers/CoolerMasterController/CMGD160Controller/CMGD160Controller.cpp @@ -0,0 +1,216 @@ +/*---------------------------------------------------------*\ +| CMGD160Controller.cpp | +| | +| Driver for Cooler Master GD160 ARGB Gaming Desk | +| | +| Logan Phillips (Eclipse) 16 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| Adapted from CMMonitor controller code | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "CMGD160Controller.h" +#include "StringUtils.h" + +CMGD160Controller::CMGD160Controller(hid_device* dev_handle, const hid_device_info& info, const std::string& name) +{ + dev = dev_handle; + device_name = name; + location = info.path; + ResetDevice(); +} + +CMGD160Controller::~CMGD160Controller() +{ + hid_close(dev); +} + +std::string CMGD160Controller::GetDeviceName() +{ + return(device_name); +} + +std::string CMGD160Controller::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string CMGD160Controller::GetSerialString() +{ + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + + if(ret != 0) + { + return(""); + } + + return(StringUtils::wstring_to_string(serial_string)); +} + +/*------------------------------------------------------------*\ +| Desk requires 2 sets of packets sent for the front and back | +| Technically you could have both sides do something different | +| Not sure why you would though.... | +| Cooler Master's software doesn't allow that anyways | +\*------------------------------------------------------------*/ + +void CMGD160Controller::SetMode(uint8_t mode_value, uint8_t speed, uint8_t brightness, const RGBColor& color) +{ + if(is_software_mode_enabled) + { + SetControlMode(false); + } + + uint8_t usb_buf[CM_GD160_PACKET_LENGTH]; + + for(int side = 1; side <= 2; side++) + { + memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); + + usb_buf[1] = 0x80; + usb_buf[2] = (mode_value == CM_GD160_OFF_MODE) ? 0x0F : 0x0B; + usb_buf[3] = 0x02; + usb_buf[4] = side; // 0x01 for front, 0x02 for back + usb_buf[5] = mode_value; + usb_buf[6] = (mode_value == CM_GD160_OFF_MODE) ? 0x00 : 0x08; + usb_buf[7] = speed; + usb_buf[8] = brightness; + usb_buf[9] = RGBGetRValue(color); + usb_buf[10] = RGBGetGValue(color); + usb_buf[11] = RGBGetBValue(color); + + hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); + } +} + +/*-------------------------------------------------*\ +| How to request current color in custom mode. | +| Not like it matters since we default to direct | +| mode and it seems to clear the current colors... | +| | +| memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); | +| usb_buf[1] = 0x80; | +| usb_buf[2] = 0x10; | +| usb_buf[3] = 0x01; or 0x02 | +| usb_buf[4] = 0x02; | +| usb_buf[5] = 0x80; | +| hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); | +\*-------------------------------------------------*/ + +void CMGD160Controller::SendColorData(const std::vector& colors, uint8_t command, uint8_t mode_byte, uint8_t brightness, bool desired_control_mode) +{ + if(is_software_mode_enabled != desired_control_mode) + { + SetControlMode(desired_control_mode); + } + + uint8_t color_data[CM_GD160_COLOR_DATA_LENGTH]; + memset(color_data, 0x00, CM_GD160_COLOR_DATA_LENGTH); + + for(unsigned int i = 0; i < colors.size() && i < (CM_GD160_LEDS_PER_SIDE * 2); i++) + { + unsigned int side = i / CM_GD160_LEDS_PER_SIDE; + unsigned int led_in_side = i % CM_GD160_LEDS_PER_SIDE; + unsigned int buffer_offset = (side * CM_GD160_SIDE_DATA_LENGTH) + (led_in_side * 3); + + color_data[buffer_offset] = RGBGetRValue(colors[i]); + color_data[buffer_offset + 1] = RGBGetGValue(colors[i]); + color_data[buffer_offset + 2] = RGBGetBValue(colors[i]); + } + + uint8_t usb_buf[CM_GD160_PACKET_LENGTH]; + + for(unsigned int side = 1; side <= 2; side++) + { + unsigned int offset = (side - 1) * CM_GD160_SIDE_DATA_LENGTH; + + for(unsigned int packet = 0; packet < 7; packet++) + { + memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); + + usb_buf[1] = (packet < 6) ? packet : 0x86; // Last packet uses 0x86 + + /*---------------------------------------------------------*\ + | First packet contains static data | + \*---------------------------------------------------------*/ + + if(packet == 0) + { + usb_buf[2] = command; + usb_buf[3] = 0x02; + usb_buf[4] = side; // 0x01 for front, 0x02 for back + usb_buf[5] = mode_byte; + usb_buf[6] = brightness; + + memcpy(&usb_buf[7], &color_data[offset], CM_GD160_FIRST_PACKET_DATA_SIZE); + offset += CM_GD160_FIRST_PACKET_DATA_SIZE; + } + else + { + memcpy(&usb_buf[2], &color_data[offset], CM_GD160_PACKET_DATA_SIZE); + offset += CM_GD160_PACKET_DATA_SIZE; + } + + hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); + } + } +} + +/*------------------------------------------------------*\ +| True enables software mode | +| False enables hardware mode | +\*------------------------------------------------------*/ + +void CMGD160Controller::SetControlMode(bool software_mode) +{ + uint8_t usb_buf[CM_GD160_PACKET_LENGTH]; + + for(int side = 1; side <= 2; side++) + { + memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); + + usb_buf[1] = 0x80; + usb_buf[2] = 0x07; + usb_buf[3] = 0x02; + usb_buf[4] = side; // 0x01 for front, 0x02 for back + usb_buf[6] = software_mode; + + hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); + } + + is_software_mode_enabled = software_mode; +} + +/*------------------------------------------------------*\ +| Reset device on discovery in case it somehow landed | +| in a bad / unresponsive state | +\*------------------------------------------------------*/ + +void CMGD160Controller::ResetDevice() +{ + uint8_t usb_buf[CM_GD160_PACKET_LENGTH]; + + memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); + usb_buf[1] = 0x80; + usb_buf[2] = 0x11; + hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); + + memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); + usb_buf[1] = 0x80; + usb_buf[2] = 0x0B; + usb_buf[3] = 0x01; + usb_buf[4] = 0x02; + hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); + + memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); + usb_buf[1] = 0x80; + usb_buf[2] = 0x18; + usb_buf[3] = 0x01; + usb_buf[4] = 0x02; + hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); + + is_software_mode_enabled = false; +} diff --git a/Controllers/CoolerMasterController/CMGD160Controller/CMGD160Controller.h b/Controllers/CoolerMasterController/CMGD160Controller/CMGD160Controller.h new file mode 100644 index 000000000..ca1178d70 --- /dev/null +++ b/Controllers/CoolerMasterController/CMGD160Controller/CMGD160Controller.h @@ -0,0 +1,67 @@ +/*---------------------------------------------------------*\ +| CMGD160Controller.h | +| | +| Driver for Cooler Master GD160 ARGB Gaming Desk | +| | +| Logan Phillips (Eclipse) 16 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| Adapted from CMMonitor controller code | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include "RGBController.h" + +#define CM_GD160_PACKET_LENGTH 65 +#define CM_GD160_COLOR_DATA_LENGTH 872 +#define CM_GD160_SIDE_DATA_LENGTH 436 // 96 LEDs * 3 bytes + header = 436 bytes per side +#define CM_GD160_LEDS_PER_SIDE 96 +#define CM_GD160_FIRST_PACKET_DATA_SIZE 58 // CM_GD160_PACKET_LENGTH - 7 (header bytes) +#define CM_GD160_PACKET_DATA_SIZE 63 // CM_GD160_PACKET_LENGTH - 2 (header bytes) + +enum +{ + CM_GD160_DIRECT_MODE = 0xFF, + CM_GD160_CUSTOM_MODE = 0xFE, + CM_GD160_SPECTRUM_MODE = 0x00, + CM_GD160_RELOAD_MODE = 0x01, + CM_GD160_RECOIL_MODE = 0x02, + CM_GD160_BREATHING_MODE = 0x03, + CM_GD160_REFILL_MODE = 0x04, + CM_GD160_OFF_MODE = 0x06 +}; + +enum +{ + CM_GD160_BRIGHTNESS_MAX = 0xFF, + CM_GD160_BRIGHTNESS_MIN = 0x00, + CM_GD160_SPEED_MAX = 0x04, + CM_GD160_SPEED_MIN = 0x00, +}; + +class CMGD160Controller +{ +public: + CMGD160Controller(hid_device* dev_handle, const hid_device_info& info, const std::string& name); + ~CMGD160Controller(); + + std::string GetDeviceName(); + std::string GetSerialString(); + std::string GetDeviceLocation(); + + void SetMode(uint8_t mode_value, uint8_t speed, uint8_t brightness, const RGBColor& color); + void SendColorData(const std::vector& colors, uint8_t command, uint8_t mode_byte, uint8_t brightness, bool enable_software_mode); + +private: + std::string device_name; + std::string serial_number; + std::string location; + hid_device* dev; + bool is_software_mode_enabled = false; + void SetControlMode(bool value); + void ResetDevice(); +}; diff --git a/Controllers/CoolerMasterController/CMGD160Controller/RGBController_CMGD160Controller.cpp b/Controllers/CoolerMasterController/CMGD160Controller/RGBController_CMGD160Controller.cpp new file mode 100644 index 000000000..87aac9133 --- /dev/null +++ b/Controllers/CoolerMasterController/CMGD160Controller/RGBController_CMGD160Controller.cpp @@ -0,0 +1,238 @@ +/*---------------------------------------------------------*\ +| RGBController_CMGD160Controller.cpp | +| | +| RGBController for Cooler Master GD160 ARGB Gaming Desk | +| | +| Logan Phillips (Eclipse) 16 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| Adapted from CMMonitor controller code | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "RGBController_CMGD160Controller.h" + +/**------------------------------------------------------------------*\ + @name Cooler Master GD160 ARGB Gaming Desk + @category Accessory + @type USB + @save :robot: + @direct :white_check_mark: + @effects :white_check_mark: + @detectors DetectCoolerMasterGD160 + @comment +\*-------------------------------------------------------------------*/ + +RGBController_CMGD160Controller::RGBController_CMGD160Controller(CMGD160Controller* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetDeviceName(); + vendor = "Cooler Master"; + type = DEVICE_TYPE_ACCESSORY; + description = "Cooler Master GD160 Gaming Desk Device"; + location = controller->GetDeviceLocation(); + serial = controller->GetSerialString(); + + mode Direct; + Direct.name = "Direct"; + Direct.value = CM_GD160_DIRECT_MODE; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + mode Spectrum; + Spectrum.name = "Spectrum Cycle"; + Spectrum.value = CM_GD160_SPECTRUM_MODE; + Spectrum.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS; + Spectrum.color_mode = MODE_COLORS_NONE; + Spectrum.speed_min = CM_GD160_SPEED_MIN; + Spectrum.speed_max = CM_GD160_SPEED_MAX; + Spectrum.speed = CM_GD160_SPEED_MAX/2; + Spectrum.brightness_min = CM_GD160_BRIGHTNESS_MIN; + Spectrum.brightness_max = CM_GD160_BRIGHTNESS_MAX; + Spectrum.brightness = CM_GD160_BRIGHTNESS_MAX; + modes.push_back(Spectrum); + + mode Reload; + Reload.name = "Reload"; + Reload.value = CM_GD160_RELOAD_MODE; + Reload.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Reload.color_mode = MODE_COLORS_MODE_SPECIFIC; + Reload.colors_min = 1; + Reload.colors_max = 1; + Reload.colors.resize(1); + Reload.speed_min = CM_GD160_SPEED_MIN; + Reload.speed_max = CM_GD160_SPEED_MAX; + Reload.speed = CM_GD160_SPEED_MAX/2; + Reload.brightness_min = CM_GD160_BRIGHTNESS_MIN; + Reload.brightness_max = CM_GD160_BRIGHTNESS_MAX; + Reload.brightness = CM_GD160_BRIGHTNESS_MAX; + modes.push_back(Reload); + + mode Recoil; + Recoil.name = "Recoil"; + Recoil.value = CM_GD160_RECOIL_MODE; + Recoil.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Recoil.color_mode = MODE_COLORS_MODE_SPECIFIC; + Recoil.colors_min = 1; + Recoil.colors_max = 1; + Recoil.colors.resize(1); + Recoil.speed_min = CM_GD160_SPEED_MIN; + Recoil.speed_max = CM_GD160_SPEED_MAX; + Recoil.speed = CM_GD160_SPEED_MAX/2; + Recoil.brightness_min = CM_GD160_BRIGHTNESS_MIN; + Recoil.brightness_max = CM_GD160_BRIGHTNESS_MAX; + Recoil.brightness = CM_GD160_BRIGHTNESS_MAX; + modes.push_back(Recoil); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = CM_GD160_BREATHING_MODE; + Breathing.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.colors_min = 1; + Breathing.colors_max = 1; + Breathing.colors.resize(1); + Breathing.speed_min = CM_GD160_SPEED_MIN; + Breathing.speed_max = CM_GD160_SPEED_MAX; + Breathing.speed = CM_GD160_SPEED_MAX/2; + Breathing.brightness_min = CM_GD160_BRIGHTNESS_MIN; + Breathing.brightness_max = CM_GD160_BRIGHTNESS_MAX; + Breathing.brightness = CM_GD160_BRIGHTNESS_MAX; + modes.push_back(Breathing); + + mode Refill; + Refill.name = "Refill"; + Refill.value = CM_GD160_REFILL_MODE; + Refill.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR; + Refill.color_mode = MODE_COLORS_MODE_SPECIFIC; + Refill.colors_min = 1; + Refill.colors_max = 1; + Refill.colors.resize(1); + Refill.speed_min = CM_GD160_SPEED_MIN; + Refill.speed_max = CM_GD160_SPEED_MAX; + Refill.speed = CM_GD160_SPEED_MAX/2; + Refill.brightness_min = CM_GD160_BRIGHTNESS_MIN; + Refill.brightness_max = CM_GD160_BRIGHTNESS_MAX; + Refill.brightness = CM_GD160_BRIGHTNESS_MAX; + modes.push_back(Refill); + + mode Custom; + Custom.name = "Custom"; + Custom.value = CM_GD160_CUSTOM_MODE; + Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS; + Custom.color_mode = MODE_COLORS_PER_LED; + Custom.brightness_min = CM_GD160_BRIGHTNESS_MIN; + Custom.brightness_max = CM_GD160_BRIGHTNESS_MAX; + Custom.brightness = CM_GD160_BRIGHTNESS_MAX; + modes.push_back(Custom); + + mode Off; + Off.name = "Off"; + Off.value = CM_GD160_OFF_MODE; + Off.flags = MODE_FLAG_AUTOMATIC_SAVE; + Off.color_mode = MODE_COLORS_NONE; + modes.push_back(Off); + + SetupZones(); +} + +RGBController_CMGD160Controller::~RGBController_CMGD160Controller() +{ + delete controller; +} + +void RGBController_CMGD160Controller::SetupZones() +{ + zone front; + front.name = "Front Desk"; + front.type = ZONE_TYPE_LINEAR; + front.leds_min = CM_GD160_LEDS_PER_SIDE; + front.leds_max = CM_GD160_LEDS_PER_SIDE; + front.leds_count = CM_GD160_LEDS_PER_SIDE; + front.matrix_map = NULL; + zones.push_back(front); + + for(unsigned int i = 0; i < CM_GD160_LEDS_PER_SIDE; i++) + { + led l; + l.name = "Front LED " + std::to_string(i + 1); + l.value = i; + leds.push_back(l); + } + + zone back; + back.name = "Back Desk"; + back.type = ZONE_TYPE_LINEAR; + back.leds_min = CM_GD160_LEDS_PER_SIDE; + back.leds_max = CM_GD160_LEDS_PER_SIDE; + back.leds_count = CM_GD160_LEDS_PER_SIDE; + back.matrix_map = NULL; + zones.push_back(back); + + for(unsigned int i = 0; i < CM_GD160_LEDS_PER_SIDE; i++) + { + led l; + l.name = "Back LED " + std::to_string(i + 1); + l.value = i; + leds.push_back(l); + } + + SetupColors(); +} + +void RGBController_CMGD160Controller::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_CMGD160Controller::DeviceUpdateLEDs() +{ + switch(modes[active_mode].value) + { + case CM_GD160_DIRECT_MODE: + controller->SendColorData(colors, 0x07, 0x01, 0xFF, true); + break; + + case CM_GD160_CUSTOM_MODE: + controller->SendColorData(colors, 0x10, 0x80, modes[active_mode].brightness, false); + break; + + default: + break; + } +} + +void RGBController_CMGD160Controller::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_CMGD160Controller::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_CMGD160Controller::DeviceUpdateMode() +{ + switch(modes[active_mode].value) + { + case CM_GD160_OFF_MODE: + case CM_GD160_SPECTRUM_MODE: + controller->SetMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, 0); + break; + + case CM_GD160_RELOAD_MODE: + case CM_GD160_RECOIL_MODE: + case CM_GD160_BREATHING_MODE: + case CM_GD160_REFILL_MODE: + controller->SetMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, modes[active_mode].colors[0]); + break; + + default: + break; + } +} diff --git a/Controllers/CoolerMasterController/CMGD160Controller/RGBController_CMGD160Controller.h b/Controllers/CoolerMasterController/CMGD160Controller/RGBController_CMGD160Controller.h new file mode 100644 index 000000000..1373267bd --- /dev/null +++ b/Controllers/CoolerMasterController/CMGD160Controller/RGBController_CMGD160Controller.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------*\ +| RGBController_CMGD160Controller.h | +| | +| RGBController for Cooler Master GD160 ARGB Gaming Desk | +| | +| Logan Phillips (Eclipse) 16 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| Adapted from CMMonitor controller code | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "CMGD160Controller.h" + +class RGBController_CMGD160Controller : public RGBController +{ +public: + RGBController_CMGD160Controller(CMGD160Controller* controller_ptr); + ~RGBController_CMGD160Controller(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + CMGD160Controller* controller; +}; \ No newline at end of file diff --git a/Controllers/CoolerMasterController/CoolerMasterControllerDetect.cpp b/Controllers/CoolerMasterController/CoolerMasterControllerDetect.cpp index ab5e92e3e..c4e14c937 100644 --- a/Controllers/CoolerMasterController/CoolerMasterControllerDetect.cpp +++ b/Controllers/CoolerMasterController/CoolerMasterControllerDetect.cpp @@ -27,6 +27,7 @@ #include "RGBController_CMRGBController.h" #include "RGBController_CMR6000Controller.h" #include "RGBController_CMMonitorController.h" +#include "RGBController_CMGD160Controller.h" #include "RGBController_CMKeyboardController.h" /*-----------------------------------------------------*\ @@ -76,6 +77,11 @@ \*-----------------------------------------------------*/ #define COOLERMASTER_GM27_FQS_PID 0x01BB +/*-----------------------------------------------------*\ +| Coolermaster Desks | +\*-----------------------------------------------------*/ +#define COOLERMASTER_GD160_PID 0x01A9 + /******************************************************************************************\ * * * DetectCoolerMasterControllers * @@ -295,6 +301,20 @@ void DetectCoolerMasterMonitor(hid_device_info* info, const std::string& name) } } +void DetectCoolerMasterGD160(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + CMGD160Controller* controller = new CMGD160Controller(dev, *info, name); + RGBController_CMGD160Controller* rgb_controller = new RGBController_CMGD160Controller(controller); + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + + /*-----------------------------------------------------*\ | Coolermaster Keyboards | | PIDs defined in `CMKeyboardDevices.h` | @@ -356,3 +376,8 @@ REGISTER_HID_DETECTOR_I ("Cooler Master Radeon RX 6900 GPU", DetectCoole | Coolermaster Monitors | \*-----------------------------------------------------*/ REGISTER_HID_DETECTOR_IPU("Cooler Master GM27-FQS ARGB Monitor", DetectCoolerMasterMonitor, COOLERMASTER_VID, COOLERMASTER_GM27_FQS_PID, 0, 0xFF00, 1); + +/*-----------------------------------------------------*\ +| Coolermaster Desks | +\*-----------------------------------------------------*/ +REGISTER_HID_DETECTOR_IPU("Cooler Master GD160 ARGB Gaming Desk", DetectCoolerMasterGD160, COOLERMASTER_VID, COOLERMASTER_GD160_PID, 0, 0xFF00, 1);