From 1a07aee7a6c299dbfdb95b04a06f2f88c8f72b95 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Thu, 13 Feb 2020 12:19:14 -0600 Subject: [PATCH] Add OpenRazer-Win32 driver to support Razer devices on Windows without official software --- .gitmodules | 3 + OpenRGB.cpp | 2 +- OpenRGB.pro | 14 + RGBController/OpenRazerWindowsDetect.cpp | 316 +++++ .../RGBController_OpenRazerWindows.cpp | 419 ++++++ .../RGBController_OpenRazerWindows.h | 1204 +++++++++++++++++ dependencies/openrazer-win32/OpenRazer.dll | Bin 0 -> 104960 bytes dependencies/openrazer-win32/linux/dmi.h | 31 + dependencies/openrazer-win32/linux/hid.h | 300 ++++ dependencies/openrazer-win32/linux/init.h | 60 + dependencies/openrazer-win32/linux/kernel.h | 98 ++ dependencies/openrazer-win32/linux/module.h | 146 ++ dependencies/openrazer-win32/linux/random.h | 16 + dependencies/openrazer-win32/linux/slab.h | 31 + .../openrazer-win32/linux/usb/input.h | 539 ++++++++ 15 files changed, 3178 insertions(+), 1 deletion(-) create mode 100644 RGBController/OpenRazerWindowsDetect.cpp create mode 100644 RGBController/RGBController_OpenRazerWindows.cpp create mode 100644 RGBController/RGBController_OpenRazerWindows.h create mode 100644 dependencies/openrazer-win32/OpenRazer.dll create mode 100644 dependencies/openrazer-win32/linux/dmi.h create mode 100644 dependencies/openrazer-win32/linux/hid.h create mode 100644 dependencies/openrazer-win32/linux/init.h create mode 100644 dependencies/openrazer-win32/linux/kernel.h create mode 100644 dependencies/openrazer-win32/linux/module.h create mode 100644 dependencies/openrazer-win32/linux/random.h create mode 100644 dependencies/openrazer-win32/linux/slab.h create mode 100644 dependencies/openrazer-win32/linux/usb/input.h diff --git a/.gitmodules b/.gitmodules index 12be370b..35a99f82 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "dependencies/libe131"] path = dependencies/libe131 url = https://github.com/CalcProgrammer1/libe131 +[submodule "razer-drivers-win32"] + path = razer-drivers-win32 + url = https://github.com/rsandoz/razer-drivers-win32 diff --git a/OpenRGB.cpp b/OpenRGB.cpp index d2808468..6d066d41 100644 --- a/OpenRGB.cpp +++ b/OpenRGB.cpp @@ -317,7 +317,7 @@ void DetectRGBControllers(void) \*-------------------------------------*/ #ifdef WIN32 //DetectAorusGPUControllers(rgb_controllers); - + DetectOpenRazerControllers(rgb_controllers); /*-------------------------------------*\ | Linux-only devices | \*-------------------------------------*/ diff --git a/OpenRGB.pro b/OpenRGB.pro index 99524cbf..02fd9fd6 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -185,6 +185,7 @@ win32:INCLUDEPATH += \ dependencies/inpout32_1501/Win32/ \ dependencies/libusb-1.0.22/include \ dependencies/hidapi \ + dependencies/openrazer-win32 \ wmi/ \ win32:SOURCES += \ @@ -194,7 +195,9 @@ win32:SOURCES += \ serial_port/find_usb_serial_port_win.cpp \ wmi/wmi.cpp \ RGBController/AorusGPUDetect.cpp \ + RGBController/OpenRazerWindowsDetect.cpp \ RGBController/RGBController_AorusGPU.cpp \ + RGBController/RGBController_OpenRazerWindows.cpp \ win32:HEADERS += \ dependencies/inpout32_1501/Win32/inpout32.h \ @@ -203,6 +206,7 @@ win32:HEADERS += \ i2c_smbus/i2c_smbus_piix4.h \ wmi/wmi.h \ RGBController/RGBController_AorusGPU.h \ + RGBController/RGBController_OpenRazerWindows.h \ win32:LIBS += \ -lws2_32 \ @@ -220,6 +224,16 @@ win32:DEFINES += \ _WINSOCK_DEPRECATED_NO_WARNINGS \ WIN32_LEAN_AND_MEAN +# Copy OpenRazer.dll to output directory +win32 +{ + copydata.commands = $(COPY_FILE) \"$$shell_path($$PWD\\dependencies\\openrazer-win32\\OpenRazer.dll)\" \"$$shell_path($$OUT_PWD)\" + first.depends = $(first) copydata + export(first.depends) + export(copydata.commands) + QMAKE_EXTRA_TARGETS += first copydata +} + #----------------------------------------------- # Linux specific project configuration #----------------------------------------------- diff --git a/RGBController/OpenRazerWindowsDetect.cpp b/RGBController/OpenRazerWindowsDetect.cpp new file mode 100644 index 00000000..93d2250f --- /dev/null +++ b/RGBController/OpenRazerWindowsDetect.cpp @@ -0,0 +1,316 @@ +#include "RGBController.h" +#include "RGBController_OpenRazerWindows.h" +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _WIN64 +#define OPENRAZERDLL "OpenRazer64.dll" +#elif WIN32 +#define OPENRAZERDLL "OpenRazer.dll" +#endif + +/******************************************************************************************\ +* * +* DetectOpenRazerControllers * +* * +* Detect devices supported by the OpenRazer kernel drivers * +* * +\******************************************************************************************/ + +void DetectOpenRazerControllers(std::vector &rgb_controllers) +{ + static HMODULE module = LoadLibrary(OPENRAZERDLL); + + if(module == nullptr) + { + return; + } + + // map DLL calls + typedef unsigned int(*INITRAZERDRIVER)(struct hid_device** hdev); + + INITRAZERDRIVER init_razer_kbd_driver = reinterpret_cast(GetProcAddress(module, "init_razer_kbd_driver")); + static struct device_attribute devkbd_attr_device_type = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_device_type")); + static struct device_attribute devkbd_attr_device_serial = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_device_serial")); + static struct device_attribute devkbd_attr_firmware_version = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_firmware_version")); + static struct device_attribute devkbd_attr_matrix_effect_custom = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_custom")); + static struct device_attribute devkbd_attr_matrix_custom_frame = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_custom_frame")); + static struct device_attribute devkbd_attr_matrix_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_brightness")); + static struct device_attribute devkbd_attr_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_none")); + static struct device_attribute devkbd_attr_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_static")); + static struct device_attribute devkbd_attr_matrix_effect_breath = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_breath")); + static struct device_attribute devkbd_attr_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_spectrum")); + static struct device_attribute devkbd_attr_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_reactive")); + static struct device_attribute devkbd_attr_matrix_effect_wave = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkbd_attr_matrix_effect_wave")); + + INITRAZERDRIVER init_razer_mousemat_driver = reinterpret_cast(GetProcAddress(module, "init_razer_mousemat_driver")); + static struct device_attribute devmousemat_attr_device_type = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_device_type")); + static struct device_attribute devmousemat_attr_device_serial = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_device_serial")); + static struct device_attribute devmousemat_attr_firmware_version = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_firmware_version")); + static struct device_attribute devmousemat_attr_matrix_effect_custom = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_custom")); + static struct device_attribute devmousemat_attr_matrix_custom_frame = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_custom_frame")); + static struct device_attribute devmousemat_attr_matrix_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_brightness")); + static struct device_attribute devmousemat_attr_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_none")); + static struct device_attribute devmousemat_attr_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_static")); + static struct device_attribute devmousemat_attr_matrix_effect_breath = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_breath")); + static struct device_attribute devmousemat_attr_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_spectrum")); + static struct device_attribute devmousemat_attr_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_reactive")); + static struct device_attribute devmousemat_attr_matrix_effect_wave = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmousemat_attr_matrix_effect_wave")); + + INITRAZERDRIVER init_razer_mouse_driver = reinterpret_cast(GetProcAddress(module, "init_razer_mouse_driver")); + static struct device_attribute devmouse_attr_device_type = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_device_type")); + static struct device_attribute devmouse_attr_device_serial = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_device_serial")); + static struct device_attribute devmouse_attr_firmware_version = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_firmware_version")); + static struct device_attribute devmouse_attr_matrix_effect_custom = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_custom")); + static struct device_attribute devmouse_attr_matrix_custom_frame = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_custom_frame")); + static struct device_attribute devmouse_attr_matrix_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_brightness")); + static struct device_attribute devmouse_attr_logo_led_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_logo_led_brightness")); + static struct device_attribute devmouse_attr_scroll_led_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_led_brightness")); + static struct device_attribute devmouse_attr_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_none")); + static struct device_attribute devmouse_attr_logo_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_logo_matrix_effect_none")); + static struct device_attribute devmouse_attr_scroll_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_matrix_effect_none")); + static struct device_attribute devmouse_attr_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_static")); + static struct device_attribute devmouse_attr_logo_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_logo_matrix_effect_static")); + static struct device_attribute devmouse_attr_scroll_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_matrix_effect_static")); + static struct device_attribute devmouse_attr_matrix_effect_breath = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_breath")); + static struct device_attribute devmouse_attr_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_spectrum")); + static struct device_attribute devmouse_attr_logo_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_logo_matrix_effect_spectrum")); + static struct device_attribute devmouse_attr_scroll_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_matrix_effect_spectrum")); + static struct device_attribute devmouse_attr_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_reactive")); + static struct device_attribute devmouse_attr_logo_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_logo_matrix_effect_reactive")); + static struct device_attribute devmouse_attr_scroll_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_matrix_effect_reactive")); + static struct device_attribute devmouse_attr_scroll_led_effect = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_led_effect")); + static struct device_attribute devmouse_attr_scroll_led_rgb = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_led_rgb")); + static struct device_attribute devmouse_attr_scroll_led_state = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_scroll_led_state")); + static struct device_attribute devmouse_attr_matrix_effect_wave = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devmouse_attr_matrix_effect_wave")); + + INITRAZERDRIVER init_razer_accessory_driver = reinterpret_cast(GetProcAddress(module, "init_razer_accessory_driver")); + static struct device_attribute devaccessory_attr_device_type = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_device_type")); + static struct device_attribute devaccessory_attr_device_serial = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_device_serial")); + static struct device_attribute devaccessory_attr_firmware_version = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_firmware_version")); + static struct device_attribute devaccessory_attr_matrix_effect_custom = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_custom")); + static struct device_attribute devaccessory_attr_matrix_custom_frame = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_custom_frame")); + static struct device_attribute devaccessory_attr_matrix_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_brightness")); + static struct device_attribute devaccessory_attr_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_none")); + static struct device_attribute devaccessory_attr_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_static")); + static struct device_attribute devaccessory_attr_matrix_effect_breath = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_breath")); + static struct device_attribute devaccessory_attr_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_spectrum")); + //static struct device_attribute devaccessory_attr_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_reactive")); + static struct device_attribute devaccessory_attr_matrix_effect_wave = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devaccessory_attr_matrix_effect_wave")); + + INITRAZERDRIVER init_razer_kraken_driver = reinterpret_cast(GetProcAddress(module, "init_razer_kraken_driver")); + static struct device_attribute devkraken_attr_device_type = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_device_type")); + static struct device_attribute devkraken_attr_device_serial = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_device_serial")); + static struct device_attribute devkraken_attr_firmware_version = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_firmware_version")); + static struct device_attribute devkraken_attr_matrix_effect_custom = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_effect_custom")); + //static struct device_attribute devkraken_attr_matrix_custom_frame = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_custom_frame")); + //static struct device_attribute devkraken_attr_matrix_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_brightness")); + static struct device_attribute devkraken_attr_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_effect_none")); + static struct device_attribute devkraken_attr_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_effect_static")); + static struct device_attribute devkraken_attr_matrix_effect_breath = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_effect_breath")); + static struct device_attribute devkraken_attr_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devkraken_attr_matrix_effect_spectrum")); + + INITRAZERDRIVER init_razer_core_driver = reinterpret_cast(GetProcAddress(module, "init_razer_core_driver")); + static struct device_attribute devcore_attr_device_type = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_device_type")); + static struct device_attribute devcore_attr_device_serial = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_device_serial")); + static struct device_attribute devcore_attr_firmware_version = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_firmware_version")); + static struct device_attribute devcore_attr_matrix_effect_custom = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_custom")); + static struct device_attribute devcore_attr_matrix_custom_frame = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_custom_frame")); + static struct device_attribute devcore_attr_matrix_brightness = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_brightness")); + static struct device_attribute devcore_attr_matrix_effect_none = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_none")); + static struct device_attribute devcore_attr_matrix_effect_static = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_static")); + static struct device_attribute devcore_attr_matrix_effect_breath = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_breath")); + static struct device_attribute devcore_attr_matrix_effect_spectrum = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_spectrum")); + static struct device_attribute devcore_attr_matrix_effect_reactive = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_reactive")); + static struct device_attribute devcore_attr_matrix_effect_wave = *(struct device_attribute*)reinterpret_cast(GetProcAddress(module, "devcore_attr_matrix_effect_wave")); + + struct hid_device* hdev; + unsigned int num; + + hdev = NULL; + num = init_razer_kbd_driver(&hdev); + for (unsigned int i = 0; i < num; i++) + { + device_fn_type* device_fn = new device_fn_type; + device_fn->device_type = &devkbd_attr_device_type; + device_fn->device_serial = &devkbd_attr_device_serial; + device_fn->firmware_version = &devkbd_attr_firmware_version; + device_fn->matrix_effect_custom = &devkbd_attr_matrix_effect_custom; + device_fn->matrix_custom_frame = &devkbd_attr_matrix_custom_frame; + device_fn->matrix_brightness = &devkbd_attr_matrix_brightness; + device_fn->matrix_effect_none = &devkbd_attr_matrix_effect_none; + device_fn->matrix_effect_static = &devkbd_attr_matrix_effect_static; + device_fn->matrix_effect_breath = &devkbd_attr_matrix_effect_breath; + device_fn->matrix_effect_spectrum = &devkbd_attr_matrix_effect_spectrum; + device_fn->matrix_effect_reactive = &devkbd_attr_matrix_effect_reactive; + device_fn->matrix_effect_wave = &devkbd_attr_matrix_effect_wave; + + RGBController_OpenRazer * razer_rgb = new RGBController_OpenRazer(&hdev[i].dev, device_fn); + + if(razer_rgb->device_index != -1) + { + rgb_controllers.push_back(razer_rgb); + } + else + { + delete razer_rgb; + } + } + + hdev = NULL; + num = init_razer_mouse_driver(&hdev); + for (unsigned int i = 0; i < num; i++) + { + device_fn_type* device_fn = new device_fn_type; + device_fn->device_type = &devmouse_attr_device_type; + device_fn->device_serial = &devmouse_attr_device_serial; + device_fn->firmware_version = &devmouse_attr_firmware_version; + device_fn->matrix_effect_custom = &devmouse_attr_matrix_effect_custom; + device_fn->matrix_custom_frame = &devmouse_attr_matrix_custom_frame; + device_fn->matrix_brightness = &devmouse_attr_matrix_brightness; + device_fn->matrix_effect_none = &devmouse_attr_matrix_effect_none; + device_fn->matrix_effect_static = &devmouse_attr_matrix_effect_static; + device_fn->matrix_effect_breath = &devmouse_attr_matrix_effect_breath; + device_fn->matrix_effect_spectrum = &devmouse_attr_matrix_effect_spectrum; + device_fn->matrix_effect_reactive = &devmouse_attr_matrix_effect_reactive; + device_fn->matrix_effect_wave = &devmouse_attr_matrix_effect_wave; + + RGBController_OpenRazer * razer_rgb = new RGBController_OpenRazer(&hdev[i].dev, device_fn); + + if(razer_rgb->device_index != -1) + { + rgb_controllers.push_back(razer_rgb); + } + else + { + delete razer_rgb; + } + } + + hdev = NULL; + num = init_razer_mousemat_driver(&hdev); + for (unsigned int i = 0; i < num; i++) + { + device_fn_type* device_fn = new device_fn_type; + device_fn->device_type = &devmousemat_attr_device_type; + device_fn->device_serial = &devmousemat_attr_device_serial; + device_fn->firmware_version = &devmousemat_attr_firmware_version; + device_fn->matrix_effect_custom = &devmousemat_attr_matrix_effect_custom; + device_fn->matrix_custom_frame = &devmousemat_attr_matrix_custom_frame; + device_fn->matrix_brightness = &devmousemat_attr_matrix_brightness; + device_fn->matrix_effect_none = &devmousemat_attr_matrix_effect_none; + device_fn->matrix_effect_static = &devmousemat_attr_matrix_effect_static; + device_fn->matrix_effect_breath = &devmousemat_attr_matrix_effect_breath; + device_fn->matrix_effect_spectrum = &devmousemat_attr_matrix_effect_spectrum; + device_fn->matrix_effect_reactive = &devmousemat_attr_matrix_effect_reactive; + device_fn->matrix_effect_wave = &devmousemat_attr_matrix_effect_wave; + + RGBController_OpenRazer * razer_rgb = new RGBController_OpenRazer(&hdev[i].dev, device_fn); + + if(razer_rgb->device_index != -1) + { + rgb_controllers.push_back(razer_rgb); + } + else + { + delete razer_rgb; + } + } + + hdev = NULL; + num = init_razer_accessory_driver(&hdev); + for (unsigned int i = 0; i < num; i++) + { + device_fn_type* device_fn = new device_fn_type; + device_fn->device_type = &devaccessory_attr_device_type; + device_fn->device_serial = &devaccessory_attr_device_serial; + device_fn->firmware_version = &devaccessory_attr_firmware_version; + device_fn->matrix_effect_custom = &devaccessory_attr_matrix_effect_custom; + device_fn->matrix_custom_frame = &devaccessory_attr_matrix_custom_frame; + device_fn->matrix_brightness = &devaccessory_attr_matrix_brightness; + device_fn->matrix_effect_none = &devaccessory_attr_matrix_effect_none; + device_fn->matrix_effect_static = &devaccessory_attr_matrix_effect_static; + device_fn->matrix_effect_breath = &devaccessory_attr_matrix_effect_breath; + device_fn->matrix_effect_spectrum = &devaccessory_attr_matrix_effect_spectrum; + device_fn->matrix_effect_reactive = NULL;//&devaccessory_attr_matrix_effect_reactive; + device_fn->matrix_effect_wave = &devaccessory_attr_matrix_effect_wave; + + RGBController_OpenRazer * razer_rgb = new RGBController_OpenRazer(&hdev[i].dev, device_fn); + + if(razer_rgb->device_index != -1) + { + rgb_controllers.push_back(razer_rgb); + } + else + { + delete razer_rgb; + } + } + + hdev = NULL; + num = init_razer_kraken_driver(&hdev); + for (unsigned int i = 0; i < num; i++) + { + device_fn_type* device_fn = new device_fn_type; + device_fn->device_type = &devkraken_attr_device_type; + device_fn->device_serial = &devkraken_attr_device_serial; + device_fn->firmware_version = &devkraken_attr_firmware_version; + device_fn->matrix_effect_custom = &devkraken_attr_matrix_effect_custom; + device_fn->matrix_custom_frame = NULL;//&devkraken_attr_matrix_custom_frame; + device_fn->matrix_brightness = NULL;//&devkraken_attr_matrix_brightness; + device_fn->matrix_effect_none = &devkraken_attr_matrix_effect_none; + device_fn->matrix_effect_static = &devkraken_attr_matrix_effect_static; + device_fn->matrix_effect_breath = &devkraken_attr_matrix_effect_breath; + device_fn->matrix_effect_spectrum = &devkraken_attr_matrix_effect_spectrum; + device_fn->matrix_effect_reactive = NULL;//&devkraken_attr_matrix_effect_reactive; + device_fn->matrix_effect_wave = NULL;//&devkraken_attr_matrix_effect_wave; + + RGBController_OpenRazer * razer_rgb = new RGBController_OpenRazer(&hdev[i].dev, device_fn); + + if(razer_rgb->device_index != -1) + { + rgb_controllers.push_back(razer_rgb); + } + else + { + delete razer_rgb; + } + } + + hdev = NULL; + num = init_razer_core_driver(&hdev); + for (unsigned int i = 0; i < num; i++) + { + device_fn_type* device_fn = new device_fn_type; + device_fn->device_type = &devcore_attr_device_type; + device_fn->device_serial = &devcore_attr_device_serial; + device_fn->firmware_version = &devcore_attr_firmware_version; + device_fn->matrix_effect_custom = &devcore_attr_matrix_effect_custom; + device_fn->matrix_custom_frame = &devcore_attr_matrix_custom_frame; + device_fn->matrix_brightness = &devcore_attr_matrix_brightness; + device_fn->matrix_effect_none = &devcore_attr_matrix_effect_none; + device_fn->matrix_effect_static = &devcore_attr_matrix_effect_static; + device_fn->matrix_effect_breath = &devcore_attr_matrix_effect_breath; + device_fn->matrix_effect_spectrum = &devcore_attr_matrix_effect_spectrum; + device_fn->matrix_effect_reactive = &devcore_attr_matrix_effect_reactive; + device_fn->matrix_effect_wave = &devcore_attr_matrix_effect_wave; + + RGBController_OpenRazer * razer_rgb = new RGBController_OpenRazer(&hdev[i].dev, device_fn); + + if(razer_rgb->device_index != -1) + { + rgb_controllers.push_back(razer_rgb); + } + else + { + delete razer_rgb; + } + } + +} /* DetectOpenRazerControllers() */ diff --git a/RGBController/RGBController_OpenRazerWindows.cpp b/RGBController/RGBController_OpenRazerWindows.cpp new file mode 100644 index 00000000..5a5731c9 --- /dev/null +++ b/RGBController/RGBController_OpenRazerWindows.cpp @@ -0,0 +1,419 @@ +/*-----------------------------------------*\ +| RGBController_OpenRazer.cpp | +| | +| Generic RGB Interface for OpenRazer | +| kernel drivers for Chroma peripherals | +| | +| Adam Honse (CalcProgrammer1) 6/15/2019 | +\*-----------------------------------------*/ + +#include "RGBController_OpenRazerWindows.h" +#include +#include +#include +#include +#include +#include + +void RGBController_OpenRazer::UpdateLEDs() +{ + switch(matrix_type) + { + case RAZER_TYPE_MATRIX_FRAME: + case RAZER_TYPE_MATRIX_NOFRAME: + case RAZER_TYPE_MATRIX_STATIC: + { + char update_value = 1; + + for (unsigned int row = 0; row < matrix_rows; row++) + { + unsigned int output_array_size; + unsigned int output_offset; + unsigned int row_offset = (row * matrix_cols); + + if(matrix_type == RAZER_TYPE_MATRIX_FRAME) + { + output_array_size = 3 + (matrix_cols* 3); + output_offset = 3; + } + else + { + output_array_size = 3; + output_offset = 0; + } + + char* output_array = new char[output_array_size]; + + if(matrix_type == RAZER_TYPE_MATRIX_FRAME) + { + output_array[0] = row; + output_array[1] = 0; + output_array[2] = matrix_cols - 1; + } + + for(unsigned int col = 0; col < matrix_cols; col++) + { + unsigned int color_idx = col + row_offset; + output_array[(col * 3) + 0 + output_offset] = (char)RGBGetRValue(colors[color_idx]); + output_array[(col * 3) + 1 + output_offset] = (char)RGBGetGValue(colors[color_idx]); + output_array[(col * 3) + 2 + output_offset] = (char)RGBGetBValue(colors[color_idx]); + } + + if(matrix_type == RAZER_TYPE_MATRIX_FRAME) + { + razer_functions->matrix_custom_frame->store(razer_device, NULL, output_array, output_array_size); + } + else if(matrix_type == RAZER_TYPE_MATRIX_NOFRAME) + { + razer_functions->matrix_effect_custom->store(razer_device, NULL, output_array, output_array_size); + } + else + { + razer_functions->matrix_effect_static->store(razer_device, NULL, output_array, output_array_size); + } + } + + if(matrix_type == RAZER_TYPE_MATRIX_FRAME) + { + razer_functions->matrix_effect_custom->store(razer_device, NULL, &update_value, 1); + } + } + break; + #if 0 + case RAZER_TYPE_NOMATRIX: + { + unsigned int output_array_size = 3; + char output_array[output_array_size]; + char update_value = 0; + + output_array[0] = (char)RGBGetRValue(colors[0]); + output_array[1] = (char)RGBGetGValue(colors[0]); + output_array[2] = (char)RGBGetBValue(colors[0]); + logo_led_rgb.write(output_array, output_array_size); + + output_array[0] = (char)RGBGetRValue(colors[1]); + output_array[1] = (char)RGBGetGValue(colors[1]); + output_array[2] = (char)RGBGetBValue(colors[1]); + scroll_led_rgb.write(output_array, output_array_size); + + logo_led_rgb.flush(); + scroll_led_rgb.flush(); + + logo_led_effect.write(&update_value, 1); + scroll_led_effect.write(&update_value, 1); + logo_led_effect.flush(); + scroll_led_effect.flush(); + } + break; + #endif + } +} + +void RGBController_OpenRazer::UpdateZoneLEDs(int zone) +{ + UpdateLEDs(); +} + +void RGBController_OpenRazer::UpdateSingleLED(int led) +{ + UpdateLEDs(); +} + +void RGBController_OpenRazer::SetupMatrixDevice(device * razer_device, device_fn_type* razer_functions, unsigned int rows, unsigned int cols) +{ + if(razer_functions->matrix_custom_frame == NULL) + { + if(razer_functions->matrix_effect_custom != NULL) + { + matrix_type = RAZER_TYPE_MATRIX_STATIC; + } + else + { + matrix_type = RAZER_TYPE_MATRIX_NOFRAME; + } + + matrix_rows = 1; + matrix_cols = 1; + } + else + { + matrix_type = RAZER_TYPE_MATRIX_FRAME; + + matrix_rows = rows; + matrix_cols = cols; + } +} + +void RGBController_OpenRazer::SetupNonMatrixDevice(device * razer_device, device_fn_type* razer_functions) +{ + matrix_type = RAZER_TYPE_NOMATRIX; +} + +RGBController_OpenRazer::RGBController_OpenRazer(device * razer_device, device_fn_type* razer_functions) +{ + char string_buf[1024]; + + this->razer_device = razer_device; + this->razer_functions = razer_functions; + + unsigned int led_count = 0; + + /*-----------------------------------------------------------------*\ + | Initialize buffer | + \*-----------------------------------------------------------------*/ + memset(string_buf, 0xFF, sizeof(string_buf)); + string_buf[1023] = '\0'; + + /*-----------------------------------------------------------------*\ + | Start device at -1. This indicates the device was not detected | + \*-----------------------------------------------------------------*/ + device_index = -1; + + /*-----------------------------------------------------------------*\ + | Get the device name from the OpenRazer driver | + \*-----------------------------------------------------------------*/ + razer_functions->device_type->show(razer_device, NULL, string_buf); + name = string_buf; + name.erase(std::remove(name.begin(), name.end(), '\n'), name.end()); + name.erase(std::remove(name.begin(), name.end(), '\r'), name.end()); + + /*-----------------------------------------------------------------*\ + | Set the description to indicate this is an OpenRazer device | + \*-----------------------------------------------------------------*/ + description = "OpenRazer Device"; + + /*-----------------------------------------------------------------*\ + | Set the device path as the location | + \*-----------------------------------------------------------------*/ + location = ""; + + /*-----------------------------------------------------------------*\ + | Initialize buffer | + \*-----------------------------------------------------------------*/ + //memset(string_buf, 0xFF, sizeof(string_buf)); + //string_buf[1023] = '\0'; + + /*-----------------------------------------------------------------*\ + | Get the serial number from the dev path | + \*-----------------------------------------------------------------*/ + //razer_functions->device_serial->show(razer_device, NULL, string_buf); + //serial = string_buf; + + /*-----------------------------------------------------------------*\ + | Initialize buffer | + \*-----------------------------------------------------------------*/ + //memset(string_buf, 0xFF, sizeof(string_buf)); + //string_buf[1023] = '\0'; + + /*-----------------------------------------------------------------*\ + | Get the firmware version from the dev path | + \*-----------------------------------------------------------------*/ + //razer_functions->firmware_version->show(razer_device, NULL, string_buf); + //version = string_buf; + + /*-----------------------------------------------------------------*\ + | Loop through all known devices to look for a name match | + \*-----------------------------------------------------------------*/ + for (unsigned int i = 0; i < RAZER_NUM_DEVICES; i++) + { + if (device_list[i]->name == name) + { + /*---------------------------------------------------------*\ + | Set device ID | + \*---------------------------------------------------------*/ + device_index = i; + + /*---------------------------------------------------------*\ + | Set device type | + \*---------------------------------------------------------*/ + type = device_list[i]->type; + + /*---------------------------------------------------------*\ + | Initialize modes | + \*---------------------------------------------------------*/ + if(razer_functions->matrix_effect_custom != NULL) + { + mode Custom; + Custom.name = "Custom"; + Custom.value = RAZER_MODE_CUSTOM; + Custom.flags = MODE_FLAG_HAS_COLOR | MODE_FLAG_PER_LED_COLOR; + modes.push_back(Custom); + } + + if(razer_functions->matrix_effect_none) + { + mode Off; + Off.name = "Off"; + Off.value = RAZER_MODE_OFF; + Off.flags = 0; + modes.push_back(Off); + } + + if(razer_functions->matrix_effect_static) + { + mode Static; + Static.name = "Static"; + Static.value = RAZER_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_COLOR; + modes.push_back(Static); + } + + if(razer_functions->matrix_effect_breath) + { + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = RAZER_MODE_BREATHING; + Breathing.flags = MODE_FLAG_HAS_COLOR | MODE_FLAG_RANDOM_COLOR; + Breathing.random = false; + modes.push_back(Breathing); + } + + if(razer_functions->matrix_effect_spectrum) + { + mode SpectrumCycle; + SpectrumCycle.name = "Spectrum Cycle"; + SpectrumCycle.value = RAZER_MODE_SPECTRUM_CYCLE; + SpectrumCycle.flags = 0; + modes.push_back(SpectrumCycle); + } + + if(razer_functions->matrix_effect_wave) + { + mode Wave; + Wave.name = "Wave"; + Wave.value = RAZER_MODE_WAVE; + Wave.flags = 0; + modes.push_back(Wave); + } + + if(razer_functions->matrix_effect_reactive) + { + mode Reactive; + Reactive.name = "Reactive"; + Reactive.value = RAZER_MODE_REACTIVE; + Reactive.flags = 0; + modes.push_back(Reactive); + } + + /*---------------------------------------------------------*\ + | Initialize file descriptors | + \*---------------------------------------------------------*/ + if(device_list[i]->matrix_type == true) + { + SetupMatrixDevice(razer_device, razer_functions, device_list[i]->rows, device_list[i]->cols); + } + else + { + SetupNonMatrixDevice(razer_device, razer_functions); + } + + /*---------------------------------------------------------*\ + | Fill in zone information based on device table | + \*---------------------------------------------------------*/ + for (int zone_id = 0; zone_id < RAZER_MAX_ZONES; zone_id++) + { + if (device_list[i]->zones[zone_id] != NULL) + { + zone new_zone; + new_zone.name = device_list[i]->zones[zone_id]->name; + new_zone.type = device_list[i]->zones[zone_id]->type; + + for (unsigned int row_id = 0; row_id < device_list[i]->zones[zone_id]->rows; row_id++) + { + std::vector new_zone_map; + + for (unsigned int col_id = 0; col_id < device_list[i]->zones[zone_id]->cols; col_id++) + { + RGBColor new_color = 0x00000000; + colors.push_back(new_color); + + led* new_led = new led(); + new_led->name = device_list[i]->zones[zone_id]->name; + leds.push_back(*new_led); + + new_zone_map.push_back(led_count); + + led_count++; + } + + new_zone.map.push_back(new_zone_map); + } + zones.push_back(new_zone); + } + } + } + } + +} + +void RGBController_OpenRazer::SetCustomMode() +{ + SetMode(RAZER_MODE_CUSTOM); +} + +void RGBController_OpenRazer::UpdateMode() +{ + char update_value = 1; + + switch(matrix_type) + { + case RAZER_TYPE_MATRIX_FRAME: + case RAZER_TYPE_MATRIX_NOFRAME: + { + switch(modes[active_mode].value) + { + case RAZER_MODE_CUSTOM: + razer_functions->matrix_effect_custom->store(razer_device, NULL, &update_value, 1); + break; + + case RAZER_MODE_OFF: + razer_functions->matrix_effect_none->store(razer_device, NULL, &update_value, 1); + break; + + case RAZER_MODE_STATIC: + razer_functions->matrix_effect_static->store(razer_device, NULL, &update_value, 1); + break; + + case RAZER_MODE_BREATHING: + razer_functions->matrix_effect_breath->store(razer_device, NULL, &update_value, 1); + break; + + case RAZER_MODE_SPECTRUM_CYCLE: + razer_functions->matrix_effect_spectrum->store(razer_device, NULL, &update_value, 1); + break; + + case RAZER_MODE_WAVE: + razer_functions->matrix_effect_wave->store(razer_device, NULL, &update_value, 1); + break; + + case RAZER_MODE_REACTIVE: + razer_functions->matrix_effect_reactive->store(razer_device, NULL, &update_value, 1); + break; + } + } + break; +#if 0 + case RAZER_TYPE_NOMATRIX: + { + switch(modes[active_mode].value) + { + case RAZER_MODE_CUSTOM: + update_value = 0; + logo_led_effect.write(&update_value, 1); + scroll_led_effect.write(&update_value, 1); + logo_led_effect.flush(); + scroll_led_effect.flush(); + break; + + case RAZER_MODE_SPECTRUM_CYCLE: + update_value = '4'; + logo_led_effect.write(&update_value, 1); + scroll_led_effect.write(&update_value, 1); + logo_led_effect.flush(); + scroll_led_effect.flush(); + break; + } + } +#endif + } +} diff --git a/RGBController/RGBController_OpenRazerWindows.h b/RGBController/RGBController_OpenRazerWindows.h new file mode 100644 index 00000000..1721f8bb --- /dev/null +++ b/RGBController/RGBController_OpenRazerWindows.h @@ -0,0 +1,1204 @@ +/*-----------------------------------------*\ +| RGBController_OpenRazerWindows.h | +| | +| Generic RGB Interface for OpenRazer | +| kernel drivers for Chroma peripherals | +| | +| Adam Honse (CalcProgrammer1) 6/15/2019 | +\*-----------------------------------------*/ + +#include "RGBController.h" +#include + +#include +#include +#include + +typedef struct +{ + struct device_attribute * device_type; + struct device_attribute * device_serial; + struct device_attribute * firmware_version; + struct device_attribute * matrix_effect_custom; + struct device_attribute * matrix_custom_frame; + struct device_attribute * matrix_brightness; + struct device_attribute * matrix_effect_none; + struct device_attribute * matrix_effect_static; + struct device_attribute * matrix_effect_breath; + struct device_attribute * matrix_effect_spectrum; + struct device_attribute * matrix_effect_reactive; + struct device_attribute * matrix_effect_wave; +} device_fn_type; + +#define RAZER_MAX_ZONES 6 + +typedef struct +{ + std::string name; + unsigned int type; + unsigned int rows; + unsigned int cols; +} razer_zone; + +typedef struct +{ + std::string name; + device_type type; + bool matrix_type; + unsigned int rows; + unsigned int cols; + const razer_zone* zones[RAZER_MAX_ZONES]; +} razer_device; + +/*-------------------------------------------------------------------------*\ +| KEYBOARDS | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer BlackWidow Chroma | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 22 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone blackwidow_chroma_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 22 +}; + +static const razer_device blackwidow_chroma_device = +{ + "Razer BlackWidow Chroma", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 22, + { + &blackwidow_chroma_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer BlackWidow Chroma Tournament Edition | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 22 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone blackwidow_chroma_te_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 22 +}; + +static const razer_device blackwidow_chroma_te_device = +{ + "Razer BlackWidow Chroma Tournament Edition", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 22, + { + &blackwidow_chroma_te_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Ornata Chroma | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 22 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone ornata_chroma_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 22 +}; + +static const razer_device ornata_chroma_device = +{ + "Razer Ornata Chroma", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 22, + { + &ornata_chroma_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer DeathStalker Chroma | +| | +| Zone "Keyboard" | +| Linear | +| 12 LEDs | +\*-------------------------------------------------------------*/ +static const razer_zone deathstalker_chroma_zone = +{ + "Keyboard", + ZONE_TYPE_LINEAR, + 1, + 12 +}; + +static const razer_device deathstalker_chroma_device = +{ + "Razer DeathStalker Chroma", + DEVICE_TYPE_KEYBOARD, + true, + 1, + 12, + { + &deathstalker_chroma_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Huntsman Elite | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 22 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone huntsman_elite_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 22 +}; + +static const razer_device huntsman_elite_device = +{ + "Razer Huntsman Elite", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 22, + { + &huntsman_elite_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| LAPTOPS | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer Blade Stealth | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 16 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone blade_stealth_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 16 +}; + +static const razer_device blade_stealth_device = +{ + "Razer Blade Stealth", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 16, + { + &blade_stealth_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Blade Pro (Late 2016) | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 25 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone blade_pro_late_2016_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 25 +}; + +static const razer_device blade_pro_late_2016_device = +{ + "Razer Blade Pro (Late 2016)", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 25, + { + &blade_pro_late_2016_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Blade Pro (2017) | +| | +| Zone "Keyboard" | +| Matrix | +| 6 Rows, 25 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone blade_pro_2017_zone = +{ + "Keyboard", + ZONE_TYPE_MATRIX, + 6, + 25 +}; + +static const razer_device blade_pro_2017_device = +{ + "Razer Blade Pro (2017)", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 25, + { + &blade_pro_2017_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| MICE | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer Mamba Tournament Edition | +| | +| Zone "Left" | +| Linear | +| 7 LEDs | +| | +| Zone "Right" | +| Linear | +| 7 LEDs | +| | +| Zone "Logo" | +| Single | +| 1 LED | +| | +| Zone "Scroll Wheel" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone mamba_te_left_zone = +{ + "Left LED Strip", + ZONE_TYPE_LINEAR, + 1, + 7 +}; + +static const razer_zone mamba_te_right_zone = +{ + "Right LED Strip", + ZONE_TYPE_LINEAR, + 1, + 7 +}; + +static const razer_zone mamba_te_logo_zone = +{ + "Logo", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone mamba_te_scroll_wheel_zone = +{ + "Scroll Wheel", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device mamba_te_device = +{ + "Razer Mamba Tournament Edition", + DEVICE_TYPE_MOUSE, + true, + 1, + 16, + { + &mamba_te_left_zone, + &mamba_te_right_zone, + &mamba_te_logo_zone, + &mamba_te_scroll_wheel_zone, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Mamba Elite | +| | +| Zone "Scroll Wheel" | +| Single | +| 1 LED | +| | +| Zone "Logo" | +| Single | +| 1 LED | +| | +| Zone "Left" | +| Linear | +| 9 LEDs | +| | +| Zone "Right" | +| Linear | +| 9 LEDs | +| | +\*-------------------------------------------------------------*/ +static const razer_zone mamba_elite_scroll_wheel_zone = +{ + "Scroll Wheel", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone mamba_elite_logo_zone = +{ + "Logo", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone mamba_elite_left_zone = +{ + "Left LED Strip", + ZONE_TYPE_LINEAR, + 1, + 9 +}; + +static const razer_zone mamba_elite_right_zone = +{ + "Right LED Strip", + ZONE_TYPE_LINEAR, + 1, + 9 +}; + +static const razer_device mamba_elite_device = +{ + "Razer Mamba Elite", + DEVICE_TYPE_MOUSE, + true, + 1, + 20, + { + &mamba_elite_scroll_wheel_zone, + &mamba_elite_logo_zone, + &mamba_elite_left_zone, + &mamba_elite_right_zone, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Diamondback Chroma | +| | +| Zone "Right" | +| Linear | +| 7 LEDs | +| | +| Zone "Bottom" | +| Linear | +| 5 LEDs | +| | +| Zone "Left" | +| Linear | +| 7 LEDs | +| | +| Zone "Logo" | +| Single | +| 1 LED | +| | +| Zone "Scroll Wheel" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone diamondback_chroma_right_zone = +{ + "Right LED Strip", + ZONE_TYPE_LINEAR, + 1, + 7 +}; + +static const razer_zone diamondback_chroma_bottom_zone = +{ + "Bottom LED Strip", + ZONE_TYPE_LINEAR, + 1, + 5 +}; + +static const razer_zone diamondback_chroma_left_zone = +{ + "Left LED Strip", + ZONE_TYPE_LINEAR, + 1, + 7 +}; + +static const razer_zone diamondback_chroma_logo_zone = +{ + "Logo", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone diamondback_chroma_scroll_wheel_zone = +{ + "Scroll Wheel", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device diamondback_chroma_device = +{ + "Razer Diamondback Chroma", + DEVICE_TYPE_MOUSE, + true, + 1, + 21, + { + &diamondback_chroma_right_zone, + &diamondback_chroma_bottom_zone, + &diamondback_chroma_left_zone, + &diamondback_chroma_logo_zone, + &diamondback_chroma_scroll_wheel_zone, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer DeathAdder Chroma | +| | +| Zone "Logo" | +| Single | +| 1 LED | +| | +| Zone "Scroll Wheel" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone deathadder_chroma_logo_zone = +{ + "Logo", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone deathadder_chroma_scroll_wheel_zone = +{ + "Scroll Wheel", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device deathadder_chroma_device = +{ + "Razer DeathAdder Chroma", + DEVICE_TYPE_MOUSE, + false, + 1, + 2, + { + &deathadder_chroma_logo_zone, + &deathadder_chroma_scroll_wheel_zone, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Naga Chroma | +| | +| Zone "Logo" | +| Single | +| 1 LED | +| | +| Zone "Scroll Wheel" | +| Single | +| 1 LED | +| | +| Zone "Numpad" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone naga_chroma_logo_zone = +{ + "Logo", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone naga_chroma_scroll_wheel_zone = +{ + "Scroll Wheel", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone naga_chroma_numpad_zone = +{ + "Numpad", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device naga_chroma_device = +{ + "Razer Naga Chroma", + DEVICE_TYPE_MOUSE, + false, + 1, + 3, + { + &naga_chroma_logo_zone, + &naga_chroma_scroll_wheel_zone, + &naga_chroma_numpad_zone, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| KEYPADS | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer Orbweaver Chroma | +| | +| Zone "Keypad" | +| Matrix | +| 4 Rows, 5 Columns | +\*-------------------------------------------------------------*/ +static const razer_zone orbweaver_chroma_zone = +{ + "Keypad", + ZONE_TYPE_MATRIX, + 4, + 5 +}; + +static const razer_device orbweaver_chroma_device = +{ + "Razer Orbweaver Chroma", + DEVICE_TYPE_KEYBOARD, + true, + 6, + 25, + { + &orbweaver_chroma_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Tartarus Chroma | +| | +| Zone "Keypad" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone tartarus_chroma_zone = +{ + "Keypad", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device tartarus_chroma_device = +{ + "Razer Tartarus Chroma", + DEVICE_TYPE_KEYBOARD, + true, + 1, + 1, + { + &tartarus_chroma_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| MOUSEMATS | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer Firefly | +| | +| Zone "LED Strip" | +| Linear | +| 15 LEDs | +\*-------------------------------------------------------------*/ +static const razer_zone firefly_zone = +{ + "LED Strip", + ZONE_TYPE_LINEAR, + 1, + 15 +}; + +static const razer_device firefly_device = +{ + "Razer Firefly", + DEVICE_TYPE_MOUSEMAT, + true, + 1, + 15, + { + &firefly_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Goliathus Extended | +| | +| Zone "LED Strip" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone goliathus_extended_zone = +{ + "LED Strip", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device goliathus_extended_device = +{ + "Razer Goliathus Extended", + DEVICE_TYPE_MOUSEMAT, + true, + 1, + 1, + { + &goliathus_extended_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| HEADSETS | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer Kraken 7.1 Chroma | +| | +| Zone "Headset" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_chroma_zone = +{ + "Headset", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device kraken_chroma_device = +{ + "Razer Kraken 7.1 Chroma", + DEVICE_TYPE_HEADSET, + true, + 1, + 1, + { + &kraken_chroma_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Kraken 7.1 V2 | +| | +| Zone "Headset" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_v2_zone = +{ + "Headset", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device kraken_v2_device = +{ + "Razer Kraken 7.1 V2", + DEVICE_TYPE_HEADSET, + true, + 1, + 1, + { + &kraken_v2_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| OTHER | +\*-------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------*\ +| Razer Core | +| | +| Zone "Side Window Lights" | +| Single | +| 1 LED | +| | +| Zone "LED Strip" | +| Linear | +| 8 LEDs | +\*-------------------------------------------------------------*/ +static const razer_zone core_side_zone = +{ + "Side Window Lights", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_zone core_led_strip_zone = +{ + "LED Strip", + ZONE_TYPE_LINEAR, + 1, + 8 +}; + +static const razer_device core_device = +{ + "Razer Core", + DEVICE_TYPE_UNKNOWN, + true, + 1, + 9, + { + &core_side_zone, + &core_led_strip_zone, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Chroma Mug Holder | +| | +| Zone "LED Strip" | +| Linear | +| 15 LEDs | +\*-------------------------------------------------------------*/ +static const razer_zone mug_holder_zone = +{ + "LED Strip", + ZONE_TYPE_LINEAR, + 1, + 15 +}; + +static const razer_device mug_holder_device = +{ + "Razer Chroma Mug Holder", + DEVICE_TYPE_UNKNOWN, + true, + 1, + 15, + { + &mug_holder_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Chroma HDK | +| | +| Zone "LED Strip" | +| Linear | +| 16 LEDs | +| | +| Zone "LED Strip" | +| Linear | +| 16 LEDs | +| | +| Zone "LED Strip" | +| Linear | +| 16 LEDs | +| | +| Zone "LED Strip" | +| Linear | +| 16 LEDs | +\*-------------------------------------------------------------*/ +static const razer_zone chromahdk_zone = +{ + "LED Strip", + ZONE_TYPE_LINEAR, + 1, + 16 +}; + +static const razer_device chromahdk_device = +{ + "Razer Chroma HDK", + DEVICE_TYPE_LEDSTRIP, + true, + 4, + 16, + { + &chromahdk_zone, + &chromahdk_zone, + &chromahdk_zone, + &chromahdk_zone, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Base Station Chroma | +| | +| Zone "LED Strip" | +| Linear | +| 15 LEDs | +\*-------------------------------------------------------------*/ +static const razer_zone base_station_zone = +{ + "LED Strip", + ZONE_TYPE_LINEAR, + 1, + 15 +}; + +static const razer_device base_station_device = +{ + "Razer Base Station Chroma", + DEVICE_TYPE_UNKNOWN, + true, + 1, + 15, + { + &base_station_zone, + NULL, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Nommo Pro | +| | +| Zone "Left Speaker" | +| Linear | +| 8 LEDs | +| | +| Zone "Right Speaker" | +| Linear | +| 8 LEDs | +| | +\*-------------------------------------------------------------*/ +static const razer_zone nommo_pro_left_zone = +{ + "Left Speaker", + ZONE_TYPE_LINEAR, + 1, + 8 +}; + +static const razer_zone nommo_pro_right_zone = +{ + "Right Speaker", + ZONE_TYPE_LINEAR, + 1, + 8 +}; + +static const razer_device nommo_pro_device = +{ + "Razer Nommo Pro", + DEVICE_TYPE_UNKNOWN, + true, + 2, + 8, + { + &nommo_pro_left_zone, + &nommo_pro_right_zone, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------*\ +| Razer Nommo Chroma | +| | +| Zone "Right Speaker" | +| Linear | +| 8 LEDs | +| | +| Zone "Left Speaker" | +| Linear | +| 8 LEDs | +| | +\*-------------------------------------------------------------*/ +static const razer_zone nommo_chroma_right_zone = +{ + "Right Speaker", + ZONE_TYPE_LINEAR, + 1, + 24 +}; + +static const razer_zone nommo_chroma_left_zone = +{ + "Left Speaker", + ZONE_TYPE_LINEAR, + 1, + 24 +}; + +static const razer_device nommo_chroma_device = +{ + "Razer Nommo Chroma", + DEVICE_TYPE_UNKNOWN, + true, + 2, + 24, + { + &nommo_chroma_right_zone, + &nommo_chroma_left_zone, + NULL, + NULL, + NULL, + NULL + } +}; + +/*-------------------------------------------------------------------------*\ +| DEVICE MASTER LIST | +\*-------------------------------------------------------------------------*/ +#define RAZER_NUM_DEVICES (sizeof(device_list) / sizeof(device_list[ 0 ])) + +static const razer_device* device_list[] = +{ +/*-----------------------------------------------------------------*\ +| KEYBOARDS | +\*-----------------------------------------------------------------*/ + &blackwidow_chroma_device, + &blackwidow_chroma_te_device, + &ornata_chroma_device, + &deathstalker_chroma_device, + &huntsman_elite_device, +/*-----------------------------------------------------------------*\ +| LAPTOPS | +\*-----------------------------------------------------------------*/ + &blade_stealth_device, + &blade_pro_late_2016_device, + &blade_pro_2017_device, +/*-----------------------------------------------------------------*\ +| MICE | +\*-----------------------------------------------------------------*/ + &mamba_te_device, + &mamba_elite_device, + &diamondback_chroma_device, + &deathadder_chroma_device, +/*-----------------------------------------------------------------*\ +| KEYPADS | +\*-----------------------------------------------------------------*/ + &orbweaver_chroma_device, + &tartarus_chroma_device, +/*-----------------------------------------------------------------*\ +| MOUSEMATS | +\*-----------------------------------------------------------------*/ + &firefly_device, + &goliathus_extended_device, +/*-----------------------------------------------------------------*\ +| HEADSETS | +\*-----------------------------------------------------------------*/ + &kraken_chroma_device, + &kraken_v2_device, +/*-----------------------------------------------------------------*\ +| OTHER | +\*-----------------------------------------------------------------*/ + &core_device, + &mug_holder_device, + &chromahdk_device, + &base_station_device, + &nommo_pro_device, + &nommo_chroma_device +}; + + +class RGBController_OpenRazer : public RGBController +{ +public: + enum + { + RAZER_MODE_CUSTOM, + RAZER_MODE_OFF, + RAZER_MODE_STATIC, + RAZER_MODE_BREATHING, + RAZER_MODE_SPECTRUM_CYCLE, + RAZER_MODE_WAVE, + RAZER_MODE_REACTIVE, + RAZER_NUM_MODES + }; + + enum + { + RAZER_TYPE_MATRIX_FRAME, + RAZER_TYPE_MATRIX_NOFRAME, + RAZER_TYPE_MATRIX_STATIC, + RAZER_TYPE_NOMATRIX, + RAZER_NUM_TYPES + }; + +public: + RGBController_OpenRazer(device * razer_device, device_fn_type* razer_functions); + void UpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void UpdateMode(); + + int device_index; + +private: + void SetupMatrixDevice(device * razer_device, device_fn_type* razer_functions, unsigned int rows, unsigned int cols); + void SetupNonMatrixDevice(device * razer_device, device_fn_type* razer_functions); + + unsigned int matrix_type; + unsigned int matrix_rows; + unsigned int matrix_cols; + + device* razer_device; + device_fn_type* razer_functions; + + //OpenRazer Sysfs Entries for Matrix Devices + std::ofstream matrix_custom_frame; + std::ofstream matrix_effect_custom; + std::ofstream matrix_effect_breath; + std::ofstream matrix_effect_none; + std::ofstream matrix_effect_reactive; + std::ofstream matrix_effect_spectrum; + std::ofstream matrix_effect_static; + std::ofstream matrix_effect_wave; + + //OpenRazer Sysfs Entries for Non-Matrix Devices + std::ofstream logo_led_effect; + std::ofstream logo_led_rgb; + std::ofstream scroll_led_effect; + std::ofstream scroll_led_rgb; +}; diff --git a/dependencies/openrazer-win32/OpenRazer.dll b/dependencies/openrazer-win32/OpenRazer.dll new file mode 100644 index 0000000000000000000000000000000000000000..e97cb0155bf045c2daa4dffdc8bc0ea63e6a47c9 GIT binary patch literal 104960 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 ja|R0*3myvr3lR$m3mFRq3l$3u3mx>sW*J7oU +#include +#include + +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "Winusb.lib") + +#define HID_STAT_ADDED 1 +#define HID_STAT_PARSED 2 + +#define HID_CONNECT_HIDINPUT 0x01 +#define HID_CONNECT_HIDRAW 0x04 +#define HID_CONNECT_HIDDEV 0x08 +#define HID_CONNECT_FF 0x20 +#define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| HID_CONNECT_HIDDEV|HID_CONNECT_FF) + +#define HID_GD_WHEEL 0x00010038 + +#define HID_REQ_GET_REPORT 0x01 +#define HID_REQ_SET_REPORT 0x09 + +#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 +#define USB_INTERFACE_PROTOCOL_MOUSE 2 + +static const GUID GUID_DEVINTERFACE = { 0xDEE824EF, 0x729B, 0x4A0E, 0x9C, 0x14, 0xB7, 0x11, 0x7D, 0x33, 0xA8, 0x17 }; + +typedef enum +{ +HID_TYPE_OTHER, +HID_TYPE_USBMOUSE, +HID_TYPE_USBNONE +} hid_type; + +struct hid_input { + struct input_dev *input; +}; + +struct hid_field { + struct hid_input *hidinput; /* associated input structure */ +}; + +struct hid_usage { + unsigned hid; + __u16 code; /* input driver code */ + __u8 type; /* input driver type */ +}; + +struct hid_driver { + char *name; + const struct hid_device_id *id_table; + int (*probe)(struct hid_device *dev, const struct hid_device_id *id); + void (*remove)(struct hid_device *dev); + int (*raw_event)(struct hid_device *hdev, struct hid_report *report, u8 *data, int size); + int (*event)(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value); + int (*input_configured)(struct hid_device *hdev, + struct hid_input *hidinput); + int (*input_mapping)(struct hid_device *hdev, + struct hid_input *hidinput, struct hid_field *field, + struct hid_usage *usage, unsigned long **bit, int *max); +}; + +struct hid_device_id { + __u16 bus; + __u32 vendor; + __u32 product; +}; + +struct hid_device { + __u16 product; + enum hid_type type; + struct device dev; + struct hid_ll_driver *ll_driver; + unsigned int status; + struct hid_driver *driver; +}; + +struct hid_ll_driver { + int (*start)(struct hid_device *hdev); + void (*stop)(struct hid_device *hdev); + int (*parse)(struct hid_device *hdev); +}; + +inline int ll_start(struct hid_device *hdev) { + printf("ll_start\n"); + return 0; +} + +inline void ll_stop(struct hid_device *hdev) { + printf("ll_stop\n"); +} + +inline int ll_parse(struct hid_device *hdev) { + printf("ll_parse\n"); + return 0; +} + +inline void dev_err(struct device** dev, const char* msg) { + printf("dev_err device=%s msg=%s", (*dev)->init_name, msg); +} + +inline void dev_info(struct device** dev, const char* msg) { + printf("dev_err device=%s msg=%s", (*dev)->init_name, msg); +} + +inline void *dev_get_drvdata(const struct device *dev) { + return dev->driver_data; +} + +inline void dev_set_drvdata(struct device *dev, void *data) { + dev->driver_data = data; +} + +inline int hid_connect(struct hid_device *hdev, unsigned int connect_mask) { + printf("hid_connect\n"); + return 0; +} + +inline int hid_parse(struct hid_device *hdev) { + int ret; + + if (hdev->status & HID_STAT_PARSED) + return 0; + + ret = hdev->ll_driver->parse(hdev); + if (!ret) + hdev->status |= HID_STAT_PARSED; + + return ret; +} + +inline void *hid_get_drvdata(struct hid_device *hdev) { + return dev_get_drvdata(&hdev->dev); +} + +inline void hid_set_drvdata(struct hid_device *hdev, void *data) { + dev_set_drvdata(&hdev->dev, data); +} + +inline int hid_hw_start(struct hid_device *hdev, unsigned int connect_mask) { + int ret = hdev->ll_driver->start(hdev); + if (ret || !connect_mask) + return ret; + ret = hid_connect(hdev, connect_mask); + if (ret) + hdev->ll_driver->stop(hdev); + return ret; +} + +inline void hid_hw_stop(struct hid_device *hdev) { + hdev->ll_driver->stop(hdev); +} + +inline void hid_err(struct hid_device *hdev, const char* msg, ...) { + va_list args; + va_start(args, msg); + printf("hid_err device=%s", hdev->dev.init_name); + printf(msg, args); + va_end(args); +} + +inline void hid_map_usage(struct hid_input* hidinput, + struct hid_usage* usage, unsigned long** bit, int* max, + __u8 type, __u16 c) +{ + +}; + +#define container_of(ptr, type, member) (type*)((char*)(ptr)-(char*)&((type *)0)->member) + +inline void close(struct device* dev) { + printf("close %04X\n", (to_usb_device(dev))->descriptor.idProduct); + struct usb_interface *intf = to_usb_interface(dev->parent); + struct usb_device *usb_dev = interface_to_usbdev(intf); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + free(hdev->ll_driver); + free(usb_dev); + free(intf->cur_altsetting); + free(intf); + free(hdev); + //TODO:cleanup malloc memory, move this function into DLL +} + +inline void openChromaDevice(struct hid_device** hdev, unsigned int* numHdev, struct hid_driver hdr) { + + for (unsigned int i = 0; hdr.id_table[i].vendor != 0; i++) { + HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE, 0, 0, DIGCF_DEVICEINTERFACE); + if (hDevInfo == INVALID_HANDLE_VALUE) { + printf("SetupDiGetClassDevs failed\n"); + return; + } + + SP_DEVINFO_DATA deviceData = { 0 }; + deviceData.cbSize = sizeof(SP_DEVINFO_DATA); + + for (unsigned int j = 0; SetupDiEnumDeviceInfo(hDevInfo, j, &deviceData); ++j) { + char deviceID[MAX_DEVICE_ID_LEN]; + if (CM_Get_Device_ID(deviceData.DevInst, deviceID, MAX_DEVICE_ID_LEN, 0)) + continue; + + char* vid = strstr(deviceID, "VID_"); + if (!vid || hdr.id_table[i].vendor != strtoul(vid+4, NULL, 16)) + continue; + + char* pid = strstr(deviceID, "PID_"); + if (!pid || hdr.id_table[i].product != strtoul(pid+4, NULL, 16)) + continue; + + SP_INTERFACE_DEVICE_DATA interfaceData = { 0 }; + interfaceData.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA); + if (!SetupDiEnumDeviceInterfaces(hDevInfo, &deviceData, &GUID_DEVINTERFACE, 0, &interfaceData)) + continue; + + DWORD dwRequiredSize = 0; + SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, 0, 0, &dwRequiredSize, 0); + SP_INTERFACE_DEVICE_DETAIL_DATA* pData = (SP_INTERFACE_DEVICE_DETAIL_DATA*)malloc(dwRequiredSize); + pData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA); + if (!SetupDiGetDeviceInterfaceDetail(hDevInfo, &interfaceData, pData, dwRequiredSize, 0, 0)) { + free(pData); + continue; + } + + HANDLE hDevice = CreateFile(pData->DevicePath + , GENERIC_READ | GENERIC_WRITE + , FILE_SHARE_READ | FILE_SHARE_WRITE + , 0 + , OPEN_EXISTING + , FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED + , 0); + if (hDevice == INVALID_HANDLE_VALUE) { + free(pData); + continue; + } + + WINUSB_INTERFACE_HANDLE hWinUSBHandle; + if (!WinUsb_Initialize(hDevice, &hWinUSBHandle)) + continue; + + SetupDiDestroyDeviceInfoList(hDevInfo); + + printf("CM_Get_Device_ID (%s)\n", deviceID); + printf("device %04X:%04X opened!\n", hdr.id_table[i].vendor, hdr.id_table[i].product); + + *hdev = (struct hid_device*)realloc(*hdev, (*numHdev+1) * sizeof(struct hid_device)); + if (!*hdev) { + printf("out of memory\n"); + continue; + } + + if (*numHdev > 0) + { + //Correct all previous pointers to their new locations + for (int old_dev = 0; old_dev < *numHdev; old_dev++) + { + (*hdev)[old_dev].dev.parent = &((*hdev)[old_dev].dev); + (*hdev)[old_dev].dev.parent_usb_interface->dev = &((*hdev)[old_dev].dev); + (*hdev)[old_dev].dev.parent_usb_interface->parent_usb_device->dev = &((*hdev)[old_dev].dev); + } + } + + struct usb_interface* intf = (struct usb_interface*)malloc(sizeof(struct usb_interface)); + intf->cur_altsetting = (struct usb_host_interface*)malloc(sizeof(struct usb_host_interface)); + intf->cur_altsetting->desc.bInterfaceProtocol = 0; + + struct usb_device *usbdevice = (struct usb_device*)malloc(sizeof(struct usb_device)); + usbdevice->descriptor.idVendor = hdr.id_table[i].vendor; + usbdevice->descriptor.idProduct = hdr.id_table[i].product; + + intf->parent_usb_device = usbdevice; + + (*hdev)[*numHdev].product = hdr.id_table[i].product; + (*hdev)[*numHdev].dev.parent = &((*hdev)[*numHdev].dev); + (*hdev)[*numHdev].dev.driver_data; + (*hdev)[*numHdev].dev.p = hWinUSBHandle; + (*hdev)[*numHdev].dev.parent_usb_interface = intf; + (*hdev)[*numHdev].dev.init_name = hdr.name; + + usbdevice->dev = &((*hdev)[*numHdev].dev); + intf->dev = &((*hdev)[*numHdev].dev); + + + (*hdev)[*numHdev].status = 2; + (*hdev)[*numHdev].driver = &hdr; + (*hdev)[*numHdev].ll_driver = (struct hid_ll_driver*)malloc(sizeof(struct hid_ll_driver)); + (*hdev)[*numHdev].ll_driver->parse = ll_parse; + (*hdev)[*numHdev].ll_driver->start = ll_start; + (*hdev)[*numHdev].ll_driver->stop = ll_stop; + + (*hdev)[*numHdev].driver->probe(&((*hdev)[*numHdev]), &(hdr.id_table[i])); + + (*numHdev)++; + } + if (!numHdev) + printf("device %04X:%04X NOT opened!\n", hdr.id_table[i].vendor, hdr.id_table[i].product); + } +} + +#endif /* HID_H_ */ diff --git a/dependencies/openrazer-win32/linux/init.h b/dependencies/openrazer-win32/linux/init.h new file mode 100644 index 00000000..090c4b0f --- /dev/null +++ b/dependencies/openrazer-win32/linux/init.h @@ -0,0 +1,60 @@ +#ifndef INIT_H_ +#define INIT_H_ + +static inline int sprint_f(char* buf, const char* fmt, ...) { + va_list args; + int i; + va_start(args, fmt); + i = sprintf_s(buf, strlen(buf) - 1, fmt, args); + va_end(args); + return i; +} +#define sprintf sprint_f + +static inline int strncpy_f(char* dest, const char* source, const size_t sourceLen) { + return strncpy_s(dest, strlen(dest) - 1, source, sourceLen); +} +#define strncpy strncpy_f + +static inline int strcpy_f(char* dest, const char* source) { + return strcpy_s(dest, strlen(dest) - 1, source); +} +#define strcpy strcpy_f + +#define strdup _strdup + +#define KERN_WARNING +#define KERN_ALERT +#define KERN_CRIT + +#define printk printf + +inline unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) { + return strtoul(cp, endp, base); +} + +inline void usleep(__int64 usec) { + HANDLE timer; + LARGE_INTEGER ft; + + ft.QuadPart = -(10 * usec); // Convert to 100 nanosecond interval, negative value indicates relative time + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0); + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); +} + +inline void msleep(__int64 msec) { + usleep(1000 * msec); +} + +inline void usleep_range(__int64 usec1, __int64 usec2) { + usleep((usec1 + usec2) / 2); +} + +inline unsigned short eflip(unsigned short val) { + return (val & 0xff) * 0xFF + (val >> 8); +} + +#endif /* INIT_H_ */ diff --git a/dependencies/openrazer-win32/linux/kernel.h b/dependencies/openrazer-win32/linux/kernel.h new file mode 100644 index 00000000..70b97775 --- /dev/null +++ b/dependencies/openrazer-win32/linux/kernel.h @@ -0,0 +1,98 @@ +#ifndef KERNEL_H_ +#define KERNEL_H_ + +#include + +#define DLL_INTERNAL __declspec( dllexport ) + +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int +#define u64 unsigned long + +#define __u8 unsigned char +#define __u16 unsigned short +#define __u32 unsigned int +#define __u64 unsigned long +#define uint8_t unsigned char +#define uint16_t unsigned short +#define uint32_t unsigned int +#define uint64_t unsigned long +#define __le8 unsigned char +#define __le16 unsigned short +#define __le32 unsigned int +#define __le64 unsigned long +#define __s8 signed char +#define __s16 signed short +#define __s32 signed int +#define __s64 signed long +#define uint unsigned int +#define ulong unsigned long + +#define socklen_t int + +#define bool int +#define true 1 +#define false 0 + +#define size_t SIZE_T +#define ssize_t SSIZE_T + +struct mutex { + CRITICAL_SECTION lock; +}; + +inline void mutex_init(struct mutex* mutex) { + InitializeCriticalSection(&mutex->lock); +} + +inline void mutex_lock(struct mutex* mutex) { + EnterCriticalSection(&mutex->lock); +} + +inline void mutex_unlock(struct mutex* mutex) { + LeaveCriticalSection(&mutex->lock); +} + +inline int mutex_trylock(struct mutex* mutex) { + return TryEnterCriticalSection(&mutex->lock); +} + +inline int mutex_is_locked(struct mutex* mutex) { + if (mutex_trylock(mutex)) { + mutex_unlock(mutex); + return 0; + } + else + return 1; +} + +inline void set_bit(int nr, volatile unsigned long *addr) { + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} +#define __set_bit set_bit + +inline void clear_bit(int nr, volatile unsigned long *addr) { + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a &= ~mask; +} + +inline int test_bit(int nr, const void *addr) { + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *a) != 0); +} + +#endif /* KERNEL_H_ */ diff --git a/dependencies/openrazer-win32/linux/module.h b/dependencies/openrazer-win32/linux/module.h new file mode 100644 index 00000000..96e14156 --- /dev/null +++ b/dependencies/openrazer-win32/linux/module.h @@ -0,0 +1,146 @@ +#ifndef MODULE_H_ +#define MODULE_H_ + +#include +#include + +#define MODULE_AUTHOR( __Declaration__ ) +#define MODULE_DESCRIPTION( __Declaration__ ) +#define MODULE_VERSION( __Declaration__ ) +#define MODULE_LICENSE( __Declaration__ ) + +#define USB_CTRL_SET_TIMEOUT 5000 + +#define USB_DIR_OUT 0 +#define USB_DIR_IN 0x80 + +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_RECIP_INTERFACE 0x01 + +#define usb_sndctrlpipe(u,d) 0 +#define usb_rcvctrlpipe(u,d) 0 + +#define PATH_MAX 512 + +struct usb_interface_descriptor { + unsigned char bInterfaceProtocol; +}; + +struct usb_host_interface { + struct usb_interface_descriptor desc; +}; + +struct device { + struct device *parent; + void *p; + const char *init_name; + void *driver_data; +struct usb_interface *parent_usb_interface; +}; + +struct usb_interface { + struct device* dev; + int num_altsetting; + struct usb_host_interface *cur_altsetting; +struct usb_device *parent_usb_device; +}; + +struct usb_device_descriptor { + unsigned short idVendor; + unsigned short idProduct; +}; + +struct usb_device { + struct device* dev; + struct usb_device_descriptor descriptor; +}; + +inline int usb_control_msg( + struct usb_device *usb_dev + , int usb_pipe + , unsigned int request + , unsigned int request_type + , unsigned int value + , unsigned int report_index + , unsigned char* buf, unsigned int size + , unsigned int timeout) +{ + WINUSB_SETUP_PACKET packet; + packet.RequestType = request_type; + packet.Request = request; + packet.Value = value; + packet.Index = report_index; + packet.Length = size; + ULONG cbSent = 0; + if (!WinUsb_ControlTransfer(usb_dev->dev->p, packet, buf, size, &cbSent, 0)) + printf("WinUsb_ControlTransfer failed\n"); + + return cbSent; +} + + + +inline struct usb_interface *to_usb_interface(struct device *dev) { + return dev->parent_usb_interface; +} + +inline struct usb_device *to_usb_device(struct device *dev) { + return dev->parent_usb_interface->parent_usb_device; +} + +inline struct usb_device *interface_to_usbdev(struct usb_interface *intf) { + return to_usb_device(intf->dev->parent); +} + +inline void usb_disable_autosuspend(struct usb_device *usb_dev) { + printf("usb_disable_autosuspend\n"); +} + +struct device_attribute { + const char* name; + ssize_t(*show)(struct device *dev, struct device_attribute *attr, char *buf); + ssize_t(*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +}; + +inline int device_create_file(struct device *device, struct device_attribute *entry) { + printf("device_create_file %s\n", entry->name); + return 0; +} + +inline void device_remove_file(struct device *device, struct device_attribute *entry) { + printf("device_remove_file %s\n", entry->name); +} + +#define HID_USB_DEVICE(ven, prod) \ + .vendor = (ven) \ + , .product = (prod) + + +#define __stringify(x) #x + +// Hack to turn Linux device macros into API calls +#define DEVICE_ATTR1(_device,_name, _mode, _show, _store) \ + struct device_attribute dev_attr_##_name; \ + DLL_INTERNAL struct device_attribute dev##_device##_attr_##_name = { \ + .name = __stringify(_name) \ + , .show = _show \ + , .store = _store \ + }; + +#define MODULE_DEVICE_TABLE(type, name) + +/*typedef struct hid_device_array_tag { + unsigned int count; + struct hid_device* hdev[]; +} hid_device_array;*/ + +#define module_hid_driver(hdr) \ +DLL_INTERNAL unsigned int init_##hdr## (struct hid_device** hdevo) { \ + unsigned int numHdevs = 0; \ + struct hid_device* hdev = NULL; \ + openChromaDevice(&hdev, &numHdevs, hdr); \ + *hdevo = hdev; \ + return numHdevs; \ +} + +#endif /* MODULE_H_ */ diff --git a/dependencies/openrazer-win32/linux/random.h b/dependencies/openrazer-win32/linux/random.h new file mode 100644 index 00000000..c32727d9 --- /dev/null +++ b/dependencies/openrazer-win32/linux/random.h @@ -0,0 +1,16 @@ +#ifndef RANDOM_H_ +#define RANDOM_H_ + +static inline void get_random_bytes(void* rand_ptr, unsigned int rand_size) { + char failed = 0; + static HCRYPTPROV prov = 0; + if (prov == 0) { + if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) + failed = 1; + } + if (!failed && !CryptGenRandom(prov, rand_size, (unsigned char*)rand_ptr)) + printf("get_random_bytes failed\n"); +} + + +#endif /* RANDOM_H_ */ diff --git a/dependencies/openrazer-win32/linux/slab.h b/dependencies/openrazer-win32/linux/slab.h new file mode 100644 index 00000000..ec07dd0a --- /dev/null +++ b/dependencies/openrazer-win32/linux/slab.h @@ -0,0 +1,31 @@ +#ifndef SLAB_H_ +#define SLAB_H_ + +typedef enum { + GFP_KERNEL, + GFP_ATOMIC, + __GFP_HIGHMEM, + __GFP_HIGH +} gfp_t; + +static inline void *kzalloc(size_t s, gfp_t gfp) { + void *p = malloc(s); + + memset(p, 0, s); + return p; +} + +inline void *kmemdup(const void *src, size_t len, gfp_t gfp) { + void *p; + p = malloc(len); + if (p) + memcpy(p, src, len); + return p; +} + +static inline void kfree(const void* p) { + free((void*)p); +} + + +#endif /* SLAB_H_ */ diff --git a/dependencies/openrazer-win32/linux/usb/input.h b/dependencies/openrazer-win32/linux/usb/input.h new file mode 100644 index 00000000..29bf6eb8 --- /dev/null +++ b/dependencies/openrazer-win32/linux/usb/input.h @@ -0,0 +1,539 @@ +#ifndef INPUT_H_ +#define INPUT_H_ + +#include +#include + +#define uint unsigned int +#define ulong unsigned long +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int +#define u64 unsigned long + +#define ABS_VOLUME 0x20 + +//input-event-codes.h +#define KEY_RESERVED 0 +#define KEY_ESC 1 +#define KEY_1 2 +#define KEY_2 3 +#define KEY_3 4 +#define KEY_4 5 +#define KEY_5 6 +#define KEY_6 7 +#define KEY_7 8 +#define KEY_8 9 +#define KEY_9 10 +#define KEY_0 11 +#define KEY_MINUS 12 +#define KEY_EQUAL 13 +#define KEY_BACKSPACE 14 +#define KEY_TAB 15 +#define KEY_Q 16 +#define KEY_W 17 +#define KEY_E 18 +#define KEY_R 19 +#define KEY_T 20 +#define KEY_Y 21 +#define KEY_U 22 +#define KEY_I 23 +#define KEY_O 24 +#define KEY_P 25 +#define KEY_LEFTBRACE 26 +#define KEY_RIGHTBRACE 27 +#define KEY_ENTER 28 +#define KEY_LEFTCTRL 29 +#define KEY_A 30 +#define KEY_S 31 +#define KEY_D 32 +#define KEY_F 33 +#define KEY_G 34 +#define KEY_H 35 +#define KEY_J 36 +#define KEY_K 37 +#define KEY_L 38 +#define KEY_SEMICOLON 39 +#define KEY_APOSTROPHE 40 +#define KEY_GRAVE 41 +#define KEY_LEFTSHIFT 42 +#define KEY_BACKSLASH 43 +#define KEY_Z 44 +#define KEY_X 45 +#define KEY_C 46 +#define KEY_V 47 +#define KEY_B 48 +#define KEY_N 49 +#define KEY_M 50 +#define KEY_COMMA 51 +#define KEY_DOT 52 +#define KEY_SLASH 53 +#define KEY_RIGHTSHIFT 54 +#define KEY_KPASTERISK 55 +#define KEY_LEFTALT 56 +#define KEY_SPACE 57 +#define KEY_CAPSLOCK 58 +#define KEY_F1 59 +#define KEY_F2 60 +#define KEY_F3 61 +#define KEY_F4 62 +#define KEY_F5 63 +#define KEY_F6 64 +#define KEY_F7 65 +#define KEY_F8 66 +#define KEY_F9 67 +#define KEY_F10 68 +#define KEY_NUMLOCK 69 +#define KEY_SCROLLLOCK 70 +#define KEY_KP7 71 +#define KEY_KP8 72 +#define KEY_KP9 73 +#define KEY_KPMINUS 74 +#define KEY_KP4 75 +#define KEY_KP5 76 +#define KEY_KP6 77 +#define KEY_KPPLUS 78 +#define KEY_KP1 79 +#define KEY_KP2 80 +#define KEY_KP3 81 +#define KEY_KP0 82 +#define KEY_KPDOT 83 + +#define KEY_ZENKAKUHANKAKU 85 +#define KEY_102ND 86 +#define KEY_F11 87 +#define KEY_F12 88 +#define KEY_RO 89 +#define KEY_KATAKANA 90 +#define KEY_HIRAGANA 91 +#define KEY_HENKAN 92 +#define KEY_KATAKANAHIRAGANA 93 +#define KEY_MUHENKAN 94 +#define KEY_KPJPCOMMA 95 +#define KEY_KPENTER 96 +#define KEY_RIGHTCTRL 97 +#define KEY_KPSLASH 98 +#define KEY_SYSRQ 99 +#define KEY_RIGHTALT 100 +#define KEY_LINEFEED 101 +#define KEY_HOME 102 +#define KEY_UP 103 +#define KEY_PAGEUP 104 +#define KEY_LEFT 105 +#define KEY_RIGHT 106 +#define KEY_END 107 +#define KEY_DOWN 108 +#define KEY_PAGEDOWN 109 +#define KEY_INSERT 110 +#define KEY_DELETE 111 +#define KEY_MACRO 112 +#define KEY_MUTE 113 +#define KEY_VOLUMEDOWN 114 +#define KEY_VOLUMEUP 115 +#define KEY_POWER 116 /* SC System Power Down */ +#define KEY_KPEQUAL 117 +#define KEY_KPPLUSMINUS 118 +#define KEY_PAUSE 119 +#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ + +#define KEY_KPCOMMA 121 +#define KEY_HANGEUL 122 +#define KEY_HANGUEL KEY_HANGEUL +#define KEY_HANJA 123 +#define KEY_YEN 124 +#define KEY_LEFTMETA 125 +#define KEY_RIGHTMETA 126 +#define KEY_COMPOSE 127 + +#define KEY_STOP 128 /* AC Stop */ +#define KEY_AGAIN 129 +#define KEY_PROPS 130 /* AC Properties */ +#define KEY_UNDO 131 /* AC Undo */ +#define KEY_FRONT 132 +#define KEY_COPY 133 /* AC Copy */ +#define KEY_OPEN 134 /* AC Open */ +#define KEY_PASTE 135 /* AC Paste */ +#define KEY_FIND 136 /* AC Search */ +#define KEY_CUT 137 /* AC Cut */ +#define KEY_HELP 138 /* AL Integrated Help Center */ +#define KEY_MENU 139 /* Menu (show menu) */ +#define KEY_CALC 140 /* AL Calculator */ +#define KEY_SETUP 141 +#define KEY_SLEEP 142 /* SC System Sleep */ +#define KEY_WAKEUP 143 /* System Wake Up */ +#define KEY_FILE 144 /* AL Local Machine Browser */ +#define KEY_SENDFILE 145 +#define KEY_DELETEFILE 146 +#define KEY_XFER 147 +#define KEY_PROG1 148 +#define KEY_PROG2 149 +#define KEY_WWW 150 /* AL Internet Browser */ +#define KEY_MSDOS 151 +#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ +#define KEY_SCREENLOCK KEY_COFFEE +#define KEY_DIRECTION 153 +#define KEY_CYCLEWINDOWS 154 +#define KEY_MAIL 155 +#define KEY_BOOKMARKS 156 /* AC Bookmarks */ +#define KEY_COMPUTER 157 +#define KEY_BACK 158 /* AC Back */ +#define KEY_FORWARD 159 /* AC Forward */ +#define KEY_CLOSECD 160 +#define KEY_EJECTCD 161 +#define KEY_EJECTCLOSECD 162 +#define KEY_NEXTSONG 163 +#define KEY_PLAYPAUSE 164 +#define KEY_PREVIOUSSONG 165 +#define KEY_STOPCD 166 +#define KEY_RECORD 167 +#define KEY_REWIND 168 +#define KEY_PHONE 169 /* Media Select Telephone */ +#define KEY_ISO 170 +#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ +#define KEY_HOMEPAGE 172 /* AC Home */ +#define KEY_REFRESH 173 /* AC Refresh */ +#define KEY_EXIT 174 /* AC Exit */ +#define KEY_MOVE 175 +#define KEY_EDIT 176 +#define KEY_SCROLLUP 177 +#define KEY_SCROLLDOWN 178 +#define KEY_KPLEFTPAREN 179 +#define KEY_KPRIGHTPAREN 180 +#define KEY_NEW 181 /* AC New */ +#define KEY_REDO 182 /* AC Redo/Repeat */ + +#define KEY_F13 183 +#define KEY_F14 184 +#define KEY_F15 185 +#define KEY_F16 186 +#define KEY_F17 187 +#define KEY_F18 188 +#define KEY_F19 189 +#define KEY_F20 190 +#define KEY_F21 191 +#define KEY_F22 192 +#define KEY_F23 193 +#define KEY_F24 194 + +#define KEY_PLAYCD 200 +#define KEY_PAUSECD 201 +#define KEY_PROG3 202 +#define KEY_PROG4 203 +#define KEY_DASHBOARD 204 /* AL Dashboard */ +#define KEY_SUSPEND 205 +#define KEY_CLOSE 206 /* AC Close */ +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 /* AC Print */ +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 /* AL Checkbook/Finance */ +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 /* AC Cancel */ +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 +#define KEY_MEDIA 226 + +#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video + outputs (Monitor/LCD/TV-out/etc) */ +#define KEY_KBDILLUMTOGGLE 228 +#define KEY_KBDILLUMDOWN 229 +#define KEY_KBDILLUMUP 230 + +#define KEY_SEND 231 /* AC Send */ +#define KEY_REPLY 232 /* AC Reply */ +#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ +#define KEY_SAVE 234 /* AC Save */ +#define KEY_DOCUMENTS 235 + +#define KEY_BATTERY 236 + +#define KEY_BLUETOOTH 237 +#define KEY_WLAN 238 +#define KEY_UWB 239 + +#define KEY_UNKNOWN 240 + +#define KEY_VIDEO_NEXT 241 /* drive next video source */ +#define KEY_VIDEO_PREV 242 /* drive previous video source */ +#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ +#define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ +#define KEY_DISPLAY_OFF 245 /* display device to off state */ + +#define KEY_WIMAX 246 + +/* Range 248 - 255 is reserved for special needs of AT keyboard driver */ + +#define BTN_MISC 0x100 +#define BTN_0 0x100 +#define BTN_1 0x101 +#define BTN_2 0x102 +#define BTN_3 0x103 +#define BTN_4 0x104 +#define BTN_5 0x105 +#define BTN_6 0x106 +#define BTN_7 0x107 +#define BTN_8 0x108 +#define BTN_9 0x109 + +#define BTN_MOUSE 0x110 +#define BTN_LEFT 0x110 +#define BTN_RIGHT 0x111 +#define BTN_MIDDLE 0x112 +#define BTN_SIDE 0x113 +#define BTN_EXTRA 0x114 +#define BTN_FORWARD 0x115 +#define BTN_BACK 0x116 +#define BTN_TASK 0x117 + +#define BTN_JOYSTICK 0x120 +#define BTN_TRIGGER 0x120 +#define BTN_THUMB 0x121 +#define BTN_THUMB2 0x122 +#define BTN_TOP 0x123 +#define BTN_TOP2 0x124 +#define BTN_PINKIE 0x125 +#define BTN_BASE 0x126 +#define BTN_BASE2 0x127 +#define BTN_BASE3 0x128 +#define BTN_BASE4 0x129 +#define BTN_BASE5 0x12a +#define BTN_BASE6 0x12b +#define BTN_DEAD 0x12f + +#define BTN_GAMEPAD 0x130 +#define BTN_A 0x130 +#define BTN_B 0x131 +#define BTN_C 0x132 +#define BTN_X 0x133 +#define BTN_Y 0x134 +#define BTN_Z 0x135 +#define BTN_TL 0x136 +#define BTN_TR 0x137 +#define BTN_TL2 0x138 +#define BTN_TR2 0x139 +#define BTN_SELECT 0x13a +#define BTN_START 0x13b +#define BTN_MODE 0x13c +#define BTN_THUMBL 0x13d +#define BTN_THUMBR 0x13e + +#define BTN_DIGI 0x140 +#define BTN_TOOL_PEN 0x140 +#define BTN_TOOL_RUBBER 0x141 +#define BTN_TOOL_BRUSH 0x142 +#define BTN_TOOL_PENCIL 0x143 +#define BTN_TOOL_AIRBRUSH 0x144 +#define BTN_TOOL_FINGER 0x145 +#define BTN_TOOL_MOUSE 0x146 +#define BTN_TOOL_LENS 0x147 +#define BTN_TOUCH 0x14a +#define BTN_STYLUS 0x14b +#define BTN_STYLUS2 0x14c +#define BTN_TOOL_DOUBLETAP 0x14d +#define BTN_TOOL_TRIPLETAP 0x14e +#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ + +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + +#define KEY_OK 0x160 +#define KEY_SELECT 0x161 +#define KEY_GOTO 0x162 +#define KEY_CLEAR 0x163 +#define KEY_POWER2 0x164 +#define KEY_OPTION 0x165 +#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ +#define KEY_TIME 0x167 +#define KEY_VENDOR 0x168 +#define KEY_ARCHIVE 0x169 +#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ +#define KEY_CHANNEL 0x16b +#define KEY_FAVORITES 0x16c +#define KEY_EPG 0x16d +#define KEY_PVR 0x16e /* Media Select Home */ +#define KEY_MHP 0x16f +#define KEY_LANGUAGE 0x170 +#define KEY_TITLE 0x171 +#define KEY_SUBTITLE 0x172 +#define KEY_ANGLE 0x173 +#define KEY_ZOOM 0x174 +#define KEY_MODE 0x175 +#define KEY_KEYBOARD 0x176 +#define KEY_SCREEN 0x177 +#define KEY_PC 0x178 /* Media Select Computer */ +#define KEY_TV 0x179 /* Media Select TV */ +#define KEY_TV2 0x17a /* Media Select Cable */ +#define KEY_VCR 0x17b /* Media Select VCR */ +#define KEY_VCR2 0x17c /* VCR Plus */ +#define KEY_SAT 0x17d /* Media Select Satellite */ +#define KEY_SAT2 0x17e +#define KEY_CD 0x17f /* Media Select CD */ +#define KEY_TAPE 0x180 /* Media Select Tape */ +#define KEY_RADIO 0x181 +#define KEY_TUNER 0x182 /* Media Select Tuner */ +#define KEY_PLAYER 0x183 +#define KEY_TEXT 0x184 +#define KEY_DVD 0x185 /* Media Select DVD */ +#define KEY_AUX 0x186 +#define KEY_MP3 0x187 +#define KEY_AUDIO 0x188 +#define KEY_VIDEO 0x189 +#define KEY_DIRECTORY 0x18a +#define KEY_LIST 0x18b +#define KEY_MEMO 0x18c /* Media Select Messages */ +#define KEY_CALENDAR 0x18d +#define KEY_RED 0x18e +#define KEY_GREEN 0x18f +#define KEY_YELLOW 0x190 +#define KEY_BLUE 0x191 +#define KEY_CHANNELUP 0x192 /* Channel Increment */ +#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ +#define KEY_FIRST 0x194 +#define KEY_LAST 0x195 /* Recall Last */ +#define KEY_AB 0x196 +#define KEY_NEXT 0x197 +#define KEY_RESTART 0x198 +#define KEY_SLOW 0x199 +#define KEY_SHUFFLE 0x19a +#define KEY_BREAK 0x19b +#define KEY_PREVIOUS 0x19c +#define KEY_DIGITS 0x19d +#define KEY_TEEN 0x19e +#define KEY_TWEN 0x19f +#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ +#define KEY_GAMES 0x1a1 /* Media Select Games */ +#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ +#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ +#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ +#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ +#define KEY_EDITOR 0x1a6 /* AL Text Editor */ +#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ +#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ +#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ +#define KEY_DATABASE 0x1aa /* AL Database App */ +#define KEY_NEWS 0x1ab /* AL Newsreader */ +#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ +#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ +#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ +#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ +#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ +#define KEY_LOGOFF 0x1b1 /* AL Logoff */ + +#define KEY_DOLLAR 0x1b2 +#define KEY_EURO 0x1b3 + +#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ +#define KEY_FRAMEFORWARD 0x1b5 +#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ +#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ + +#define KEY_DEL_EOL 0x1c0 +#define KEY_DEL_EOS 0x1c1 +#define KEY_INS_LINE 0x1c2 +#define KEY_DEL_LINE 0x1c3 + +#define KEY_FN 0x1d0 +#define KEY_FN_ESC 0x1d1 +#define KEY_FN_F1 0x1d2 +#define KEY_FN_F2 0x1d3 +#define KEY_FN_F3 0x1d4 +#define KEY_FN_F4 0x1d5 +#define KEY_FN_F5 0x1d6 +#define KEY_FN_F6 0x1d7 +#define KEY_FN_F7 0x1d8 +#define KEY_FN_F8 0x1d9 +#define KEY_FN_F9 0x1da +#define KEY_FN_F10 0x1db +#define KEY_FN_F11 0x1dc +#define KEY_FN_F12 0x1dd +#define KEY_FN_1 0x1de +#define KEY_FN_2 0x1df +#define KEY_FN_D 0x1e0 +#define KEY_FN_E 0x1e1 +#define KEY_FN_F 0x1e2 +#define KEY_FN_S 0x1e3 +#define KEY_FN_B 0x1e4 + +#define KEY_BRL_DOT1 0x1f1 +#define KEY_BRL_DOT2 0x1f2 +#define KEY_BRL_DOT3 0x1f3 +#define KEY_BRL_DOT4 0x1f4 +#define KEY_BRL_DOT5 0x1f5 +#define KEY_BRL_DOT6 0x1f6 +#define KEY_BRL_DOT7 0x1f7 +#define KEY_BRL_DOT8 0x1f8 +#define KEY_BRL_DOT9 0x1f9 +#define KEY_BRL_DOT10 0x1fa + +#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ +#define KEY_NUMERIC_1 0x201 /* and other keypads */ +#define KEY_NUMERIC_2 0x202 +#define KEY_NUMERIC_3 0x203 +#define KEY_NUMERIC_4 0x204 +#define KEY_NUMERIC_5 0x205 +#define KEY_NUMERIC_6 0x206 +#define KEY_NUMERIC_7 0x207 +#define KEY_NUMERIC_8 0x208 +#define KEY_NUMERIC_9 0x209 +#define KEY_NUMERIC_STAR 0x20a +#define KEY_NUMERIC_POUND 0x20b + +/* We avoid low common keys in module aliases so they don't get huge. */ +#define KEY_MIN_INTERESTING KEY_MUTE +#define KEY_MAX 0x2ff +#define KEY_CNT (KEY_MAX+1) + +#define EV_SYN 0x00 +#define EV_KEY 0x01 +#define EV_REL 0x02 +#define EV_ABS 0x03 +#define EV_MSC 0x04 +#define EV_SW 0x05 +#define EV_LED 0x11 +#define EV_SND 0x12 +#define EV_REP 0x14 +#define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 +#define EV_MAX 0x1f +#define EV_CNT (EV_MAX+1) + +#define SYN_REPORT 0 + +#define BITS_PER_BYTE 8 +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) +#define DECLARE_BITMAP(name,bits) unsigned long name[BITS_TO_LONGS(bits)] + +struct input_dev { + const char *name; + const char *phys; + unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; + unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; +}; + +static inline void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { + printf("input_event\n"); +} + +static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) { + input_event(dev, EV_KEY, code, value); +} + +static inline void input_sync(struct input_dev *dev) { + input_event(dev, EV_SYN, SYN_REPORT, 0); +} + + +#endif /* INPUT_H_ */