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 12be370b5..35a99f822 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 d28084688..6d066d41b 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 99524cbff..02fd9fd60 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 000000000..93d2250f4 --- /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 000000000..5a5731c9b --- /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 000000000..1721f8bbb --- /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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 +#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 000000000..090c4b0f6 --- /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 000000000..70b977753 --- /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 000000000..96e14156f --- /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 000000000..c32727d92 --- /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 000000000..ec07dd0a0 --- /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 000000000..29bf6eb87 --- /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_ */