Skip to content

[RFC] HID: ayaneo: qualify vendor interface and add native ring cycle - #122

Closed
sknowledge1 wants to merge 19 commits into
OpenGamingCollective:features/ayaneofrom
sknowledge1:ayaneo3-rgb-20260924
Closed

sknowledge1 wants to merge 19 commits into
OpenGamingCollective:features/ayaneofrom
sknowledge1:ayaneo3-rgb-20260924

Conversation

@sknowledge1

Copy link
Copy Markdown

The AYANEO 3 controller exposes gamepad, keyboard and vendor-command HID interfaces under the same 1c4f:0002 ID. The existing special-driver match can displace hid-generic from the input interfaces. The rings also need a firmware-timed colour cycle: repeated host RGB writes visibly flicker on the tested device.

This four-commit RFC builds on the existing AYANEO driver in features/ayaneo at 1470e083da998b2b80d3ff1289a3c528417390d6:

  1. Gate hid-ayaneo on the known vendor descriptor and AYANEO 3 DMI match.
  2. Have hid-generic consult a special driver's match callback before yielding an interface. This shared HID change deserves explicit maintainer review alongside commit 1.
  3. Expose firmware-timed rainbow through a documented LED effect ABI, with fixed tempo and normal brightness control.
  4. Keep HID replies available while LED unregister drains the final acknowledgement during removal.

On a locally patched AYANEO 3, both rings showed steady colours, breathing and smooth synchronized native cycling at 30%, 60% and 100% brightness. Joysticks, buttons and menus remained usable through direct effect transitions, InputPlumber recovery, driver reattachment and packaged sleep/wake. The earlier software-written cycle flickered, so it is not a fallback. The candidate source passed checkpatch.pl --no-tree --no-signoff without errors or warnings, and the reviewed diffs applied to the exact OGC base. This is one-device, patched-stack evidence, not a stock Bazzite or Linux-mainline pass.

The series is attributed with Assisted-by: Codex:GPT-6 in each commit. Human code and provenance review was completed before submission. Native userspace work is tracked in InputPlumber #734, OpenGamepadUI #552, and Bazzite #5893. Mainline submission can follow the OGC/Bazzite integration review.

pastaq and others added 19 commits September 18, 2026 19:45
Adds platform driver for AYN Loki and Tectoy Zeenix lines of handheld
devices. This patch implements a hwmon interface for EC provided manual
PWM fan control and user defined fan curves. A global ACPI lock is used
when reading or writing from the EC.

There are 4 fan modes implemented in this patch. Modes 0-3 act in
accordance with the standard hwmon logic where 0 is 100% fan speed, 1 is
manual control, and 2 is automatic control. As the EC only provides 3
modes by default, mode 0 is implemented by setting the device to manual
and then setting fan speed to 100% directly. In mode 1 the PWM duty cycle
is set in sysfs with values [0-255], which are then scaled to the EC max
of 128. Mode 4 is an automatic mode where the fan curve is user defined.
There are 5 total set points and each set point takes a temperature in
Celsius [0-100] and a PWM duty cycle [0-255]. When the CPU temperature
reaches a given set point, the corresponding duty cycle is automatically
set by the EC.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds temperature sensors to the ayn-ec hwmon interface. These read-only
values include Battery, Motherboard, Charger IC, vCore, and CPU Core, as
well as labels for each entry. The temperature values provided by the EC
are whole numbers in degrees Celsius. As hwmon expects millidegrees, we
scale the raw value up.

`sensors` output after this patch is applied:
aynec-isa-0000
Adapter: ISA adapter
fan1:        1876 RPM
Battery:      +29.0°C
Motherboard:  +30.0°C
Charger IC:   +30.0°C
vCore:        +36.0°C
CPU Core:     +48.0°C

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds an EC controlled LED Multicolor Class Device for controlling the
RGB rings around the joysticks.

The EC provides a single register for each of the colors red, green, and
blue, as well as a mode switching register. The EC accepts values
[0-255] for all colors. There are two available effects: breathe, which is
the default when the device is started, and monocolor. When resuming from
sleep the user selected effect will be overwritten by the EC, so the
driver retains the last setting and resets on resume. When setting a
color, each color register is set before a final "write" code is sent to
the device. The EC may briefly reflect the "write" code when writing, but
quickly changes to the "monocolor" value once complete. The driver
interprets both of these values as "monocolor" in _show to simplify the
sysfs exposed to the user.

Two custom attributes are added to the standard LED parent device:
effect, a RW file descriptor used to set the effect, and effect_index,
which enumerates the available valid options.

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
Adds ABI documentation for the ayn-ec platform driver

