Feat/lamparray fa608wv#147
Conversation
- Add HidrawDevinfo struct (8 bytes: __u32 bustype, __s16 vendor, __s16 product) matching the kernel struct exactly. - Add HIDIOCGRAWINFO / HIDIOCSFEATURE / HIDIOCGFEATURE ioctl number helpers. HIDIOCGRAWINFO uses size=8 (0x80084803), matching the kernel. - Add HidRaw::raw_info() -> HidrawDevinfo (reads VID/PID directly from hidraw, disambiguating LampArray-capable devices on I2C-HID where USB ATTRS are absent). - Add HidRaw::set_feature_report() and get_feature_report() for HID Feature reports (used by LampArray Control/Range/Attributes reports). - Add HidRaw::from_i2c_device() constructor that opens /dev/hidrawN in R/W with O_NONBLOCK. O_NONBLOCK defends against the i2c-hid kernel driver blocking during daemon init on some models (observed on ASUS TUF A16 FA608WV). - Add libc = "0.2" direct dependency (was transitively pulled in through udev already). All existing HidRaw call sites are unchanged. This is purely additive.
New async factory method on DeviceHandle that: 1. Reads VID/PID via HIDIOCGRAWINFO (removes any ambiguity from sysfs string formatting). 2. Whitelists ASUS vendor (0x0B05) and PID 0x19B6 (LampArray-capable keyboards on I2C-HID, first confirmed on ASUS TUF A16 FA608WV ITE5570). 3. Builds an Aura with is_lamparray=true and backlight=None (LampArray devices do not expose the legacy asus::kbd_backlight sysfs node). 4. Registers as AuraDeviceType::LaptopKeyboard2021 (which asusctl already maps for PID 0x19B6). The PID whitelist is intentionally narrow for the first PR. Adding more PIDs as users confirm support is a one-line change.
The existing init_hid_devices filters HID devices by USB parent only, silently skipping any device on I2C-HID. On ASUS 2024+ laptops the keyboard backlight controller is often an ITE chip on I2C-HID exposing the standard Microsoft HID LampArray usage page, and was never even probed. Changes: - When the USB-side path produces zero devices, fall through to a new init_i2c_hid_device helper. - init_i2c_hid_device walks the udev parent chain for the HID_ID property (format BUS:VENDOR:PRODUCT), parses VID/PID as numeric (BUG: previous drafts compared padded 8-char hex string against '0b05' and always failed), filters ASUS vendor, and opens the hidraw endpoint via HidRaw::from_i2c_device. - On success, calls DeviceHandle::maybe_lamparray and registers the device on the zbus server at /xyz/ljones/aura/lamparray_<pid>. - Every step logs at INFO level (Step1..Step6) with clear error reporting to make troubleshooting on new hardware straightforward. USB legacy path is entirely unchanged.
Adds the write side of the LampArray support. aura_laptop::mod.rs: - Add is_lamparray: bool field to Aura struct. - Add lamparray_push_rgb_i() helper: disables autonomous mode (HIDIOCSFEATURE [0x46, 0x00]) then sends LampRangeUpdate (HIDIOCSFEATURE [0x45, 0x01, LampIdStart(2 LE), LampIdEnd(2 LE), R, G, B, I]) covering the whole LampCount range. - Add lamparray_write_effect(&self, mode: &AuraEffect) — non-locking variant used when the caller does not hold the config lock. Uses try_lock with a Med intensity fallback to avoid deadlock. - Add lamparray_write_effect_locked(&self, config: &AuraConfig, mode: &AuraEffect) — called from write_current_config_mode which already owns the config lock, avoiding the double-lock deadlock. - Add lamparray_set_brightness() and lamparray_set_aura_power() with the same lock-safe pattern. - write_effect_and_apply short-circuits into the LampArray branch when is_lamparray is true. aura_laptop::trait_impls.rs: - Route set_led_mode / set_led_mode_data through lamparray_write_effect_locked when is_lamparray is true. - Skip the redundant set_brightness call for LampArray devices (brightness is encoded in the intensity byte of range update; the legacy path did a separate call that on LampArray fell back to white and overwrote the color). - Every zbus method that previously returned MissingFunction( "No LED backlight control available") when backlight was None now early-returns into the LampArray branch when is_lamparray is true. USB legacy path unchanged (branches are gated on self.is_lamparray).
With Type=dbus and TimeoutSec=10, systemd considers the service ready only when the name xyz.ljones.Asusd appears on the bus. If DeviceManager::new blocks for any reason (a slow HID init on a flaky controller, an initial discovery over many hidraw endpoints), the name never gets registered in time and systemd kills the process. Fix: call server.request_name(DBUS_NAME) BEFORE DeviceManager::new, and wrap DeviceManager::new in a non-fatal match (errors logged, but the daemon keeps running so users can still get platform / fancurves / armoury interfaces even if HID discovery fails). The zbus server accepts incoming method calls after request_name regardless of whether DeviceManager has finished.
|
Do you know what did you actually copy/pasted and how it works, without the need of an AI? I need to know because what you posted is what you will need to maintain: you can't expect to leave the burden to Nero and others. On top of that you have copy/pasted LITERALLY EVERYTHING. |
|
I'm not saying not to do so or not to use an AI, just that you MUST know how the code you have posted work |
|
Hi @scardracs, fair pushback and thanks for pressing on this. Let me be upfront and then walk through what I actually understand. Yes, I used AI (Claude Opus 4.7) to write and iterate on this patch. I'm not going to hide it. What I want to explain is the loop I actually ran, because it wasn't "prompt in, code out": every iteration was tested against my real hardware, and every commit I made came out of a specific bug I saw with my own eyes in journal logs. Why I got into this in the first placeMy laptop is an ASUS TUF Gaming A16 FA608WV in dual boot: Pop!_OS 24.04 and Windows 11 on separate NVMe drives. On Windows the keyboard RGB works out of the box because Windows queries the right driver (Armoury Crate / Dynamic Lighting). On Linux nothing worked — What I understood about the root causeTwo macro-problems:
The 6 bugs I actually hit while iterating (each one caught by reading
|
…owWave/Pulse) - Add effect_task field on Aura for tokio JoinHandle tracking - Add lamparray_stop_effect_task/lamparray_spawn_effect helpers - Route write_effect and write_effect_locked to spawn_effect for non-Static modes - Probe LampCount once before task start so animation loop never touches GET_FEATURE at 30 FPS - Implement 30 FPS Breathe (sinusoidal I), Pulse (asymmetric spike), RainbowCycle (HSV hue rotation), RainbowWave (reverse HSV rotation on LampCount=1 where there is no spatial wave) - Speed enum mapped to ~4s / ~2s / ~0.8s period for Low/Med/High - Task is aborted before spawning new effect and before power-state changes (no overlapping frames) - Task releases hid lock between frames so brightness/other callers can interleave
The dynamic-effect spawn path used bare tokio::spawn() which panics when called from the zbus Connection executor thread (not a tokio runtime thread). Capture tokio::runtime::Handle at Aura construction (guaranteed tokio context via maybe_lamparray async fn) and use Handle::spawn() which works from any thread. Fixes core-dump on any 'asusctl aura effect breathe/rainbow-cycle/ rainbow-wave/pulse' invocation.
I don't want you to hide it ;) I was more worried that you were using it without knowing what it was doing or what you were doing.
If you have Windows please send me your ThrottleGear_FA608WV.xml file: it is inside C:\Program File or C:\ProgramData (I don't remember which one).
aura_lamparray would be a better solution IMHO but as said Nero has the last talk
Ah, giusto perché tu lo sappia, sia io che Nero siamo italiani. |
Move all LampArray-specific code out of aura_laptop into its own module
sibling to aura_slash / aura_anime / aura_scsi. This is a cleaner mapping
of the actual protocol split: LampArray is HID Usage Page 0x59 standard,
distinct from the ASUS proprietary aura HID protocol used by USB
keyboards.
- New: asusd/src/aura_lamparray/{mod.rs, effects.rs, trait_impls.rs}
- New: DeviceHandle::LampArray(LampArray) variant in aura_types.rs
- Removed: Aura::is_lamparray flag and all branching from aura_laptop
- Behavior unchanged: same D-Bus path, same commands, same protocol
Wrap the Step1..Step6 discovery, HidRaw::from_i2c_device trace, raw_info ioctl trace, and other low-level lifecycle logs in a debug_info! macro that expands to info! only when built with debug assertions. Release builds stay quiet; developers debugging PID whitelist or i2c-hid open blocking issues still get the full trace. The debug_info! macro was introduced in the aura_lamparray refactor for the LampArray-specific probe/effect trace; this commit extends the same pattern to the underlying rog-platform HidRaw ioctl helpers so the release journal is fully quiet. Retains top-level info!: - LampArray device discovery outcomes (Found candidate, ready) - Effect task lifecycle (spawn / cancel / write_effect_and_apply) - Startup lifecycle (Startup ready, DeviceManager initialized)
|
Updatee — pushed the two follow-up commits you suggested:
Behavior on the FA608WV is identical after the refactor — static/breathe/rainbow-cycle/rainbow-wave all still work via ThrottleGear XML: attached below, grabbed from
If you need me to grab a different file from the Windows partition let me know — I have it mounted read-only on Linux, so it's a couple minutes to pull anything else. Grazie mille del feedback preciso su entrambi i round di review. Se Nero ha un preference sull'organizzazione del modulo (es. tenere |
|
It's not nero but @NeroReflex |
|
oh scusa @NeroReflex |
|
That's why I asked you about your ThrottleGear [1]. I have wrote a program [2] which extract the wattage limits set by Asus/AMD/Intel/Nvidia and make a patch for it automatically. [1] https://lore.kernel.org/platform-driver-x86/20260701164003.4271-1-scardracs@disroot.org/ This way your device will be officially supported by both linux and asusctl (you'll be able to set power wattage on your device) |
Honestly i would have imagined it differently in my mind. |
You have been tagged by mistake ':) |
|
Amazing, thanks for the context — everything clicks together now. I hadn't realized Cloned, built, and ran it locally on my FA608WV: $ ./ThrottleGear-0.2.4 -i ThrottleGear_FA608WV.xml -c Numbers match what I'd expect from Armoury Crate under Windows on this SKU (90W PPT max on AC / 65W on DC, 115W total NVIDIA power on AC = 90W base TGP + 25W Dynamic Boost). Very clean output — the Please tag me when the lore patch hits Very good week for the FA608WV — LampArray keyboard in userland (this PR) + full asus-armoury power support upstream. 🇮🇹 |
|
Grazie mille davvero, per tutto! And honestly huge thanks to you and everyone in the Linux community putting in this kind of work in your spare time — my laptop went from "half-broken" to fully working in a week thanks to people like you. I'll wait for updates on the lore patch and be ready to test the moment it lands. Small thing — if you have a PayPal (or GitHub Sponsors), I'd genuinely like to buy you a coffee. Programmer tradition ☕ 🙏🇮🇹 |
No biggies, we are all in the same boat
That depends on lipo. Honestly, it would take 3/4 weeks and it's normal
Don't mention it, I'm not doing it for money |
|
Now that I'm thinking about it you should write Closes: #148 at the end of your open post |
|
Sorry, my bad — I misread your earlier "Closes: #148 at the end of your open post" as a suggestion to close the PR itself (rather than adding the Reopened. |
@v3zz0 I opened a new PR for it without the need of libc. If you have suggestions please look at mine and close this one |

PR draft per opengamingcollective/asusctl
Titolo
Description (incolla nel campo description della PR)
Summary
Adds support for ASUS keyboard backlight controllers exposed via the Microsoft HID LampArray standard (HID Usage Tables 1.5, Usage Page
0x59) on the I2C-HID bus. The current asusd code only probes for ASUS HID devices behind a USB parent, missing all the I2C-HID controllers (ITE5570 and similar) that ASUS has been shipping on 2024+ laptops including the TUF Gaming A16 FA608WV (0B05:19B6).Without this patch, on these machines:
asusctl aura ...returns success but does nothing physicallyasusd::asus::kbd_backlightsysfs writes return success but the EC ignores themrog-control-centerdisplays the keyboard panel but no color change reaches the hardwareWith this patch:
/xyz/ljones/aura/lamparray_<pid>asusctl aura effect static -c RRGGBBsets the keyboard color in real timerog-control-centerkeyboard panel changes color nativelyasus-wmipaths are completely untouchedHardware tested
0B05:19B6)7.0.11-76070011-generic, BIOSFA608WV.309Architecture
Bugs identified and fixed during development
(in case it helps reviewing each commit)
USB-only discovery:
init_hid_devicesrejected any HID device whose parent didn't have subsystemusb/devtypeusb_device. I2C-HID devices were never even probed. Fix: fallbackinit_i2c_hid_devicewalking the udev parent chain for the HIDHID_IDproperty when USB path produces no match.HIDIOCGRAWINFOioctl size mismatch: the macro was computingsize=12instead of8(the kernelstruct hidraw_devinfois__u32 bustype; __s16 vendor; __s16 product= 8 bytes).ioctl()was returningENOTTYsilently. Fix: use_IOR('H', 0x03, 8)=0x80084803.VID/PID parsed as string:
HID_IDproperty isBUS:VENDOR:PRODUCTwith VENDOR/PRODUCT padded to 8 hex chars (e.g.0018:00000B05:000019B6). Comparingvendor_str.to_lowercase() == "0b05"always false. Fix: numeric parse withu32::from_str_radix(vendor_str, 16), compare against0x0b05.HidRaw::from_i2c_deviceopen blocking on i2c-hid driver: the synchronousOpenOptions::open()on/dev/hidraw1could block inside the i2c-hid kernel driver. Fix: addcustom_flags(libc::O_NONBLOCK)to the open call.systemd
Type=dbustimeout:request_name(DBUS_NAME)was called AFTERDeviceManager::new(...). If discovery took >10s, the bus name never appeared → systemd killed asusd. Fix: moverequest_namebeforeDeviceManager::new. Discovery failures are now non-fatal and logged viamatch.AuraConfiglock deadlock:lamparray_write_effectwas acquiring a secondself.config.lock().awaitwhile the zbus method (e.g.set_led_mode_data) already held the lock. Fix: split intolamparray_write_effect(&self, mode)(try_lock+ sane fallback) andlamparray_write_effect_locked(&self, config: &AuraConfig, mode)(called fromwrite_current_config_modewhich already owns the lock).Double-push overwriting color with white:
set_led_mode_datawas callingwrite_effect_and_apply(effect)(correct color sent) THENset_brightness(config.brightness)which on the LampArray branch fell back to white(0xff,0xff,0xff)and overwrote the color. Fix: in the zbus methods, whenis_lamparrayis true, skip the redundantset_brightnesscall (the brightness is already encoded in the intensity byte of the range update)."No LED backlight control available": the legacy
backlight.is_some()check inAura::set_brightnessetc. returned the error for LampArray devices (backlight: Nonebecause LampArray controllers do not expose theasus::kbd_backlightsysfs node). Fix: every method that previously matched onself.backlightnow early-returns into the LampArray branch whenself.is_lamparrayis true.Files modified
Total: ~708 net new lines. All changes gated behind
self.is_lamparray/ new probe path — zero behavior change on existing USB/asus-wmi/Slash/AniMe/Ally machines.Test plan
Discovery (visible in
journalctl -u asusd)D-Bus
CLI
Log confirms each push:
GUI
rog-control-centerkeyboard tab — color picker now changes the keyboard in real time.Notes for reviewers
LampArrayAttributesResponseon the FA608WV reportsLampCount=1so this SKU is single-zone. Other SKUs in the family may report higher counts; the code already iterates0..LampCount-1in the range update.matches!(pid, 0x19b6)) is intentionally narrow for the first PR. Adding more PIDs as users confirm support is a one-line change.O_NONBLOCKon the hidraw open is defensive: on the FA608WV without it the i2c-hid driver could stall the entire tokio runtime during init. Setting it is harmless for USB devices (ignored by uhid).init_hid_devicesonly falls back to I2C when the USB path produces zero devices.Related
0B05)Hardware info dump (FA608WV)
Come aprire la PR (passi pratici)
Commits suggeriti (granulari, più facili da reviewere)
Se preferisci, puoi spezzare ulteriormente in commits semantici:
rog-platform: define HidrawDevinfo, ioctl helpers (set/get feature report, raw_info)rog-platform: add HidRaw::from_i2c_device with O_NONBLOCK openaura: add maybe_lamparray DeviceHandle factoryaura: add is_lamparray flag and write_effect path on Auraaura: route brightness/mode zbus calls through LampArray branchaura: I2C-HID discovery fallback in init_hid_devicesdaemon: register dbus name before device discovery to avoid systemd timeoutaura: avoid double-push that overwrites color with white on lamparrayaura: granular logging across I2C-HID discovery pathCloses: #148