From 4b94d2adb874c9f46cf0ca1e6ce1dd8262c0f004 Mon Sep 17 00:00:00 2001 From: vhaudiquet Date: Tue, 26 Sep 2023 22:13:10 +0200 Subject: [PATCH] driver: g-wolves full refactor --- drivers/g-wolves/Makefile | 17 ++-- drivers/g-wolves/{htx => }/README.md | 7 +- drivers/g-wolves/devices/gwolves-hts_plus.png | Bin 0 -> 34596 bytes .../htx_0.png => devices/gwolves-htx.png} | Bin drivers/g-wolves/devices/hts_plus.h | 11 +++ drivers/g-wolves/devices/htx.h | 11 +++ drivers/g-wolves/{htx/htx.c => g-wolves.c} | 47 +++++++---- drivers/g-wolves/{htx/htx.h => g-wolves.h} | 74 +++++++++--------- drivers/g-wolves/htx/Makefile | 12 --- 9 files changed, 108 insertions(+), 71 deletions(-) rename drivers/g-wolves/{htx => }/README.md (76%) create mode 100644 drivers/g-wolves/devices/gwolves-hts_plus.png rename drivers/g-wolves/{htx/htx_0.png => devices/gwolves-htx.png} (100%) create mode 100644 drivers/g-wolves/devices/hts_plus.h create mode 100644 drivers/g-wolves/devices/htx.h rename drivers/g-wolves/{htx/htx.c => g-wolves.c} (53%) rename drivers/g-wolves/{htx/htx.h => g-wolves.h} (64%) delete mode 100644 drivers/g-wolves/htx/Makefile diff --git a/drivers/g-wolves/Makefile b/drivers/g-wolves/Makefile index 61533ed..a6adab1 100644 --- a/drivers/g-wolves/Makefile +++ b/drivers/g-wolves/Makefile @@ -1,7 +1,14 @@ -SUBDIRS := $(wildcard */.) +CC=gcc +CFLAGS=$(shell pkg-config --cflags libusb-1.0) -O3 -Wall -shared +LDFLAGS=$(shell pkg-config --libs libusb-1.0) -all: $(SUBDIRS) -$(SUBDIRS): - $(MAKE) -C $@ +ASSETS=$(shell find devices/ -name '*.png') +FINAL_ASSETS=$(BUILD_DIR)/drivers/assets/gwolves-htx.png +BUILD_DIR=../../build/ -.PHONY: all $(SUBDIRS) +all: $(BUILD_DIR)/drivers/g-wolves.so + +$(BUILD_DIR)/drivers/g-wolves.so: g-wolves.c | $(BUILD_DIR)/drivers/ + $(CC) $(CFLAGS) -o $@ $^ +$(BUILD_DIR)/drivers/assets/%.png: devices/%.png | $(BUILD_DIR)/drivers/assets + cp $^ $@ diff --git a/drivers/g-wolves/htx/README.md b/drivers/g-wolves/README.md similarity index 76% rename from drivers/g-wolves/htx/README.md rename to drivers/g-wolves/README.md index 06a5f0d..162c36c 100644 --- a/drivers/g-wolves/htx/README.md +++ b/drivers/g-wolves/README.md @@ -1,11 +1,15 @@ -# G-Wolves HTX driver +# G-Wolves driver G-Wolves USB Vendor ID: 0x33e4 Product IDs: +- G-Wolves HTS+ 4K Wired: 0x5408 +- G-Wolves HTS+ 4K Wireless: 0x5407 - G-Wolves HTX 4K Wired: 0x5708 - G-Wolves HTX 4K Wireless: 0x5707 +All of the G-Wolves devices use the same protocol. + ## Features The device works using USB HID feature reports. @@ -15,4 +19,3 @@ The SET_REPORT command can be used, setting a command byte to the desired comman to get an output (for example, you set report with COMMAND_DPI_SETTINGS, and then get report to obtain a DPI_SETTINGS_REPORT structure). - diff --git a/drivers/g-wolves/devices/gwolves-hts_plus.png b/drivers/g-wolves/devices/gwolves-hts_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..0a0de554b4f61450f22f55774c152da2cf431fa0 GIT binary patch literal 34596 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%0D}KXn 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 PTB|ItE>|IA9`yeJn%n-x literal 0 HcmV?d00001 diff --git a/drivers/g-wolves/htx/htx_0.png b/drivers/g-wolves/devices/gwolves-htx.png similarity index 100% rename from drivers/g-wolves/htx/htx_0.png rename to drivers/g-wolves/devices/gwolves-htx.png diff --git a/drivers/g-wolves/devices/hts_plus.h b/drivers/g-wolves/devices/hts_plus.h new file mode 100644 index 0000000..a70cf05 --- /dev/null +++ b/drivers/g-wolves/devices/hts_plus.h @@ -0,0 +1,11 @@ +#ifndef HTS_PLUS_H +#define HTS_PLUS_H + +#define HTS_PLUS_4K_PRODUCT_ID_WIRED 0x5408 +#define HTS_PLUS_4K_PRODUCT_ID_WIRELESS 0x5407 +#define HTS_PLUS_4K_PRODUCT_NAME "HTS+ 4K" + +#define HTS_DPI_MAX_VALUE 26000 +#define HTS_DPI_MAX_LEVEL_COUNT 5 + +#endif diff --git a/drivers/g-wolves/devices/htx.h b/drivers/g-wolves/devices/htx.h new file mode 100644 index 0000000..de92a57 --- /dev/null +++ b/drivers/g-wolves/devices/htx.h @@ -0,0 +1,11 @@ +#ifndef HTX_H +#define HTX_H + +#define HTX_4K_PRODUCT_ID_WIRED 0x5708 +#define HTX_4K_PRODUCT_ID_WIRELESS 0x5707 +#define HTX_4K_PRODUCT_NAME "HTX 4K" + +#define HTX_DPI_MAX_VALUE 26000 +#define HTX_DPI_MAX_LEVEL_COUNT 5 + +#endif diff --git a/drivers/g-wolves/htx/htx.c b/drivers/g-wolves/g-wolves.c similarity index 53% rename from drivers/g-wolves/htx/htx.c rename to drivers/g-wolves/g-wolves.c index 7dd108a..372e3d2 100644 --- a/drivers/g-wolves/htx/htx.c +++ b/drivers/g-wolves/g-wolves.c @@ -1,19 +1,19 @@ -#include "htx.h" +#include "g-wolves.h" -static int htx_send_command(libusb_device_handle* hand, uint8_t command, uint8_t size, void* report, bool wireless) +static int send_command(libusb_device_handle* hand, uint8_t command, uint8_t size, void* report, bool wireless) { if(wireless) { // If wireless, ask receiver for mouse command first - struct HTX_REPORT_WIRELESS w_report = {0}; - int res = htx_send_command(hand, COMMAND_WIRELESS_MOUSE, REPORT_WIRELESS_MOUSE_SIZE, &w_report, false); + struct REPORT_WIRELESS w_report = {0}; + int res = send_command(hand, COMMAND_WIRELESS_MOUSE, REPORT_WIRELESS_MOUSE_SIZE, &w_report, false); if(res <= 0) return res; if(!w_report.mouse_connected) return -1; } - htx_report_header_t* head = report; + report_header_t* head = report; head->report_size = size; head->command = command; if(wireless) @@ -51,12 +51,28 @@ uint32_t driver_getkey(void) static int count = 0; count++; - if(count == 1) - return (DEVICE_VENDOR_ID << 16) | DEVICE_PRODUCT_ID_WIRED; - else if(count == 2) - return (DEVICE_VENDOR_ID << 16) | DEVICE_PRODUCT_ID_WIRELESS; + // Register ALL G-Wolves compatible devices + uint16_t id = 0; + switch(count) + { + case 1: + id = HTX_4K_PRODUCT_ID_WIRED; + break; + case 2: + id = HTX_4K_PRODUCT_ID_WIRELESS; + break; + case 3: + id = HTS_PLUS_4K_PRODUCT_ID_WIRED; + break; + case 4: + id = HTS_PLUS_4K_PRODUCT_ID_WIRELESS; + break; + default: + id = 0; + } - return 0; + if(id == 0) return 0; + return (VENDOR_ID << 16) | id; } char* driver_get_name(void* handle) @@ -68,11 +84,14 @@ char* driver_get_name(void* handle) switch(desc.idProduct) { - case 0x5708: - case 0x5707: - return "HTX 4K"; + case HTX_4K_PRODUCT_ID_WIRED: + case HTX_4K_PRODUCT_ID_WIRELESS: + return HTX_4K_PRODUCT_NAME; + case HTS_PLUS_4K_PRODUCT_ID_WIRED: + case HTS_PLUS_4K_PRODUCT_ID_WIRELESS: + return HTS_PLUS_4K_PRODUCT_NAME; default: - return "HTX ACE"; + return "Unknown G-Wolves mice"; } } diff --git a/drivers/g-wolves/htx/htx.h b/drivers/g-wolves/g-wolves.h similarity index 64% rename from drivers/g-wolves/htx/htx.h rename to drivers/g-wolves/g-wolves.h index f63951a..520fc57 100644 --- a/drivers/g-wolves/htx/htx.h +++ b/drivers/g-wolves/g-wolves.h @@ -7,12 +7,10 @@ #include #include -#define DEVICE_VENDOR_ID 0x33e4 -#define DEVICE_PRODUCT_ID_WIRED 0x5708 -#define DEVICE_PRODUCT_ID_WIRELESS 0x5707 +#include "devices/htx.h" +#include "devices/hts_plus.h" -#define DPI_MAX_VALUE 26000 -#define DPI_MAX_LEVEL_COUNT 5 +#define VENDOR_ID 0x33e4 #define REPORT_MAX_SIZE 0x40 // 64 Bytes @@ -40,7 +38,7 @@ #define COMMAND_BATTERY 0x8F #define COMMAND_WIRELESS_MOUSE 0x90 // -> send the next report to mouse, checking if mouse is connected -typedef struct HTX_DPI_LEVEL +typedef struct DPI_LEVEL { uint8_t dpi_x_high; uint8_t dpi_x_low; @@ -52,51 +50,51 @@ typedef struct HTX_DPI_LEVEL uint8_t led_r; uint8_t led_g; uint8_t led_b; -} __attribute__((packed)) htx_dpi_level_t; +} __attribute__((packed)) dpi_level_t; -typedef struct HTX_REPORT_HEADER +typedef struct REPORT_HEADER { uint8_t a1; // 0xa1: request_type on receive, 0x00 on set uint8_t report_size; // report size, after header uint8_t command; // COMMAND uint8_t wireless; // 0 on wired, 1 on wireless -} __attribute__((packed)) htx_report_header_t; +} __attribute__((packed)) report_header_t; -struct HTX_REPORT_DPI_SETTINGS +struct REPORT_DPI_SETTINGS { - htx_report_header_t header; + report_header_t header; uint8_t level_current; // current dpi level uint8_t level_count; // count of dpi levels - htx_dpi_level_t levels[5]; + dpi_level_t levels[5]; uint8_t zeros[23]; } __attribute__((packed)); -struct HTX_REPORT_UNKNOWN_0 +struct REPORT_UNKNOWN_0 { - htx_report_header_t header; + report_header_t header; uint8_t value0; uint8_t value1; - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 2]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 2]; } __attribute__((packed)); -struct HTX_REPORT_UNKNOWN_1 +struct REPORT_UNKNOWN_1 { - htx_report_header_t header; + report_header_t header; uint8_t value0; uint8_t value1; - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 2]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 2]; } __attribute__((packed)); -struct HTX_REPORT_CLICK_DEBOUNCE_SETTINGS +struct REPORT_CLICK_DEBOUNCE_SETTINGS { - htx_report_header_t header; + report_header_t header; // A = 0ms B = 1 ms C = 2 ms D = 3 ms E = 4 ms uint8_t debounce_preset; // 0x00 = A, 0x01 = B, 0x02 = C, 0x03 = D, 0x04 = E, AUTO = 0x00 @@ -107,38 +105,38 @@ struct HTX_REPORT_CLICK_DEBOUNCE_SETTINGS uint8_t zeros[REPORT_MAX_SIZE - 8]; } __attribute__((packed)); -struct HTX_REPORT_LIFT_OFF +struct REPORT_LIFT_OFF { - htx_report_header_t header; + report_header_t header; // 1 = Low, 2 = High uint8_t lift_off; - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 1]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 1]; } __attribute__((packed)); -struct HTX_REPORT_ANGLE_SNAP +struct REPORT_ANGLE_SNAP { - htx_report_header_t header; + report_header_t header; // 0 = disabled, 1 = enabled uint8_t angle_snap; - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 1]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 1]; } __attribute__((packed)); -struct HTX_REPORT_MOTION_SYNC +struct REPORT_MOTION_SYNC { - htx_report_header_t header; + report_header_t header; uint8_t motion_sync; - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 1]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 1]; } __attribute__((packed)); -struct HTX_REPORT_UNKNOWN_6 +struct REPORT_UNKNOWN_6 { - htx_report_header_t header; + report_header_t header; uint8_t value0; uint8_t value1; @@ -147,23 +145,23 @@ struct HTX_REPORT_UNKNOWN_6 uint8_t value4; uint8_t value5; - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 5]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 5]; } __attribute__((packed)); -struct HTX_REPORT_BATTERY +struct REPORT_BATTERY { - htx_report_header_t header; + report_header_t header; uint8_t battery_status; // 0 : not charging, 1 : charging uint8_t battery_level; // in % - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 2]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 2]; } __attribute__((packed)); -struct HTX_REPORT_WIRELESS +struct REPORT_WIRELESS { - htx_report_header_t header; + report_header_t header; uint8_t mouse_connected; // 0 if disconnected, else 1 - uint8_t zeros[REPORT_MAX_SIZE - sizeof(htx_report_header_t) - 1]; + uint8_t zeros[REPORT_MAX_SIZE - sizeof(report_header_t) - 1]; } __attribute__((packed)); diff --git a/drivers/g-wolves/htx/Makefile b/drivers/g-wolves/htx/Makefile deleted file mode 100644 index d879f80..0000000 --- a/drivers/g-wolves/htx/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -CC=gcc -CFLAGS=$(shell pkg-config --cflags libusb-1.0) -O3 -Wall -shared -LDFLAGS=$(shell pkg-config --libs libusb-1.0) - -BUILD_DIR=../../../build/ - -all: $(BUILD_DIR)/drivers/gwolves-htx.so - -$(BUILD_DIR)/drivers/gwolves-htx.so: htx.c | $(BUILD_DIR)/drivers/ - $(CC) $(CFLAGS) -o $@ $^ -$(BUILD_DIR)/drivers/assets/gwolves-htx.png: htx_0.png | $(BUILD_DIR)/drivers/assets - cp $^ $@