Files
mestre/wifi-bt-architecture.md
Joakim 2526d5b087 feat: M3 complete — WiFi, BT keyboard and mouse
Bluetooth (RTL8723D USB combo chip):
- GPIO pin 357 (active low) enables WiFi/BT hardware via x6200_gpio_set()
- bluez5_utils 5.64 (downgraded from 5.79 — HID input plugin broken in 5.79)
- rtl8723d_config.bin added to overlay (missing from linux-firmware package)
- S45wifi-bt: GPIO enable + modprobe btusb/uhid/hidp at boot
- S85bt-keyboard: auto-connect loop with scan+connect every 20s

WiFi (RTL8723DU):
- out-of-tree lwfinger/rtw88 driver (RTW88_8723DU not in kernel 6.1 mainline)
- linux-firmware RTL_RTW88 for rtw88/rtw8723d_fw.bin
- regulatory.db for cfg80211
- wpa_supplicant with multi-network config in /etc/wpa_supplicant.conf
- S46wifi: wpa_supplicant + udhcpc at boot

Key findings:
- RTL8723D USB WiFi (0bda:d723) requires out-of-tree rtw88 on kernel 6.1
- BT and WiFi share same USB device, both need GPIO 357 = 0 to power on
- bluez5 5.79 HID input plugin not linked into bluetoothd (build system bug)
2026-05-09 21:02:53 +02:00

9.4 KiB

X6200 WiFi and Bluetooth Architecture

A detailed technical account of how WiFi and Bluetooth work on the Xiegu X6200, reverse-engineered during Mestre development (May 2026).

Hardware Overview

The X6200 uses a Realtek RTL8723D combo chip for both WiFi and Bluetooth. It is connected to the Allwinner R16 SoC via USB and appears as a single USB device:

USB ID: 0bda:d723  Realtek Semiconductor Corp. 802.11n WLAN Adapter
Bus:    USB 3 (musb-hdrc, high-speed)

The device exposes three USB interfaces:

  • Interface 0+1: Bluetooth (class 0xE0, Wireless, RF)
  • Interface 2: WiFi (class 0xFF, Vendor Specific)

Both WiFi and Bluetooth share the same USB device and antenna.

The Power Control Problem

The RTL8723D chip is powered off at boot. It does not appear on the USB bus until explicitly powered on via a GPIO pin. Without this step, neither WiFi nor Bluetooth will work regardless of what drivers or software is loaded.

The power control pin is managed via the X6200Control library:

GPIO chip: 0  (sun8i-a33 main GPIO controller)
GPIO pin:  357
Logic:     Active LOW (0 = powered ON, 1 = powered OFF)

This is controlled via the x6200_gpio_set() function from libaether_x6200_control.so:

import ctypes
lib = ctypes.CDLL("libaether_x6200_control.so")
lib.x6200_gpio_init.restype = ctypes.c_bool
lib.x6200_gpio_set.argtypes = [ctypes.c_int, ctypes.c_int]
lib.x6200_gpio_init()
lib.x6200_gpio_set(357, 0)   # 0 = ON (active low!)

Critical: gpio_init() must be called before gpio_set(). The active-low logic is counterintuitive — sending 1 powers the chip OFF, sending 0 powers it ON.

After powering on, the USB device appears within 1-3 seconds:

usb 3-1: new high-speed USB device number 2 using musb-hdrc
usb 3-1: New USB device found, idVendor=0bda, idProduct=d723

Bluetooth

Driver

The Bluetooth interface of the RTL8723D is handled by the standard Linux kernel btusb driver with the btrtl firmware loader.

Required kernel modules (compiled as =m):

CONFIG_BT=m
CONFIG_BT_HCIBTUSB=m
CONFIG_BT_RFCOMM=m
CONFIG_BT_BNEP=m
CONFIG_BT_HIDP=m
CONFIG_UHID=y          ← required for HID input devices
CONFIG_INPUT_UINPUT=y  ← required for HID input devices

Load order:

modprobe btusb    # registers hci0 and loads firmware
modprobe uhid     # userspace HID device support
modprobe hidp     # HID over Bluetooth protocol

Firmware

The RTL8723D Bluetooth requires two firmware files:

File Purpose
rtl_bt/rtw8723d_fw.bin Main BT firmware
rtl_bt/rtw8723d_config.bin Configuration (10 bytes)

Both files are required. Without rtw8723d_config.bin, hciconfig hci0 up fails with:

Bluetooth: hci0: RTL: mandatory config file rtl_bt/rtw8723d_config not found

rtw8723d_config.bin is not included in Buildroot's BR2_PACKAGE_LINUX_FIRMWARE_RTL_87XX_BT package (as of 2025.02). It must be added to the rootfs overlay manually:

br2_external/board/x6200/rootfs-overlay/lib/firmware/rtl_bt/rtw8723d_config.bin

Source: https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain/rtl_bt/rtw8723d_config.bin

BlueZ Version

BlueZ 5.64 is required. BlueZ 5.79 (Buildroot 2025.02 default) has a build system bug where the HID input plugin (input_init) is not linked into bluetoothd despite --enable-hid being passed to configure. Symptoms:

Failed to connect: org.bluez.Error.NotAvailable br-connection-profile-unavailable

The bug manifests because builtin_modules in the generated Makefile is empty and the input profile is never registered via btd_profile_register(). Downgrading to BlueZ 5.64 resolves the issue.

To force BlueZ 5.64 in Buildroot, override the version in a local .mk file or patch buildroot/package/bluez5_utils/bluez5_utils.mk.

HID Profile Requirements

For Bluetooth HID devices (keyboard, mouse) to connect, bluetoothd must be started with --compat:

/usr/libexec/bluetooth/bluetoothd --compat &

And /etc/bluetooth/input.conf must have:

[General]
UserspaceHID=true
ClassicBondedOnly=false

Pairing a Device

First-time pairing via bluetoothctl:

power on
agent on
default-agent
scan on
# Wait for device to appear, then:
pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX
connect XX:XX:XX:XX:XX:XX

Once trusted, subsequent connections are automatic via the S85bt-keyboard init script.

Auto-reconnect

The S85bt-keyboard init script polls every 20 seconds and reconnects if the device is not connected. It uses scan on before each connection attempt to make the device visible:

{
    echo "power on"; sleep 1
    echo "scan on"; sleep 8
    echo "scan off"; sleep 1
    echo "connect $KEYBOARD_ADDR"; sleep 3
    echo "quit"
} | bluetoothctl

WiFi

Driver

The RTL8723D USB WiFi interface is NOT supported by any in-tree driver in Linux 6.1. Specifically:

Driver Status in 6.1
rtl8xxxu Does not support 0bda:d723
r8723bs SDIO only, not USB
rtw88 Only has PCIe variant (RTW88_8723DE), USB variant added in 6.2

The solution is the out-of-tree lwfinger/rtw88 driver, which backports USB support for RTL8723D to older kernels. This is the same approach used by the Xiegu X6100 community.

Buildroot package: br2_external/package/rtw88/rtw88.mk

RTW88_VERSION = 461b696b51317ba4ca585a4ddb32f2e72cd4efc9
RTW88_SITE = https://github.com/lwfinger/rtw88
RTW88_SITE_METHOD = git
RTW88_LICENSE = GPL-2.0
$(eval $(kernel-module))
$(eval $(generic-package))

After loading, the driver creates wlan0:

3: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
    link/ether cc:64:1a:52:91:85 brd ff:ff:ff:ff:ff:ff

Firmware

Two firmware components are required:

Component Buildroot symbol File
WiFi firmware BR2_PACKAGE_LINUX_FIRMWARE_RTL_RTW88 rtw88/rtw8723d_fw.bin
Regulatory DB BR2_PACKAGE_LINUX_FIRMWARE_REGULATORY regulatory.db

Note: After adding BR2_PACKAGE_LINUX_FIRMWARE_RTL_RTW88, you must run linux-firmware-dirclean before rebuilding, otherwise the br-firmware.tar archive is not regenerated and the firmware file will not appear in the target:

./scripts/build.sh linux-firmware-dirclean
./scripts/build.sh linux-firmware
./scripts/build.sh

Network Configuration

WiFi is configured via wpa_supplicant with a multi-network configuration file at /etc/wpa_supplicant.conf:

ctrl_interface=/var/run/wpa_supplicant
update_config=1
country=SE

network={
    ssid="Network_1"
    psk="password_1"
    priority=10
}

network={
    ssid="Network_2"
    psk="password_2"
    priority=5
}

wpa_supplicant automatically connects to the highest-priority available network. Add as many network={} blocks as needed.

The file is installed in the rootfs overlay but should be considered sensitive — do not commit real passwords to git.

Boot Sequence

S35wifi-bt (or S45wifi-bt)
    → x6200_gpio_init()
    → x6200_gpio_set(357, 0)    ← powers on RTL8723D
    → modprobe btusb            ← registers hci0
    → modprobe uhid
    → modprobe hidp
    → sleep 3                   ← wait for USB enumeration

S40bluetoothd
    → bluetoothd --compat       ← BlueZ daemon

S46wifi
    → ip link set wlan0 up
    → wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
    → udhcpc -i wlan0           ← DHCP client

S85bt-keyboard
    → auto-connect loop (scan + connect every 20s)

Ordering is critical: The GPIO power-on script must run before bluetoothd and wpa_supplicant. Without GPIO 357 = 0, neither WiFi nor Bluetooth hardware is visible on the USB bus.

Known Quirks

GPIO is active low. gpio_set(357, 0) = ON, gpio_set(357, 1) = OFF. This is the opposite of what one might expect.

Single USB device, two functions. WiFi and BT share 0bda:d723. Powering on the chip enables both simultaneously. There is no way to enable one without the other.

rtw8723d_config.bin is missing from linux-firmware package. Buildroot's BR2_PACKAGE_LINUX_FIRMWARE_RTL_87XX_BT does not include this 10-byte config file. Must be added to overlay manually.

BlueZ 5.79 HID input plugin is broken. Downgrade to 5.64 for working Bluetooth keyboard and mouse support.

lwfinger/rtw88 is pinned to a specific commit. The driver is under active development; newer commits may break things. Pin to a known-good commit in rtw88.mk.

linux-firmware-dirclean required after adding RTW88 firmware. Buildroot caches br-firmware.tar and does not regenerate it when new firmware symbols are added to .config. Always run linux-firmware-dirclean after changing firmware selection.

References

  • lwfinger/rtw88 — out-of-tree RTW88 driver with USB support for RTL8723DU
  • AetherRadio/X6200Control — GPIO control library; x6200_pin_wifi (pin 357) is defined in include/aether_radio/x6200_control/low/gpio.h
  • gdyuldin/AetherX6200Buildroot — reference Buildroot configuration; provided the rtw88 package recipe that Mestre adapts
  • Linux kernel drivers/net/wireless/realtek/rtw88/ — mainline RTW88 driver (USB variant added in 6.2, not available in 6.1)
  • Realtek RTL8723D datasheet — combo WiFi+BT chip used in X6200