From 01ee20ddba41ee99dc024b28a7baba340031652e Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sat, 29 Aug 2026 21:53:02 +0200 Subject: [PATCH] aports: extract vendor blobs before udev coldplug so first-boot audio fully works The preset fix (6ecc1dc) makes the unit run, but multi-user is too late: the sound card probes at ~21 s, hard-fails (-2, no retry) on the missing ACF, and the extractor's amp rebind at ~60 s cannot re-form a card whose machine driver already failed. Re-probing the machine driver does re-form it, but a late-formed card has a dead capture path - the wcd9378 TX sequencer refuses PS0 (act_ps 0x3) until the next boot. So rebinding after the fact can never fully win; extraction has to happen before the drivers probe. - fp6-vendor-blobs.service: DefaultDependencies=no, run after remount-fs and before systemd-udev-trigger, so blobs exist before module coldplug. multi-user stays a second Wants as a post-udev retry if the early run failed (by-partlabel/make-dynpart-mappings fallbacks need udev). - aw88261-acf.manifest: add 'rebind platform sound' so the fallback path at least recovers playback the same boot (capture then heals on reboot). - fp6-vendor-blobs.post-upgrade (pkgrel 1): systemctl preset + immediate extract, so installs of the 2026-08-24 image (unit shipped disabled, no version bump to deliver the preset) finally heal via plain apk upgrade. - soc-fairphone-fp6-audio pkgrel 1: carries the manifest change. Verified on the dev phone with the exact staged bytes (sha256-compared): simulated fresh install (ACF removed, reboot) extracts at 13.3 s, coldplug probes the amps at 15.1 s, card init at 20.9 s loads the ACF cleanly, and a 1 kHz speaker-to-mic loopback passes on that same first boot with zero TX sequencer warnings; next boot takes the all-dests-present fast path in 25 ms. Evidence: fp6 repo journal/blobs/, 2026-08-29. Assisted-by: Claude:claude-fable-5 --- aports/device/fp6-vendor-blobs/APKBUILD | 13 +++++++--- .../fp6-vendor-blobs.post-upgrade | 10 +++++++ .../fp6-vendor-blobs/fp6-vendor-blobs.service | 26 ++++++++++++++----- .../device/soc-fairphone-fp6-audio/APKBUILD | 4 +-- .../aw88261-acf.manifest | 12 ++++++--- 5 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 aports/device/fp6-vendor-blobs/fp6-vendor-blobs.post-upgrade diff --git a/aports/device/fp6-vendor-blobs/APKBUILD b/aports/device/fp6-vendor-blobs/APKBUILD index d0d793c..6cd43ae 100644 --- a/aports/device/fp6-vendor-blobs/APKBUILD +++ b/aports/device/fp6-vendor-blobs/APKBUILD @@ -14,13 +14,14 @@ maintainer="Jorijn van der Graaf " pkgname=fp6-vendor-blobs pkgver=1 -pkgrel=0 +pkgrel=1 pkgdesc="On-device extraction of vendor blobs from the stock Android partitions" url="https://forgejo.catcrafts.net/Catcrafts/fp6-img" arch="noarch" license="MIT" # fallback mapper for when the initramfs didn't map the dynamic partitions depends="make-dynpart-mappings" +install="$pkgname.post-upgrade" options="!check" source=" fp6-vendor-blobs-extract @@ -35,8 +36,12 @@ package() { "$pkgdir"/usr/lib/systemd/system/fp6-vendor-blobs.service # enabled unconditionally: the unit is a fast no-op once every manifest # dest exists, and blobs appearing on first boot must not depend on a - # manual systemctl enable - mkdir -p "$pkgdir"/etc/systemd/system/multi-user.target.wants + # manual systemctl enable. sysinit = the real (pre-coldplug) run; + # multi-user = the post-udev retry if the early run failed (see unit) + mkdir -p "$pkgdir"/etc/systemd/system/sysinit.target.wants \ + "$pkgdir"/etc/systemd/system/multi-user.target.wants + ln -s /usr/lib/systemd/system/fp6-vendor-blobs.service \ + "$pkgdir"/etc/systemd/system/sysinit.target.wants/fp6-vendor-blobs.service ln -s /usr/lib/systemd/system/fp6-vendor-blobs.service \ "$pkgdir"/etc/systemd/system/multi-user.target.wants/fp6-vendor-blobs.service # ...and a preset, because the symlink alone does NOT survive: image @@ -51,6 +56,6 @@ package() { sha512sums=" a71b2c86f980734d0aae6e135b26272fe52ae5603050bea52f55f7e74c8bd98c62b6194047711248d4fef40851792adc47d77c40016d99a0d68ecd2459894b80 fp6-vendor-blobs-extract -e2c03e5016f1848c57e6160ce432530b181ff5d34a5aaf1822f0ffa5fe71d16691657ada4a5789c4d4209e14e83f43aab072d01f644b07b93648f91e2a7bb0ca fp6-vendor-blobs.service +b4c290095d9f39515378dfef08de720ce49324210342aa13c131dfce1103785e796e6f821f0c659671a4c44b46f466ce0e03f11f216fdcdee2a99db5e7970800 fp6-vendor-blobs.service 9e79dd0aed13f11a71282aa24b2a26331e85c105e25ab0c0fed6189b8c300769a5f4308b18b91d9855868d658ad3a57c03e26c9b11bd27fd5e03f9a5decbbd6a fp6-vendor-blobs.preset " diff --git a/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.post-upgrade b/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.post-upgrade new file mode 100644 index 0000000..c495e57 --- /dev/null +++ b/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.post-upgrade @@ -0,0 +1,10 @@ +#!/bin/sh +# Re-apply the preset: images built before the preset file existed (the +# 2026-08-24 image) shipped the unit `disabled; preset: disabled`, so an +# upgrade must enable it or those installs never extract anything. Then +# extract immediately rather than at the next boot (--if-device makes that +# a quiet no-op inside build/CI chroots). A card that already hard-failed +# this boot recovers playback via the manifest's rebind lines; capture +# needs the next boot (journal/blobs/ 2026-08-29). +systemctl preset fp6-vendor-blobs.service 2>/dev/null || : +exec /usr/lib/fp6-vendor-blobs/extract --if-device diff --git a/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.service b/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.service index 200326e..73bcae7 100644 --- a/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.service +++ b/aports/device/fp6-vendor-blobs/fp6-vendor-blobs.service @@ -1,10 +1,24 @@ [Unit] Description=Extract vendor blobs from the stock Android partitions -# The dynamic-partition mappings come from the initramfs and the dests live -# on the rootfs, so local-fs ordering is enough. Deliberately not ordered -# against driver/audio bringup: the extractor re-probes consumers itself -# (manifest rebind lines), so it never has to win a race. -After=local-fs.target +# Must run BEFORE udev coldplug loads the consuming drivers: a sound card +# that probes without its firmware hard-fails (-2, never retried), and while +# a later re-probe of the machine driver re-forms the card, that late-formed +# card has a dead capture path (wcd9378 TX sequencer refuses PS0 - fp6 repo +# journal/blobs/ 2026-08-29). Only extraction-before-probe yields a fully +# working card, so this runs pre-coldplug; the manifest rebind lines remain +# as the fallback for consumers that probed anyway (playback recovers same +# boot, capture needs the next boot) and for on-device re-extraction after a +# package upgrade. +# The dynamic-partition mappings come from the initramfs (device nodes exist +# pre-udev) and the dests live on the rootfs, so remount-fs ordering is +# enough. multi-user is a deliberate second Wants: if the early run failed +# (e.g. no mappings pre-udev), the multi-user start job retries it after +# udev, where the by-partlabel/make-dynpart-mappings fallbacks work. +DefaultDependencies=no +After=systemd-remount-fs.service +Before=systemd-udev-trigger.service sysinit.target shutdown.target +Conflicts=shutdown.target +RequiresMountsFor=/usr/lib/firmware [Service] Type=oneshot @@ -12,4 +26,4 @@ RemainAfterExit=yes ExecStart=/usr/lib/fp6-vendor-blobs/extract [Install] -WantedBy=multi-user.target +WantedBy=sysinit.target multi-user.target diff --git a/aports/device/soc-fairphone-fp6-audio/APKBUILD b/aports/device/soc-fairphone-fp6-audio/APKBUILD index 6393c1f..0478cce 100644 --- a/aports/device/soc-fairphone-fp6-audio/APKBUILD +++ b/aports/device/soc-fairphone-fp6-audio/APKBUILD @@ -11,7 +11,7 @@ maintainer="Jorijn van der Graaf " pkgname=soc-fairphone-fp6-audio pkgver=4 -pkgrel=0 +pkgrel=1 pkgdesc="Fairphone 6 audio topology and UCM profile" url="https://forgejo.catcrafts.net/Catcrafts/audioreach-topology" arch="noarch" @@ -47,7 +47,7 @@ package() { sha512sums=" 51071c574b9f5899c78ba9fe1b6f3bbda2195e6d274014a05869ae56ed0ff18e15678bd7d78cd68846900d3c579556328e229842152cffd943186d43344ed33c fp6-tplg.bin -bdfe413494b6815cf96843d83c6c9e8deb757b083d7577c93eab460de49d1cd00b8615c115c25d71f6488de4e65f04d5f02bca816b2c31747880a22613e547a3 aw88261-acf.manifest +0240a36e6fae76f6df576c5ffc93241f6d59e03db429811d61c746561743ddb4690cb925028546a6c3d69dcc867aead5ddf1c85b12a0065195ea9c6621fa847f aw88261-acf.manifest 3bb268f9fcb8d1c0b42741b67da42b6361bab259e7211d9930919995ebe7dcf67826e6d4f00ff5e4fe5b52067fe90d00212158c3b4879d1bee481e87f0623206 ucm-milos-fp6.conf 2a189c3141fedc43f8eb19f4df1e43487223d524e27da3f948556d224cca1f493f6815ada191953fb79a19d5c5abadb21de7b3ece7b74b0929338c216e21e84a HiFi.conf ec63fa5363738a43c9eee4b1be70201e2d2076ec817031fda087e61d781e81dc67351be44faf8b056a2939875a139cd909f7c311115bb1150e17ad4493846606 50-echo-cancel.conf diff --git a/aports/device/soc-fairphone-fp6-audio/aw88261-acf.manifest b/aports/device/soc-fairphone-fp6-audio/aw88261-acf.manifest index 7fc47cd..88fbc16 100644 --- a/aports/device/soc-fairphone-fp6-audio/aw88261-acf.manifest +++ b/aports/device/soc-fairphone-fp6-audio/aw88261-acf.manifest @@ -3,8 +3,14 @@ # journal/blobs/, 2026-08-24). Slot A first, slot B as fallback; the copy # must hash-match the blob the audio stack was tested with. file vendor_a,vendor_b firmware/aw882xx_acf.bin /usr/lib/firmware/qcom/milos/fairphone/fp6/aw88261_acf.bin af723973655ba5901948d4a22212323e39ce53ff0156021185720af4af6ab0b3 -# the amps bind on i2c probe but request the ACF only at card init, which -# races the extractor on first boot and is never retried on failure - a -# forced fresh probe of both amps makes audio work that same boot either way +# Rebinds are the FALLBACK for a card that probed before extraction (the +# service normally runs pre-coldplug, so they no-op). The amps bind on i2c +# probe but request the ACF only at card init, never retried on failure; and +# when that failed card init already took the machine driver down (-2, not a +# defer), re-probing the amps alone cannot re-form the card - the platform +# device needs a fresh probe too. Note the recovered card plays back fine +# but its capture path is dead until the next boot (wcd9378 TX sequencer +# refuses PS0 on a late-formed card - journal/blobs/ 2026-08-29). rebind i2c 6-0034 rebind i2c 6-0035 +rebind platform sound