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)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ build/
|
||||
# Local overrides
|
||||
local.mk
|
||||
.env
|
||||
wpa_supplicant.conf
|
||||
|
||||
17
README.md
17
README.md
@@ -41,12 +41,15 @@ The product name **Virtuoso** is reserved for when (if!) Mestre actually deliver
|
||||
|
||||
| # | Milestone | Status |
|
||||
|---|----------------------------------------------------------------------|--------|
|
||||
| 1 | Boot a recent Buildroot LTS on the X6200 (serial console) | 🟡 In progress |
|
||||
| 2 | Forward-port LCD panel driver — full display output | ⚪ Planned |
|
||||
| 3 | piHPSDR running on X6200 with working audio | ⚪ Planned |
|
||||
| 4 | `mestre` service: evdev → ALSA virtual MIDI bridge | ⚪ Planned |
|
||||
| 5 | End-to-end: X6200 controlling Hermes-Lite 2 as a control head | ⚪ Planned |
|
||||
| 6 | First-boot wizard, settings persistence, polished UX | ⚪ Planned |
|
||||
| 1 | Boot a recent Buildroot LTS on the X6200 (serial console) | ✅ 2026-05-03 |
|
||||
| 2 | Working audio stack | ✅ 2026-05-06 |
|
||||
| 3 | WiFi and Bluetooth keyboard and mouse | ✅ 2026-05-09 |
|
||||
| 4 | Forward-port LCD panel driver — full display output | ✅ 2026-05-03 |
|
||||
| 5 | piHPSDR running on X6200, controlled by mouse and keyboard | ⚪ Planned |
|
||||
| 6 | piHPSDR audio — HL2 audio via SoC speaker | ⚪ Planned |
|
||||
| 7 | `mestre` service: evdev → ALSA virtual MIDI bridge | ⚪ Planned |
|
||||
| 8 | End-to-end: X6200 controlling Hermes-Lite 2 as a control head | ⚪ Planned |
|
||||
| 9 | First-boot wizard, settings persistence, polished UX | ⚪ Planned |
|
||||
| ∞ | Earn the right to call it Virtuoso | ⚪ TBD |
|
||||
|
||||
## Architecture
|
||||
@@ -66,7 +69,7 @@ The architecture is deliberately patch-free: piHPSDR is used as-is, and the MIDI
|
||||
|
||||
## Building
|
||||
|
||||
> ⚠️ **Pre-1.0**: build instructions are aspirational while milestone 1 is in progress.
|
||||
> ⚠️ **Pre-1.0**: actively developed. Core build works; some milestones still in progress.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
|
||||
255
audio-architecture.md
Normal file
255
audio-architecture.md
Normal file
@@ -0,0 +1,255 @@
|
||||
# X6200 Audio Architecture
|
||||
|
||||
A detailed technical account of how audio works on the Xiegu X6200,
|
||||
reverse-engineered during Mestre development (May 2026).
|
||||
|
||||
## Overview
|
||||
|
||||
The X6200 has two distinct audio sources and one audio output path.
|
||||
Understanding the distinction between them is essential for any software
|
||||
that wants to produce sound on this radio.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ X6200 Hardware │
|
||||
│ │
|
||||
│ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ RF Front │ │ Allwinner│ │
|
||||
│ │ End │ │ R16 │ (SoC / Application CPU) │
|
||||
│ │ + FPGA │ │ │ │
|
||||
│ └────┬─────┘ └────┬─────┘ │
|
||||
│ │ RX audio │ DAC audio │
|
||||
│ │ (analog) │ (digital → analog via codec) │
|
||||
│ └──────┬────────┘ │
|
||||
│ │ │
|
||||
│ ┌────▼─────┐ │
|
||||
│ │ Audio │ ← voice_rec bit selects source │
|
||||
│ │ MUX │ (controlled via I2C to MCU) │
|
||||
│ └────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌────▼─────┐ │
|
||||
│ │ PA │ ← Power Amplifier │
|
||||
│ │ (Class D)│ enabled by rxvol_set > 0 │
|
||||
│ └────┬─────┘ │
|
||||
│ │ │
|
||||
│ ┌────▼─────┐ │
|
||||
│ │ Speaker │ │
|
||||
│ └──────────┘ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## The Two Audio Sources
|
||||
|
||||
### Source 1: RX-Radio Audio (default)
|
||||
|
||||
The RF front-end and FPGA process the received RF signal and produce
|
||||
an analog audio output — the classic "radio receiver sound". This is
|
||||
the default audio source at power-on. It is completely independent of
|
||||
the SoC and ALSA; it bypasses the codec entirely and is fed directly
|
||||
into the audio MUX.
|
||||
|
||||
This is why you hear receiver noise immediately when the X6200 boots,
|
||||
even before Linux has fully started.
|
||||
|
||||
### Source 2: SoC DAC Audio
|
||||
|
||||
The Allwinner R16 SoC contains an integrated audio codec
|
||||
(`sun8i-a33-audio`) which can produce digital audio, converted to
|
||||
analog via the DAC. This is the source used by software running on
|
||||
the SoC — piHPSDR, aplay, PulseAudio, etc.
|
||||
|
||||
This source goes through the standard Linux ALSA stack:
|
||||
|
||||
```
|
||||
Application (piHPSDR, aplay)
|
||||
→ PulseAudio (mixing, resampling)
|
||||
→ ALSA (hw:0,0 / pcmC0D0p)
|
||||
→ sun8i-a33-audio codec driver
|
||||
→ DAC (analog output)
|
||||
→ Audio MUX
|
||||
→ PA
|
||||
→ Speaker
|
||||
```
|
||||
|
||||
## The Audio MUX — The Critical Control Point
|
||||
|
||||
A hardware multiplexer inside the MCU/FPGA selects which source
|
||||
reaches the power amplifier and speaker. This MUX is controlled
|
||||
via I2C, **not** via ALSA or any Linux kernel interface.
|
||||
|
||||
### I2C Protocol
|
||||
|
||||
The X6200 MCU sits on I2C bus 0, address `0x72`. All hardware control
|
||||
uses the X6200Control library protocol: a 6-byte write transaction
|
||||
consisting of a 2-byte register address followed by a 4-byte value.
|
||||
|
||||
The audio MUX is controlled by the `voice_rec` bit in the
|
||||
`sple_atue_trx` register (command index 12, address `0x0030`):
|
||||
|
||||
| voice_rec bit | Audio source heard in speaker |
|
||||
|---------------|-------------------------------|
|
||||
| 0 (default) | RX-radio (RF receiver) |
|
||||
| 1 | SoC DAC (software audio) |
|
||||
|
||||
**To switch to SoC DAC audio:**
|
||||
```bash
|
||||
i2ctransfer -y 0 w6@0x72 0x00 0x30 0x08 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
**To switch back to RX-radio audio:**
|
||||
```bash
|
||||
i2ctransfer -y 0 w6@0x72 0x00 0x30 0x00 0x00 0x00 0x00
|
||||
```
|
||||
|
||||
## The Power Amplifier — The Other Critical Control Point
|
||||
|
||||
The speaker PA (power amplifier) is not always on. It is enabled
|
||||
as a side effect of setting the speaker volume via `x6200_control_rxvol_set()`.
|
||||
When `rxvol = 0` (the default after `x6200_control_init()`), the PA
|
||||
is effectively off and nothing is heard regardless of the MUX position
|
||||
or ALSA configuration.
|
||||
|
||||
This is why setting the correct mixer levels alone is not sufficient —
|
||||
the MCU must be told to activate the PA via the I2C control protocol.
|
||||
|
||||
## The ALSA Codec — Clock Dependency
|
||||
|
||||
The `sun8i-a33-audio` codec requires its master clock (`pll-audio`,
|
||||
22.5792 MHz) to be running for DAC output to work. The kernel's
|
||||
clock framework only enables this clock when a consumer holds an
|
||||
active reference — i.e., when an application has the PCM device open.
|
||||
|
||||
**This is the most subtle requirement:** if no process holds
|
||||
`/dev/snd/pcmC0D0p` open, the audio clocks are disabled and the
|
||||
codec produces no output, even if the ALSA mixer is correctly
|
||||
configured and voice_rec is set to DAC mode.
|
||||
|
||||
PulseAudio, running in system mode, holds the PCM device open
|
||||
continuously. This is what keeps the clocks running at all times
|
||||
and makes reliable audio possible.
|
||||
|
||||
```
|
||||
PulseAudio running → pcmC0D0p open → pll-audio enabled → codec active
|
||||
```
|
||||
|
||||
Without PulseAudio (or equivalent), every `aplay` invocation would
|
||||
need to wait for the codec to stabilise after the clock starts —
|
||||
and the X6200 MCU may reset the MUX during this window.
|
||||
|
||||
## The ALSA Mixer — Required Configuration
|
||||
|
||||
The codec's internal mixer must be configured correctly for audio
|
||||
to flow from the DAC to the analog output. The critical controls are:
|
||||
|
||||
| numid | Name | Required value |
|
||||
|-------|-----------------------------------|----------------|
|
||||
| 2 | AIF1 DA0 Playback Volume | 160, 160 |
|
||||
| 7 | Headphone Playback Volume | 58 |
|
||||
| 8 | Headphone Playback Switch | on, on |
|
||||
| 20 | AIF1 Data Digital ADC Cap. Switch | on, on |
|
||||
| 26 | AIF1 DA0 Stereo Playback Route | 3, 3 (Mix Mono)|
|
||||
| 28 | AIF1 Slot 0 Digital DAC PB Switch | on, on |
|
||||
| 31 | DAC Playback Switch | off, off |
|
||||
|
||||
Note that `DAC Playback Switch` (numid=31) must be **off** — this is
|
||||
counterintuitive but correct. The signal path goes through AIF1,
|
||||
not the direct DAC path.
|
||||
|
||||
These values are saved in `/var/lib/alsa/asound.state` and restored
|
||||
at boot via `alsactl restore` (init script `S50alsa`).
|
||||
|
||||
## Complete Initialisation Sequence
|
||||
|
||||
The following sequence must be performed in this exact order at boot:
|
||||
|
||||
### Step 1: ALSA mixer state (S50alsa)
|
||||
```bash
|
||||
alsactl restore
|
||||
```
|
||||
Restores the correct mixer levels from `/var/lib/alsa/asound.state`.
|
||||
|
||||
### Step 2: PulseAudio (S50pulseaudio)
|
||||
```bash
|
||||
pulseaudio --system --daemonize --disallow-exit --exit-idle-time=-1
|
||||
```
|
||||
Starts PulseAudio in system mode. This opens `pcmC0D0p` and keeps
|
||||
the ALSA clocks running continuously.
|
||||
|
||||
### Step 3: X6200 hardware init (S70mestre-audio)
|
||||
```python
|
||||
lib.x6200_control_init() # Establishes I2C state, sends all_cmd
|
||||
lib.x6200_control_spmode_set(False) # Speaker mode (not headphone)
|
||||
lib.x6200_control_rxvol_set(50) # Enables PA, sets volume (0-100)
|
||||
```
|
||||
`x6200_control_init()` sends a full command packet to the MCU via I2C,
|
||||
establishing all register values. **It sets rxvol=0** (PA off) as
|
||||
its default. `rxvol_set(50)` must follow immediately to enable the PA.
|
||||
|
||||
### Step 4: Switch audio MUX to SoC DAC (S70mestre-audio)
|
||||
```bash
|
||||
i2ctransfer -y 0 w6@0x72 0x00 0x30 0x08 0x00 0x00 0x00
|
||||
```
|
||||
Sets the `voice_rec` bit, switching the speaker from RX-radio audio
|
||||
to SoC DAC audio. From this point, any audio played via PulseAudio
|
||||
or directly to `hw:0,0` (44100 Hz, stereo, S16_LE) will be heard
|
||||
in the speaker.
|
||||
|
||||
## Mestre's Implementation
|
||||
|
||||
Mestre's init scripts implement this sequence:
|
||||
|
||||
```
|
||||
S50alsa → alsactl restore
|
||||
S50pulseaudio → pulseaudio --system
|
||||
S70mestre-audio → x6200_control_init + rxvol_set + voice_rec switch
|
||||
S96keepalive → I2C PMU keepalive (prevents automatic power-off)
|
||||
```
|
||||
|
||||
The audio MUX switch command (`voice_rec=on`) is permanent until the
|
||||
next `x6200_control_init()` call — it does not need to be repeated.
|
||||
However, the PMU keepalive (separate from audio) must run continuously
|
||||
or the radio will power off after approximately 180 seconds.
|
||||
|
||||
## Volume Control
|
||||
|
||||
Speaker volume is controlled via `x6200_control_rxvol_set(vol)` where
|
||||
`vol` is 0-100. This sends an I2C command to the MCU which adjusts
|
||||
an analog gain stage. **It is not reflected in the ALSA mixer** and
|
||||
cannot be read or set via `amixer`.
|
||||
|
||||
The ALSA mixer `Headphone Playback Volume` (numid=7) and
|
||||
`AIF1 DA0 Playback Volume` (numid=2) affect the digital gain
|
||||
in the codec but are set to fixed values at boot and not used
|
||||
for runtime volume control in Mestre.
|
||||
|
||||
## Known Quirks
|
||||
|
||||
**rxvol_set defaults to 0 after init.** Every call to
|
||||
`x6200_control_init()` resets the speaker volume to 0 (PA off).
|
||||
Always call `rxvol_set(N)` immediately after `init()`.
|
||||
|
||||
**voice_rec is reset by x6200_control_init().** If `init()` is called
|
||||
again (e.g., after a crash), the MUX reverts to RX-radio mode and
|
||||
the full init sequence must be repeated.
|
||||
|
||||
**PulseAudio must start before mestre-audio.** If PulseAudio is not
|
||||
running when the audio MUX is switched, the codec clocks may not be
|
||||
active and the switch may have no audible effect.
|
||||
|
||||
**44100 Hz stereo S16_LE** is the correct format for direct hardware
|
||||
playback (`hw:0,0`). PulseAudio handles resampling from other rates.
|
||||
|
||||
## References
|
||||
|
||||
- [gdyuldin/X6200Control](https://github.com/gdyuldin/X6200Control) —
|
||||
I2C control library source, including the `sple_atue_trx` register
|
||||
layout and `voice_rec` bit definition.
|
||||
- [gdyuldin/x6200_gui](https://github.com/gdyuldin/x6200_gui) —
|
||||
Reference implementation of the full audio init sequence
|
||||
(`audio_play_en()`, `audio_init()`, `radio_init()`).
|
||||
- [AetherRadio/X6100Control](https://github.com/AetherRadio/X6100Control) —
|
||||
X6100 control library (protocol-compatible with X6200), used to
|
||||
understand the register map before X6200Control source was available.
|
||||
- Allwinner R16 / sun8i-a33 audio driver: `sound/soc/sunxi/` in the
|
||||
Linux kernel tree. The codec is `sun8i-codec` with an AIF1 I2S
|
||||
interface to the SoC's audio PLL.
|
||||
@@ -1,5 +1,6 @@
|
||||
menu "Mestre"
|
||||
|
||||
source "$BR2_EXTERNAL_MESTRE_PATH/package/x6200-control/Config.in"
|
||||
source "$BR2_EXTERNAL_MESTRE_PATH/package/rtw88/Config.in"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -35,3 +35,8 @@ CONFIG_SND_DUMMY=m
|
||||
# Expose kernel config via /proc/config.gz (useful for debugging)
|
||||
CONFIG_IKCONFIG=y
|
||||
CONFIG_IKCONFIG_PROC=y
|
||||
|
||||
# HID via userspace (required for Bluetooth HID devices)
|
||||
CONFIG_UHID=y
|
||||
CONFIG_INPUT_UINPUT=y
|
||||
|
||||
|
||||
@@ -56,11 +56,13 @@ CONFIG_NET_IPIP=y
|
||||
# CONFIG_INET_DIAG is not set
|
||||
# CONFIG_IPV6 is not set
|
||||
CONFIG_CAN=y
|
||||
CONFIG_BT=m
|
||||
CONFIG_BT_RFCOMM=m
|
||||
CONFIG_BT_BNEP=m
|
||||
CONFIG_BT_HIDP=m
|
||||
CONFIG_BT_HCIBTUSB=m
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_RFCOMM=y
|
||||
CONFIG_BT_BNEP=y
|
||||
CONFIG_BT_HIDP=y
|
||||
CONFIG_BT_HCIBTUSB=y
|
||||
CONFIG_UHID=y
|
||||
CONFIG_HIDRAW=y
|
||||
CONFIG_CFG80211=m
|
||||
CONFIG_CFG80211_DEVELOPER_WARNINGS=y
|
||||
CONFIG_CFG80211_CERTIFICATION_ONUS=y
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Section "Device"
|
||||
Identifier "LCD"
|
||||
Driver "fbdev"
|
||||
Option "Rotate" "CCW"
|
||||
EndSection
|
||||
45
br2_external/board/x6200/rootfs-overlay/etc/init.d/S35wifi-bt
Executable file
45
br2_external/board/x6200/rootfs-overlay/etc/init.d/S35wifi-bt
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
# S45wifi-bt — aktiverar WiFi/BT-chipet (RTL8723D) via GPIO
|
||||
#
|
||||
# X6200:s WiFi/BT-chip är avstängt vid boot och måste aktiveras
|
||||
# via GPIO pin 357 (active low) innan kernel-drivern kan använda det.
|
||||
#
|
||||
# Måste köras innan S40bluetoothd startar.
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting WiFi/BT hardware"
|
||||
python3 - << 'PYEOF'
|
||||
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) # active low — 0 = ON
|
||||
PYEOF
|
||||
sleep 1
|
||||
modprobe btusb
|
||||
modprobe uhid
|
||||
modprobe hidp
|
||||
sleep 3
|
||||
echo "OK"
|
||||
;;
|
||||
stop)
|
||||
python3 - << 'PYEOF'
|
||||
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, 1) # 1 = OFF
|
||||
PYEOF
|
||||
echo "WiFi/BT hardware stopped"
|
||||
;;
|
||||
restart)
|
||||
$0 stop; sleep 1; $0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
44
br2_external/board/x6200/rootfs-overlay/etc/init.d/S46wifi
Executable file
44
br2_external/board/x6200/rootfs-overlay/etc/init.d/S46wifi
Executable file
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
# S46wifi — ansluter till WiFi via wpa_supplicant
|
||||
#
|
||||
# Körs efter S45wifi-bt (GPIO aktivering av chipet).
|
||||
# Använder /etc/wpa_supplicant.conf för nätverkslista.
|
||||
|
||||
IFACE="wlan0"
|
||||
PIDFILE="/var/run/wpa_supplicant.pid"
|
||||
LOG="/var/log/wifi.log"
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting WiFi"
|
||||
ip link set "$IFACE" up
|
||||
sleep 2
|
||||
|
||||
wpa_supplicant -B \
|
||||
-i "$IFACE" \
|
||||
-c /etc/wpa_supplicant.conf \
|
||||
-P "$PIDFILE" \
|
||||
>> "$LOG" 2>&1
|
||||
|
||||
# Hämta IP via DHCP
|
||||
sleep 3
|
||||
dhclient "$IFACE" >> "$LOG" 2>&1 || \
|
||||
udhcpc -i "$IFACE" -b -p /var/run/udhcpc.pid >> "$LOG" 2>&1
|
||||
|
||||
echo "OK"
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping WiFi"
|
||||
[ -f "$PIDFILE" ] && kill $(cat "$PIDFILE") 2>/dev/null
|
||||
rm -f "$PIDFILE"
|
||||
ip link set "$IFACE" down
|
||||
echo "OK"
|
||||
;;
|
||||
restart)
|
||||
$0 stop; sleep 1; $0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
58
br2_external/board/x6200/rootfs-overlay/etc/init.d/S85bt-keyboard
Executable file
58
br2_external/board/x6200/rootfs-overlay/etc/init.d/S85bt-keyboard
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
# S85bt-keyboard — auto-connect Linocell BTK16 BT-tangentbord
|
||||
#
|
||||
# Försöker ansluta tangentbordet vid boot och startar en bakgrundsprocess
|
||||
# som reconnectar automatiskt när tangentbordet kommer inom räckhåll.
|
||||
#
|
||||
# Tangentbordet måste vara parat och trustat sedan tidigare.
|
||||
# Para manuellt med: bluetoothctl pair ED:96:00:23:E2:02
|
||||
# bluetoothctl trust ED:96:00:23:E2:02
|
||||
|
||||
KEYBOARD_ADDR="ED:96:00:23:E2:02"
|
||||
PIDFILE="/var/run/bt-keyboard.pid"
|
||||
LOG="/var/log/bt-keyboard.log"
|
||||
|
||||
connect_keyboard() {
|
||||
bluetoothctl power on > /dev/null 2>&1
|
||||
bluetoothctl connect "$KEYBOARD_ADDR" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
watch_loop() {
|
||||
while true; do
|
||||
# Kolla om tangentbordet är anslutet
|
||||
if ! bluetoothctl info "$KEYBOARD_ADDR" 2>/dev/null | grep -q "Connected: yes"; then
|
||||
connect_keyboard
|
||||
fi
|
||||
sleep 10
|
||||
done
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo "Starting BT keyboard auto-connect"
|
||||
|
||||
# Försök första anslutning i bakgrunden (tangentbordet kanske inte är i närheten)
|
||||
(sleep 5 && connect_keyboard) &
|
||||
|
||||
# Starta watch-loop som reconnectar när tgb dyker upp
|
||||
watch_loop >> "$LOG" 2>&1 &
|
||||
echo $! > "$PIDFILE"
|
||||
echo "OK"
|
||||
;;
|
||||
stop)
|
||||
echo "Stopping BT keyboard auto-connect"
|
||||
if [ -f "$PIDFILE" ]; then
|
||||
kill $(cat "$PIDFILE") 2>/dev/null
|
||||
rm -f "$PIDFILE"
|
||||
fi
|
||||
bluetoothctl disconnect "$KEYBOARD_ADDR" > /dev/null 2>&1
|
||||
echo "OK"
|
||||
;;
|
||||
restart)
|
||||
$0 stop; sleep 1; $0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {start|stop|restart}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
116
br2_external/board/x6200/rootfs-overlay/etc/ssh/sshd_config
Normal file
116
br2_external/board/x6200/rootfs-overlay/etc/ssh/sshd_config
Normal file
@@ -0,0 +1,116 @@
|
||||
# $OpenBSD: sshd_config,v 1.104 2021/07/02 05:11:21 dtucker Exp $
|
||||
|
||||
# This is the sshd server system-wide configuration file. See
|
||||
# sshd_config(5) for more information.
|
||||
|
||||
# This sshd was compiled with PATH=/bin:/sbin:/usr/bin:/usr/sbin
|
||||
|
||||
# The strategy used for options in the default sshd_config shipped with
|
||||
# OpenSSH is to specify options with their default value where
|
||||
# possible, but leave them commented. Uncommented options override the
|
||||
# default value.
|
||||
|
||||
#Port 22
|
||||
#AddressFamily any
|
||||
#ListenAddress 0.0.0.0
|
||||
#ListenAddress ::
|
||||
|
||||
#HostKey /etc/ssh/ssh_host_rsa_key
|
||||
#HostKey /etc/ssh/ssh_host_ecdsa_key
|
||||
#HostKey /etc/ssh/ssh_host_ed25519_key
|
||||
|
||||
# Ciphers and keying
|
||||
#RekeyLimit default none
|
||||
|
||||
# Logging
|
||||
#SyslogFacility AUTH
|
||||
#LogLevel INFO
|
||||
|
||||
# Authentication:
|
||||
|
||||
#LoginGraceTime 2m
|
||||
PermitRootLogin yes
|
||||
#StrictModes yes
|
||||
#MaxAuthTries 6
|
||||
#MaxSessions 10
|
||||
|
||||
#PubkeyAuthentication yes
|
||||
|
||||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
|
||||
# but this is overridden so installations will only check .ssh/authorized_keys
|
||||
AuthorizedKeysFile .ssh/authorized_keys
|
||||
|
||||
#AuthorizedPrincipalsFile none
|
||||
|
||||
#AuthorizedKeysCommand none
|
||||
#AuthorizedKeysCommandUser nobody
|
||||
|
||||
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
|
||||
#HostbasedAuthentication no
|
||||
# Change to yes if you don't trust ~/.ssh/known_hosts for
|
||||
# HostbasedAuthentication
|
||||
#IgnoreUserKnownHosts no
|
||||
# Don't read the user's ~/.rhosts and ~/.shosts files
|
||||
#IgnoreRhosts yes
|
||||
|
||||
# To disable tunneled clear text passwords, change to no here!
|
||||
#PasswordAuthentication yes
|
||||
#PermitEmptyPasswords no
|
||||
|
||||
# Change to no to disable s/key passwords
|
||||
#KbdInteractiveAuthentication yes
|
||||
|
||||
# Kerberos options
|
||||
#KerberosAuthentication no
|
||||
#KerberosOrLocalPasswd yes
|
||||
#KerberosTicketCleanup yes
|
||||
#KerberosGetAFSToken no
|
||||
|
||||
# GSSAPI options
|
||||
#GSSAPIAuthentication no
|
||||
#GSSAPICleanupCredentials yes
|
||||
|
||||
# Set this to 'yes' to enable PAM authentication, account processing,
|
||||
# and session processing. If this is enabled, PAM authentication will
|
||||
# be allowed through the KbdInteractiveAuthentication and
|
||||
# PasswordAuthentication. Depending on your PAM configuration,
|
||||
# PAM authentication via KbdInteractiveAuthentication may bypass
|
||||
# the setting of "PermitRootLogin prohibit-password".
|
||||
# If you just want the PAM account and session checks to run without
|
||||
# PAM authentication, then enable this but set PasswordAuthentication
|
||||
# and KbdInteractiveAuthentication to 'no'.
|
||||
#UsePAM no
|
||||
|
||||
#AllowAgentForwarding yes
|
||||
#AllowTcpForwarding yes
|
||||
#GatewayPorts no
|
||||
#X11Forwarding no
|
||||
#X11DisplayOffset 10
|
||||
#X11UseLocalhost yes
|
||||
#PermitTTY yes
|
||||
#PrintMotd yes
|
||||
#PrintLastLog yes
|
||||
#TCPKeepAlive yes
|
||||
#PermitUserEnvironment no
|
||||
#Compression delayed
|
||||
#ClientAliveInterval 0
|
||||
#ClientAliveCountMax 3
|
||||
#UseDNS no
|
||||
#PidFile /var/run/sshd.pid
|
||||
#MaxStartups 10:30:100
|
||||
#PermitTunnel no
|
||||
#ChrootDirectory none
|
||||
#VersionAddendum none
|
||||
|
||||
# no default banner path
|
||||
#Banner none
|
||||
|
||||
# override default of no subsystems
|
||||
Subsystem sftp /usr/libexec/sftp-server
|
||||
|
||||
# Example of overriding settings on a per-user basis
|
||||
#Match User anoncvs
|
||||
# X11Forwarding no
|
||||
# AllowTcpForwarding no
|
||||
# PermitTTY no
|
||||
# ForceCommand cvs server
|
||||
@@ -0,0 +1,16 @@
|
||||
ctrl_interface=/var/run/wpa_supplicant
|
||||
update_config=1
|
||||
country=SE
|
||||
|
||||
# Lägg till dina nätverk här:
|
||||
network={
|
||||
ssid="Ditt_natverk_1"
|
||||
psk="ditt_losenord_1"
|
||||
priority=10
|
||||
}
|
||||
|
||||
network={
|
||||
ssid="Ditt_natverk_2"
|
||||
psk="ditt_losenord_2"
|
||||
priority=5
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBaWQsEKvTUbfTSKEa9sEuu7LpJm9Z07eSluIQV7+AxA joakim@cameron
|
||||
@@ -126,7 +126,17 @@ BR2_PACKAGE_STRACE=y
|
||||
# - Network Manager (using simple /etc/network/interfaces for now)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
BR2_GLOBAL_PATCH_DIR="../br2_external/board/x6200/patches"
|
||||
|
||||
# x6200
|
||||
BR2_PACKAGE_X6200_CONTROL=y
|
||||
|
||||
# MISC
|
||||
BR2_PACKAGE_PYTHON3=y
|
||||
BR2_PACKAGE_PYTHON3_CTYPES=y
|
||||
BR_PACKAGE_JOE=y
|
||||
|
||||
# Audio
|
||||
BR2_PACKAGE_ALSA_UTILS=y
|
||||
BR2_PACKAGE_ALSA_UTILS_APLAY=y
|
||||
BR2_PACKAGE_ALSA_UTILS_AMIXER=y
|
||||
@@ -135,12 +145,47 @@ BR2_PACKAGE_ALSA_LIB=y
|
||||
BR2_PACKAGE_ALSA_LIB_MIXER=y
|
||||
BR2_PACKAGE_ALSA_LIB_PCM=y
|
||||
BR2_PACKAGE_ALSA_LIB_RAWMIDI=y
|
||||
BR2_PACKAGE_X6200_CONTROL=y
|
||||
BR2_PACKAGE_PYTHON3=y
|
||||
BR2_PACKAGE_PYTHON3_CTYPES=y
|
||||
BR2_PACKAGE_PULSEAUDIO=y
|
||||
BR2_PACKAGE_PULSEAUDIO_DAEMON=y
|
||||
BR2_PACKAGE_PULSEAUDIO_MODULE_ALSA=y
|
||||
BR2_PACKAGE_PULSEAUDIO=y
|
||||
BR2_PACKAGE_PULSEAUDIO_DAEMON=y
|
||||
BR2_PACKAGE_PULSEAUDIO_MODULE_ALSA=y
|
||||
|
||||
# X11
|
||||
BR2_PACKAGE_XORG7=y
|
||||
BR2_PACKAGE_XSERVER_XORG_SERVER=y
|
||||
BR2_PACKAGE_XAPP_XINIT=y
|
||||
BR2_PACKAGE_XDRIVER_XF86_VIDEO_FBDEV=y
|
||||
BR2_PACKAGE_XDRIVER_XF86_INPUT_LIBINPUT=y
|
||||
BR2_PACKAGE_XKEYBOARD_CONFIG=y
|
||||
BR2_PACKAGE_LIBINPUT=y
|
||||
BR2_PACKAGE_XTERM=y
|
||||
|
||||
# GTK3
|
||||
BR2_PACKAGE_LIBGTK3=y
|
||||
BR2_PACKAGE_LIBGTK3_X11=y
|
||||
BR2_PACKAGE_LIBEPOXY=y
|
||||
|
||||
# BT TGB MOUSE & WIFI
|
||||
BR2_PACKAGE_LINUX_FIRMWARE=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE_RTL_87XX=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE_RTL_87XX_BT=y
|
||||
BR2_PACKAGE_BLUEZ5_UTILS=y
|
||||
BR2_PACKAGE_BLUEZ5_UTILS_CLIENT=y
|
||||
BR2_PACKAGE_BLUEZ5_UTILS_DEPRECATED=y
|
||||
BR2_PACKAGE_BLUEZ5_UTILS_TOOLS=y
|
||||
BR2_PACKAGE_BLUEZ5_UTILS_PLUGINS_HID=y
|
||||
BR2_PACKAGE_BLUEZ5_UTILS_TOOLS_HID2HCI=y
|
||||
BR2_PACKAGE_EUDEV=y
|
||||
BR2_PACKAGE_XKEYBOARD_CONFIG=y
|
||||
BR2_PACKAGE_XINPUT=y
|
||||
BR2_PACKAGE_XAPP_XRANDR=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE_RTL_RTW88=y
|
||||
BR2_PACKAGE_RTW88=y
|
||||
BR2_PACKAGE_LINUX_FIRMWARE_REGULATORY=y
|
||||
BR2_PACKAGE_WPA_SUPPLICANT=y
|
||||
BR2_PACKAGE_WPA_SUPPLICANT_PASSPHRASE=y
|
||||
BR2_PACKAGE_WPA_SUPPLICANT_CTRL_IFACE=y
|
||||
BR2_PACKAGE_DHCP=y
|
||||
BR2_PACKAGE_DHCP_CLIENT=y
|
||||
|
||||
8
br2_external/package/rtw88/Config.in
Normal file
8
br2_external/package/rtw88/Config.in
Normal file
@@ -0,0 +1,8 @@
|
||||
config BR2_PACKAGE_RTW88
|
||||
bool "rtw88 out-of-tree WiFi driver"
|
||||
depends on BR2_LINUX_KERNEL
|
||||
help
|
||||
Out-of-tree Realtek rtw88 driver from lwfinger/rtw88.
|
||||
Adds RTL8723DU USB WiFi support not available in kernel 6.1.
|
||||
|
||||
https://github.com/lwfinger/rtw88
|
||||
16
br2_external/package/rtw88/rtw88.mk
Normal file
16
br2_external/package/rtw88/rtw88.mk
Normal file
@@ -0,0 +1,16 @@
|
||||
################################################################################
|
||||
#
|
||||
# rtw88 — out-of-tree Realtek WiFi driver
|
||||
# Includes RTL8723DU USB support not yet in kernel 6.1 mainline.
|
||||
# Based on gdyuldin/AetherX6200Buildroot's recipe.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
RTW88_VERSION = 461b696b51317ba4ca585a4ddb32f2e72cd4efc9
|
||||
RTW88_SITE = https://github.com/lwfinger/rtw88
|
||||
RTW88_SITE_METHOD = git
|
||||
RTW88_LICENSE = GPL-2.0
|
||||
RTW88_INSTALL_STAGING = YES
|
||||
|
||||
$(eval $(kernel-module))
|
||||
$(eval $(generic-package))
|
||||
326
wifi-bt-architecture.md
Normal file
326
wifi-bt-architecture.md
Normal file
@@ -0,0 +1,326 @@
|
||||
# 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`:
|
||||
|
||||
```python
|
||||
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:
|
||||
```bash
|
||||
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`:
|
||||
|
||||
```bash
|
||||
/usr/libexec/bluetooth/bluetoothd --compat &
|
||||
```
|
||||
|
||||
And `/etc/bluetooth/input.conf` must have:
|
||||
```ini
|
||||
[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:
|
||||
|
||||
```sh
|
||||
{
|
||||
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`
|
||||
|
||||
```makefile
|
||||
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:
|
||||
|
||||
```bash
|
||||
./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`:
|
||||
|
||||
```ini
|
||||
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](https://github.com/lwfinger/rtw88) — out-of-tree
|
||||
RTW88 driver with USB support for RTL8723DU
|
||||
- [AetherRadio/X6200Control](https://github.com/gdyuldin/X6200Control) —
|
||||
GPIO control library; `x6200_pin_wifi` (pin 357) is defined in
|
||||
`include/aether_radio/x6200_control/low/gpio.h`
|
||||
- [gdyuldin/AetherX6200Buildroot](https://github.com/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
|
||||
Reference in New Issue
Block a user