Signed-off-by: Derek J. Clark <derekjohn.clark@gmail.com>
…ntation Contribution by CVMagic (https://github.com/CVMagic)

aw87xxx: Use strscpy instead of strlcpy

awinic: i2c_driver cleanup and fixes

This is deliberately an OGC-carried patch and must not be sent upstream.

(cherry picked from commit 91a51cacadb95ba80227663a75fd113552b18e45)
Signed-off-by: Hijae Song <hijae@naver.com>
…gging purposes, but also fixed Reset Pin GPIO initialization issue with Ayn Loki Mini

This is deliberately an OGC-carried patch and must not be sent upstream.

(cherry picked from commit 4b4179efc86828f8762f0819aabf4413a3ba0d27)
Signed-off-by: Hijae Song <hijae@naver.com>
…a second I2C chip if specified in ACPI

This is deliberately an OGC-carried patch and must not be sent upstream.

(cherry picked from commit ed123302c7dde72a935052370de4a9b2ff3e1feb)
Signed-off-by: Hijae Song <hijae@naver.com>
…sume.

This is deliberately an OGC-carried patch and must not be sent upstream.

(cherry picked from commit 92392036d95ffdf9fc2b4b42c3dd31a8939d4027)
Signed-off-by: Hijae Song <hijae@naver.com>
This is deliberately an OGC-carried patch and must not be sent upstream.

(cherry picked from commit dac32102659fa0ae4f2692ed81810ceb834ed584)
Signed-off-by: Hijae Song <hijae@naver.com>
Multiple AyaNeo/Ayn/Orange Pi devices ship the aw87xxx amplifier with
different firmware blobs. Select the firmware filename by DMI board/
product match so each device's blob coexists under /lib/firmware
without collision, falling back to the original single filename when
no match is found.

This is deliberately an OGC-carried patch and must not be sent upstream.

Co-developed-by: bouhaa <boukehaarsma23@gmail.com>
Co-developed-by: Antheas Kapenekakis <git@antheas.dev>
Signed-off-by: Hijae Song <hijae@naver.com>
linux/of_gpio.h has been removed from the tree. None of these
files actually use anything from it (no of_gpio_* calls), so drop
the dead include to fix the build.

This is deliberately an OGC-carried patch and must not be sent upstream.

Signed-off-by: Hijae Song <hijae@naver.com>
…mponent

Newer kernels (6.16+) changed snd_soc_unregister_component()'s
signature. Add a version-gated wrapper so the driver still builds
across the kernel versions this branch needs to support.

This is deliberately an OGC-carried patch and must not be sent upstream.

Signed-off-by: Hijae Song <hijae@naver.com>
The valid-GPIO branch fell through without ever requesting the
reset pin, leaving it unclaimed. Request it with devm_gpio_request_one()
so the driver actually owns and can drive the reset line.

This is deliberately an OGC-carried patch and must not be sent upstream.

Signed-off-by: Hijae Song <hijae@naver.com>
The ALC269VB codec's internal speaker pin isn't configured
correctly on the AyaNeo AIR 1S out of the box, so no audio
plays even once the aw87xxx amplifier driver (added earlier in
this branch) is working. Add a pin fixup matching the AIR 1S's
PCI SSID that sets pin 0x1a to 0x90170110, restoring internal
speaker output.

This is deliberately an OGC-carried patch and must not be sent upstream.

Co-developed-by: linh1987
(cherry picked from commit 89eb9630d9114c38f35edc4041daf8b1d25886d3)
Signed-off-by: Hijae Song <hijae@naver.com>
The AYANEO 3 handheld has a detachable controller with swappable
modules ("Magic Modules"). The controller exposes three USB HID
interfaces behind 1c4f:0002 (a generic SigmaMicro VID/PID, hence the
DMI gate): a gamepad, a keyboard for the extra buttons, and a vendor
interface accepting 65-byte commands.

Add a driver for the vendor interface providing module identification
(module_left/module_right sysfs attributes), software eject of the
modules (eject sysfs attribute, blocking until the firmware confirms
the release handshake), and RGB control of the joystick rings as a
multicolor LED class device ("<device name>:rgb:joystick_rings";
userspace such as InputPlumber matches the function suffix). The
firmware's fixed breathing pattern is exposed through the hw_pattern
trigger ABI.

This complements the ayaneo-ec platform driver, which exposes module
attach state and controller power. A full physical eject is performed
by writing to eject and then cutting power through ayaneo-ec's
controller_power attribute; that orchestration is deliberately left
to userspace.

The protocol was reverse engineered in the Handheld Daemon project by
Antheas Kapenekakis. Tested on an AYANEO 3: module identification,
RGB solid and breathing, a full eject/reinsert/repower cycle, and
repeated driver unbinds under a concurrent brightness-write load.
Signed-off-by: Matías Martínez <hello@matias.me>
Reviewed-by: Denis Benato <denis.benato@linux.dev>
Link: https://lore.kernel.org/r/20260917160722.89391-1-hello@matias.me
The 1c4f:0002 controller has gamepad, keyboard and vendor HID interfaces.
Only the vendor command interface belongs to hid-ayaneo; the other two
must remain with hid-generic. Match the known vendor descriptor prefix
on AYANEO 3 and retain the parsed-usage probe check.

Assisted-by: Codex:GPT-6
Signed-off-by: sknowledge <216877555+sknowledge1@users.noreply.github.com>
An ID-table match alone does not prove that a special driver wants an
interface. Honor its match callback before hid-generic yields the bind,
so the AYANEO gamepad and keyboard interfaces retain normal input.

Assisted-by: Codex:GPT-6
Signed-off-by: sknowledge <216877555+sknowledge1@users.noreply.github.com>
Repeated RGB changes visibly flicker on AYANEO 3. Let firmware perform
colour cycling without periodic host updates. Expose explicit effect
selection and discovery on the multicolour LED, with fixed tempo and
normal brightness control. Preserve cached colour, trigger exclusion and
non-LED packet fields.

Mode and amplitude mapping were cross-checked against hhd-dev/hhd
revision 5b49c5d904257e042a704ade958fac0ba57af4b1,
src/hhd/device/ayaneo/const.py. The ABI follows existing driver
effect/effect_index practice and needs review.

Assisted-by: Codex:GPT-6
Signed-off-by: sknowledge <216877555+sknowledge1@users.noreply.github.com>
The HID core holds driver_input_lock when invoking remove. LED
unregister requests Off and waits for raw_event to acknowledge it. Allow
callbacks while LED unregister and queued brightness work drain, then
block callbacks again before closing the transport. This avoids waiting
for a reply that core has prevented from arriving.

Assisted-by: Codex:GPT-6
Signed-off-by: sknowledge <216877555+sknowledge1@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Sep 24, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: ac7c152c-0068-4dd6-9d64-98472d337e14

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pastaq pastaq left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a revisit. You're retaining a split effects paradigm that makes very little sense.

It should also be noted that the original author of this series is still working on upstreaming it, so I'm disinclined to start adding patches on top of that while it is in flux. I'd strongly encourage you work with them directly on getting the changes you desire included in that patch set for v4.

This should have been against unstable since it hasn't been pushed to LKML as well. The patches don't carry the required tags.

Clearing the effect restores normal multicolour interpretation
using the current brightness and cached intensity.

What: /sys/class/leds/*:rgb:joystick_rings/effect_index

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're adding this entry then it will need to convert the existing mono color and breathe effect to use it as well.

Comment thread drivers/hid/hid-ayaneo.c
cfg->right.b = aya->rgb[2];
if (aya->rainbow) {
/*
* HHD's AYANEO implementation uses HSV (275, 100, brightness)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Police AI comments. They don't need to mention other tools or things that were done previously.

I genuinely have no idea what is going on here.

Comment thread drivers/hid/hid-ayaneo.c
}

/*
* Native effects use separate attributes, as on other handheld HID LED

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hid-lenovo-go-s, hid-lenovo-go, hid-oxp, hid-msi, or hid-asus have all their effects in effects, there is no split.

Comment thread drivers/hid/hid-ayaneo.c
* Native effects use separate attributes, as on other handheld HID LED
* drivers. Do not overload hw_pattern's brightness/time pairs with modes.
*/
static const char * const ayaneo_effect_names[] = { "none", "rainbow" };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The const are at the top.

This should be indexed

Comment thread drivers/hid/hid-ayaneo.c
static ssize_t effect_index_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "none rainbow\n");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should loop through the const here, otherwise what is the point of it?

Comment thread drivers/hid/hid-ayaneo.c
bool resp_pending;

u8 rgb[3];
u8 brightness;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already stored on the led_cdev and the led_mc subleds, reuse that.

Comment thread drivers/hid/hid-ayaneo.c

u8 rgb[3];
u8 brightness;
bool pulse;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove

Comment thread drivers/hid/hid-ayaneo.c
struct ayaneo, mcled);

guard(mutex)(&aya->lock);
return sysfs_emit(buf, "%s\n", ayaneo_effect_names[aya->rainbow]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're mixing a bool and an int. Store the current effect in drvdata then retrieve it by index. See other drivers for a good implementation.

Comment thread drivers/hid/hid-ayaneo.c
guard(mutex)(&cdev->led_access);
if (led_sysfs_is_disabled(cdev))
return -EBUSY;
#if IS_ENABLED(CONFIG_LEDS_TRIGGERS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for?

Comment thread drivers/hid/hid-ayaneo.c

guard(mutex)(&aya->lock);
previous = aya->rainbow;
if (previous == !!effect)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!! ... ?

@matmartinez

Copy link
Copy Markdown

v4 is on the list with both of your findings folded in and credited (the rainbow effect and the removal acknowledgement fix): https://lore.kernel.org/linux-input/20260925061941.75121-1-hello@matias.me/ — the interface handling went the hid-lenovo-go-s route as discussed above. The OGC sync PR is #123. Thanks again for the catches; I think this RFC can close in favour of that, but I'll leave that to you and @pastaq.

@sknowledge1

Copy link
Copy Markdown
Author

v4 is on the list with both of your findings folded in and credited (the rainbow effect and the removal acknowledgement fix): https://lore.kernel.org/linux-input/20260925061941.75121-1-hello@matias.me/ — the interface handling went the hid-lenovo-go-s route as discussed above. The OGC sync PR is #123. Thanks again for the catches; I think this RFC can close in favour of that, but I'll leave that to you and @pastaq.

Agreed, closed.

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.

8 participants