Skip to content

Add support for the Holtek A09F RGB mouse, including drivers and ligh…#93

Open
juampe wants to merge 1 commit into
CalcProgrammer1:masterfrom
juampe:holtek-void-support
Open

Add support for the Holtek A09F RGB mouse, including drivers and ligh…#93
juampe wants to merge 1 commit into
CalcProgrammer1:masterfrom
juampe:holtek-void-support

Conversation

@juampe
Copy link
Copy Markdown

@juampe juampe commented May 23, 2026

Summary

This PR adds support for the Phoenix Void RGB gaming mouse (Holtek A09F chip, VID 0x04D9 / PID 0xA09F, also sold as E-Signal LUOM G10). The driver was implemented from scratch by reverse-engineering USB captures from the device.

New Files

Controllers/HoltekController/HoltekA09FController/HoltekA09FController.h

Low-level protocol driver header. Defines:

  • All 12 mode selector byte-arrays (Off, Standard, Breathing, Neon, Wave, Key Reaction, Trailing, Drag, Slide, Yo-Yo, Marbles, Flying Star)
  • Mode value enum (HOLTEK_A09F_MODE_VALUE_*)
  • HoltekA09FController class: constructor/destructor, SetMode(), SetDPIColors(), IsReady()

Controllers/HoltekController/HoltekA09FController/HoltekA09FController.cpp

Low-level driver implementation:

  • Opens the device via both HIDAPI (EP0 control transfers) and libusb (interrupt transfers on interface 2, endpoint 0x03)
  • Detaches any kernel driver from interface 2 and claims it exclusively; gracefully handles duplicate HID collection registrations via IsReady()
  • SendSelector(): sends an 8-byte EP0 Feature SET_REPORT (bmRequestType=0x21, bRequest=0x09, wValue=0x0300, wIndex=2) to prime each transaction
  • SendBlock(): sends a 32-byte payload via libusb_interrupt_transfer
  • SendApplySequence(): executes the full 6-transaction protocol (TX0–TX5) that configures mode + DPI colours and persists the setting to device flash
  • SetMode(): selects the mode selector, handles the Off mode (standard selector + zeroed B1)
  • SetDPIColors(): packs up to 8 RGB triplets into the B1 block and re-sends the apply sequence

Controllers/HoltekController/HoltekA09FController/RGBController_HoltekA09F.h / .cpp

OpenRGB integration layer:

  • Device type: DEVICE_TYPE_MOUSE, vendor "Holtek"
  • 12 modes, all flagged MODE_FLAG_AUTOMATIC_SAVE (device persists settings on every apply — no separate save command exists in the protocol)
  • Modes with per-LED colour support use MODE_FLAG_HAS_PER_LED_COLOR | MODE_COLORS_PER_LED
  • One zone: "DPI Stages" (linear, 8 LEDs — one per DPI stage), each LED individually addressable
  • DeviceUpdateLEDs()SetDPIColors(); DeviceUpdateMode()SetMode()

Modified Files

Controllers/HoltekController/HoltekControllerDetect.cpp

  • Added #include directives for the new controller pair
  • Added #define HOLTEK_A09F_PID 0xA09F
  • Added DetectHoltekA09FControllers(): opens the HID path, constructs HoltekA09FController, checks IsReady() to skip duplicate collection entries, and registers the RGBController_HoltekA09F
  • Added REGISTER_HID_DETECTOR_I("Phoenix Void", DetectHoltekA09FControllers, HOLTEK_VID, HOLTEK_A09F_PID, 1) — interface 1, no usage-page filter (the device exposes the relevant interface there)

Protocol Details

The Holtek A09F firmware accepts configuration via 6 sequential transactions. Each transaction is gated by one or more 8-byte EP0 selector writes that prime the firmware state machine, followed by one or two 32-byte interrupt OUT payloads on endpoint 0x03:

TX0: SEL_C1 … SEL_C6  →  SEL_MODE  →  SEL_C8  →  B0  (32 bytes, fixed header)
TX1: SEL_B1                           →  B1   (32 bytes: 8 × RGB DPI colours)
TX2: SEL_B2                           →  B2   (32 bytes: DPI values)
TX3: SEL_B3                           →  B3 + B4
TX4: SEL_B5                           →  B5 + B4
TX5: SEL_B7                           →  B7   (cleanup / off marker)

The mode is encoded entirely in the selector at position 7 of TX0. All data blocks except B1 are fixed across all modes and colour configurations. Settings survive USB reconnection, OS reboots, and KVM switches.

Checklist

  • Compiles cleanly with no errors or warnings
  • Static mode tested: ./openrgb --noautoconnect --device N --mode Static --color FF0000 — colour applied and persists after reboot
  • All 12 modes selectable from the GUI
  • Off mode correctly turns off all LEDs
  • Duplicate HID collection entries handled (no double-registration)
  • No debug output, no temporary code
  • No new external dependencies (libusb already used by OpenRGB)

Testing Notes

Tested on:

  • Linux 7.0
  • Device: Phoenix Void RGB gaming mouse / E-Signal LUOM G10 — VID 0x04D9 / PID 0xA09F
  • Interface 1 via HIDAPI + interface 2 via libusb
  • Modes confirmed working: Off, Static, Breathing, Neon, Wave, Key Reaction, Trailing, Drag, Slide, Yo-Yo, Marbles, Flying Star
  • Setting persists across: USB reconnect, reboot, KVM switch

Breaking Changes

None. All existing Holtek detectors (A070, A1FA) are unchanged. The new detector is additive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant