44 Commits

Author SHA1 Message Date
Douglas Teles c9fa2ae9d3 archr: package scripts and alpm hooks so they ship through pacman
The archr scripts (archr-update, archr-flash-sync, archr-depmod,
wifictl, governors, ...) and the alpm hooks were installed in
post_install, which writes into the assembled image only, so they never
entered the pacman package: every one of them was flash-only. That is
why the dual update path could deliver package contents but not its own
plumbing, and the depmod fix would not have reached existing installs.
Move the copy into makeinstall_target so the package carries them and
pacman -Syu updates them like anything else.
2026-07-08 21:37:13 -03:00
Douglas Teles faa9c6f6c4 update: stop the linux package from wiping out-of-tree modules
Installing the linux package through pacman overwrote modules.dep with
the copy generated at kernel build time, which predates every
out-of-tree module: the joypad and the WiFi drivers vanished from the
index and the console booted with dead input and no network
(reproduced on real hardware). Two independent layers fix it: the repo
generator no longer ships any depmod-generated index inside packages
(modules.builtin*/order stay, they are kernel-owned depmod inputs),
and a new alpm hook rebuilds the index over the full overlay tree
after any transaction that touches kernel modules. linux goes to rel 3
so updated devices pick the clean package.
2026-07-08 21:22:34 -03:00
Douglas Teles 14db5f1ffb archr-update: sanitize the channel and seed the pacman local db
Two failures kept every device from ever seeing an update. The ES
settings historically stored updates.branch=auto, which pointed the
mirrorlist at a repo tag that does not exist, so the metadata sync
always failed. And freshly flashed images carry an empty pacman local
database, so even with a working mirror there was nothing to compare
against and every check reported no updates. Fall back to stable for
unknown channels and seed the local db once from the published
archr-localdb tarball.

Known limitation of the remote seed: it reflects the newest repo
state, so the first check after seeding reports the current batch as
already installed. Baking the per-image database at build time is the
follow-up.
2026-07-08 18:28:41 -03:00
Douglas Teles b29af12832 RK3326: hold RTL8852AU out of the build, lwfinger tree breaks on 6.12
rtw_pwrctrl.c fails to compile against 6.12.94; the package stays in
the tree for a future port, and the common BU/CU variants remain in.
2026-07-08 18:00:14 -03:00
Douglas Teles 9723e3e09c packages: bump linux and kernel-firmware so MT7921U flows via pacman
The MT7921U enablement changes the kernel image and the firmware list;
without a REV bump pacman would never offer them and only reflashes
would pick the new driver up. The flash-sync hook then lands the new
kernel on the boot partition.
2026-07-08 17:55:15 -03:00
Douglas Teles c1b9f27838 RK3326: add out-of-tree drivers for the RTL8852 USB WiFi 6 family
The four-distro dongle census left the RTL8852AU/BU/CU chips as the
remaining orphans: common WiFi 6 dongles with no mainline USB support
on 6.12 (the in-kernel rtw89 only starts covering them in 6.17).
Package the maintained vendor drivers (morrownr for BU and CU, both
declaring kernels 5.15 to 6.14; lwfinger for AU, with version guards
up to 6.9 and strscpy fallbacks in place) pinned to current HEADs,
modeled on the sibling morrownr packages. No udev hand-off rules: the
USB IDs bind by modalias since nothing else claims them. RTL8831 and
AIC8800 stay untouched; they serve validated hardware.
2026-07-08 17:53:51 -03:00
Douglas Teles 2d04170214 RK3326: enable the in-tree MT7921U driver with its firmware
Common WiFi 6 dongles use the MediaTek MT7921U, which mainline has
supported since 5.18, but the kernel config never enabled the USB
glue and the firmware list did not ship the MT7961 blobs. Cheapest
gap found in the four-distro dongle driver census.
2026-07-08 17:44:08 -03:00
Douglas Teles 01bfa9a5c7 readme: reposition the project as an Arch Linux distribution
Arch R stopped being a ROCKNIX fork a long time ago: the OS is Arch
Linux ARM with pacman and the built-in updater (SteamOS-like model),
and only the image build tooling descends from the LibreELEC family
through JELOS/ROCKNIX. Refresh the outdated claims along the way: the
GPU stack ships libmali (Panfrost is not exposed), images are gzip not
xz, the board table now matches config.xml, DDR trains at 666MHz, and
the update, sleep and power LED features from 2.1 are documented.
2026-07-07 22:20:54 -03:00
Douglas Teles 8275879350 gen-pacman-repo: create the seed root before invoking pacman
pacman resolves the --root path before doing any work and errors out
when it does not exist, so the seed always failed after the cleanup rm.
2026-07-07 22:03:09 -03:00
Douglas Teles ccb3eaaa86 gen-pacman-repo: seed the local db with an aarch64 no-sig config
The host pacman applies the host architecture and signature policy to
the seed transaction, so every aarch64 package was rejected and the
local-db tarball was silently skipped, leaving freshly flashed images
without an upgradable base.
2026-07-07 22:01:20 -03:00
Douglas Teles 330c4199a6 packages: give quirks, sleep and system-utils a real version
Empty PKG_VERSION made gen-pacman-repo fall back to a garbage version
derived from the install dirname (quirks--quirks.-1) and broke the
package.mk lookup, so the PKG_REV bump was never honoured and pacman
could not see these packages as upgradable. Version them 2.1; vercmp
ranks it above the old garbage string, so 2.0 installs upgrade cleanly.
2026-07-07 21:59:07 -03:00
Douglas Teles 8b0f09c43e flash-sync: update only DTBs the image already ships
The per-image DTB set is curated by config.xml (the clone image carries
boards the original image deliberately leaves out), so the sync must
never add files to /flash/dtbs, only refresh the ones present. Caught
on the first hardware run: a clean sync on the original image added
three clone-only DTBs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:59:57 -03:00
Douglas Teles 6faa39c570 update: let kernel and DTB fixes flow through pacman via flash-sync
Until now anything living on the FAT boot partition (kernel Image and
the device trees) was reflash-only, breaking the promise that every
update can arrive either by rewriting the image or through pacman and
the ES update menu. Close the gap with three pieces:

- The linux package now ships the kernel image in the rootfs under
  /usr/share/bootloader/Image next to the device_trees it already
  installs, so a pacman upgrade of linux delivers both.
- archr-flash-sync copies Image to /flash/KERNEL (refreshing the
  KERNEL.md5 sidecar) and device_trees/*.dtb to /flash/dtbs, but only
  the files whose sha256 actually changed, each written as a verified
  .new temp in the same FAT directory and renamed over the original so
  the torn-write window is the rename alone. /flash/overlays (the
  user's panel overlay), extlinux, boot scripts and u-boot are never
  touched; u-boot/TPL live in raw sectors where a torn write bricks
  the card, so the bootloader intentionally stays image-flash only.
- An alpm PostTransaction hook (HookDir /etc/pacman.d/hooks) fires the
  sync whenever a transaction touches the bootloader payload.

gen-pacman-repo now prunes the .image build-plumbing directory from
packages, which would otherwise dump a duplicate raw kernel at /.image
on every update.

Hardware test pending: run archr-flash-sync by hand over SSH and check
the device still boots with the synced KERNEL and dtbs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 20:10:49 -03:00
Douglas Teles 56cd1626d6 packages: bump PKG_REV so today's fixes flow through pacman updates
These packages have empty or upstream-pinned PKG_VERSION, so without a
PKG_REV bump pacman never sees the new build as an update and the fixes
would only reach users through a reflash. Covers headphone_sense and
input.service (system-utils), the LED and audio quirks (quirks), the
s2idle defaults (sleep), the Soysauce SDL mapping (gamecontrollerdb)
and the rewritten udev swap rule (RTL8188EUS).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:46:39 -03:00
Douglas Teles f99aff1149 RK3326: route the Soysauce PMIC interrupt to GPIO0_A7
Live debugging showed the whole rk817 interrupt line dead on the
Soysauce (zero counts in /proc/interrupts for pwrkey, jack and charger
events across button presses). The vendor DTB wires pmic_int to
GPIO0_A7 while the shared r3xs.dtsi listens on GPIO0_B2, so every PMIC
interrupt was lost: power key, headphone detect, charger plug and the
suspend wake source. Override the interrupt and the pinctrl in the
soysauce DTS only; the other family members really use GPIO0_B2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:29:51 -03:00
Douglas Teles 5f1f6182cf fake-suspend: cut the panel backlight even when DPMS handles the blank
The compositor path blanked the framebuffer but could leave the panel
backlight powered, so the "sleeping" console showed a black yet lit
screen and kept burning the display power budget. Turn the backlight
off through bl_power in both paths and restore it on wake.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:24:07 -03:00
Douglas Teles a0a45889f4 system-utils: enable input.service on RK3326
The whole power-button fake-suspend chain was dead code: input.service
(input_sense) is the only thing that turns KEY_POWER presses into
archr-fake-suspend calls, the R33S and RG351 dpad-volbright quirks even
restart it when active, but no package ever enabled it, so the power
key fell through to logind's kernel suspend, which locks up on px30.
Enable it for RK3326. Hardware test note: input_sense also reacts to
KEY_VOLUME events, so watch for double-stepping volume on the rocker;
if it doubles, the second handler needs to yield.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:23:05 -03:00
Douglas Teles 34b76db065 RK3326: default to fake-suspend, kernel suspend proven unwakeable
Hardware test on the Soysauce (2026-07-07) killed both kernel suspend
paths: SuspendState=mem hangs on entry and freeze (s2idle) enters but
never wakes, not even from an armed RTC alarm with every wakeup source
enabled (PMIC pwrkey, rk817 i2c and rtc0 all report enabled). Real
debugging needs UART on the pads.

Make the power button useful instead of a lockup: ship the RK3326
sleep.conf with AllowSuspend=no so logind's HandlePowerKey=suspend
becomes a no-op, and seed system.suspendmode=off through a platform
030-suspend_mode quirk so the archr-fake-suspend path (already wired
to the power key via input_sense) stops exiting early. The quirk also
serves the "default" choice of the ES SUSPEND MODE menu, and on boot
it repairs pacman-upgraded installs whose storage still carries the
old mem-first sleep.conf. Users can still opt in to real suspend
through the same menu (the suspendmode script rewrites the conf with
AllowSuspend=yes), and the sleep.sh state-preservation hooks stay in
place for the day s2idle works.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 19:20:16 -03:00
Douglas Teles 62edc065ad inputs: single source of truth for the built-in gamepad configs
Every platform pad needed three hand-maintained files (es_input.cfg,
the RetroArch autoconfig and gamecontrollerdb.txt) and nothing checked
they agreed; the Soysauce pad shipped without the SDL entry, so ports
saw no controller. Add projects/ArchR/inputs: one JSON definition per
pad plus gen-input-configs, which verifies the three artifacts against
the defs (wired as a fail-fast gate on the docker-% Makefile targets),
regenerates them on demand, imports legacy entries, and computes SDL
GUIDs the same way the runtime does, including the name-embedded form
SDL uses when vendor*product is zero.

The 17 platform pads were imported from the current artifacts and the
migration already caught two real inconsistencies. The GO-Super
gamecontrollerdb line carried a numeric-form GUID, but the pad reports
vendor 0 so SDL derives the name-embedded GUID at runtime (the form the
device-captured es_input block always had); the line is now fixed to
1900bb3e474f2d537570657220476100 and its RetroArch cfg canonicalized.
And retrogame_joypad legitimately ships different mappings per bus
(guide:b10 only on 0x19), now modeled explicitly as a per-GUID map.

Verification is semantic for es_input blocks and RetroArch cfgs (the
legacy files mix tabs and spaces) and byte-exact for gamecontrollerdb
lines, with GUIDs always recomputed from the identity fields.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:31:41 -03:00
Douglas Teles 205c5bccb3 sleep: default RK3326 to s2idle, preserve ALSA and governor state
Suspend on the R36S family hangs because the shipped sleep.conf orders
SuspendState as "mem standby freeze" and px30 mainline has no working
S3, so the kernel commits to a state it cannot leave. Ship
SuspendState=freeze on RK3326; the power button is the rk817 PMIC
pwrkey, which every board DTS already marks wakeup-source, and logind
already routes HandlePowerKey=suspend through systemd-sleep into this
hook.

Borrow the state discipline from the dArkOS sleep hooks: blank the
backlight before the kernel path runs, snapshot the full mixer state
with alsactl (the rk817 can lose its routing across s2idle and the
existing restore only re-set the master volume), and save/restore the
cpu/gpu/dmc governors. dwc2 reload on resume was already covered by
modules.bad.

Untested on hardware: needs a device check that s2idle enters (screen
and audio off), the pwrkey wakes it, and audio routing plus USB gadget
survive the round trip.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:28:53 -03:00
Douglas Teles 8aacf5c823 headphone_sense: sync the startup path with the real jack switch state
The boot-time probe read a legacy /sys/class/gpio number that mainline
kernels never expose, so the initial audio path was always the speaker
guess and a reboot with headphones plugged started routed wrong. Query
the actual EV_SW/SW_HEADPHONE_INSERT bit through evtest --query (exit
10 = bit set; on these boards the switch is inverted, value 0 means
inserted) with the legacy gpio node as fallback, make an empty "$2"
follow the detected state instead of forcing speakers, and bail out
before the event loop when the board has no jack input device at all
(evtest on an empty path just dies and burns service restarts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 18:27:14 -03:00
Douglas Teles bd6fb8d0a9 gamecontrollerdb: add the Soysauce GO-Super Gamepad SDL mapping
SDL-based games and ports never recognized the Soysauce pad because
gamecontrollerdb.txt only knew r36s_Gamepad; RetroArch and ES have
their own configs, which is why "some games" needed manual input setup
(Reddit report on the 2.0 thread). GUID derived the same way SDL does:
bus 0x19 (host), crc16 of the device name (verified against the
r36s_Gamepad entry), vendor 0, product 0x1100, version 0x0100 from the
DTS; the button/axis layout matches the r36s entry, which is the same
physical layout the validated RetroArch config already uses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 17:30:48 -03:00
Douglas Teles 0be7aab31b emulationstation: default power LED selection to on, matching boot
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 17:03:08 -03:00
Douglas Teles df92325273 RK3326: fix the shipped-but-broken v2.0 fixes for issues #19 and #35
Issue #19 (RTL8188EUS dongle can scan but never authenticates): the
udev swap rule shipped in v2.0 was structurally a no-op. It matched
the usb_device add event and echoed the device name ("1-1") into
rtl8xxxu's unbind node, but USB drivers bind to the interface
("1-1:1.0"), and at usb_device add time nothing is bound yet anyway;
the follow-up modprobe never rebinds an interface the in-tree driver
already claimed. Users confirmed the auth failure survived into the
release. Rewrite the rule to match the usb_interface event, where the
kernel has already finished its synchronous bind, and deterministically
move the interface: unbind from rtl8xxxu (no-op if it lost the probe
race) and write it into 8188eu's bind node via udev's own %k
substitution (no shell $$ escaping to get wrong).

Issue #35 (R36S Clone V20 speaker silent, headphones fine): the V20-era
clone boards route the speaker through the external amplifier exactly
like the Soysauce (the eeclone DTS already ships rk817-sound-amplified)
but the R36S Clone quirk never exported the playback mux paths nor the
jack input device. Reporters on the issue validated this exact config
by hand-editing the quirk. Also fix headphone_sense: every amixer cset
passed the control name unquoted, so names with spaces ("Playback Mux")
split into two arguments and the call failed; and the boot-time jack
probe read a legacy /sys/class/gpio node that mainline kernels don't
expose, now guarded with a speaker-path default.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 16:18:39 -03:00
Douglas Teles 4385a37cbf RK3326: fix Soysauce power LED polarity, surface DISABLE POWER LED
Live debugging on the Soysauce (USB SSH, watcher on the led sysfs while
the user drove the ES menu) showed the whole chain working but the LED
responding inverted: the blue power LED is wired active high, so the
GPIO_ACTIVE_LOW in the DTS made "off" light it and "on" darken it
(heartbeat looked normal because a blink is a blink upside down). Flip
the polarity and default the LED on so early boot keeps the stock look.
The led-red node was a phantom: the physical red LED belongs to the
charger IC and toggling GPIO0_A5 changes nothing, so drop it.

The DISABLE POWER LED switch in ES is gated on DEVICE_PWR_LED_CONTROL,
which sits in the 999-export allowlist but was never set by any quirk,
so the item was invisible on every device. Set it for the R36S family.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 15:42:40 -03:00
Douglas Teles 413b62304b RK3326: describe the R36S/R33S power LED so the ES menu can drive it
The power LED menu never worked on the R36S Original and Clone because
nothing consumes the old JELOS quirk vars on mainline: 002-disable-led
and battery_led_status poke BSP gpio numbers (gpio77) through the
legacy /sys/class/gpio interface that no longer exists, and the R36S
DTB did not describe the LED at all.

Describe the hardware in the DTS instead. The R36S Original has a
bicolor power LED behind a single line (GPIO2_B5, BSP gpio77): high is
red, low is the green side, high impedance lights both halves orange,
so there is no hardware off; exposed as red:status. The R33S has a mono
blue active-low LED on the same pin (the old quirk wrote 1 to disable
it), exposed as blue:status with true off. The Clone already had proper
LED nodes; its sysfs name is blue:power (color:function, no label).

Point DEVICE_POWER_LED at the right sysfs name per device so
batocera-gameforce (POWER LED COLOR and DISABLE POWER LED paths) finds
the LED, and drop the dead 002-disable-led quirks. On the Original,
"off" shows the stock steady green and "on" shows red; heartbeat pulses
between the two colors.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:58:41 -03:00
Douglas Teles 5c5dcd3c4a rkbin: retry the RK3326 TPL DDR frequency at 666MHz
The boot-loop investigation exonerated everything except the original
786MHz TPL: a full hardware bisect (no patches, 024 only, 0026 only,
both) booted every combination at 333MHz with byte-verified TPL
signatures inside the images, which means the earlier "666 and 333 also
fail" results came from flashing stale copies of the 786 image. 666MHz
therefore goes back in for a clean, checksum-verified hardware test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:28:12 -03:00
Douglas Teles a30e6ea7f5 emulationstation: fix clipped Internet Status, wire DISABLE POWER LED
Bump to the ES fork fix: the async INTERNET STATUS row now reserves the
cell for the widest value so NOT CONNECTED no longer clips, and the
DISABLE POWER LED switch actually drives the LED (it used to write a
conf key nothing consumed). 096-powerled honours powerled.disabled at
boot so the choice survives a restart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:28:12 -03:00
Douglas Teles d652e2d7bd rkbin: drop the RK3326 TPL DDR frequency to 666MHz
786MHz failed the hardware boot test on the Soysauce: the screen lights
and the SoC resets in a loop before U-Boot, meaning the TPL DDR
training does not converge at that speed on these chips (dArkOS only
reaches 786 via the BSP dmc driver's runtime retraining, which is
gentler than a fixed cold init). 666MHz keeps twice the bandwidth of
the old 333MHz baseline; 528 (dArkOS's powersave floor) is the next
step down if any board still fails.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 20:48:07 -03:00
Douglas Teles 39e4a5ebcf rkbin: fix sed delimiter clashing with the alternation pipes
The frequency rewrite used | both as the sed delimiter and inside the
group alternation, so post_unpack failed and the previous build shipped
no images. Use # as the delimiter; verified against the generated
parameter dump (all five freq fields now rewrite to 786).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 23:02:56 -03:00
Douglas Teles 6794a56987 RK3326: gameplay priority and RetroArch tuning from the dArkOS analysis
- Launch emulators at nice -19 like dArkOS does; with the full-preempt
  kernel this keeps frame pacing stable when background work wakes up
  mid-frame.
- audio_latency 64 to 128, matching dArkOS on the same alsathread
  driver and hardware: the 64ms buffer underruns audibly on heavy
  cores, which users read as instability.
- fastforward_frameskip on: skip rendering during fast-forward and give
  the GPU time back to the core.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 22:59:19 -03:00
Douglas Teles d80eb6c482 RK3326: raise the TPL DDR frequency from 333MHz to 786MHz
The performance gap users report against dArkOS ("more FPS, more
stable") is dominated by memory bandwidth. Our TPL blob initialises
every DDR type at 333MHz (verified via ddrbin_tool -g: lp2/ddr3/lp3/
ddr4/lp4 all 333) and mainline has no px30 dmc driver, so the memory
never leaves 333MHz. dArkOS runs the BSP dmc_ondemand governor, which
scales the same boards up to the 786MHz ceiling of the vendor R36S DTB
dmc table (528/666/786, verified by decompiling their shipped DTB), and
even its powersave mode pins 528MHz: their WORST case has 60% more
memory bandwidth than our best.

Rewrite the frequency fields inside the TPL with Rockchip's ddrbin_tool
(the long-standing ArkOS "DDR fix") so DDR comes up at 786MHz from
boot, for both the standard and the UART5 clone TPL variants. Override
with RK3326_DDR_FREQ=666 if a board proves unstable.

MUST be boot-tested on hardware before any release: a board whose DDR
cannot run 786MHz will hang in the TPL before U-Boot even starts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 22:59:19 -03:00
Douglas Teles 235f113c25 fs-resize: gate resize2fs on fsck, fix sd* boot partition name, explain warnings
Analysis of a first-boot resize log (docs/resize.log):

- The two FAT warnings it records are expected and harmless. The 256MB
  boot partition ships the same out-of-spec FAT32 (16375 clusters, below
  the 65525 minimum) as ROCKNIX and the rest of the RK3326 ecosystem;
  vendor U-Boots are only tested against that layout, so reformatting it
  is exactly the change that has caused boot loops before. The
  boot-sector/backup difference is the kernel vfat dirty flag, written
  to the primary sector only while /flash is mounted read-write; the
  shipped image was verified to carry identical primary and backup
  sectors. The script now appends a NOTE to the log so the warnings stop
  being reported as failures.

Real defects fixed:

- resize2fs ran regardless of the e2fsck result; on unfixed corruption
  (exit above 2) growing the filesystem would compound the damage. The
  resize is now skipped in that case, leaving the grown partition for a
  later retry after a manual fsck.
- The boot-partition path was hardcoded as ${DISK}p1, which is wrong for
  /dev/sdX disks (sdXp1 does not exist), so the FAT serial
  randomization silently never ran there. Derive the partition name per
  device type alongside DISK.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 22:39:12 -03:00
Douglas Teles 1d892b9231 emulationstation: bump for the enumeration pre-warm
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 22:02:06 -03:00
Douglas Teles 3cd958e549 es-menu: provide the missing set-audio, power LED and resolution backends
Three ES menu backends did not exist on ArchR, so the menus silently did
nothing and every ES start logged "command not found":

- set-audio (AUDIO OUTPUT menu): implemented for PipeWire via wpctl
  (list/get/set validated on hardware); card profiles are not exposed,
  so the profile row hides itself.
- batocera-gameforce (POWER LED COLOR menu): drives the gpio-led power
  indicator (blue by default, DEVICE_POWER_LED overrides; the red LED
  remains the charging indicator owned by powerstate). heartbeat/on/off
  validated on the Soysauce. A new 096-powerled autostart replays the
  persisted choice at boot.
- archr-resolution (archr-config lsoutputs): lists connected DRM
  connectors.

emulationstation: bump for the enhanced PowerSaver default (idle menu
CPU measured 25% to 10% on hardware).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 21:51:32 -03:00
Douglas Teles 6a66a44a8e emulationstation: bump for the binary gamelist cache
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 21:14:48 -03:00
Douglas Teles fd304683a3 emulationstation: async settings menus, drop phantom boost dep, enable LTO
Bump to 37f12a02d, which moves every synchronous shell call out of the
settings-menu UI thread (the network menu ping alone could freeze the
interface for six seconds; audio, bluetooth, overclock, overscan,
storage and the ad-hoc WiFi path all stalled the render loop).

boost was listed in PKG_DEPENDS_TARGET but nothing in the source
includes or links it; drop the phantom dependency. Enable LTO for a
smaller, cache-friendlier binary on the A35.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:56:41 -03:00
Douglas Teles 492a61eee2 wifi: free the USB OTG port when WiFi is off (internal-WiFi mux boards)
Some clones (XiFan R36Max2 family) wire the internal USB WiFi module to
the same OTG data lines as the physical USB port through a hardware mux
gpio: WiFi and the port are mutually exclusive, and users report that on
the stock OS disabling WiFi brings the port back.

Port ROCKNIX's 0026 USB2 PHY patch, which reads switch-gpios from the
otg-port node and exposes usb_switch_gpio / usb_switch_ext in sysfs
(boot default: internal WiFi). ROCKNIX itself never toggles the mux from
userspace, so the physical port stays dead there; wire it to our WiFi
toggle instead: wifictl enable routes the mux to the internal module,
wifictl disable flips it to the external port and powers its vbus. The
sysfs writes are no-ops on boards without the mux, and the patch is
inert unless the generated overlay (USBMUX hardware variant on the site)
adds switch-gpios to the PHY.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:32:04 -03:00
Douglas Teles 94d26a87fd RK3326: drop the dedicated r36tmax DTS, deliver it via overlay instead
ArchR does not ship per-board device trees: the base DTB stays generic
and board specifics come from the generated overlay. The r36tmax.dts
ported from ROCKNIX baked panel, joypad and SDIO WiFi into a dedicated
tree, against that architecture.

The overlay path is verified feasible for the one genuinely new surface
(the rk912/rk915 SDIO WiFi): runtime overlays cannot delete properties,
but mmc_of_parse performs no card-detection setup at all when
"non-removable" is present (host.c "Parse Card Detection"), so an
overlay can neutralize the clone base's second-SD-slot cd-gpios on
&sdio and repurpose the controller for the WiFi module (pwrseq node,
supports-rk912, sdio caps). That fragment moves to the web overlay
generator; the rk915 driver and the supports-rk912 kernel patch stay in
the OS image since they are generic and inert without the DT properties.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:24:59 -03:00
Douglas Teles 88647c6e07 RK3326: build and ship the r36tmax DTB in the clone image
The kernel make target and the /dtbs/ payload come from the config.xml
device file list, not from the kernel Makefile registration alone, so
the new rk3326-aislpc-r36tmax.dts was compiled into nothing. List it
under the clone subdevice: the R36T Max flashes the clone image and
selects the DTB via the extlinux FDT line, like the soysauce does on
the original image.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:15:49 -03:00
Douglas Teles 9de9224f80 archr: day-resolution PKG_VERSION, seconds broke image assembly
The build system re-evaluates package.mk on every step and derives
PKG_INSTALL from PKG_NAME-PKG_VERSION. With the seconds-resolution
timestamp introduced in 9ff72420c6 the build and install steps computed
different versions, so scripts/install silently skipped a PKG_INSTALL
directory that did not exist and image assembly died in post_install
("sed: can't read .../system.cfg"). Use the build day instead: stable
across the steps of one build, still bumps per release so pacman ships
archr updates.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:06:21 -03:00
Douglas Teles 2424c658de README: drop false HDMI claim and stale panel-overlay section
Bug report 5 called out hardware claims that are not true. The RK3326
boards have no HDMI or any video output, so remove "HDMI audio/video
output" from the feature list. Qualify Bluetooth (works via a USB
adapter, there is no internal radio). Rewrite the Display Panels section
and the overlays feature bullet: the 43 pre-generated overlays and the
config/archr-dts + mipi-generator tree they referenced were removed in
2.0 in favor of the online overlay generator, and report 3 shows users
still following the stale instructions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:01:01 -03:00
Douglas Teles 45dd6ff144 wifi: robust dongle connects and visible feedback while connecting
Bug report 1: an Edimax USB dongle sees the network but the connect
fails with a generic error (works on dArkOS). Bug report 4: pressing B
after typing the passphrase looks like a freeze while the console is
silently trying to connect.

wifictl: scan until the target SSID actually shows up in iwd's results
(up to 12s) instead of a fixed 2s sleep; slow USB dongles were reaching
iwctl connect before the network existed in the scan cache, which fails
immediately. Extend the association wait from 15s to 30s and log the
real iwctl connect output plus the outcome to /var/log/wifictl.log so
failures (wrong passphrase, WPA1/TKIP networks that iwd does not
support, timeouts) stop being an indistinguishable "network error".

emulationstation: bump to 8a257e1fa, which wraps both WiFi connect call
sites in a GuiLoading busy spinner instead of blocking the UI thread.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:01:01 -03:00
Douglas Teles a738af646b RK3326: support the R36T Max internal SDIO WiFi (rk912/rk915)
Users reported the R36T Max clone does not even scan for networks on the
2.0 clone image while the stock OS and Aurknix work (bug report 2). The
R36T Max internal WiFi is an rk912/rk915 SDIO module, which the clone
image had no driver, no DTS wiring and no SDIO quirks for. Port the
working support from ROCKNIX/Aurknix:

- rk915 driver package (AveyondFly/rk915, WiFi/BT SDIO), added to
  ADDITIONAL_DRIVERS.
- 024-mainline-linux-hacks-for-rk915.patch: MMC_CAP2_WIFI_RK912 cap
  behind the supports-rk912 DT property; bypasses the SDIO CIS size
  check and power cycling that break this module's initialization.
- rk3326-aislpc-r36tmax.dts: dedicated device tree (sdio_pwrseq, sdio
  node with supports-rk912, correct joypad wiring including the analog
  stick inversion users hit on the generic clone DTB). Adapted to the
  archr-singleadc-joypad and archr,generic-dsi compatibles.
- Temperature sensor quirk for the "AISLPC R36TMax" model string.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:01:01 -03:00
71 changed files with 4906 additions and 193 deletions
+5
View File
@@ -118,7 +118,12 @@ docker-image-pull:
# Runs host-side on purpose: the website repo is not mounted into the build
# container. The sync script is itself non-fatal, and the guard keeps it off
# non-build docker targets (docker-shell, docker-update, ...).
# Before any docker build, fail fast if the three shipped input-config
# artifacts drifted from the per-pad definitions (see projects/ArchR/inputs).
# Verification only: the build never rewrites the artifacts by itself.
docker-%:
@./projects/ArchR/inputs/gen-input-configs verify >/dev/null || \
{ ./projects/ArchR/inputs/gen-input-configs verify; exit 1; }
./scripts/get_env > .env
BUILD_DIR="$(DOCKER_WORK_DIR)" $(DOCKER_CMD) run $(PODMAN_ARGS) $(INTERACTIVE) --init --env-file .env --rm --user $(UID):$(GID) $(GLOBAL_SETTINGS) $(LOCAL_SSH_KEYS_FILE) $(EMULATIONSTATION_SRC) -v "$(PWD)":"$(DOCKER_WORK_DIR)" -v /tmp:/tmp -w "$(DOCKER_WORK_DIR)" $(DOCKER_EXTRA_OPTS) $(DOCKER_IMAGE) $(COMMAND)
@if [ "$*" = "RK3326" ]; then ./scripts/repo/sync-site-bases; fi
+46 -35
View File
@@ -3,7 +3,7 @@
</p>
<p align="center">
<strong>Arch Linux-based gaming distribution for handheld devices.</strong>
<strong>Arch Linux gaming distribution for handheld devices.</strong>
</p>
<p align="center">
@@ -14,22 +14,27 @@
---
Arch R is a custom Linux distribution for the **R36S** handheld gaming console and all its variants, built on top of [ROCKNIX](https://github.com/ROCKNIX/distribution) with an **Arch Linux-based** build environment. It supports **16 board profiles** and **20 display panels** across original and clone hardware.
Arch R is an **Arch Linux** distribution for the **R36S** handheld gaming console and its many variants. In the same spirit as SteamOS, it pairs a genuine Arch userland (pacman, systemd, up-to-date packages) with a curated console experience: flash it, turn the device on, play. System updates are delivered through the built-in updater, kernel included; reflashing is only needed for a fresh install or recovery.
The image build pipeline descends from the LibreELEC family of embedded build systems (through JELOS and ROCKNIX), but the operating system it assembles is Arch Linux ARM, not a JELOS derivative.
## Features
- Arch Linux-based build system with Docker support.
- Kernel 6.12 LTS with board auto-detection via SARADC.
- Mesa Panfrost open-source GPU driver (GLES 3.1, no proprietary blobs).
- EmulationStation frontend with RetroArch and 18+ cores pre-installed.
- Full audio support with speaker/headphone auto-switch.
- Battery monitoring with capacity reporting and LED warning.
- 43 pre-generated MIPI panel overlays (15 original + 18 clone + 10 soysauce variants), one per motherboard revision.
- Genuine Arch Linux ARM base with pacman and signed package repositories (stable, next and dev channels).
- Built-in system updater in EmulationStation; kernel and device trees update through it too, with checksum-verified writes to the boot partition.
- Mainline kernel 6.12 LTS with board auto-detection via SARADC.
- Memory clock trained at 666MHz from boot (twice the BSP-era default) and tuned Mali-G31 graphics.
- EmulationStation frontend with RetroArch and 18+ cores pre-installed, plus PortMaster.
- Full audio support with speaker/headphone auto-switch across board revisions.
- Power button light sleep: screen and backlight fully off, instant wake.
- Power LED control (on, off, heartbeat) on every supported family.
- USB WiFi dongle support, including the common RTL8188EUS family (TP-Link, Edimax).
- MIPI panel overlays for every known motherboard revision, generated on demand by the online overlay generator at https://arch-r.io/overlay-generator/ (or during flashing by the Arch R Flasher). The generator also extracts board-specific wiring (audio amplifier, jack detect, LEDs, PMIC interrupt) from your stock DTB.
- Separate images for original and clone boards, both with hardware auto-detection.
- Integrated cross-device local and remote network play.
- Fine-grained control for battery life and performance.
- Bluetooth audio and controller support.
- HDMI audio/video output, USB audio.
- Bluetooth audio and controller support (via USB Bluetooth adapter; the boards have no internal radio).
- USB audio devices (DACs, headsets, controllers with audio).
- Device sync with Syncthing and rclone.
- VPN support with WireGuard, Tailscale, and ZeroTier.
- Built-in scraping and RetroAchievements.
@@ -40,17 +45,16 @@ Arch R is a custom Linux distribution for the **R36S** handheld gaming console a
| Board | Image |
|-------|-------|
| R36S (original), R33S | Original |
| R36S (original), R33S, R36S Soysauce | Original |
| Odroid Go Advance / v1.1 / Super | Original |
| Anbernic RG351V / RG351M | Original |
| GameForce Chi, MagicX XU10 | Original |
| K36 / R36S clones / EE Clone | Clone |
| Powkiddy RGB10 / RGB10X / RGB20S | Clone |
| MagicX XU-Mini-M, BatLexp G350 | Clone |
| GameForce Chi, MagicX XU10, Powkiddy RGB10 | Original |
| K36 / R36S V20 clones / EE Clone | Clone |
| Powkiddy RGB10X, MagicX XU-Mini-M | Clone |
### Display Panels
Arch R ships 43 pre-generated MIPI panel overlays covering all known R36S display variants, named after the exact motherboard revision (e.g. `R36S-V21_2024-12-18_2551.dtbo`, `G80CA-MB_V1.3-20251212_Panel_8.dtbo`). Panel selection is done by copying the correct `.dtbo` file to `overlays/mipi-panel.dtbo` on the boot partition. Sources live under `config/archr-dts/{original,clone,soysauce}/<MB-revision>/`; the build extracts the panel description from each revision's `rk3326-r36s-linux.dtb` via `config/mipi-generator/generator.sh`.
Panel overlays are not baked into the images. Generate the overlay for your exact motherboard revision at the online generator, https://arch-r.io/overlay-generator/ (pick your board, or upload the stock `dtb` from the SD card that shipped with the device), then copy the resulting file to `overlays/mipi-panel.dtbo` on the boot partition. The Arch R Flasher can also generate and install the overlay during flashing. The `/flash/overlays/` folder on a fresh install contains a `README.txt` with the same instructions.
## Quick Start
@@ -59,15 +63,22 @@ Download the latest images from [Releases](https://github.com/archr-linux/Arch-R
- **Original image** -- for genuine R36S and compatible boards.
- **Clone image** -- for K36 clones and compatible boards.
Flash to a MicroSD card:
The easiest path is the [Arch R Flasher](https://github.com/archr-linux/archr-flasher), which downloads, verifies, flashes and installs your panel overlay in one go. Manual flashing works too:
```bash
xz -d ArchR-R36S-*.img.xz
gzip -d ArchR-R36S-*.img.gz
sudo dd if=ArchR-R36S-*.img of=/dev/sdX bs=4M status=progress
sync
```
Insert the SD card and power on. The correct board DTB is selected automatically.
Always verify the download against the published `SHA256SUMS` before flashing. Insert the SD card and power on; the correct board DTB is selected automatically.
## Updates
- **In place (default after install)**: EmulationStation > Updates, or `archr-update` over SSH. Updates come from the signed pacman repository; after each transaction the boot partition is synchronized automatically, so kernel and device-tree fixes arrive without reflashing. User overlays and configuration are never touched.
- **Reflash**: for fresh installs, recovery, or the rare low-level bootloader change (TPL/U-Boot, e.g. a DDR frequency change), which lives outside the filesystem.
Release channel is configurable (stable, next, dev) under updates settings.
## Building from Source
@@ -90,7 +101,7 @@ make docker-image-build
make docker-RK3326
```
Output images are generated in `target/`.
Output images are generated in `target/`. Add `OFFICIAL=yes` for release-stamped images.
### Build Commands
@@ -105,23 +116,23 @@ Output images are generated in `target/`.
Arch R separates **board configuration** from **panel configuration**:
- **Board DTB** = hardware profile (GPIOs, PMIC, joypad, audio codec). Selected automatically by U-Boot via SARADC.
- **Panel overlay** = display init sequence and timings. Applied on top of the board DTB at boot time.
- **Board DTB** = hardware profile (GPIOs, PMIC, joypad, audio codec). Selected automatically by U-Boot via SARADC. One generic DTB per hardware family; board-revision differences are carried by the overlay.
- **Panel overlay** = display init sequence, timings and board-specific wiring extracted from the stock DTB. Applied on top of the board DTB at boot time.
This means the same image works on all boards of a variant. Only the panel overlay needs to match the specific display.
This means the same image works on all boards of a variant. Only the overlay needs to match the specific device.
### Boot Flow
```
Power On
U-Boot (BSP or mainline)
boot.scr: read SARADC hwrev, select board DTB
U-Boot (mainline, legacy BSP loader for clone boards)
boot script: read SARADC hwrev, select board DTB
sysboot: load kernel + DTB + overlay from extlinux.conf
Kernel 6.12 + initramfs
mount root (ext4) + storage
mount root (ext4) + storage, resolved by partition label
switch_root to systemd
systemd
archr-autostart (quirks, governors, audio)
archr-autostart (quirks by device-tree model, governors, audio)
EmulationStation
```
@@ -130,7 +141,7 @@ Power On
| Partition | Filesystem | Label | Purpose |
|-----------|-----------|-------|---------|
| 1 | FAT32 | ARCHR | Boot (kernel, DTBs, overlays, boot.scr) |
| 2 | ext4 | ARCHR_ROOT | Root filesystem |
| 2 | ext4 | ARCHR_ROOT | Root filesystem (Arch Linux ARM) |
| 3 | ext4 | STORAGE | User data, ROMs, configs |
## Community
@@ -139,7 +150,7 @@ Contributions are welcome. Please open issues or pull requests on [GitHub](https
## Licenses
**Arch R** is a fork of [ROCKNIX](https://github.com/ROCKNIX/distribution), which is a fork of [JELOS](https://github.com/JustEnoughLinuxOS/distribution/). All upstream licenses apply.
The Arch R operating system is Arch Linux ARM plus original Arch R software. The image build tooling in this repository descends from [ROCKNIX](https://github.com/ROCKNIX/distribution) and [JELOS](https://github.com/JustEnoughLinuxOS/distribution/); the licenses of that inherited tooling continue to apply to the portions derived from it.
You are free to:
@@ -168,12 +179,12 @@ Like any Linux distribution, this project is not the work of one person. It is t
Special thanks to:
- **[ROCKNIX](https://github.com/ROCKNIX/distribution)** -- the upstream distribution that Arch R is forked from. ROCKNIX provided the complete build system, device support, EmulationStation integration, and the foundation for handheld gaming on Linux.
- **[JELOS](https://github.com/JustEnoughLinuxOS/distribution/)** -- the project that ROCKNIX was originally forked from.
- **[CoreELEC](https://coreelec.org/)** and **[LibreELEC](https://libreelec.tv/)** -- the embedded Linux distributions whose build system forms the backbone of this project.
- **[Arch Linux](https://archlinux.org/)** and **[Arch Linux ARM](https://archlinuxarm.org/)** -- the operating system Arch R is built on.
- **[ROCKNIX](https://github.com/ROCKNIX/distribution)** and **[JELOS](https://github.com/JustEnoughLinuxOS/distribution/)** -- the projects whose build tooling and RK3326 device knowledge Arch R inherited and still learns from.
- **[CoreELEC](https://coreelec.org/)** and **[LibreELEC](https://libreelec.tv/)** -- the embedded Linux distributions whose build system forms the backbone of the image pipeline.
- **[Hardkernel](https://www.hardkernel.com/)** -- for the Odroid Go Advance BSP U-Boot and kernel device trees.
- **[Rockchip](https://www.rock-chips.com/)** -- for the RK3326 SoC and rkbin firmware.
- **[Mesa](https://mesa3d.org/)** -- for the Panfrost open-source GPU driver.
- **[Rockchip](https://www.rock-chips.com/)** -- for the RK3326 SoC, rkbin firmware and the libmali GPU driver.
- **[Mesa](https://mesa3d.org/)** -- for the open-source graphics stack.
- **[RetroArch](https://www.retroarch.com/)** and **[Libretro](https://www.libretro.com/)** -- for the emulation framework and cores.
- **[EmulationStation](https://emulationstation.org/)** -- for the frontend.
- All developers and contributors across the open-source community who made this possible.
@@ -15,6 +15,22 @@
this = "r33s";
};
gpio-leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&power_led_pin>;
led-0 {
/* Mono blue power LED on GPIO2_B5 (BSP gpio77), active
* low: the old JELOS quirk wrote 1 through the legacy
* gpio sysfs to turn it off. sysfs name is blue:status. */
color = <LED_COLOR_ID_BLUE>;
function = LED_FUNCTION_STATUS;
gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_LOW>;
default-state = "on";
};
};
builtin_gamepad: r33s_joypad {
compatible = "archr-singleadc-joypad";
pinctrl-names = "default";
@@ -107,6 +123,12 @@
};
&pinctrl {
leds {
power_led_pin: power-led-pin {
rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
btns {
btn_pins: btn-pins {
rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>,
@@ -15,6 +15,23 @@
this = "r36s";
};
gpio-leds {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&power_led_pin>;
led-0 {
/* Bicolor power LED behind a single line (BSP gpio77 =
* GPIO2_B5): driving it high lights red, low shows the
* green side, so there is no hardware "off". Exposed as
* the red half; sysfs name is red:status. */
color = <LED_COLOR_ID_RED>;
function = LED_FUNCTION_STATUS;
gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_HIGH>;
default-state = "off";
};
};
joypad: odroidgo3-joypad {
compatible = "odroidgo3-joypad";
pwms = <&pwm0 0 200000000 0>;
@@ -202,6 +219,12 @@
};
&pinctrl {
leds {
power_led_pin: power-led-pin {
rockchip,pins = <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
btns {
btn_pins: btn-pins {
rockchip,pins = <1 RK_PB4 RK_FUNC_GPIO &pcfg_pull_up>,
@@ -24,20 +24,19 @@
this = "soysauce";
};
/* LED indicators (soysauce-specific) */
/* LED indicators (soysauce-specific). Only the blue power LED is
* GPIO-driven; the red one is hardwired to the charger IC (toggling
* the old led-red node on GPIO0_A5 did nothing on hardware, so the
* node was a phantom and got dropped). The line is active HIGH:
* declaring it active low inverted the whole ES power LED menu
* (off lit the LED, on darkened it, heartbeat looked normal). */
leds {
compatible = "gpio-leds";
led-red {
gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_LOW>;
label = "red";
default-state = "off";
};
led-blue {
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_HIGH>;
label = "blue";
default-state = "off";
default-state = "on";
};
};
@@ -276,3 +275,16 @@
};
};
};
/* The Soysauce routes the PMIC interrupt to GPIO0_A7, not the GPIO0_B2
* the rest of the family uses (vendor DTB pmic_int pinctrl says pin 7).
* With the wrong pin every rk817 interrupt is lost: power key, jack
* detect, charger plug events and the suspend wake path (verified live:
* /proc/interrupts stayed at zero across button presses). */
&rk817 {
interrupts = <RK_PA7 IRQ_TYPE_LEVEL_LOW>;
};
&pmic_int {
rockchip,pins = <0 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
};
@@ -2173,7 +2173,7 @@ CONFIG_MT7663_USB_SDIO_COMMON=m
CONFIG_MT7663U=m
CONFIG_MT7663S=m
# CONFIG_MT7921S is not set
# CONFIG_MT7921U is not set
CONFIG_MT7921U=m
# CONFIG_MT7925U is not set
CONFIG_WLAN_VENDOR_MICROCHIP=y
# CONFIG_WILC1000_SDIO is not set
+1 -1
View File
@@ -61,7 +61,7 @@
# for a list of additional drivers see packages/linux-drivers
# Space separated list is supported,
# e.g. ADDITIONAL_DRIVERS="DRIVER1 DRIVER2"
ADDITIONAL_DRIVERS="RTL8188EUS RTL8812AU RTL8814AU RTL8821AU RTL8821CU RTL88x2BU RTL8831 AIC8800 mali-bifrost"
ADDITIONAL_DRIVERS="rk915 RTL8188EUS RTL8812AU RTL8814AU RTL8821AU RTL8821CU RTL88x2BU RTL8831 RTL8852BU RTL8852CU AIC8800 mali-bifrost"
# Additional Firmware to use ( )
# Space separated list is supported,
@@ -0,0 +1,238 @@
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index 1bbff11..xxxxxxx 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c 2025-12-07 05:25:03.000000000 +0800
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c 2026-03-24 08:32:09.772362168 +0800
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -189,6 +190,8 @@
* @port_id: flag for otg port or host port.
* @suspended: phy suspended flag.
* @vbus_attached: otg device vbus status.
+ * @switch_gpio: GPIO descriptor for USB signal routing switch.
+ * @ext_supply: regulator for external USB device power supply.
* @host_disconnect: usb host disconnect status.
* @bvalid_irq: IRQ number assigned for vbus valid rise detection.
* @id_irq: IRQ number assigned for ID pin detection.
@@ -209,6 +212,8 @@
unsigned int port_id;
bool suspended;
bool vbus_attached;
+ struct gpio_desc *switch_gpio;
+ struct regulator *ext_supply;
bool host_disconnect;
int bvalid_irq;
int id_irq;
@@ -640,6 +645,24 @@
.owner = THIS_MODULE,
};
+/*
+ * Check if we should be in USB host mode.
+ * Returns true if:
+ * - EXTCON_USB_HOST is set, OR
+ * - switch_gpio exists and is low (internal device mode)
+ */
+static bool rockchip_usb2phy_is_host_mode(struct rockchip_usb2phy *rphy,
+ struct rockchip_usb2phy_port *rport)
+{
+ if (rphy->edev && extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0)
+ return true;
+
+ if (rport->switch_gpio && gpiod_get_value_cansleep(rport->switch_gpio) == 0)
+ return true;
+
+ return false;
+}
+
static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
{
struct rockchip_usb2phy_port *rport =
@@ -666,7 +689,7 @@
rockchip_usb2phy_power_off(rport->phy);
fallthrough;
case OTG_STATE_B_IDLE:
- if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) {
+ if (rockchip_usb2phy_is_host_mode(rphy, rport)) {
dev_dbg(&rport->phy->dev, "usb otg host connect\n");
rport->state = OTG_STATE_A_HOST;
rockchip_usb2phy_power_on(rport->phy);
@@ -740,7 +763,7 @@
sch_work = true;
break;
case OTG_STATE_A_HOST:
- if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) {
+ if (!rockchip_usb2phy_is_host_mode(rphy, rport)) {
dev_dbg(&rport->phy->dev, "usb otg host disconnect\n");
rport->state = OTG_STATE_B_IDLE;
rockchip_usb2phy_power_off(rport->phy);
@@ -1042,6 +1065,115 @@
return IRQ_HANDLED;
}
+/*
+ * Helper to find OTG port
+ */
+static struct rockchip_usb2phy_port *
+rockchip_usb2phy_find_switch_port(struct rockchip_usb2phy *rphy)
+{
+ unsigned int i;
+
+ for (i = 0; i < rphy->phy_cfg->num_ports; i++) {
+ if (rphy->ports[i].port_id == USB2PHY_PORT_OTG)
+ return &rphy->ports[i];
+ }
+ return NULL;
+}
+
+static ssize_t usb_switch_gpio_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rockchip_usb2phy *rphy = dev_get_drvdata(dev);
+ struct rockchip_usb2phy_port *rport;
+
+ rport = rockchip_usb2phy_find_switch_port(rphy);
+ if (!rport || !rport->switch_gpio)
+ return sysfs_emit(buf, "unsupported\n");
+
+ return sysfs_emit(buf, "%d\n",
+ gpiod_get_value_cansleep(rport->switch_gpio));
+}
+
+static ssize_t usb_switch_gpio_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rockchip_usb2phy *rphy = dev_get_drvdata(dev);
+ struct rockchip_usb2phy_port *rport;
+ unsigned int val;
+ int ret;
+
+ rport = rockchip_usb2phy_find_switch_port(rphy);
+ if (!rport || !rport->switch_gpio)
+ return -ENOTSUPP;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ gpiod_set_value_cansleep(rport->switch_gpio, val ? 1 : 0);
+ dev_info(dev, "switch_gpio set to %d\n", val ? 1 : 0);
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_switch_gpio);
+
+static ssize_t usb_switch_ext_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rockchip_usb2phy *rphy = dev_get_drvdata(dev);
+ struct rockchip_usb2phy_port *rport;
+
+ rport = rockchip_usb2phy_find_switch_port(rphy);
+ if (!rport || !rport->ext_supply)
+ return sysfs_emit(buf, "unsupported\n");
+
+ return sysfs_emit(buf, "%d\n", regulator_is_enabled(rport->ext_supply));
+}
+
+static ssize_t usb_switch_ext_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct rockchip_usb2phy *rphy = dev_get_drvdata(dev);
+ struct rockchip_usb2phy_port *rport;
+ unsigned int val;
+ int ret;
+
+ rport = rockchip_usb2phy_find_switch_port(rphy);
+ if (!rport || !rport->ext_supply)
+ return -ENOTSUPP;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val)
+ ret = regulator_enable(rport->ext_supply);
+ else
+ ret = regulator_disable(rport->ext_supply);
+
+ if (ret) {
+ dev_err(dev, "failed to %s ext-supply: %d\n",
+ val ? "enable" : "disable", ret);
+ return ret;
+ }
+ dev_info(dev, "ext-supply %s\n", val ? "enabled" : "disabled");
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_switch_ext);
+
+static struct attribute *rockchip_usb2phy_switch_attrs[] = {
+ &dev_attr_usb_switch_gpio.attr,
+ &dev_attr_usb_switch_ext.attr,
+ NULL,
+};
+
+static const struct attribute_group rockchip_usb2phy_switch_group = {
+ .attrs = rockchip_usb2phy_switch_attrs,
+};
+
static irqreturn_t rockchip_usb2phy_id_irq(int irq, void *data)
{
struct rockchip_usb2phy_port *rport = data;
@@ -1281,6 +1413,34 @@
mutex_init(&rport->mutex);
+ /*
+ * Get optional switch GPIO for USB signal routing.
+ * Some devices use a GPIO to multiplex USB signals between
+ * an external USB port and an internal device (like WiFi).
+ * Default to internal device (GPIO low) on init.
+ */
+ rport->switch_gpio = devm_fwnode_gpiod_get(rphy->dev,
+ of_fwnode_handle(child_np),
+ "switch", GPIOD_OUT_LOW,
+ "usb-switch");
+ if (IS_ERR(rport->switch_gpio)) {
+ if (PTR_ERR(rport->switch_gpio) != -ENOENT)
+ dev_warn(rphy->dev, "failed to get switch GPIO: %ld\n",
+ PTR_ERR(rport->switch_gpio));
+ rport->switch_gpio = NULL;
+ } else if (rport->switch_gpio) {
+ gpiod_set_value_cansleep(rport->switch_gpio, 0);
+ dev_info(rphy->dev, "USB switch GPIO initialized, default to internal device\n");
+ }
+
+ rport->ext_supply = devm_regulator_get_optional(&rport->phy->dev, "ext");
+ if (IS_ERR(rport->ext_supply)) {
+ rport->ext_supply = NULL;
+ } else if (rport->ext_supply) {
+ regulator_enable(rport->ext_supply);
+ dev_info(rphy->dev, "ext-supply regulator initialized, default enabled\n");
+ }
+
rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1);
if (rport->mode == USB_DR_MODE_HOST ||
rport->mode == USB_DR_MODE_UNKNOWN) {
@@ -1480,6 +1640,13 @@
}
}
+ /* Create sysfs for USB switch control */
+ if (rockchip_usb2phy_find_switch_port(rphy)) {
+ ret = sysfs_create_group(&dev->kobj, &rockchip_usb2phy_switch_group);
+ if (ret)
+ dev_warn(dev, "failed to create usb_switch sysfs: %d\n", ret);
+ }
+
return PTR_ERR_OR_ZERO(provider);
put_child:
@@ -0,0 +1,81 @@
diff -ur linux-6.12.29/drivers/mmc/core/host.c linux_for_rk915/drivers/mmc/core/host.c
--- linux-6.12.29/drivers/mmc/core/host.c 2025-05-18 06:25:00.000000000 +0000
+++ linux_for_rk915/drivers/mmc/core/host.c 2025-06-28 17:43:59.825733795 +0000
@@ -403,6 +403,8 @@
host->caps2 |= MMC_CAP2_NO_SD;
if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC;
+ if (device_property_read_bool(dev, "supports-rk912"))
+ host->caps2 |= MMC_CAP2_WIFI_RK912;
if (device_property_read_bool(dev, "no-mmc-hs400"))
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
diff -ur linux-6.12.29/drivers/mmc/core/sdio.c linux_for_rk915/drivers/mmc/core/sdio.c
--- linux-6.12.29/drivers/mmc/core/sdio.c 2025-05-18 06:25:00.000000000 +0000
+++ linux_for_rk915/drivers/mmc/core/sdio.c 2025-06-28 17:43:59.827733748 +0000
@@ -1076,7 +1076,8 @@
* removable card is checked from a detect work later on in the resume
* process.
*/
- if (!mmc_card_keep_power(host)) {
+ if (!mmc_card_keep_power(host) &&
+ !(host->caps2 & MMC_CAP2_WIFI_RK912)) {
mmc_power_up(host, host->card->ocr);
/*
* Tell runtime PM core we just powered up the card,
diff -ur linux-6.12.29/drivers/mmc/core/sdio_cis.c linux_for_rk915/drivers/mmc/core/sdio_cis.c
--- linux-6.12.29/drivers/mmc/core/sdio_cis.c 2025-05-18 06:25:00.000000000 +0000
+++ linux_for_rk915/drivers/mmc/core/sdio_cis.c 2025-06-28 17:43:59.826733772 +0000
@@ -190,15 +191,15 @@
pr_warn("%s: card has broken SDIO 1.1 CIS, forcing SDIO 1.0\n",
mmc_hostname(card->host));
vsn = SDIO_SDIO_REV_1_00;
- } else if (size < min_size) {
+ } else if (size < min_size && !(card->host->caps2 & MMC_CAP2_WIFI_RK912)) {
return -EINVAL;
}
/* TPLFE_MAX_BLK_SIZE */
func->max_blksize = buf[12] | (buf[13] << 8);
/* TPLFE_ENABLE_TIMEOUT_VAL, present in ver 1.1 and above */
- if (vsn > SDIO_SDIO_REV_1_00)
+ if (vsn > SDIO_SDIO_REV_1_00 && !(card->host->caps2 & MMC_CAP2_WIFI_RK912))
func->enable_timeout = (buf[28] | (buf[29] << 8)) * 10;
else
func->enable_timeout = jiffies_to_msecs(HZ);
diff -ur linux-6.12.29/drivers/mmc/host/dw_mmc.c linux_for_rk915/drivers/mmc/host/dw_mmc.c
--- linux-6.12.29/drivers/mmc/host/dw_mmc.c 2025-05-18 06:25:00.000000000 +0000
+++ linux_for_rk915/drivers/mmc/host/dw_mmc.c 2025-06-28 17:44:02.417672518 +0000
@@ -295,6 +295,10 @@
SDMMC_CMD_PRV_DAT_WAIT, 0);
}
+ if ((mmc->caps2 & MMC_CAP2_WIFI_RK912) &&
+ (cmd->opcode == SD_IO_RW_DIRECT))
+ cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
+
if (cmd->flags & MMC_RSP_PRESENT) {
/* We expect a response, so set this bit */
cmdr |= SDMMC_CMD_RESP_EXP;
@@ -1263,7 +1267,8 @@
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
- if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags))
+ if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags) &&
+ !(slot->mmc->caps2 & MMC_CAP2_WIFI_RK912))
clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
mci_writel(host, CLKENA, clk_en_a);
diff -ur linux-6.12.29/include/linux/mmc/host.h linux_for_rk915/include/linux/mmc/host.h
--- linux-6.12.29/include/linux/mmc/host.h 2025-05-18 06:25:00.000000000 +0000
+++ linux_for_rk915/include/linux/mmc/host.h 2025-06-28 17:45:54.422123779 +0000
@@ -404,6 +404,7 @@
#define MMC_CAP2_CRYPTO 0
#endif
#define MMC_CAP2_ALT_GPT_TEGRA (1 << 28) /* Host with eMMC that has GPT entry at a non-standard location */
+#define MMC_CAP2_WIFI_RK912 (1 << 29)
int fixed_drv_type; /* fixed driver type for non-removable media */
+56
View File
@@ -0,0 +1,56 @@
# Built-in gamepad definitions (single source of truth)
Every built-in platform pad must exist in THREE shipped artifacts:
1. `packages/ui/emulationstation/config/common/es_input.cfg` (EmulationStation)
2. `packages/emulators/libretro/retroarch/retroarch-joypads/gamepads/<name>.cfg` (RetroArch)
3. `packages/apps/gamecontrollerdb/config/gamecontrollerdb.txt` (SDL games and ports)
Historically these were maintained by hand and nothing checked they agreed:
the Soysauce pad shipped without the SDL entry, so ports saw no controller.
The JSON files in `defs/` are now the source of truth and `gen-input-configs`
keeps the three artifacts honest.
## Daily use
`make docker-*` refuses to build if the artifacts drifted from `defs/`:
./gen-input-configs verify # what CI/build runs
./gen-input-configs write # regenerate artifacts from defs
Only external controllers (USB/Bluetooth pads inherited from upstream
databases) stay unmanaged; the managed set is exactly the defs directory.
## Adding a new pad (example: a future R36T Max)
1. On the device, read the identity:
cat /proc/bus/input/devices # Name=, Vendor=, Product=, Version=
2. Compute the GUID the runtime will use (bus 0x19 for platform drivers):
./gen-input-configs guid "r36tmax_Gamepad" --vendor 1 --product 0x1199 --version 0x0100
Vendor or product zero switches SDL to the name-embedded GUID form
automatically, exactly like the runtime does (that mismatch was the
Soysauce bug).
3. Copy the closest def (`defs/r36s_Gamepad.json`), adjust name, identity,
buses, the SDL mapping string, the ES inputs and the RetroArch keys.
4. Materialize and check:
./gen-input-configs write "r36tmax_Gamepad"
./gen-input-configs verify
5. Commit the def together with the regenerated artifacts.
## Fidelity rules (deliberate)
* gamecontrollerdb line: byte-exact; the GUID is always recomputed from the
identity fields (use `guid_override` only for entries that predate the
tool and cannot be reproduced; none of the platform pads needs it).
* RetroArch cfg and es_input block: semantically exact (key/value sets);
comments, blank lines and ordering are not preserved by `write`.
* `sdl_mapping` may be a per-GUID dict when buses legitimately differ
(retrogame_joypad ships guide:b10 only on the 0x19 bus line).
@@ -0,0 +1,204 @@
{
"name": "GO-Super Gamepad",
"vendor": 0,
"product": 4352,
"version": 256,
"buses": [
25
],
"sdl_mapping": "platform:Linux,a:b1,b:b0,dpdown:b14,dpleft:b15,+lefty:+a1,-leftx:-a0,+leftx:+a0,-lefty:-a1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,dpright:b16,+righty:+a3,-rightx:-a2,+rightx:+a2,-righty:-a3,rightshoulder:b5,rightstick:b12,righttrigger:b7,back:b8,start:b9,dpup:b13,x:b2,y:b3,",
"retroarch": {
"input_device": "GO-Super Gamepad",
"input_driver": "udev",
"input_vendor_id": "0000",
"input_product_id": "1100",
"input_b_btn": "0",
"input_a_btn": "1",
"input_x_btn": "2",
"input_y_btn": "3",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "6",
"input_r2_btn": "7",
"input_up_btn": "13",
"input_down_btn": "14",
"input_left_btn": "15",
"input_right_btn": "16",
"input_select_btn": "8",
"input_start_btn": "9",
"input_l3_btn": "11",
"input_r3_btn": "12",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_r_x_plus_axis": "+2",
"input_r_x_minus_axis": "-2",
"input_r_y_plus_axis": "+3",
"input_r_y_minus_axis": "-3",
"input_enable_hotkey_btn": "8",
"input_exit_emulator_btn": "9",
"input_screenshot_btn": "0",
"input_pause_toggle_btn": "1",
"input_menu_toggle_btn": "2",
"input_fps_toggle_btn": "3",
"input_state_slot_increase_btn": "13",
"input_state_slot_decrease_btn": "14",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_rewind_btn": "6",
"input_toggle_fast_forward_btn": "7"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "16",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "2",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "2",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "3",
"value": "1"
}
]
}
@@ -0,0 +1,202 @@
{
"name": "GO-Ultra Gamepad",
"vendor": 0,
"product": 0,
"version": 0,
"buses": [
3
],
"sdl_mapping": "platform:Linux,a:b1,b:b0,dpdown:b15,dpleft:b16,guide:b11,+lefty:+a1,-leftx:-a0,+leftx:+a0,-lefty:-a1,leftshoulder:b5,leftstick:b12,lefttrigger:b7,dpright:b17,+righty:+a3,-rightx:-a2,+rightx:+a2,-righty:-a3,rightshoulder:b6,rightstick:b13,righttrigger:b8,back:b9,start:b10,dpup:b14,x:b3,y:b4,",
"retroarch": {
"input_device": "GO-Ultra Gamepad",
"input_driver": "udev",
"input_b_btn": "0",
"input_a_btn": "1",
"input_x_btn": "3",
"input_y_btn": "4",
"input_l_btn": "5",
"input_r_btn": "6",
"input_l2_btn": "7",
"input_r2_btn": "8",
"input_up_btn": "14",
"input_down_btn": "15",
"input_left_btn": "16",
"input_right_btn": "17",
"input_select_btn": "9",
"input_start_btn": "10",
"input_l3_btn": "12",
"input_r3_btn": "13",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_r_x_plus_axis": "+2",
"input_r_x_minus_axis": "-2",
"input_r_y_plus_axis": "+3",
"input_r_y_minus_axis": "-3",
"input_enable_hotkey_btn": "11",
"input_exit_emulator_btn": "10",
"input_screenshot_btn": "0",
"input_pause_toggle_btn": "1",
"input_menu_toggle_btn": "3",
"input_fps_toggle_btn": "4",
"input_state_slot_increase_btn": "14",
"input_state_slot_decrease_btn": "15",
"input_load_state_btn": "5",
"input_save_state_btn": "6",
"input_rewind_btn": "7",
"input_toggle_fast_forward_btn": "8"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "16",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "17",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "2",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "3",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "4",
"value": "1"
}
]
}
@@ -0,0 +1,191 @@
{
"name": "GameForce ACE Gamepad",
"vendor": 0,
"product": 0,
"version": 0,
"buses": [
3
],
"sdl_mapping": "a:b1,b:b0,dpdown:b13,dpleft:b14,lefty:a1,leftx:a0,leftshoulder:b5,leftstick:b10,lefttrigger:-a2,dpright:b15,+righty:+a4,-rightx:-a3,+rightx:+a3,-righty:-a4,rightshoulder:b6,rightstick:b11,righttrigger:-a5,back:b7,guide:b9,start:b8,dpup:b12,x:b3,y:b4,platform:Linux,",
"retroarch": {
"input_driver": "udev",
"input_device": "GameForce ACE Gamepad",
"input_b_btn": "0",
"input_y_btn": "4",
"input_select_btn": "7",
"input_start_btn": "8",
"input_up_btn": "12",
"input_down_btn": "13",
"input_left_btn": "14",
"input_right_btn": "15",
"input_a_btn": "1",
"input_x_btn": "3",
"input_l_btn": "5",
"input_r_btn": "6",
"input_l2_axis": "-2",
"input_r2_axis": "-5",
"input_l3_btn": "10",
"input_r3_btn": "11",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_r_x_plus_axis": "+3",
"input_r_x_minus_axis": "-3",
"input_r_y_plus_axis": "+4",
"input_r_y_minus_axis": "-4",
"input_enable_hotkey_btn": "9"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "lefttrigger",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "right",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "4",
"value": "1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "4",
"value": "-1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "righttrigger",
"type": "axis",
"id": "5",
"value": "-1"
},
{
"name": "select",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "3",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "4",
"value": "1"
}
]
}
@@ -0,0 +1,209 @@
{
"name": "H700 Gamepad",
"vendor": 18507,
"product": 5343,
"version": 256,
"buses": [
25
],
"sdl_mapping": "platform:Linux,x:b3,a:b1,b:b0,y:b2,back:b8,guide:b10,start:b9,dpleft:b15,dpdown:b14,dpright:b16,dpup:b13,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
"retroarch": {
"input_driver": "udev",
"input_device": "H700 Gamepad",
"input_device_display_name": "Anbernic RG35XX Gamepad",
"input_vendor_id": "18507",
"input_product_id": "5343",
"input_b_btn": "0",
"input_a_btn": "1",
"input_y_btn": "2",
"input_x_btn": "3",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "6",
"input_r2_btn": "7",
"input_select_btn": "8",
"input_start_btn": "9",
"input_l3_btn": "11",
"input_r3_btn": "12",
"input_up_btn": "13",
"input_down_btn": "14",
"input_left_btn": "15",
"input_right_btn": "16",
"input_enable_hotkey_btn": "10",
"input_exit_emulator_btn": "9",
"input_pause_toggle_btn": "1",
"input_menu_toggle_btn": "3",
"input_fps_toggle_btn": "2",
"input_screenshot_btn": "nul",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_toggle_fast_forward_btn": "7",
"input_rewind_btn": "6",
"input_analog_dpad_mode": "0",
"input_gun_trigger_mbtn": "1",
"input_joypad_index": "0",
"input_l_x_minus_axis": "-0",
"input_l_x_plus_axis": "+0",
"input_l_y_minus_axis": "-1",
"input_l_y_plus_axis": "+1",
"input_mouse_index": "0",
"input_r_x_minus_axis": "-2",
"input_r_x_plus_axis": "+2",
"input_r_y_minus_axis": "-3",
"input_r_y_plus_axis": "+3",
"input_state_slot_increase_btn": "nul",
"input_state_slot_decrease_btn": "nul"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "16",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "2",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "3",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "2",
"value": "1"
}
]
}
@@ -0,0 +1,199 @@
{
"name": "RGB20S Gamepad",
"vendor": 18507,
"product": 4471,
"version": 375,
"buses": [
25
],
"sdl_mapping": "platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b12,start:b13,dpleft:b10,dpdown:b9,dpright:b11,dpup:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b14,rightstick:b15,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
"retroarch": {
"input_driver": "udev",
"input_device": "RGB20S Gamepad",
"input_device_display_name": "RGB20S Gamepad",
"input_b_btn": "0",
"input_y_btn": "3",
"input_select_btn": "12",
"input_start_btn": "13",
"input_a_btn": "1",
"input_x_btn": "2",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "6",
"input_r2_btn": "7",
"input_l3_btn": "14",
"input_r3_btn": "15",
"input_up_btn": "8",
"input_down_btn": "9",
"input_left_btn": "10",
"input_right_btn": "11",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_r_x_plus_axis": "+2",
"input_r_x_minus_axis": "-2",
"input_r_y_plus_axis": "+3",
"input_r_y_minus_axis": "-3",
"input_enable_hotkey_btn": "12",
"input_exit_emulator_btn": "13",
"input_menu_toggle_btn": "2",
"input_fps_toggle_btn": "3",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_rewind_btn": "6",
"input_toggle_fast_forward_btn": "7"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "2",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "2",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "3",
"value": "1"
}
]
}
@@ -0,0 +1,203 @@
{
"name": "XU10 Gamepad",
"vendor": 50096,
"product": 512,
"version": 16,
"buses": [
25
],
"sdl_mapping": "platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,guide:b16,start:b9,dpleft:b14,dpdown:b13,dpright:b15,dpup:b12,leftshoulder:b4,lefttrigger:b7,rightshoulder:b5,righttrigger:b6,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
"retroarch": {
"input_device": "XU10 Gamepad",
"input_driver": "udev",
"input_device_display_name": "MagicX XU10 Gamepad",
"input_b_btn": "1",
"input_a_btn": "2",
"input_x_btn": "3",
"input_y_btn": "0",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "7",
"input_r2_btn": "6",
"input_up_btn": "12",
"input_down_btn": "13",
"input_left_btn": "14",
"input_right_btn": "15",
"input_select_btn": "8",
"input_start_btn": "9",
"input_l3_btn": "10",
"input_r3_btn": "11",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_r_x_plus_axis": "+2",
"input_r_x_minus_axis": "-2",
"input_r_y_plus_axis": "+3",
"input_r_y_minus_axis": "-3",
"input_enable_hotkey_btn": "16",
"input_exit_emulator_btn": "9",
"input_screenshot_btn": "0",
"input_pause_toggle_btn": "1",
"input_menu_toggle_btn": "2",
"input_fps_toggle_btn": "3",
"input_state_slot_increase_btn": "7",
"input_state_slot_decrease_btn": "6",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_rewind_btn": "10",
"input_toggle_fast_forward_btn": "11"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "2",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "16",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "2",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "3",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "0",
"value": "1"
}
]
}
@@ -0,0 +1,199 @@
{
"name": "XU Mini M Gamepad",
"vendor": 50096,
"product": 512,
"version": 16,
"buses": [
25
],
"sdl_mapping": "platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,guide:b16,start:b9,dpleft:b14,dpdown:b13,dpright:b15,dpup:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
"retroarch": {
"input_driver": "udev",
"input_device": "XU Mini M Gamepad",
"input_device_display_name": "MagicX XU Mini M Gamepad",
"input_b_btn": "0",
"input_y_btn": "3",
"input_select_btn": "8",
"input_start_btn": "9",
"input_up_btn": "12",
"input_down_btn": "13",
"input_left_btn": "14",
"input_right_btn": "15",
"input_a_btn": "1",
"input_x_btn": "2",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "6",
"input_r2_btn": "7",
"input_l3_btn": "10",
"input_r3_btn": "11",
"input_l_x_plus_axis": "+1",
"input_l_x_minus_axis": "-1",
"input_l_y_plus_axis": "-0",
"input_l_y_minus_axis": "+0",
"input_r_x_plus_axis": "+3",
"input_r_x_minus_axis": "-3",
"input_r_y_plus_axis": "-2",
"input_r_y_minus_axis": "+2",
"input_enable_hotkey_btn": "16",
"input_exit_emulator_btn": "9",
"input_menu_toggle_btn": "2",
"input_fps_toggle_btn": "3",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_rewind_btn": "6",
"input_toggle_fast_forward_btn": "7"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "16",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "rightanalogdown",
"type": "axis",
"id": "2",
"value": "-1"
},
{
"name": "rightanalogleft",
"type": "axis",
"id": "3",
"value": "-1"
},
{
"name": "rightanalogright",
"type": "axis",
"id": "3",
"value": "1"
},
{
"name": "rightanalogup",
"type": "axis",
"id": "2",
"value": "1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "2",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "3",
"value": "1"
}
]
}
@@ -0,0 +1,157 @@
{
"name": "odroidgo2_joypad",
"vendor": 1,
"product": 1,
"version": 257,
"buses": [
25
],
"sdl_mapping": "platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b10,start:b13,dpleft:b8,dpdown:b7,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b11,rightshoulder:b5,righttrigger:b12,leftx:a0,lefty:a1,",
"retroarch": {
"input_driver": "udev",
"input_device": "odroidgo2_joypad",
"input_device_display_name": "Odroid GO Advance Joypad",
"input_b_btn": "0",
"input_y_btn": "3",
"input_select_btn": "10",
"input_start_btn": "13",
"input_a_btn": "1",
"input_x_btn": "2",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "11",
"input_r2_btn": "12",
"input_up_btn": "6",
"input_down_btn": "7",
"input_left_btn": "8",
"input_right_btn": "9",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_enable_hotkey_btn": "10",
"input_exit_emulator_btn": "13",
"input_menu_toggle_btn": "2",
"input_fps_toggle_btn": "3",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_rewind_btn": "11",
"input_toggle_fast_forward_btn": "12"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "2",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "3",
"value": "1"
}
]
}
@@ -0,0 +1,171 @@
{
"name": "odroidgo2_v11_joypad",
"vendor": 1,
"product": 2,
"version": 257,
"buses": [
25
],
"sdl_mapping": "platform:Linux,x:b2,a:b1,b:b0,y:b3,back:b8,start:b9,dpleft:b14,dpdown:b13,dpright:b15,dpup:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,",
"retroarch": {
"input_driver": "udev",
"input_device": "odroidgo2_v11_joypad",
"input_device_display_name": "Odroid GO Advance Joypad v1.1",
"input_b_btn": "0",
"input_y_btn": "3",
"input_select_btn": "8",
"input_start_btn": "9",
"input_a_btn": "1",
"input_x_btn": "2",
"input_l_btn": "4",
"input_r_btn": "5",
"input_l2_btn": "6",
"input_r2_btn": "7",
"input_l3_btn": "10",
"input_r3_btn": "11",
"input_up_btn": "12",
"input_down_btn": "13",
"input_left_btn": "14",
"input_right_btn": "15",
"input_l_x_plus_axis": "+0",
"input_l_x_minus_axis": "-0",
"input_l_y_plus_axis": "+1",
"input_l_y_minus_axis": "-1",
"input_enable_hotkey_btn": "8",
"input_exit_emulator_btn": "9",
"input_menu_toggle_btn": "2",
"input_fps_toggle_btn": "3",
"input_load_state_btn": "4",
"input_save_state_btn": "5",
"input_rewind_btn": "6",
"input_toggle_fast_forward_btn": "7"
},
"es_inputs": [
{
"name": "a",
"type": "button",
"id": "1",
"value": "1"
},
{
"name": "b",
"type": "button",
"id": "0",
"value": "1"
},
{
"name": "down",
"type": "button",
"id": "13",
"value": "1"
},
{
"name": "hotkeyenable",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "left",
"type": "button",
"id": "14",
"value": "1"
},
{
"name": "leftanalogdown",
"type": "axis",
"id": "1",
"value": "1"
},
{
"name": "leftanalogleft",
"type": "axis",
"id": "0",
"value": "-1"
},
{
"name": "leftanalogright",
"type": "axis",
"id": "0",
"value": "1"
},
{
"name": "leftanalogup",
"type": "axis",
"id": "1",
"value": "-1"
},
{
"name": "leftshoulder",
"type": "button",
"id": "4",
"value": "1"
},
{
"name": "leftthumb",
"type": "button",
"id": "10",
"value": "1"
},
{
"name": "lefttrigger",
"type": "button",
"id": "6",
"value": "1"
},
{
"name": "right",
"type": "button",
"id": "15",
"value": "1"
},
{
"name": "rightshoulder",
"type": "button",
"id": "5",
"value": "1"
},
{
"name": "rightthumb",
"type": "button",
"id": "11",
"value": "1"
},
{
"name": "righttrigger",
"type": "button",
"id": "7",
"value": "1"
},
{
"name": "select",
"type": "button",
"id": "8",
"value": "1"
},
{
"name": "start",
"type": "button",
"id": "9",
"value": "1"
},
{
"name": "up",
"type": "button",
"id": "12",
"value": "1"
},
{
"name": "x",
"type": "button",
"id": "2",
"value": "1"
},
{
"name": "y",
"type": "button",
"id": "3",
"value": "1"
}
]
}

Some files were not shown because too many files have changed in this diff Show More