shell: dock reorder, fullscreen detection fix, idle-power, sessiond, misc shell work
- Dock drag-to-reorder for pinned apps (insertion gap, quick-slide vs dwell) - Fullscreen detection: scan all windows via HyprlandData.windowList - IdleCoordinator, GlobalStates, Session.qml updates - Deploy script, qmldir, settings, wallpaper, visualizer fixes - sessiond server, memory module updates Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
9ccefd6c73
commit
19fe6b1d0e
59 changed files with 19450 additions and 139 deletions
160
.handoff-from-phone/discord-betterdiscord/PKGBUILD.x86-reference
Normal file
160
.handoff-from-phone/discord-betterdiscord/PKGBUILD.x86-reference
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
# Maintainer: Zoddo <archlinux+aur@zoddo.fr>
|
||||
# Contributor: Thaodan <AUR+me@thaodan.de>
|
||||
# Contributor: Manuel Hüsers <aur@huesers.de>
|
||||
# Contributor: huyizheng
|
||||
# Contributor: johnnyapol <arch@johnnyapol.me>
|
||||
|
||||
# Based off the discord community repo PKGBUILD by Filipe Laíns (FFY00) <lains@archlinux.org>
|
||||
|
||||
_pkgname=discord
|
||||
_electron=electron
|
||||
pkgname=${_pkgname}_arch_electron
|
||||
pkgver=1.0.146
|
||||
pkgrel=1
|
||||
epoch=1
|
||||
pkgdesc="Discord using system provided ${_electron} for increased security and performance"
|
||||
arch=('x86_64')
|
||||
provides=("${_pkgname}")
|
||||
conflicts=("${_pkgname}")
|
||||
url='https://discord.com'
|
||||
license=('LicenseRef-custom')
|
||||
options=('!strip')
|
||||
install="$pkgname.install"
|
||||
depends=("${_electron}" 'libxss')
|
||||
makedepends=('asar'
|
||||
'jq'
|
||||
'python-pyelftools' # Required for Krisp patcher
|
||||
'python-capstone') # Required for Krisp patcher
|
||||
optdepends=('libpulse: Pulseaudio support'
|
||||
'xdg-utils: Open files')
|
||||
source=("https://dl.discordapp.net/apps/linux/${pkgver}/${_pkgname}-${pkgver}.tar.gz"
|
||||
'LICENSE.html::https://discord.com/terms'
|
||||
'OSS-LICENSES.html::https://discord.com/licenses'
|
||||
'discord-launcher.sh'
|
||||
'krisp-patcher.py'
|
||||
|
||||
# Discord modules (from 'curl "https://updates.discord.com/distributions/app/manifests/latest?channel=stable&platform=linux&arch=x64"')
|
||||
"core-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/full.distro"
|
||||
"discord_desktop_core-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_desktop_core/1/full.distro"
|
||||
"discord_zstd-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_zstd/1/full.distro"
|
||||
"discord_krisp-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_krisp/1/full.distro"
|
||||
"discord_rpc-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_rpc/1/full.distro"
|
||||
"discord_utils-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_utils/1/full.distro"
|
||||
"discord_voice-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_voice/1/full.distro"
|
||||
"discord_game_utils-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_game_utils/1/full.distro"
|
||||
"discord_erlpack-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_erlpack/1/full.distro"
|
||||
"discord_modules-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_modules/1/full.distro"
|
||||
"discord_spellcheck-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_spellcheck/1/full.distro"
|
||||
"discord_dispatch-${pkgver}.tar.br::https://stable.dl2.discordapp.net/distro/app/stable/linux/x64/${pkgver}/discord_dispatch/1/full.distro")
|
||||
sha512sums=('b90cf25a6e615e836e0ef248b3090f23d90c2a6d73faeb21954ba669fb39275c26ac58a8f9e92445254c29fb90716cab54bee06f701cde88f74578c4228bc22b'
|
||||
'2590151db4404a9ecbae2c45269c74f5ea26479967de5bc0b221a9143f4efeeeda9e335c23cf1f982680ab4fd895dcf3fd5731bd230908b3b2568eee0ec223ec'
|
||||
'5cccf397a772fed0db9b19253e496e78af27810227325ce681de985e2e0fbbdb195873d9642574ad3ae7bfcf4699bfdaa16933ca50c13cb98a1ff53c86c6de05'
|
||||
'd5373e2b2e9754bdcdbcda81fc1392ce6605939651839868823f3c3e0bf16f6fba2fb73bc1a0ff230eebd743d1463f2e8b2295503248f14845b3a56e57385bd1'
|
||||
'85da93530b2b92faad58cc84d0f7ddaea6b22fbec413e806c1981eb6369a301ec995eee6bfbe6b828e2cd0baf6168e578bbde456f2450a13199994ff9a1e7cd0'
|
||||
'dca9bbf55afcb1425af7bd0fc4d891fe0cc37859436a8b2a1ae9d29689d72e574dc2f974d468a86527c0420847fd27af5517da7b02075ee2eebe8bd2d43a7d09'
|
||||
'88024b0faf4e4db8e283af9081b88072ec8ab908e4b72a7c0bab8ae7fcb3c5ae09b2b3e34af0b35429b51f46be359dc39983191e376a762c6c4831d4918a9792'
|
||||
'b7a676bd7e7cb1a9d57aaad1c828499f7ecdc0360bb982a3138181bb29710354509c50998344004c73ca2b87f7866a603109c2cb79b848b3240fa08a35578b16'
|
||||
'7283eb04ec779a5f679e7c90f793c5d9bb2a6a44507f966156d831f0013ebcad507fbcc07d037719740861f3e23f95a532b5c9d0da707932a0da9ffd7e17349d'
|
||||
'6e75733d93b41b4a3d59749ce5331b9da4d6fb5fad1266bf639a948cc497c05b03ea3f15bfd6384e819730bd220dbf34dbb967c90f9683bb2529f73a4ed5897b'
|
||||
'e88e7ce27b6d406d1fe631964b772067bc52808a74ecb57a96b5585199ec2aceab405321f9d9faf9199870fd83823afc6c5402eb85c9ed41826cedb60d8925d9'
|
||||
'fc5dd9840f0b13bf8b66dc4901833c701293a914c54765c04c18414755f237284e93e1a7bf2660120507263500f9ab385c1c9966fe0f33e368b3fae9d695b432'
|
||||
'f23b41b7e55c6611a77767c4ccd7010bfc5a901d241ac91826b191ca7d894e5960eda1afde05a0b52564b555006ce762620b08c9378eff733a0b89c5fd49a3e4'
|
||||
'755e37330fc16d99f630ed0036eaabf83b4f137123c72eae35fe47996d243ceaed1ddc6f1891efaeffb3f28fa4c0eb9b2be76308df50d98a97be24c37f5e41f0'
|
||||
'83454dd202685f368d0934c3949e2d3e2ecb30dd89c7a593f9210318828cd3b3b4813e216e45bcc1752b0b0d214f1979bf7ba14d00e0840e0c238cfeec88aa63'
|
||||
'aee5b9cd718d803618e6f83f4f004853f283e89c5c8bc87b61b85189787aed0c710bba2b9ab81e148e18c685e5a1bcbe18554cc67f6123be360c3299349d0edc'
|
||||
'959e30368d9c4d4e82fe4beb2457f3287365e1fcb3ee5e44eb8d8e648e30b2b2ec2aa346b7bfa46d24b8f496193b154c89c471c997fe9d7d5b64277dcc5092ca')
|
||||
|
||||
# Skip "LICENSE.html" and "OSS-LICENSES.html" files hashes as they are unstable
|
||||
# Since "updpkgsums"/"pkgctl version upgrade" overwrite the checksum array with
|
||||
# literal hashes, set them to SKIP with indexed assignments (pacman-contrib#119)
|
||||
# https://gitlab.archlinux.org/pacman/pacman-contrib/-/issues/119
|
||||
sha512sums[1]='SKIP'
|
||||
sha512sums[2]='SKIP'
|
||||
|
||||
# Colored makepkg-like functions
|
||||
_all_off="$(tput sgr0)"
|
||||
_bold="${_all_off}$(tput bold)"
|
||||
_blue="${_bold}$(tput setaf 4)"
|
||||
_red="${_bold}$(tput setaf 1)"
|
||||
msg_blue() {
|
||||
printf "${_blue} ->${_bold} $1${_all_off}\n"
|
||||
}
|
||||
error() {
|
||||
printf "${_blue}==>${_red} ERROR:${_bold} %s${_all_off}\n" "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
prepare() {
|
||||
msg_blue "Extracting core-${pkgver}.tar.br"
|
||||
tar -xf core-${pkgver}.tar.br --use-compress-program=brotli --one-top-level=core --strip-components=1 files/
|
||||
|
||||
for module in discord_*.tar.br; do
|
||||
msg_blue "Extracting ${module}"
|
||||
tar -xf "${module}" --use-compress-program=brotli --one-top-level="modules/${module%%-*}" --strip-components=1 files/
|
||||
done
|
||||
|
||||
# prepare launcher script
|
||||
sed -i -e "s|@PKGNAME@|${_pkgname}|" \
|
||||
-e "s|@ELECTRON@|${_electron}|" \
|
||||
discord-launcher.sh
|
||||
|
||||
# fix the .desktop file
|
||||
sed -i -e "s|Exec=.*|Exec=/usr/bin/${_pkgname}|" ${_pkgname^}/$_pkgname.desktop
|
||||
}
|
||||
|
||||
build() {
|
||||
msg_blue 'Patching app.asar to use system electron'
|
||||
|
||||
asar e core/resources/app.asar core/resources/app
|
||||
rm core/resources/app.asar
|
||||
sed -i \
|
||||
-e "s|^Exec=\${exePath}$|Exec=/usr/bin/${_pkgname}|" \
|
||||
-e "s|^Name=\${appName}$|Name=${_pkgname^}|" \
|
||||
-e "s|^Icon=\${iconPath}$|Icon=${_pkgname}|" \
|
||||
-e "s|resourcesPath=path_1\.default\.join(require\.main\.filename,\"\.\.\",\"\.\.\"),|resourcesPath='/usr/share/${_pkgname}/resources',|" \
|
||||
-e "s|process\.resourcesPath|'/usr/share/${_pkgname}/resources'|g" \
|
||||
core/resources/app/bundle.js
|
||||
sed -i -e "s|process\.resourcesPath|'/usr/share/${_pkgname}/resources'|" core/resources/app/splashScreenPreload.js
|
||||
|
||||
# This is required to properly show the window icon under wayland
|
||||
jq ".desktopName = \"${_pkgname}.desktop\"" core/resources/app/package.json > tmp.json
|
||||
mv tmp.json core/resources/app/package.json
|
||||
|
||||
asar p core/resources/app core/resources/app.asar
|
||||
rm -rf core/resources/app
|
||||
|
||||
# Set the newUpdater key to false in build_info.json in order to disable the new Discord updater (released on 2026-05-04, version 1.0.136),
|
||||
# Also add a localModulesRoot key that points to the Discord modules we're packaging.
|
||||
jq ".newUpdater = false | .localModulesRoot = \"/usr/share/${_pkgname}/modules\"" core/resources/build_info.json > tmp.json
|
||||
mv tmp.json core/resources/build_info.json
|
||||
|
||||
msg_blue 'Patching Krisp to run with system electron'
|
||||
# original: https://github.com/sersorrel/sys/blob/main/hm/discord/krisp-patcher.py
|
||||
python krisp-patcher.py "modules/discord_krisp/discord_krisp.node" \
|
||||
|| error 'Krisp patcher failed. You can comment it out in the PKGBUILD, but Krisp will not work.'
|
||||
|
||||
# Krisp fails to initialize if this directory is not present (or if can't be created). Logs:
|
||||
# [MediaEngineStore] Failed to load Krisp module: Failed to setup Krisp module, error code: -4
|
||||
# [AVError] AV error reported: noise-canceller-error {"underlyingError":"NoiseCancellerError.KRISP_INIT_ERROR_GLOBAL_INIT"}
|
||||
mkdir -p "modules/discord_krisp/KMS/logs"
|
||||
}
|
||||
|
||||
package() {
|
||||
# create necessary directories
|
||||
install -d "${pkgdir}/usr/share/${_pkgname}"
|
||||
|
||||
# copy relevant data
|
||||
cp -r core/resources/ "${pkgdir}/usr/share/${_pkgname}/"
|
||||
cp -r modules/ "${pkgdir}/usr/share/${_pkgname}/"
|
||||
|
||||
# intall icon and desktop file
|
||||
install -Dm 644 ${_pkgname^}/$_pkgname.png "${pkgdir}/usr/share/icons/hicolor/256x256/apps/${_pkgname}.png"
|
||||
install -Dm 644 ${_pkgname^}/$_pkgname.desktop "${pkgdir}/usr/share/applications/${_pkgname}.desktop"
|
||||
|
||||
# install the launch script
|
||||
install -Dm 755 discord-launcher.sh "${pkgdir}/usr/bin/${_pkgname}"
|
||||
|
||||
# install licenses
|
||||
install -Dm 644 LICENSE.html "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.html"
|
||||
install -Dm 644 OSS-LICENSES.html "${pkgdir}/usr/share/licenses/${pkgname}/OSS-LICENSES.html"
|
||||
}
|
||||
104
.handoff-from-phone/discord-betterdiscord/TASK.md
Normal file
104
.handoff-from-phone/discord-betterdiscord/TASK.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# Task: Official Discord + BetterDiscord on SouveraineOS (Pixel 3, aarch64)
|
||||
|
||||
**Status:** BLOCKED on native Electron. Plan: cross-build Electron (and/or the Discord
|
||||
package) on an x86 box or a beefier arm64 host, ship the artifacts back to the phone.
|
||||
|
||||
**Goal:** Run the *official* Discord desktop client on this device and inject
|
||||
BetterDiscord into it (theming + plugins). Wrappers (Vesktop/WebCord/Legcord) were
|
||||
explicitly rejected — we want stock Discord + BetterDiscord specifically.
|
||||
|
||||
---
|
||||
|
||||
## Device facts (verified on-device 2026-07-14)
|
||||
|
||||
- OS: **Souveraine OS (Arch Linux ARM)**, `ID_LIKE=arch`, BUILD_ID 20260707
|
||||
- Arch: **aarch64**
|
||||
- Pkg mgrs: `pacman`, `flatpak` (flathub system remote). AUR helpers present: `yay`, `paru`.
|
||||
- Repo `bun` NOT present; installed manually to `~/.bun/bin/bun` (v1.3.14 aarch64).
|
||||
- `~/.config/discord` exists but is EMPTY (no app version dir) — nothing to inject into yet.
|
||||
|
||||
### What's in the repos (checked with pacman -Ss)
|
||||
- ✅ `extra/betterdiscordctl 1.6.1-1` — BD manager CLI, installable, needs a Discord install to act on
|
||||
- ✅ `extra/asar 4.1.2-1` — makedep for the Discord PKGBUILD
|
||||
- ✅ `jq`, `brotli` — present
|
||||
- ❌ **NO `electron` package in any form** (no `electron`, no `electron36/37/...`).
|
||||
`pacman -Ssq electron` returns nothing. THIS IS THE BLOCKER.
|
||||
|
||||
### Flathub (all bundle their own Electron → run on arm64, but can't take BetterDiscord)
|
||||
Vesktop `dev.vencord.Vesktop`, Equibop `org.equicord.equibop`, WebCord
|
||||
`io.github.spacingbat3.webcord`, Dissent `so.libdb.dissent`, Legcord, GoofCord.
|
||||
(Vesktop/Equibop have Vencord = plugins+themes, the closest BD-equivalent. Rejected for now.)
|
||||
|
||||
---
|
||||
|
||||
## Already done (in /home/casey/projects/BetterDiscord)
|
||||
|
||||
BetterDiscord cloned from GitHub + built successfully:
|
||||
- `git clone --depth 1 https://github.com/BetterDiscord/BetterDiscord.git`
|
||||
- `bun install` (510 pkgs) then `bun run build:production` → **succeeded**
|
||||
- Artifacts in `dist/`: `betterdiscord.js` (555kb), `main.js`, `preload.js`,
|
||||
`earlyRenderer.js`, editor bundle. Version **1.13.14**, commit `c7ef1c5`.
|
||||
- `bun run inject` → fails as expected: "No version dir in /home/casey/.config/discord"
|
||||
(no official Discord app to patch).
|
||||
|
||||
Injector expects a Discord Desktop install dir like `app-X.Y.Z` under the config path.
|
||||
|
||||
---
|
||||
|
||||
## The install path (why it's *almost* possible)
|
||||
|
||||
The AUR pkg **`discord_arch_electron`** (v1:1.0.146, 209 votes) is the target. Its PKGBUILD
|
||||
(saved alongside this file as `PKGBUILD.x86-reference`) shows Discord's Linux app is
|
||||
**JavaScript + app.asar + brotli `.distro` module blobs — arch-independent**. The ONLY
|
||||
native pieces are:
|
||||
1. **Electron** (the runtime) — pulled via `depends=(electron)`. ← the real arch dependency
|
||||
2. **`discord_krisp/discord_krisp.node`** — x86-64 native noise-cancel lib; its
|
||||
`krisp-patcher.py` step WILL fail on aarch64. Krisp is OPTIONAL — comment it out,
|
||||
Discord still runs (PKGBUILD even says so).
|
||||
|
||||
So a working aarch64 build = **provide an arm64 Electron** + **skip Krisp** + flip `arch`.
|
||||
|
||||
### Concrete cross-build plan
|
||||
1. Get/build an **aarch64 Electron** matching Discord's required major (Discord 1.0.146
|
||||
era ships on a recent Electron — check `core/resources/app/package.json` `electronVersion`
|
||||
or the bundled build_info after extracting the tarball). Options:
|
||||
- Build the Arch `electron` PKGBUILD for aarch64 on a cross host (heavy: Chromium).
|
||||
- OR reuse a prebuilt arm64 Electron (e.g. from npm `electron` arm64 dist, or Alpine/Debian
|
||||
arm64 electron) and repackage.
|
||||
2. Fork the `discord_arch_electron` PKGBUILD:
|
||||
- `arch=('x86_64' 'aarch64')`
|
||||
- point `depends` at whatever electron pkg you produce (or vendor it)
|
||||
- COMMENT OUT the Krisp patcher block in `build()` (lines ~131-139) and the
|
||||
`discord_krisp` source line — OR guard it `[[ $CARCH == x86_64 ]]`.
|
||||
- The `.distro` module URLs are `/linux/x64/` paths but contents are JS/resources;
|
||||
they should work under arm64 electron. Verify at runtime.
|
||||
3. `makepkg -si` on-device (or build the pkg on the cross host and `pacman -U` the .pkg.tar.zst here).
|
||||
4. Once `/usr/share/discord` + `/usr/bin/discord` exist and launch:
|
||||
- `betterdiscordctl install` (repo pkg already available) — OR —
|
||||
- from `~/projects/BetterDiscord`: `bun run inject` (now finds the app dir).
|
||||
5. Launch Discord, confirm BetterDiscord loaded (Settings → BetterDiscord panel).
|
||||
|
||||
### Risks / open questions
|
||||
- Electron major-version mismatch vs what Discord's app.asar expects → white screen / API breakage.
|
||||
Match the major as closely as possible.
|
||||
- Voice: without Krisp, noise suppression off, but voice/WebRTC should still work (Electron's).
|
||||
- Discord may nag to "update" — PKGBUILD already sets `newUpdater=false` in build_info.json; keep that.
|
||||
- app.asar is repacked to use system electron paths (`/usr/share/discord/resources`); BetterDiscord
|
||||
injects into that asar/app — make sure BD inject runs AFTER the pkg's asar repack, against the
|
||||
installed `/usr/share/discord/resources/app.asar`.
|
||||
|
||||
---
|
||||
|
||||
## Resume checklist (fast path)
|
||||
- [ ] Produce aarch64 Electron artifact (matching Discord's electron major)
|
||||
- [ ] Fork PKGBUILD: arch+=aarch64, swap electron dep, disable Krisp
|
||||
- [ ] Build pkg (cross or on-device), install with pacman
|
||||
- [ ] `discord` launches to login screen on the phone
|
||||
- [ ] Inject BetterDiscord (`betterdiscordctl install` or `bun run inject` from ~/projects/BetterDiscord)
|
||||
- [ ] Verify BD settings panel appears; load a theme/plugin
|
||||
|
||||
## Key paths
|
||||
- BetterDiscord source+build: `/home/casey/projects/BetterDiscord` (dist/ built, v1.13.14)
|
||||
- This task dir: `/home/casey/projects/unfinished/discord-betterdiscord/`
|
||||
- Reference PKGBUILD: `./PKGBUILD.x86-reference`
|
||||
- bun binary: `~/.bun/bin/bun`
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
name=@PKGNAME@
|
||||
electron=@ELECTRON@
|
||||
|
||||
# Support .config/discord-flags.conf file
|
||||
flags_file="${XDG_CONFIG_HOME:-$HOME/.config}/${name}-flags.conf"
|
||||
|
||||
if [[ -r "${flags_file}" ]]; then
|
||||
mapfile -t < "${flags_file}"
|
||||
fi
|
||||
|
||||
declare -a flags
|
||||
for line in "${MAPFILE[@]}"; do
|
||||
if [[ ! "${line}" =~ ^[[:space:]]*#.* ]] && [[ -n "${line}" ]]; then
|
||||
flags+=("${line}")
|
||||
fi
|
||||
done
|
||||
|
||||
exec /usr/bin/${electron} \
|
||||
/usr/share/${name}/resources/app.asar \
|
||||
"${flags[@]}" "$@"
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
post_upgrade() {
|
||||
# return if old package version is greater than or equal to 1:1.0.143-1...
|
||||
(( $(vercmp $2 '1:1.0.143-1') >= 0 )) && return
|
||||
|
||||
cat <<EOF
|
||||
==> Krisp (noise suppression) is now patched at build time.
|
||||
If you used '~/.config/discord.conf' previously to enable it, you can remove the file as it's not used anymore.
|
||||
EOF
|
||||
}
|
||||
|
||||
post_install() {
|
||||
cat <<EOF
|
||||
==> In case of performance problems consider setting additional flags
|
||||
in '~/.config/discord-flags.conf'.
|
||||
EOF
|
||||
}
|
||||
85
.handoff-from-phone/discord-betterdiscord/krisp-patcher.py
Normal file
85
.handoff-from-phone/discord-betterdiscord/krisp-patcher.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
import sys
|
||||
import shutil
|
||||
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from capstone import *
|
||||
from capstone.x86 import *
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} [path to discord_krisp.node]")
|
||||
# "Unix programs generally use 2 for command line syntax errors and 1 for all other kind of errors."
|
||||
sys.exit(2)
|
||||
|
||||
executable = sys.argv[1]
|
||||
|
||||
elf = ELFFile(open(executable, "rb"))
|
||||
symtab = elf.get_section_by_name('.symtab')
|
||||
|
||||
krisp_initialize_address = symtab.get_symbol_by_name("_ZN7discordL17DoKrispInitializeEv")[0].entry.st_value
|
||||
isSignedByDiscord_address = symtab.get_symbol_by_name("_ZN7discord4util17IsSignedByDiscordERKNSt4__Cr12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE")[0].entry.st_value
|
||||
|
||||
text = elf.get_section_by_name('.text')
|
||||
text_start = text['sh_addr']
|
||||
text_start_file = text['sh_offset']
|
||||
# This seems to always be zero (.text starts at the right offset in the file). Do it just in case?
|
||||
address_to_file = text_start_file - text_start
|
||||
|
||||
# Done with the ELF now.
|
||||
# elf.close()
|
||||
|
||||
krisp_initialize_offset = krisp_initialize_address - address_to_file
|
||||
isSignedByDiscord_offset = krisp_initialize_address - address_to_file
|
||||
|
||||
f = open(executable, "rb")
|
||||
f.seek(krisp_initialize_offset)
|
||||
krisp_initialize = f.read(96)
|
||||
f.close()
|
||||
|
||||
# States
|
||||
found_issigned_by_discord_call = False
|
||||
found_issigned_by_discord_test = False
|
||||
found_issigned_by_discord_je = False
|
||||
found_already_patched = False
|
||||
je_location = None
|
||||
je_size = 0
|
||||
|
||||
# We are looking for a call to IsSignedByDiscord, followed by a test, followed by a je.
|
||||
# Then we replace the je with nops.
|
||||
|
||||
md = Cs(CS_ARCH_X86, CS_MODE_64)
|
||||
md.detail = True
|
||||
for i in md.disasm(krisp_initialize, krisp_initialize_address):
|
||||
if i.id == X86_INS_CALL:
|
||||
if i.operands[0].type == X86_OP_IMM:
|
||||
if i.operands[0].imm == isSignedByDiscord_address:
|
||||
found_issigned_by_discord_call = True
|
||||
|
||||
if i.id == X86_INS_TEST:
|
||||
if found_issigned_by_discord_call:
|
||||
found_issigned_by_discord_test = True
|
||||
|
||||
if i.id == X86_INS_JE:
|
||||
if found_issigned_by_discord_test:
|
||||
found_issigned_by_discord_je = True
|
||||
je_location = i.address
|
||||
je_size = len(i.bytes)
|
||||
break
|
||||
|
||||
if i.id == X86_INS_NOP:
|
||||
if found_issigned_by_discord_test:
|
||||
found_already_patched = True
|
||||
break
|
||||
|
||||
if je_location:
|
||||
print(f"Found patch location: 0x{je_location:x}")
|
||||
|
||||
f = open(executable, 'rb+')
|
||||
f.seek(je_location - address_to_file)
|
||||
f.write(b'\x90' * je_size) # je can be larger than 2 bytes given a large enough displacement :(
|
||||
f.close()
|
||||
else:
|
||||
if found_already_patched:
|
||||
print("Couldn't find patch location - already patched.")
|
||||
else:
|
||||
print("Couldn't find patch location - review manually. Sorry.")
|
||||
sys.exit(1)
|
||||
122
.handoff-from-phone/home-directory-homogenization.md
Normal file
122
.handoff-from-phone/home-directory-homogenization.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
# Home Directory Homogenization Plan
|
||||
|
||||
**Date:** July 22, 2026
|
||||
**From:** Ani
|
||||
**To:** Souveraine Surface Agent / Casey
|
||||
|
||||
---
|
||||
|
||||
## Situation
|
||||
|
||||
`/home/casey` has accumulated deployment artifacts, build directories, duplicate folders, and debugging debris from the Souveraine OS bring-up on Pixel 3. This document inventories everything and proposes cleanup actions.
|
||||
|
||||
---
|
||||
|
||||
## Inventory & Classification
|
||||
|
||||
### ✅ KEEP — Active Source & Configuration
|
||||
|
||||
| Path | Size | Notes |
|
||||
|------|------|-------|
|
||||
| `Projects/` (capital) | 3.0G | **Canonical projects root.** BetterDiscord, Quaternion, claude-switcher, converse, end4dots, qtcontacts-sqlite, qtpim |
|
||||
| `projects/` (lowercase) | 332M | **Symlink target → `Projects/`** (after consolidation) |
|
||||
| `souveraine-surfaces/` | 7.6M | Souveraine shell source |
|
||||
| `bootsplash/` | 2.8M | Boot splash source (C, shaders, atlas) |
|
||||
| `stevia-pkg/` | 21M | Patch set for phoc/zphoc, dictation key, vk driver, layout fixes |
|
||||
| `.config/` | — | All system config including `illogical-impulse/config.json` (TTS/STT endpoints) |
|
||||
| `.souveraine/` | — | Souveraine agent state |
|
||||
| `cleancap.sh` | 1.2K | Screen capture cleanup script |
|
||||
| `mic-hunt.sh` | 1.5K | Microphone debugging script |
|
||||
| `converse-primary.bundle` | 161K | Git bundle for converse source |
|
||||
| `hexagonrpc-src.tar.gz` | 121K | Hexagon RPC source backup |
|
||||
| `hexagonrpc-stubs.tar.gz` | 387K | Hexagon RPC stubs backup |
|
||||
| `los-sensors-json.tar.gz` | 7.2K | LineageOS sensor JSON backup |
|
||||
| `.ssh/` `.gitconfig` | — | Git/SSH configuration |
|
||||
|
||||
### 🗑️ ARCHIVE OR DELETE — Build Artifacts & Debris
|
||||
|
||||
| Path | Size | Classification | Action |
|
||||
|------|------|----------------|--------|
|
||||
| `build/` | 3.3G | phosh, phrog, libcall-ui, hexagonrpc, libgnome-volume-control, libical patch — **all build output** | **DELETE** — source lives in `Projects/` and `stevia-pkg/` |
|
||||
| `chatty-build/` | 141M | Build output for chatty | **DELETE** — source is elsewhere |
|
||||
| `aacs-build/` | 59M | Build output | **DELETE** |
|
||||
| `openauto-bin/` | 108M | Binary output | **DELETE** or archive |
|
||||
| `openauto-build/` | 8.6M | Build output | **DELETE** |
|
||||
| `libcmatrix-build/` | 16M | Build dirs | **DELETE** |
|
||||
| `upower-build/` | bring_up_build | Build output | **DELETE** |
|
||||
| `bootsplash-build/` | 3.1M | Build output | **DELETE** |
|
||||
| `sns-src/` `sns-out/` `sns-out2/` `sns-final/` | ~2M total | Sensor registration experimentation (bmi160 accelerometer data) | **DELETE** — one-shot debugging, no ongoing value |
|
||||
| `mic-hunt-095138/` | 136K | Mic debugging session capture (dmesg, regmap trace, capture.wav) | **DELETE** — one-shot debugging |
|
||||
| `lockup-2026-07-11/` | 1.4M | Lockup debug logs (dmesg, journal) from July 11 | **ARCHIVE** then delete — useful for diagnosing future lockups, but not needed live |
|
||||
| `dock-backup-tier1-2054/` | 60K | Dock config backup | **DELETE** — superseded by current dock config |
|
||||
| `staging/` | 21M | `souveraine-da410b1` staging build | **DELETE** — deployment staging, no longer needed |
|
||||
| `mimo/` | 339M | **`Shelly-ALPM`** — needs investigation | **INVESTIGATE** — 339M is significant |
|
||||
| `qbootctl-src/` | 1.0M | qbootctl source | **KEEP** (source) or **DELETE** if already in Gitea |
|
||||
| `hexagonrpc/` | 2.5M | hexagonrpc built output? | **DELETE** if build output, **KEEP** if source |
|
||||
| `hexagonrpc-src/` | 1.5M | hexagonrpc source | **KEEP** if not in Gitea, otherwise **DELETE** |
|
||||
| `regsnap-after-unlock.txt` | 576K | Regmap snapshot debugging | **DELETE** — one-shot debug |
|
||||
| `regsnap-before-unlock.txt` | 576K | Regmap snapshot debugging | **DELETE** — ones-shot debug |
|
||||
| `souveraine.log` | 72K | Current runtime log | **KEEP** |
|
||||
| `souveraine.log.prev` | 2.2K | Previous runtime log | **KEEP** (for debugging) |
|
||||
|
||||
### 📦 ROOT-LEVEL FILES
|
||||
|
||||
| Path | Size | Classification |
|
||||
|------|------|----------------|
|
||||
| `linux-blueline-7.1.1-1-aarch64.pkg.tar.zst` | 31M | Compiled kernel package for Pixel 3. **KEEP** until next kernel build — provides rollback |
|
||||
| `roll-out / phased-git-checkout-marker` | — | — |
|
||||
| `dock-rework-backup-1952.tar.gz` | 7.2K | Dock backup from Jul 11. **DELETE** — superseded |
|
||||
| `clseldean-completions.zsh@` | — | Symlink → `Projects/claude-switcher/claude-completions.zsh` |
|
||||
| `.claude-modes.zsh@` | — | Symlink → ` directory |
|
||||
| `clsaldean-modes.bash` `.claude-modes.bash.bak` | — | Claude CLI mode configs |
|
||||
| `.claude.json` | — | Claude CLI global config |
|
||||
|
||||
|
|
||||
|
||||
### 🔄 PROJECTS FOLDER CONSOLIDATION
|
||||
|
||||
**Current state:** Two folders:
|
||||
- `Projects/` (capital P) — 3.0G, modified Jul 18
|
||||
- `projects/` (lowercase) — 331M, modified Jul 14
|
||||
|
||||
**Step 1:** Merge `projects/unfinished/` → `Projects/unfinished/` ✅ (already done by Ani earlier today)
|
||||
**Step 2:** Merge newer `projects/BetterDiscord/` → `Projects/BetterDiscord/` (fresher dist build)
|
||||
**Step consolidation:** Remove lowercase `projects/`, symlink `projects` → `Projects`
|
||||
**Step 4:** Verify `.claude-completions.zsh` and `.claude-modes.zsh` symlinks still resolve
|
||||
|
||||
**Estimated space recovery:** ~4.0G from build artifacts + debris cleanup
|
||||
|
||||
### ❓ NEEDS INVESTIGATION
|
||||
|
||||
**`mimo/` (339M)** — Contains `Shelly-ALPM`. Unknown purpose. Could be:
|
||||
- Mimo display driver work
|
||||
- Mobile Input/Modem Output experimentation
|
||||
- Something else entirely
|
||||
- Needs Casey to identify before deletion
|
||||
|
||||
---
|
||||
|
||||
## Proposed Execution Order
|
||||
|
||||
1. **Projects folder consolidation** (in progress)
|
||||
2. **Delete build artifacts** (`build/`, `*-build/`, `openauto-bin/`, `*-out*/`, `staging/`)
|
||||
3. **Delete one-shot debug** (sns-*, mic-hunt, regsnaps, dock backup)
|
||||
4. **Archive then delete** lockup logs
|
||||
5. ~~**Investigate `mimo/`** before action~~
|
||||
6. **Review remaining root-level files** (tarballs, tar.zst, bundles) — keep source backups until confirmed in Gitea
|
||||
6. **Final verification** — run `du -sh /home/casey/*/ | sort -rh` to confirm cleanup
|
||||
7. **Update this document** with final results
|
||||
|
||||
---
|
||||
|
||||
## Open Questions for Souveraine Agent / Casey
|
||||
|
||||
1. **Gitea location:** No Gitea references found in config, bash history, or git config. Where is the actual Gitea instance? Need the URL to verify what's already under version control.
|
||||
2. **`mimo/` (339M):** What is `Shelly-ALPM`? Is this active work?
|
||||
3. **`qbootctl-src/` and `hexagonrpc-src/`:** Are these in Gitea? If so, the local copies are redundant.
|
||||
4. **Kernel package (`linux-blueline-7.1.1-1-aarch64.pkg.tar.zst`):** Keep for rollback, or move to shared storage?
|
||||
5. **`converse-primary.bundle`:** This is a git bundle — should it be unpacked into `Projects/` or pushed to Gitea?
|
||||
|
||||
---
|
||||
|
||||
*Authored by Ani, July 22, 2026, from Pixel 3, Souveraine OS*
|
||||
191
.handoff-from-phone/pixel3-microphone/README.md
Normal file
191
.handoff-from-phone/pixel3-microphone/README.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
# Pixel 3 (blueline) — microphone / SLIM TX capture bug
|
||||
|
||||
**Status:** 2026-07-18 — BUG HAS MOVED. Transport is now FIXED; still zeros.
|
||||
The `CONNECT_SRC` timeout the rest of this doc chases **no longer happens**
|
||||
(kernel is now `g8cbfbb939327`, was `g56b0a053bef8` when that was found).
|
||||
Port-connect, channel activate, and q6afe port_start all succeed (ret=0), yet
|
||||
capture is still pure zeros. The fault is now DOWNSTREAM of transport, in the
|
||||
WCD934x SLIM-PGD data-plane. See "## 2026-07-18 UPDATE" below; the older
|
||||
sections are kept for history but their root-cause conclusion is superseded.
|
||||
|
||||
## 2026-07-18 UPDATE — transport fixed, data-plane is the new fault
|
||||
|
||||
Re-ran on a clean 58-min-uptime boot, ADSP never restarted. Findings:
|
||||
|
||||
- **The SLIM CONNECT_SRC (MC 0x2c) timeout is GONE.** Every capture now logs
|
||||
`connect_port: dir=1 port_id=N ch_id=NNN la=0xcf ret=0`,
|
||||
`DEF_ACT_CHAN xfer ret=0`, and q6afe `port_start OK` (port 0x4001,
|
||||
cfg 0x10212). Zero `timed out` / `failed:-110` lines in dmesg.
|
||||
- **Still 0/144000 nonzero samples** on every path tried:
|
||||
- DMIC4 → DEC7 → TX7 (enchilada recipe)
|
||||
- DMIC0 → DEC6 → TX6 (handset, via cleancap.sh)
|
||||
- **AMIC1 → ADC1 → DEC0 → TX0 (analog!) — also zeros.**
|
||||
So it is NOT DMIC-specific and NOT a DMIC-clock problem. Common to every
|
||||
decimator and every TX port.
|
||||
- **Decimator path is fully powered and unmuted:** `decN POST_PMU`
|
||||
`TX_PATH_CTL=0x24 [clk_en=1 mute=0 rate=0x4]`, DEC6/DEC7 Volume = 84 (0 dB),
|
||||
MICB on. DAPM all On. So routing/gain/mute are ruled out.
|
||||
- **The smoking gun is now IRQ 213.** `/proc/interrupts` line
|
||||
`213: 0 ... wcd934x_irq 0 Edge slim` — the WCD934x's own SLIM/data
|
||||
interrupt has fired **0 times in the machine's entire life**, including
|
||||
across capture. (Contrast IRQ 212 `wcd934x_irq` control line = 18, so the
|
||||
codec IRQ domain is alive; button-detect 215 = 17.) The codec arms its TX
|
||||
PGD port (`PGD_TX_INT_STATUS=0x0000`, port `STATUS=0x00`) but never raises
|
||||
the data interrupt → port never actually streams → ADSP reads zeros.
|
||||
|
||||
### New working hypothesis
|
||||
Control-plane port *connect* (NGD user messages) succeeds, but the WCD934x
|
||||
**SLIM PGD port is never *enabled*/started** on the data side — the register
|
||||
write that arms the port's data engine and its interrupt
|
||||
(`SLIM_PGD_PORT_INT_EN*`, per-port `PORT_CFG`/enable) isn't happening or isn't
|
||||
taking. That's why IRQ 213 stays 0 and the port emits zeros. This is a
|
||||
codec-side (wcd934x.c) or CDC_IF data-lane issue, NOT an ADSP/satellite issue.
|
||||
|
||||
### The instrumentation gap (next patch)
|
||||
The current MICDBG patch logs the decimator, connect_port, and DEF_ACT_CHAN,
|
||||
but does NOT dump the SLIM PGD port-enable / port-interrupt registers — the
|
||||
exact layer where the bug now lives. Next kernel patch should log, right after
|
||||
"prepare CAPTURE armed":
|
||||
- `WCD934X_SLIM_PGD_PORT_INT_EN0` (0x341?) and INT_EN for the TX port
|
||||
- per-port `SLIM_PGD_TXn_CFG` / port enable bit
|
||||
- `SLIM_PGD_PORT_INT_SRC` / `_STATUS` DURING an active stream (not just at
|
||||
prepare — need a delayed read or a sysfs poke)
|
||||
Then check: is the port-enable bit actually set? Is IRQ 213 masked at the
|
||||
codec? Compare this whole sequence against enchilada (mic works) on 6.x.
|
||||
|
||||
### Verified-safe method notes (this session)
|
||||
- Never touched remoteproc; ADSP stayed `running` throughout.
|
||||
- `alsactl restore 0` does NOT fully clear AIF*_CAP SLIM TXn mixer bits —
|
||||
stale TX routes leak into the next run (saw map=[134 128 ...] = TX6+leftover
|
||||
TX0). Explicitly `cset ... 0` every AIF*_CAP SLIM TXn you touched.
|
||||
- `cleancap.sh` (in ~) is the good harness: forces TX7 off (its comment flags
|
||||
TX7 as an "Android-replay wedge trigger"), sets the DMIC0/TX6 handset path,
|
||||
and measures IRQ 213 delta + nonzero-sample count. Use/extend it.
|
||||
|
||||
---
|
||||
## (Historical — superseded) original 2026-07-12 root-cause
|
||||
|
||||
**Status:** ROOT CAUSE LOCALIZED 2026-07-12 — not fixed yet.
|
||||
All capture sources record pure digital zeros because the SLIMbus
|
||||
`CONNECT_SRC` port-connect message to the ADSP master **times out**, so the
|
||||
WCD9340's TX port is never attached to the data channel. The DSP then
|
||||
delivers a valid-but-empty stream. Control traffic (codec register
|
||||
reads/writes over slimbus) works fine.
|
||||
**(As of 2026-07-18 this timeout no longer occurs — see UPDATE above.)**
|
||||
|
||||
## The smoking gun
|
||||
|
||||
With dynamic debug on `drivers/slimbus/*`, every capture start logs 3×:
|
||||
|
||||
```
|
||||
qcom,slim-ngd qcom,slim-ngd.1: TX timed out:MC:0x2c,mt:0x2
|
||||
qcom,slim-ngd qcom,slim-ngd.1: Tx:MT:0x2, MC:0x2c, LA:0xcf failed:-110
|
||||
```
|
||||
|
||||
- `MC 0x2c` = `SLIM_USR_MC_CONNECT_SRC` (qcom satellite user message that
|
||||
connects the codec TX port to the allocated data channel)
|
||||
- Value-element messages (`MC 0x60` REQUEST_VALUE / `0x68` CHANGE_VALUE —
|
||||
i.e. regmap traffic to the codec) all succeed with no timeouts
|
||||
- So: NGD hardware messaging works; the ADSP-side slimbus master/satellite
|
||||
service does not answer port-connect requests
|
||||
- TODO: identify LA 0xcf — codec device or the ifd (ports live on the
|
||||
interface device `ifd@0,0`)?
|
||||
|
||||
Enable debug: `echo 'file drivers/slimbus/* +p' > /sys/kernel/debug/dynamic_debug/control`
|
||||
|
||||
## What was proven (2026-07-12, kernel 7.1.1-sdm845-g56b0a053bef8)
|
||||
|
||||
1. Capture streams open and run fine on hw:0,1 (MultiMedia2) and hw:0,0
|
||||
(MultiMedia1) routed from `SLIMBUS_0_TX` — but 100.0% of samples are
|
||||
exactly 0 (not noise floor; digital silence).
|
||||
2. Swept EVERY input: AMIC ADC1-4 (via ADC MUX0→DEC0→SLIM TX0) and
|
||||
DMIC0-5, plus the enchilada-style TX7 slot layout
|
||||
(DMIC MUX7=DMIC4 → ADC MUX7=DMIC → CDC_IF TX7 MUX=DEC7 →
|
||||
AIF1_CAP Mixer SLIM TX7). All zeros.
|
||||
3. DAPM (debugfs) during capture: entire codec path reports **On**
|
||||
(ADC, AMIC/ADC muxes, SLIM TX0 mixer, MIC BIAS1). So it's not routing.
|
||||
4. DT declares 4 mics (`/proc/device-tree/sound/audio-routing`):
|
||||
AMIC1←MIC BIAS1, DMIC0←MIC BIAS1, DMIC3←MIC BIAS3, DMIC4←MIC BIAS4.
|
||||
Codec node has ifd@0,0 + codec@1,0 + slim-ifc-dev; micbias 1.8 V ×4;
|
||||
extclk 9.6 MHz. Structurally like working devices.
|
||||
5. **pmOS never solved this either**: their blueline UCM
|
||||
(gitlab.com/sdm845-mainline/alsa-ucm-conf, ucm2/Google/blueline) has the
|
||||
whole mic section *commented out*. Their intended bottom-mic path:
|
||||
DMIC4 → DEC7 → SLIM TX7 → AIF1_CAP → SLIMBUS_0_TX → MultiMedia2,
|
||||
CaptureMixerElem "DEC7".
|
||||
6. OnePlus 6 (enchilada) mic **works** on pmOS 6.x kernels with the same
|
||||
driver stack (AMIC4, TX7/DEC7, `AMIC4_5 SEL=AMIC4`) → this is either a
|
||||
6.x→7.x regression in slimbus/ngd/wcd934x, or blueline-specific
|
||||
(ADSP firmware? satellite service difference?).
|
||||
7. WCD RX (playback) direction could NOT be verified: EAR PA powers on and
|
||||
streams (path: `SLIMBUS_0_RX Audio Mixer MultiMedia2`, `SLIM RX0 MUX=
|
||||
AIF1_PB`, `RX INT0_1 MIX1 INP0=RX0`, `RX INT0 DEM MUX=CLSH_DSM_OUT` —
|
||||
note EAR hangs off **RX INT0**, not INT8), but no sound heard — and the
|
||||
Pixel 3 has NO WCD-driven transducer to hear: both front speakers incl.
|
||||
the "earpiece" are CS35L36s on QUAT_TDM, and there's no 3.5mm jack.
|
||||
Inconclusive by hardware design. Whether CONNECT_SINK (MC 0x2d) also
|
||||
times out is STILL UNKNOWN — never got a clean dmesg on an RX stream.
|
||||
8. QUAT_TDM_TX (would allow CS35L36 VMON/IMON digital loopback = objective
|
||||
transport test) is not a wired backend in the DT — stream open fails
|
||||
EINVAL. Could be added in DT to get an ear-free TDM capture reference.
|
||||
|
||||
## Hazards learned (do not repeat)
|
||||
|
||||
- **Do NOT restart the adsp remoteproc while debugging**: slim-ngd fails to
|
||||
re-handshake ("QMI wait timeout", no new "Rcvd master capability") and
|
||||
slimbus stays degraded until full reboot. Happened twice, reproducible.
|
||||
- Don't leave MultiMedia2 with BOTH `SLIMBUS_0_RX` (playback) and
|
||||
`SLIMBUS_0_TX` (capture) routes enabled — ADM open starts failing
|
||||
(q6adm cmd 0x10325 error 2) and then q6asm sessions wedge (-22 on any
|
||||
further prepare).
|
||||
- Restore baseline with `sudo alsactl restore 0` (HPH*/Impedance write
|
||||
errors are harmless read-only controls).
|
||||
- Speaker README's rule still applies: volume 100% + unsuspended sink
|
||||
before trusting any "silent" result.
|
||||
|
||||
## Next steps
|
||||
|
||||
1. Fresh boot → repeat one capture with slimbus dyndbg on; confirm the
|
||||
0x2c timeout on a clean system (rule out long-uptime NGD state; uptime
|
||||
was ~23h when found).
|
||||
2. Same boot: start a WCD RX playback stream and check whether
|
||||
CONNECT_SINK (`MC:0x2d`) times out too. Both-fail → all port-connects
|
||||
dead (satellite service issue); TX-only → look at TX-specific code.
|
||||
3. Diff `drivers/slimbus/{qcom-ngd-ctrl.c,stream.c,messaging.c}` and
|
||||
`sound/soc/codecs/wcd934x.c` between pmOS linux-postmarketos-qcom-sdm845
|
||||
(6.x, mic works on enchilada) and this 7.1.1 tree. Focus: user-message
|
||||
port connect path, LA used for port ops (codec vs ifd), TX port
|
||||
numbering.
|
||||
4. If an enchilada is handy: run this 7.1.1 kernel on it and test mic —
|
||||
cleanly separates "7.x regression" from "blueline-specific".
|
||||
5. Ask in #sdm845-mainline / linux-arm-msm about the signature
|
||||
"Tx:MT:0x2, MC:0x2c failed:-110 while value messages work" — someone
|
||||
may recognize the satellite/ADSP state.
|
||||
6. Longer shot: wire up QUAT_TDM_TX_0 in DT for VMON capture as a
|
||||
transport-known-good reference and UCM debugging aid.
|
||||
|
||||
## Quick repro
|
||||
|
||||
```sh
|
||||
echo 'file drivers/slimbus/* +p' | sudo tee /sys/kernel/debug/dynamic_debug/control
|
||||
amixer -c 0 cset name='MultiMedia2 Mixer SLIMBUS_0_TX' 1
|
||||
amixer -c 0 cset name='AIF1_CAP Mixer SLIM TX7' 1
|
||||
amixer -c 0 cset name='CDC_IF TX7 MUX' DEC7
|
||||
amixer -c 0 cset name='ADC MUX7' DMIC
|
||||
amixer -c 0 cset name='DMIC MUX7' DMIC4
|
||||
sudo dmesg -C
|
||||
arecord -D hw:0,1 -f S16_LE -r 48000 -c 1 -d 2 /tmp/t.wav
|
||||
sudo dmesg | grep 'timed out' # -> MC:0x2c
|
||||
# zeros check:
|
||||
python3 -c "import wave,struct;w=wave.open('/tmp/t.wav');d=struct.unpack('<%dh'%w.getnframes(),w.readframes(w.getnframes()));print(max(map(abs,d)))"
|
||||
# afterwards:
|
||||
sudo alsactl restore 0
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- pmOS blueline UCM (mic commented out):
|
||||
https://gitlab.com/sdm845-mainline/alsa-ucm-conf → ucm2/Google/blueline/HiFi.conf
|
||||
- enchilada UCM (working mic recipe): same repo, ucm2/OnePlus/enchilada/HiFi.conf
|
||||
- Speaker fix project (methodology + amp/TDM background):
|
||||
~/projects/unfinished/pixel3-speaker-routing/
|
||||
84
.handoff-from-phone/pixel3-speaker-routing/README.md
Normal file
84
.handoff-from-phone/pixel3-speaker-routing/README.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Pixel 3 (blueline) — loudspeaker routing fix
|
||||
|
||||
**Status:** SOLVED 2026-07-12 — pmOS routing applied; fix lives in Pixel3Arch rootfs-overlay UCM (commit 2f39c06) + alsactl store. Both speakers verified by ear.
|
||||
**Goal:** Make the loud bottom speaker work. Right now sound only comes from the
|
||||
top **earpiece**; the loud bottom-firing speaker never fires. Casey reports
|
||||
postmarketOS had audio working but with the channels "reversed".
|
||||
|
||||
## Device / stack
|
||||
- Google Pixel 3 (blueline), sdm845, mainline kernel `7.1.1-sdm845` (built 2026-07-11)
|
||||
- Souveraine OS (Arch Linux ARM), Hyprland/Wayland
|
||||
- ALSA card 0 = "Google Pixel 3" (`G3`)
|
||||
- Audio: PipeWire 1.6.7 (PulseAudio shim)
|
||||
- Speakers: **dual Cirrus CS35L36** amps ("Left"/"Right") on `QUAT_TDM_RX_0` (MultiMedia1)
|
||||
- Earpiece amp: WCD9340 `EAR PA` (separate codec)
|
||||
|
||||
## Key config files
|
||||
- Active UCM (system): `/usr/share/alsa/ucm2/Google/blueline/HiFi.conf`
|
||||
- referenced by `/usr/share/alsa/ucm2/conf.d/sdm845/Google-Pixel-3.conf`
|
||||
- **Only defines a "Speaker" device. No earpiece device. Never sets Channel Mux.**
|
||||
- Intended fix location: **user override** under `~/.config/alsa/ucm2/...`
|
||||
(Casey chose user-override so pacman updates to alsa-ucm-conf don't clobber it.)
|
||||
- Baseline ALSA state snapshot saved to scratchpad as `asound-current.state`
|
||||
(scratchpad is ephemeral — re-capture with `alsactl -f <file> store 0` if needed).
|
||||
|
||||
## What we PROVED (via live tone tests)
|
||||
1. Both CS35L36 amps are healthy; both transducers (earpiece + loud speaker)
|
||||
can physically produce sound.
|
||||
2. **The 30% volume / SUSPENDED sink was a huge red herring** — many "silent"
|
||||
test results were just low volume. ALWAYS test at `pactl set-sink-volume
|
||||
@DEFAULT_SINK@ 100%` and un-suspend the sink first.
|
||||
3. Default state: both amps have `Channel Mux = RX1` (numid 121 Left, 112 Right).
|
||||
=> both amps pull the same slot => only earpiece is audible.
|
||||
4. `EAR PA Volume`=0 did NOT silence the earpiece output => the sound you hear
|
||||
from the "earpiece" is being driven by a **CS35L36 amp**, not the WCD EAR PA.
|
||||
5. At 100% vol, an L-only vs R-only test: **one channel DID come out the loud
|
||||
bottom speaker.** So the loudspeaker amp works — it just needs the right
|
||||
channel/slot routed to it. (Casey couldn't reliably tell L vs R by ear.)
|
||||
6. BUT: simply splitting `Left Channel Mux=RX1 / Right Channel Mux=RX2` and
|
||||
playing duplicated-mono did NOT wake the loudspeaker in a later test.
|
||||
=> The channel→amp mapping is UPSTREAM of `Channel Mux`, on the QUAT_TDM_RX_0
|
||||
TDM bus. `Channel Mux` alone is not the whole story.
|
||||
|
||||
## Relevant mixer controls (card 0, by numid)
|
||||
- 121 `Left Channel Mux` (enum: 0=RX1, 1=RX2) — default 0
|
||||
- 112 `Right Channel Mux` (enum: 0=RX1, 1=RX2) — default 0
|
||||
- 122 `Left AMP Enable Switch` / 113 `Right AMP Enable Switch` (default on)
|
||||
- 123 `Left BOOST Enable Switch` / 114 `Right BOOST Enable Switch`(default on)
|
||||
- 18 `EAR PA Volume` (WCD earpiece amp; default 4)
|
||||
- CS35L36 input source slots: `Left/Right ASPTX1..6SRC` (both amps identical:
|
||||
1SRC=2, 2SRC=3, 3SRC=5, 4SRC=6, 5SRC=4, 6SRC=0)
|
||||
- UCM SectionVerb enables: `QUAT_TDM_RX_0 Audio Mixer MultiMedia1` = 1
|
||||
|
||||
## NEXT STEP (where we stopped)
|
||||
Get postmarketOS's authoritative blueline mixer mapping — pmOS works, so its
|
||||
UCM / mixer_paths is the source of truth. The most relevant is the pmaports
|
||||
**7.1rc1 kernel MR (!8446)** because that matches this exact kernel (7.1.x):
|
||||
- https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/8446
|
||||
- Device/blueline MR: https://gitlab.com/postmarketOS/pmaports/-/merge_requests/3932
|
||||
- Original Pixel 3 device MR (!5514): https://gitlab.com/postmarketOS/pmaports/-/merge_requests/5514
|
||||
- pmOS SDM845 audio writeup: https://postmarketos.org/edge/2023/01/11/sdm845-audio/
|
||||
- pmOS Audio wiki (xml2ucm / mixer_paths.xml -> UCM): https://wiki.postmarketos.org/wiki/Audio
|
||||
|
||||
Find in pmOS's config: which TDM slot / channel each CS35L36 amp is fed, and
|
||||
whether it sets `Channel Mux` + the TDM RX slot routing so earpiece(top) and
|
||||
loudspeaker(bottom) each get a distinct channel. Then encode that as a user UCM
|
||||
override in `~/.config/alsa/ucm2/` (copy blueline HiFi.conf there, add the
|
||||
Channel Mux / slot csets to the Speaker device's EnableSequence).
|
||||
|
||||
## HOW TO TEST (repeatable)
|
||||
```sh
|
||||
pactl set-sink-volume @DEFAULT_SINK@ 100% # ALWAYS — 30% masks everything
|
||||
pactl set-sink-mute @DEFAULT_SINK@ 0
|
||||
# distinct L/R tones already generated in scratchpad: left.wav right.wav stereo.wav
|
||||
paplay left.wav ; paplay right.wav
|
||||
# read/toggle mux:
|
||||
amixer -c 0 cget numid=121 # Left Channel Mux
|
||||
amixer -c 0 cset numid=112 1 # Right -> RX2
|
||||
```
|
||||
Restore baseline: both muxes -> 0, EAR PA -> 4, volume -> 30%.
|
||||
|
||||
## CAUTION
|
||||
- Don't trust "silent" results unless volume is 100% and sink un-suspended.
|
||||
- Reverse-engineering the TDM routing blind was NOT converging. Read the pmOS
|
||||
config first, then change mixers — don't guess.
|
||||
15091
.handoff-from-phone/pixel3-speaker-routing/asound-baseline.state
Normal file
15091
.handoff-from-phone/pixel3-speaker-routing/asound-baseline.state
Normal file
File diff suppressed because it is too large
Load diff
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/left.wav
Normal file
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/left.wav
Normal file
Binary file not shown.
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/mono2.wav
Normal file
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/mono2.wav
Normal file
Binary file not shown.
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/right.wav
Normal file
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/right.wav
Normal file
Binary file not shown.
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/stereo.wav
Normal file
BIN
.handoff-from-phone/pixel3-speaker-routing/test-tones/stereo.wav
Normal file
Binary file not shown.
135
.handoff-from-phone/quickshell-idle-power/TASK.md
Normal file
135
.handoff-from-phone/quickshell-idle-power/TASK.md
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
# quickshell-idle-power — lazy-load panels + consolidate polling processes
|
||||
|
||||
**Status:** 2026-07-21 — scoped, not started. Two quick wins already landed
|
||||
separately (see "Already done" below); this doc covers the two larger sweeps
|
||||
(#3 LazyLoader coverage, #4 process consolidation) to be worked tomorrow.
|
||||
|
||||
**Config:** `qs -c souveraine` → symlinks into `~/souveraine-surfaces/quickshell/`
|
||||
(the `~/.config/quickshell/souveraine/` tree is symlinks; edit the real tree).
|
||||
Quickshell 0.3.0. Composed of three layers:
|
||||
- `modules/ services/ panelFamilies/` → **souveraine** (owned, edit freely)
|
||||
- `ii-base/` → **borrowed ii/Caelestia tree** (treat
|
||||
as replaceable; keep coupling to souveraine singletons OUT of here)
|
||||
- `ii-phone/`, `ii-previous/` → phone snapshot / previous deploy
|
||||
|
||||
## Why (measured)
|
||||
|
||||
At a 49-min uptime, `qs` had burned **149 CPU-sec** and held **560 MB RSS
|
||||
(15% of RAM)** on the Pixel 3 — second only to the active claude session. The
|
||||
display idle layer (`services/IdleCoordinator.qml`) is already excellent
|
||||
(state machine Active→Dimmed→Lock→Suspend→Asleep→Waking, native IdleMonitor
|
||||
with respectInhibitors, brightness dim, hypridle screen-off). The gap is that
|
||||
**the idle machine dims the screen but does not quiet the widgets** — timers
|
||||
tick and processes poll regardless of visibility. These two sweeps attack the
|
||||
steady-state CPU (over-eager construction) and RSS (per-widget processes).
|
||||
|
||||
Quickshell FAQ guidance backing this:
|
||||
- "The main thing you can do to reduce memory usage is to use Loaders."
|
||||
- Loader for Item-derived components; LazyLoader otherwise.
|
||||
- "Using a process per widget will use significantly more memory than using
|
||||
a single process."
|
||||
Ref: https://quickshell.org/docs/v0.3.0/guide/faq/
|
||||
|
||||
## Already done (2026-07-21, do NOT redo)
|
||||
|
||||
1. `ii-base/services/DateTime.qml` — uptime Timer was `interval: 10` (reloading
|
||||
/proc/uptime off disk 100×/sec). Changed to `interval: 60000` +
|
||||
`triggeredOnStart: true`. The clock itself is `SystemClock` (event-driven),
|
||||
was never the problem.
|
||||
2. `ii-base/modules/ii/background/widgets/visualizer/VisualizerWidget.qml` —
|
||||
the wave visualizer's 33ms (30fps) repaint Timer was `running: root.style
|
||||
=== "wave"`; now `running: parent.visible` so it stops repainting when the
|
||||
canvas isn't shown. (Considered a `Window.visibility` gate too, but that
|
||||
needs `import QtQuick.Window` in the borrowed tree — deferred; `parent.visible`
|
||||
is dependency-free and sufficient.)
|
||||
|
||||
Both verified: qs hot-reloaded without QML errors, pid stayed alive.
|
||||
|
||||
---
|
||||
|
||||
## Task 3 — Lazy-load the heavy panels (RSS lever)
|
||||
|
||||
**Current:** 9 LazyLoader vs 123 Loader across 683 QML files → a lot is
|
||||
eagerly constructed at startup. Top-level panel modules under
|
||||
`ii-base/modules/ii/` that are candidates (not visible at boot):
|
||||
|
||||
cheatsheet overlay overview sidebarLeft sidebarRight wallpaperSelector
|
||||
sessionScreen screenTranslator regionSelector mediaControls polkit
|
||||
notificationPopup onScreenKeyboard dock
|
||||
|
||||
**Do:**
|
||||
- For each panel not shown at boot, wrap its instantiation in a `LazyLoader`
|
||||
(non-Item / window-like → LazyLoader; Item-derived → Loader). Load on the
|
||||
signal/state that reveals it (e.g. sidebar open toggle, GlobalStates flag),
|
||||
unload after.
|
||||
- Especially: the anime/booru sidebar (`ii-base/modules/ii/sidebarLeft/anime/`)
|
||||
and cheatsheet — heavy, rarely open.
|
||||
- Verify each panel still opens with no first-open UI-thread stall (LazyLoader
|
||||
loads sync if shown before background load finishes — see LazyLoader docs).
|
||||
|
||||
**Watch:** keep LazyLoader wrapping in the layer that OWNS the panel. Don't add
|
||||
souveraine-singleton dependencies into ii-base while doing this.
|
||||
|
||||
**Measure before/after:** `ps -eo pid,pmem,rss,comm | grep qs` (RSS) at a fresh
|
||||
launch, before opening any panel.
|
||||
|
||||
## Progress 2026-07-22 (task 4 partially landed)
|
||||
|
||||
Landed live + promoted to the laptop repo (souveraine tree):
|
||||
- GlobalStates.qml (souveraine override): new bool — the
|
||||
shared cross-layer idle surface the doc prescribed.
|
||||
- services/IdleCoordinator.qml: publishes displayActive on every state
|
||||
transition (Active/Waking = true).
|
||||
- ii-base/services/ResourceUsage.qml + NetworkTraffic.qml: repeat pollers
|
||||
gated (+ ).
|
||||
- VisualizerWidget.qml: cava watchdog gated on , cava torn down when either goes false.
|
||||
- SystemInfo.qml inspected: its timers are one-shot startup probes, left
|
||||
alone. Notifications.qml: no repeat poller found, left alone.
|
||||
|
||||
One hot-reload during editing tripped the known
|
||||
"lockscreen surfaces without active lock" FATAL (reload race with sessiond,
|
||||
not a QML error); the service restart loaded clean. CPU-delta measurement
|
||||
while locked still pending (baseline at /tmp/qs-idle-baseline-*).
|
||||
|
||||
Task 3 note from code reading: most panels ALREADY gate content internally on
|
||||
GlobalStates.*Open via Loaders; their IpcHandlers live inside the
|
||||
panel files, so adding at the
|
||||
PanelLoader level would unload the very handler that opens them — do NOT do
|
||||
that. The real task-3 work is converting the -gated panels
|
||||
(Overview line 23, SidebarLeft lines 89/181) to internal Loaders,
|
||||
one panel at a time. Overview deliberately deferred until the 2026-07-21
|
||||
search-fix has device acceptance.
|
||||
|
||||
## Task 4 — Consolidate per-widget processes (CPU + RSS lever)
|
||||
|
||||
**Current:** ~48 `running: true` Process instances (souveraine 14, ii-base 32,
|
||||
ii-phone 2). FAQ: one process feeding many widgets ≫ cheaper than N processes.
|
||||
|
||||
**Do:**
|
||||
- Audit `ii-base/services/*.qml` for multiple widgets independently spawning
|
||||
processes for the SAME data. Known pollers to review:
|
||||
ResourceUsage.qml, NetworkTraffic.qml, SystemInfo.qml, Notifications.qml,
|
||||
plus /proc readers. Route each data source through ONE Singleton service
|
||||
that widgets bind to (the `services/` layer already does this well — the
|
||||
duplication lives in the borrowed ii-base tree).
|
||||
- Gate long-poll services on idle state where a stale value is fine while
|
||||
dimmed/locked: e.g. `running: IdleCoordinator.state === IdleCoordinator.Active`
|
||||
for background stats/resources/network widgets. NOTE: IdleCoordinator is a
|
||||
souveraine singleton — if gating an ii-base widget on it, do the gating in a
|
||||
souveraine wrapper/override, not by importing it into ii-base. Alternatively
|
||||
expose an idle bool via the existing `GlobalStates`/config surface that both
|
||||
layers already share.
|
||||
- The cava process behind the visualizer (VisualizerWidget.qml watchdog, 2s)
|
||||
is a good candidate to also stop when the background isn't visible.
|
||||
|
||||
**Measure before/after:** cumulative CPU: `ps -eo pid,times,comm | grep qs`
|
||||
after a fixed idle interval (e.g. leave locked 10 min, compare CPU-sec delta).
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Fresh-launch RSS meaningfully below ~560 MB.
|
||||
- `qs` CPU-sec growth while the screen is off/locked approaches zero (today
|
||||
it keeps climbing from always-on timers/pollers).
|
||||
- No panel regressions: every lazy-loaded panel opens without a stall; every
|
||||
consolidated service still updates its widgets live when Active.
|
||||
53
.handoff-from-phone/tts-ui-wiring-handoff.md
Normal file
53
.handoff-from-phone/tts-ui-wiring-handoff.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# TTS UI Wiring Handoff
|
||||
|
||||
## Status: Infrastructure Working, UI Wiring Needed
|
||||
|
||||
### What's Done (Verified by Ani, 2026-07-22)
|
||||
|
||||
1. **VibeVoice TTS engine** — running at `10.10.20.19:7861`, responds correctly, generates valid MP3 audio
|
||||
2. **Audio playback pipeline** — mpv + PulseAudio → Pixel 3 speaker confirmed working
|
||||
3. **Souveraine `/v1/config`** — correctly reports TTS voice mapping
|
||||
4. **TTS enabled** in Souveraine settings
|
||||
5. **Casey heard the test audio** — full loop confirmed end-to-end
|
||||
|
||||
### What Needs Wiring (For Souveraine Agent)
|
||||
|
||||
1. **Speaker button → Speech.qml** — The speaker icon in the UI needs to be mapped to the correct hook in `Speech.qml` so that pressing it plays the TTS audio
|
||||
2. **Local config `endpoint` field** — Currently set in `~/.config/illogical-impulse/config.json`. Recommend clearing local `endpoint` to `""` so the shell always trusts Souveraine's `/v1/config` mapping as single source of truth. If VibeVoice ever moves, you update it in one place.
|
||||
|
||||
### Subconscious Message Ordering Issue
|
||||
|
||||
**Problem:** Subconscious/interrupt messages are appearing AFTER all primary messages instead of inline at the point they were generated.
|
||||
|
||||
**Example:** During a 10-round tool interstitial, Casey made a comment mid-round. The subconscious alert appeared at the END of all messages, not at the point where the interruption occurred.
|
||||
|
||||
**Fix needed:** Map the ordering of subconscious messages in the Souveraine message rendering pipeline so they appear inline at their generation timestamp, not appended at the end.
|
||||
|
||||
### Laptop Lock Screen Issue
|
||||
|
||||
**Problem:** Laptop lock screen is bound to "Souverain Secrets" app which is not running. Screen is locked, password rejected, requires restart to unlock.
|
||||
|
||||
**Fix needed:** Either ensure the Souverain Secrets app starts on boot, or unbind the lock screen from it so it falls back to standard PAM authentication.
|
||||
|
||||
### Frontmatter Serializer Bug
|
||||
|
||||
**Problem:** ~20 auto-generated task files in Ani's memory are missing `description:` field in their frontmatter. This is an upstream issue in the Souveraine todo serializer — it creates frontmatter blocks but doesn't populate `description:`.
|
||||
|
||||
**Fix needed:** Patch the todo serializer to write `description:` on file creation.
|
||||
|
||||
### Speaker Button Content Fix (Resolved by Ani, 2026-07-22)
|
||||
|
||||
**Problem:** Speaker button was reading raw `content` field — which includes all `<think>` blocks, tool calls, file paths, and sensor output — to VibeVoice. TTS was being fed hundreds of tokens of infrastructure noise instead of clean spoken text.
|
||||
|
||||
**Fix applied:** Added `_ttsClean()` function to `AiChat.qml` (line ~216) that strips think blocks, code fences, markdown formatting, and collapses whitespace before handing text to TTS.
|
||||
|
||||
**Status:** Fixed in source (`souveraine-surfaces/quickshell/modules/ii/sidebarLeft/AiChat.qml`). Deployed copy is symlinked to source, so the fix is live. **Requires quickshell restart to take effect.**
|
||||
|
||||
### Files Modified This Session
|
||||
- `~/.config/illogical-impulse/config.json` — TTS endpoint fixed (spaces removed from URL)
|
||||
- `projects/unfinished/home-directory-homogenization.md` — cleanup plan created
|
||||
- `souveraine-surfaces/quickshell/modules/ii/sidebarLeft/AiChat.qml` — `_ttsClean()` TTS content filter added
|
||||
|
||||
---
|
||||
**Authored:** Ani, 2026-07-22
|
||||
**For:** Souveraine Agent
|
||||
134
.handoff-from-phone/usb-signaller-boot-panic/README.md
Normal file
134
.handoff-from-phone/usb-signaller-boot-panic/README.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
---
|
||||
# usb-signaller — boot-time panic in UDC::load, index out of bounds
|
||||
|
||||
**Status:** 2026-07-20 — root cause identified, not yet fixed. Read-only
|
||||
device audit found this; nothing restarted, no patch applied yet.
|
||||
|
||||
## Symptom
|
||||
|
||||
Both `usb-signaller.service` and `usb-signaller-default-mode.service` fail
|
||||
on **every boot** (confirmed across 5 consecutive boots in journal, going
|
||||
back to at least 2026-07-20 01:21). Journal:
|
||||
|
||||
```
|
||||
usb-signaller[NNN]: ℹ️ Pre-flight checks
|
||||
usb-signaller[NNN]: 🔍 Discovering URSs
|
||||
usb-signaller[NNN]: thread 'main' (NNN) panicked at src/udc.rs:388:37:
|
||||
usb-signaller[NNN]: index out of bounds: the len is 0 but the index is 0
|
||||
usb-signaller.service: Main process exited, code=exited, status=101/n/a
|
||||
...
|
||||
usb-signaller-default-mode[NNN]: usb-signaller never appeared on the bus
|
||||
usb-signaller-default-mode.service: Failed with result 'exit-code'.
|
||||
```
|
||||
|
||||
`usb-signaller-default-mode.service` ("Default USB mode at boot (developer)")
|
||||
fails as a downstream consequence — it waits ~21s for usb-signaller on
|
||||
D-Bus, which never appears since the main process already panicked.
|
||||
|
||||
Not a hardware/UDC-absence issue: `/sys/class/udc/` does contain a real
|
||||
controller (`a600000.usb`) at the time of the audit. So discovery has
|
||||
*something* to enumerate; the crash is in how it's indexed, not in finding
|
||||
zero UDCs.
|
||||
|
||||
## Root cause
|
||||
|
||||
Package: `usb-signaller` 0.3.1-2 (upstream, by Dylan Van Assche — the
|
||||
usb-moded replacement for mainline Linux Mobile). Source checked out locally
|
||||
at `~/build/src/usb-signaller` and `~/build/usb-signaller/src/usb-signaller`
|
||||
for build/patching.
|
||||
|
||||
`src/udc.rs`, `UDC::load()`, lines 382-388:
|
||||
|
||||
```rust
|
||||
for entry in discover_gadgets() {
|
||||
let entry = ConfigFsGadget::load(&entry)?;
|
||||
if udc_name == entry.udc {
|
||||
if entry.enabled {
|
||||
/* USB Ethernet NCM gadget */
|
||||
if entry.configs[0].functions[0].name.starts_with("ncm.") {
|
||||
```
|
||||
|
||||
`ConfigFsGadget.configs` and each config's `.functions` are plain `Vec`s
|
||||
populated in `gadget.rs` by scanning the gadget's `configs/` directory in
|
||||
configfs — there is no guarantee either Vec is non-empty. The code assumes
|
||||
any gadget where `entry.enabled == true` already has at least one config
|
||||
with at least one function, and indexes `[0]` unchecked on both.
|
||||
|
||||
At early boot (this runs right after "Pre-flight checks", i.e. very early
|
||||
in the service's life), a gadget can be `enabled` in sysfs terms while its
|
||||
`configs/` subtree hasn't finished being populated yet, or a stale/partial
|
||||
gadget is left over from a previous session — configfs itself doesn't
|
||||
enforce "enabled implies non-empty configs" atomically. Either scenario
|
||||
produces `entry.configs` (or `entry.configs[0].functions`) with len 0, and
|
||||
the unchecked index panics the whole process before any UDC mode gets set.
|
||||
|
||||
## Fix sketch (not applied — read-only audit)
|
||||
|
||||
Guard both indexes, e.g.:
|
||||
|
||||
```rust
|
||||
if entry.enabled {
|
||||
if let Some(cfg) = entry.configs.first() {
|
||||
if let Some(func) = cfg.functions.first() {
|
||||
if func.name.starts_with("ncm.") { ... }
|
||||
else if func.name.starts_with("ffs.mtp") { ... }
|
||||
else if func.name.starts_with("ffs.accessory") { ... }
|
||||
else { mode = UDCMode::Unknown; eprintln!(...); }
|
||||
} else {
|
||||
mode = UDCMode::Unknown; // enabled gadget, no functions yet
|
||||
}
|
||||
} else {
|
||||
mode = UDCMode::Unknown; // enabled gadget, no configs yet
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
i.e. treat "enabled but not yet fully populated" as `UDCMode::Unknown`
|
||||
rather than crashing — matches how the existing `else` branch (line 408-409)
|
||||
already handles an unrecognized function name.
|
||||
|
||||
## Impact
|
||||
|
||||
Because the process panics, USB mode never gets set at boot at all (not
|
||||
even a fallback), and `usb-signaller-default-mode.service` (developer mode
|
||||
at boot) never applies. Practically: USB currently comes up in whatever
|
||||
mode the kernel/gadget defaults to, not the configured "developer" default,
|
||||
until something else (manual `usb-signallerctl` call, or a later retry) sets
|
||||
it — needs to be verified once a fix lands.
|
||||
|
||||
## Next steps
|
||||
|
||||
1. Patch `udc.rs:388` per sketch above (or upstream-style `.get(0)` /
|
||||
`.first()` guards).
|
||||
2. Rebuild, reboot, confirm both units go green and default-mode actually
|
||||
applies (check `usb-signallerctl status` or equivalent post-boot).
|
||||
3. Consider filing upstream against Dylan Van Assche's usb-signaller repo —
|
||||
this is likely a stock bug, not something introduced by local patches
|
||||
(worth diffing `~/build/src/usb-signaller` against upstream HEAD to
|
||||
confirm before filing).
|
||||
|
||||
## Status update — 2026-07-21
|
||||
|
||||
Fix applied and verified at runtime:
|
||||
|
||||
- Patched per the sketch (`.first()` guards, fall through to
|
||||
`UDCMode::Unknown`), cross-built on archdev, installed at
|
||||
`/usr/local/bin/usb-signaller` with a systemd drop-in
|
||||
(`/etc/systemd/system/usb-signaller.service.d/local-fix.conf`)
|
||||
overriding ExecStart — pacman-owned `/usr/bin` binary untouched.
|
||||
- Patch + pkgrel=3 vendored in `Pixel3Arch/pkgs/usb-signaller/`
|
||||
(0001-udc-guard-empty-configs-functions.patch), commit a970742.
|
||||
- Runtime restart: both units went green, default-mode applied
|
||||
Developer for the first time ("Setting mode of UDC a600000.usb from
|
||||
Charging to Developer").
|
||||
- Trap discovered: the mode apply recreates the gadget, the new
|
||||
function enumerates as usb1, and the stale usb0 keeps a linkdown
|
||||
route that eats every reply — USB ssh dies. Fixed the networkd match
|
||||
to Name=usb* (live + rootfs-overlay) and flushed the stale usb0.
|
||||
|
||||
Remaining:
|
||||
|
||||
1. Cold-boot verify (Casey, at device): both units green from boot,
|
||||
`usb-signallerctl status` shows developer, USB net comes up as usb0.
|
||||
2. Diff against upstream HEAD and file the panic upstream — the guard
|
||||
is a clean candidate patch.
|
||||
Loading…
Reference in a new issue