From 0a82d2c2d7cd77a337b4126ca3772d1ed7ebc579 Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Tue, 28 Jul 2026 12:02:19 +0300 Subject: [PATCH] Give Bluetooth its factory address from the DPP partition The WCN3990 has no burned-in Bluetooth address, so the kernel registers the controller unconfigured and bluetoothd never sees it. The factory address is on the machine all along: QCOM/BT.PROVISION on the DPP partition, a three-byte header followed by the six-byte address. c630-bt-addr reads it and hands it to btmgmt before bluetooth.service starts. Verified on hardware: controller configures, powers, scans, and streams A2DP. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_011XgGF5wfxLDAybVnNz6eNQ --- build/stage2.sh | 1 + .../etc/systemd/system/c630-bt-addr.service | 15 ++++++ overlay/usr/local/sbin/c630-bt-addr | 53 +++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 overlay/etc/systemd/system/c630-bt-addr.service create mode 100755 overlay/usr/local/sbin/c630-bt-addr diff --git a/build/stage2.sh b/build/stage2.sh index 8c3f342..d4b2b63 100755 --- a/build/stage2.sh +++ b/build/stage2.sh @@ -284,6 +284,7 @@ chroot "$ROOTFS" passwd -l root # without tqftpserv, since the modem fetches the WLAN firmware over TFTP. chroot "$ROOTFS" systemctl enable \ c630-growfs.service \ + c630-bt-addr.service \ sshd.service \ NetworkManager.service \ systemd-resolved.service \ diff --git a/overlay/etc/systemd/system/c630-bt-addr.service b/overlay/etc/systemd/system/c630-bt-addr.service new file mode 100644 index 0000000..8ce2a8d --- /dev/null +++ b/overlay/etc/systemd/system/c630-bt-addr.service @@ -0,0 +1,15 @@ +[Unit] +Description=Set the C630 Bluetooth factory address from the DPP partition +# The WCN3990 has no burned-in address; the controller stays unconfigured and +# invisible to bluetoothd until one is set. See /usr/local/sbin/c630-bt-addr. +Before=bluetooth.service +ConditionPathExists=/dev/disk/by-partlabel/DPP + +[Service] +Type=oneshot +ExecStart=/usr/local/sbin/c630-bt-addr +RemainAfterExit=yes +StandardOutput=journal + +[Install] +WantedBy=multi-user.target diff --git a/overlay/usr/local/sbin/c630-bt-addr b/overlay/usr/local/sbin/c630-bt-addr new file mode 100755 index 0000000..f74a6f3 --- /dev/null +++ b/overlay/usr/local/sbin/c630-bt-addr @@ -0,0 +1,53 @@ +#!/usr/bin/bash +# +# Give the Bluetooth controller its factory address. +# +# The WCN3990 has no burned-in Bluetooth address. The kernel brings the +# controller up, downloads its firmware, and then registers it *unconfigured* — +# it answers on /sys/class/bluetooth but does not appear in the management +# interface, so bluetoothctl reports "No default controller available" and +# nothing works until userspace supplies an address. +# +# The factory address is on the machine, in the Windows provisioning partition +# (GPT label DPP, FAT): QCOM/BT.PROVISION is nine bytes — a three-byte header +# followed by the six-byte address in display order. QCOM/WLAN.PROVISION holds +# the WiFi MAC in the same layout, sharing the same OUI block, which is how the +# layout was recognised. +# +# Setting it flips the controller from unconfigured to configured and powered. + +set -euo pipefail + +for _ in $(seq 30); do + [ -d /sys/class/bluetooth/hci0 ] && break + sleep 1 +done +if [ ! -d /sys/class/bluetooth/hci0 ]; then + echo "c630-bt-addr: no Bluetooth controller appeared; nothing to do" + exit 0 +fi + +if ! btmgmt info | grep -q "Index list with 0 items"; then + echo "c630-bt-addr: controller already configured; nothing to do" + exit 0 +fi + +dpp=/dev/disk/by-partlabel/DPP +if [ ! -b "$dpp" ]; then + echo "c630-bt-addr: no DPP partition; cannot recover the factory address" >&2 + exit 0 +fi + +mnt=$(mktemp -d) +trap 'umount "$mnt" 2>/dev/null || true; rmdir "$mnt"' EXIT +mount -o ro "$dpp" "$mnt" + +prov="$mnt/QCOM/BT.PROVISION" +if [ ! -f "$prov" ] || [ "$(stat -c %s "$prov")" -lt 9 ]; then + echo "c630-bt-addr: $prov missing or too short" >&2 + exit 0 +fi + +addr=$(od -An -tx1 -j3 -N6 "$prov" | tr -s ' ' '\n' | grep . | paste -sd:) +btmgmt --index 0 public-addr "$addr" +echo "c630-bt-addr: set hci0 public address to $addr"