From 4b31d0239296b6003751948e09d964e16855b533 Mon Sep 17 00:00:00 2001 From: Shen Mintao Date: Sat, 25 Jul 2026 15:29:46 +0800 Subject: [PATCH 1/6] docs: explain hardware branch selection --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index 3b5916b..0013efc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,21 @@ # AIC8800D80 Linux Driver This driver is for the AIC8800D80 chipset, supported by devices such as the Tenda U11 and AX913B. +> [!IMPORTANT] +> **Choose the branch for your hardware revision before installing.** If the +> driver log reports `chip_id=7, chip_mcu_id=1` on an AIC8800D80 or +> AIC8800DC/DW device, use the +> [`legacy-mcu1`](https://github.com/shenmintao/aic8800d80/tree/legacy-mcu1) +> branch. It contains the matched legacy firmware and loader profile required +> to avoid the deterministic firmware upload timeout at `0x170400`. Use +> `main` when `chip_mcu_id=0` or when the MCU revision is unknown. +> +> Hardware revision takes precedence over the Bluetooth feature branch. MCU1 +> devices should remain on `legacy-mcu1`, which initializes Bluetooth for the +> kernel's standard `btusb` driver. After switching branches, rerun +> `sudo ./install.sh` and reboot; switching the Git branch alone does not +> replace the firmware already installed under `/lib/firmware`. + Added support for devices with Vendor ID 368B (tested). Tested on Linux kernel 6.16 with Ubuntu 25.04 and 6.1.0.27 with Debian 12. From c83ae8b4e6db36362ebbfdac7b7b3ed15948f5cc Mon Sep 17 00:00:00 2001 From: Shen Mintao Date: Fri, 24 Jul 2026 12:04:57 +0800 Subject: [PATCH 2/6] test: unify Wi-Fi and Bluetooth installation --- INSTALL_SCRIPT.md | 8 +- README.md | 51 +++++++++++-- aic.rules | 4 + bazzite/README.md | 4 +- bazzite/aic8800d80.spec | 8 +- diagnose_bt.sh | 129 ++++++++++++++++++++++++++++++++ install.sh | 107 +++++++++++++++++++++----- tests/unified-wifi-bt/README.md | 72 ++++++++++++++++++ 8 files changed, 351 insertions(+), 32 deletions(-) create mode 100644 diagnose_bt.sh create mode 100644 tests/unified-wifi-bt/README.md diff --git a/INSTALL_SCRIPT.md b/INSTALL_SCRIPT.md index 9eda17c..90017c9 100644 --- a/INSTALL_SCRIPT.md +++ b/INSTALL_SCRIPT.md @@ -2,12 +2,16 @@ ## Overview -This automated installation script (`install.sh`) simplifies the process of installing the AIC8800D80 WiFi driver on Linux systems. +This automated installation script (`install.sh`) installs the AIC8800 Wi-Fi +driver and firmware loader on Linux systems. Wi-Fi/Bluetooth combo adapters use +the standard kernel `btusb` driver after firmware initialization. - Automatic Secure Boot detection - Automatic dependency installation - Automatic driver compilation and installation - Automatic module loading on boot +- Automatic cleanup of obsolete `aic_btusb` configuration +- Wi-Fi-only and Wi-Fi/Bluetooth combo adapter support from the same branch - Comprehensive error handling - Colored output and logging - Compatible with Ubuntu, Debian, Fedora, and derivatives (DKMS supported `dkms.conf`) @@ -37,4 +41,4 @@ This script is used to diagnose build issues with the AIC8800D80 driver. Useful ```bash # Make the script executable and run it chmod +x diagnostic_build.sh && sudo ./diagnostic_build.sh -``` \ No newline at end of file +``` diff --git a/README.md b/README.md index 0013efc..c12a507 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# AIC8800D80 Linux Driver +# AIC8800 Linux Wi-Fi and Bluetooth Driver This driver is for the AIC8800D80 chipset, supported by devices such as the Tenda U11 and AX913B. > [!IMPORTANT] @@ -20,7 +20,10 @@ Added support for devices with Vendor ID 368B (tested). Tested on Linux kernel 6.16 with Ubuntu 25.04 and 6.1.0.27 with Debian 12. -> **Bluetooth Support**: The [`bluetooth`](https://github.com/shenmintao/aic8800d80/tree/bluetooth) branch fully supports Bluetooth. This main branch only provides Wi-Fi functionality. Please switch to the `bluetooth` branch if you need Bluetooth support. +The same driver supports Wi-Fi-only adapters and Wi-Fi/Bluetooth combo +adapters. On combo devices, `aic_load_fw` uploads the AIC firmware and the +standard Linux `btusb` driver handles the Bluetooth HCI interface. The obsolete +custom `aic_btusb` module is not used. ### Disclaimer I did not develop this software, The code is sourced from the Tenda U11 driver. I only made some modifications to the code to adapt it to newer kernel versions. Apart from compilation issues, I am unable to address other problems. @@ -35,18 +38,18 @@ Before installing the driver, delete all aic8800-related folders under /lib/firm #### Method 2: Manual Installation #### Copy udev rules: -Copy the aic.rules file to /lib/udev/rules.d/: +Copy the aic.rules file to /usr/lib/udev/rules.d/: ```bash -sudo cp aic.rules /lib/udev/rules.d/ +sudo cp aic.rules /usr/lib/udev/rules.d/ ``` #### Copy firmware: -Copy the aic8800D80 folder from ./fw to /lib/firmware/: +Copy the firmware directories from `./fw` to `/lib/firmware/`: ```bash -sudo cp -r ./fw/aic8800D80 /lib/firmware/ +sudo cp -r ./fw/aic8800* /lib/firmware/ ``` #### Navigate to the driver directory: @@ -113,3 +116,39 @@ If the device is still not active, check the kernel logs for any errors related sudo dmesg ``` +### Bluetooth on Combo Adapters + +Bluetooth support does not require a separate AIC transport module. After +`aic_load_fw` initializes a combo adapter, the kernel automatically binds its +Bluetooth interface to `btusb`. A Wi-Fi-only adapter does not expose that +interface, so the Bluetooth path remains inactive. + +Verify the expected modules and controller with: + +```bash +lsmod | grep -E 'aic_load_fw|aic8800_fdrv|btusb' +lsusb -t +bluetoothctl list +``` + +To scan after a controller appears: + +```bash +bluetoothctl +power on +scan on +``` + +If Bluetooth is missing or reports HCI timeouts, run the read-only diagnostic +script and attach its output together with the current boot log: + +```bash +chmod +x diagnose_bt.sh +sudo ./diagnose_bt.sh +sudo journalctl -k -b --no-pager +``` + +The installer removes active references to the retired `aic_btusb` integration. +It does not force-load `btusb` or globally change the Bluetooth rfkill state; +normal kernel device matching and the user's system policy remain in control. + diff --git a/aic.rules b/aic.rules index ac85c00..31820c3 100644 --- a/aic.rules +++ b/aic.rules @@ -1,3 +1,4 @@ +# AIC8800 USB mass-storage mode switch rules KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5721", SYMLINK+="aicudisk", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5723", SYMLINK+="tendaudisk", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5724", SYMLINK+="ugreenax900", RUN+="/usr/bin/eject /dev/%k" @@ -7,3 +8,6 @@ KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5727", SYMLINK+="ten KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572a", SYMLINK+="tendaudiskv5", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572c", SYMLINK+="cudydiskv2", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572f", SYMLINK+="aicudisk572f", RUN+="/usr/bin/eject /dev/%k" + +# AIC8800D80 "Pandora" clone: switch 1111:1111 to its operational USB ID. +ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1111", ATTR{idProduct}=="1111", RUN+="/bin/sh -c 'if [ -x /usr/sbin/usb_modeswitch ]; then exec /usr/sbin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111; elif [ -x /usr/bin/usb_modeswitch ]; then exec /usr/bin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111; fi'" diff --git a/bazzite/README.md b/bazzite/README.md index 9b572b0..5d56e68 100644 --- a/bazzite/README.md +++ b/bazzite/README.md @@ -56,7 +56,9 @@ sudo rpm-ostree install "$rpm_path" sudo systemctl reboot ~~~ -After reboot, the Wi-Fi module and firmware loader will be available. +After reboot, the Wi-Fi module and firmware loader will be available. On combo +adapters, Bluetooth is handled by the standard `btusb` kernel module after +firmware initialization. This RPM is built for the kernel reported by `uname -r`. Rebuild and reinstall it after a Bazzite kernel upgrade. diff --git a/bazzite/aic8800d80.spec b/bazzite/aic8800d80.spec index 62c6ec1..31ed88a 100644 --- a/bazzite/aic8800d80.spec +++ b/bazzite/aic8800d80.spec @@ -5,7 +5,7 @@ Name: aic8800d80 Version: %{shortcommit} Release: 1%{?dist} -Summary: AIC8800D80 USB Wi-Fi driver +Summary: AIC8800 USB Wi-Fi and Bluetooth firmware driver License: GPL-2.0-only URL: https://github.com/shenmintao/aic8800d80 @@ -22,9 +22,9 @@ Requires(post): /usr/sbin/depmod Requires(postun): /usr/sbin/depmod %description -Out-of-tree AIC8800D80 USB Wi-Fi driver with udev mode-switch rules and all -firmware variants shipped by the upstream repository. This main-branch package -does not install a custom Bluetooth transport driver. +Out-of-tree AIC8800 USB driver with Wi-Fi support, Bluetooth firmware loading, +udev mode-switch rules, and all firmware variants shipped by the upstream +repository. Combo adapters use the standard Linux btusb transport driver. %prep %autosetup -n %{name}-%{commit} diff --git a/diagnose_bt.sh b/diagnose_bt.sh new file mode 100644 index 0000000..c7ff142 --- /dev/null +++ b/diagnose_bt.sh @@ -0,0 +1,129 @@ +#!/bin/bash +# Diagnose Bluetooth on AIC8800 Wi-Fi/Bluetooth combo adapters. +# +# aic_load_fw initializes the device and uploads the AIC firmware. The +# standard in-kernel btusb driver must then bind to the Bluetooth HCI USB +# interface. The removed aic_btusb module must not be installed or loaded. + +echo "=== AIC8800 Bluetooth diagnostics ===" +echo "" + +echo "1. AIC USB devices:" +if command -v lsusb >/dev/null 2>&1; then + lsusb | grep -iE 'a69c|368b|3625' || echo " No known AIC USB ID found" +else + echo " lsusb is not installed" +fi +echo "" + +echo "2. USB interfaces and bound drivers:" +bt_interface_found=false +btusb_bound=false +for dev in /sys/bus/usb/devices/*; do + [ -f "$dev/idVendor" ] || continue + [ -f "$dev/idProduct" ] || continue + + vid=$(cat "$dev/idVendor" 2>/dev/null) + pid=$(cat "$dev/idProduct" 2>/dev/null) + case "$vid" in + a69c|368b|3625) ;; + *) continue ;; + esac + + echo " Device: $vid:$pid" + for intf in "$dev"/*:*; do + [ -d "$intf" ] || continue + class=$(cat "$intf/bInterfaceClass" 2>/dev/null) + subclass=$(cat "$intf/bInterfaceSubClass" 2>/dev/null) + protocol=$(cat "$intf/bInterfaceProtocol" 2>/dev/null) + driver=$(basename "$(readlink "$intf/driver" 2>/dev/null)" 2>/dev/null) + echo " $(basename "$intf"): ${class:-??}/${subclass:-??}/${protocol:-??} -> ${driver:-unbound}" + + if [ "$driver" = "btusb" ]; then + btusb_bound=true + bt_interface_found=true + elif [ "$class" = "e0" ] && [ "$subclass" = "01" ] && [ "$protocol" = "01" ]; then + bt_interface_found=true + fi + done +done +echo "" + +echo "3. Relevant kernel modules (combo expectation: aic_load_fw + btusb):" +lsmod | grep -E '^(aic_load_fw|aic8800_fdrv|aic_btusb|btusb|bluetooth)[[:space:]]' || \ + echo " No related module is currently loaded" +echo "" + +echo "4. Bluetooth controllers:" +if command -v bluetoothctl >/dev/null 2>&1; then + bluetoothctl list 2>/dev/null || echo " No controller reported by bluetoothctl" +elif command -v hciconfig >/dev/null 2>&1; then + hciconfig -a 2>/dev/null || echo " No controller reported by hciconfig" +else + echo " BlueZ command-line tools are not installed" +fi +echo "" + +echo "5. Firmware, btusb, and HCI log messages:" +dmesg 2>/dev/null | grep -iE 'fw_patch|fw_adid|aicbt|bluetooth|btusb|hci' | tail -80 || true +echo "" + +echo "6. Bluetooth rfkill state:" +if command -v rfkill >/dev/null 2>&1; then + rfkill list bluetooth 2>/dev/null || echo " No Bluetooth rfkill entry" +else + echo " rfkill is not installed" +fi +echo "" + +echo "7. Obsolete aic_btusb installation/configuration:" +legacy_refs_found=false +mapfile -t legacy_modprobe_files < <( + grep -RIlE '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' \ + /etc/modprobe.d /run/modprobe.d /usr/local/lib/modprobe.d \ + /usr/lib/modprobe.d /lib/modprobe.d 2>/dev/null || true +) +mapfile -t legacy_udev_files < <( + grep -RIl 'aic_btusb/new_id' \ + /etc/udev/rules.d /run/udev/rules.d \ + /usr/lib/udev/rules.d /lib/udev/rules.d 2>/dev/null || true +) + +for legacy_file in "${legacy_modprobe_files[@]}"; do + echo " Obsolete modprobe directive: $legacy_file" + legacy_refs_found=true +done +for legacy_file in "${legacy_udev_files[@]}"; do + echo " Obsolete udev binding rule: $legacy_file" + legacy_refs_found=true +done +if lsmod | awk '{print $1}' | grep -qx 'aic_btusb'; then + echo " Obsolete aic_btusb module is loaded" + legacy_refs_found=true +fi +if modinfo -n aic_btusb >/dev/null 2>&1; then + echo " Obsolete module file: $(modinfo -n aic_btusb 2>/dev/null)" + legacy_refs_found=true +fi +if [ "$legacy_refs_found" = false ]; then + echo " No active aic_btusb module, directive, or binding rule found (expected)" +fi +echo "" + +echo "=== Assessment ===" +if ! lsmod | awk '{print $1}' | grep -qx 'aic_load_fw'; then + echo "- aic_load_fw is not loaded; run: sudo modprobe aic8800_fdrv" +fi +if [ "$bt_interface_found" = true ] && [ "$btusb_bound" = false ]; then + echo "- A Bluetooth USB interface exists but is not bound to btusb." + echo " Check for a btusb blacklist, then try: sudo modprobe btusb" +fi +if dmesg 2>/dev/null | grep -iE 'hci[0-9]+:.*(command|opcode|tx).*timed out|hci[0-9]+: link tx timeout' | tail -1 | grep -q .; then + echo "- HCI timeout detected. Confirm that aic_load_fw uploaded the firmware before btusb bound." + echo " Also check for obsolete aic_btusb configuration above." +fi +if [ "$bt_interface_found" = false ]; then + echo "- No Bluetooth HCI USB interface was found. This is normal for a Wi-Fi-only adapter." +fi + +echo "=== Diagnostics complete ===" diff --git a/install.sh b/install.sh index 4d82ae3..ce2a4f1 100755 --- a/install.sh +++ b/install.sh @@ -323,6 +323,46 @@ check_kernel_build_tree() { # Firmware Installation ############################################################################# +cleanup_legacy_bluetooth_config() { + local legacy_conf="/etc/modprobe.d/aic8800-bt.conf" + local legacy_udev="/etc/udev/rules.d/90-aic8800-mode-switch.rules" + local changed=false + + if [ -f "$legacy_conf" ] && grep -Eq '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' "$legacy_conf"; then + print_info "Removing obsolete aic_btusb directives from $legacy_conf..." + if [ ! -f "${legacy_conf}.aic8800-backup" ]; then + cp -a "$legacy_conf" "${legacy_conf}.aic8800-backup" >> "$LOG_FILE" 2>&1 + fi + sed -i -E '/^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)/d' "$legacy_conf" + if ! grep -Eq '^[[:space:]]*[^#[:space:]]' "$legacy_conf"; then + rm -f "$legacy_conf" + fi + changed=true + fi + + if [ -f "$legacy_udev" ] && grep -q 'aic_btusb/new_id' "$legacy_udev"; then + print_info "Removing obsolete aic_btusb binding rules from $legacy_udev..." + if [ ! -f "${legacy_udev}.aic8800-backup" ]; then + cp -a "$legacy_udev" "${legacy_udev}.aic8800-backup" >> "$LOG_FILE" 2>&1 + fi + sed -i '/aic_btusb\/new_id/d' "$legacy_udev" + changed=true + fi + + if lsmod | awk '{print $1}' | grep -qx 'aic_btusb'; then + print_info "Unloading obsolete aic_btusb module..." + if modprobe -r aic_btusb >> "$LOG_FILE" 2>&1; then + changed=true + else + print_warning "aic_btusb is still in use; reboot or replug the adapter after installation." + fi + fi + + if [ "$changed" = true ]; then + print_success "Legacy Bluetooth configuration cleaned up." + fi +} + install_firmware() { print_step "Installing firmware..." @@ -334,6 +374,8 @@ install_firmware() { exit 1 fi + cleanup_legacy_bluetooth_config + # Remove old firmware versions if [ -d "/lib/firmware" ] && [ -n "$(find /lib/firmware -maxdepth 1 -name 'aic8800*' -type d 2>/dev/null)" ]; then print_info "Removing existing firmware..." @@ -351,6 +393,8 @@ install_firmware() { fi done + print_success "Firmware installed for all supported chip variants." + # Install udev rules local rules_source="${SCRIPT_DIR}/aic.rules" local rules_dest="/usr/lib/udev/rules.d/aic.rules" @@ -526,22 +570,23 @@ refresh_initramfs() { ############################################################################# load_module() { - print_step "Loading kernel module..." + print_step "Loading kernel modules..." # Update module dependencies print_info "Updating module dependencies..." depmod -a >> "$LOG_FILE" 2>&1 - # Unload module if already loaded if lsmod | grep -q "$MODULE_NAME"; then - print_info "Module already loaded. Reloading..." + print_info "Wi-Fi module already loaded. Reloading..." modprobe -r "$MODULE_NAME" >> "$LOG_FILE" 2>&1 || true fi - # Load the module + # aic8800_fdrv depends on aic_load_fw, which initializes both Wi-Fi-only + # adapters and the Bluetooth firmware on combo adapters. If a standard HCI + # USB interface appears afterwards, the kernel USB modalias loads btusb. print_info "Loading $MODULE_NAME..." if modprobe "$MODULE_NAME" >> "$LOG_FILE" 2>&1; then - print_success "Module loaded successfully." + print_success "Wi-Fi module loaded successfully." # Verify module is loaded print_info "Waiting for module to initialize..." @@ -555,15 +600,17 @@ load_module() { done if [ "$module_loaded" = true ]; then - print_success "Module is active in kernel." + print_success "Wi-Fi module is active in kernel." else - print_warning "Module may not be fully initialized yet." + print_warning "Wi-Fi module may not be fully initialized yet." fi else - print_warning "Module installed but could not be loaded immediately." + print_warning "Wi-Fi module installed but could not be loaded immediately." print_info "This may be due to Secure Boot or missing hardware." print_info "Try rebooting or check: sudo dmesg | grep aic8800" fi + + print_info "Combo adapters use the standard btusb driver when their Bluetooth interface appears." } ############################################################################# @@ -583,14 +630,22 @@ verify_installation() { print_warning "DKMS status unclear: $dkms_status" fi - # Check if module is loaded + # Check if the Wi-Fi module is loaded if lsmod | grep -q "$MODULE_NAME"; then - print_success "Kernel module is loaded." - echo "" - lsmod | grep aic + print_success "Wi-Fi kernel module is loaded." else - print_info "Module not currently loaded (this is OK if no hardware is connected)." + print_info "Wi-Fi module not currently loaded (this is OK if no hardware is connected)." fi + + if lsmod | awk '{print $1}' | grep -qx 'btusb' || compgen -G '/sys/class/bluetooth/hci*' > /dev/null; then + print_success "A Bluetooth controller or the standard btusb module is present." + else + print_info "No Bluetooth controller is present (normal for Wi-Fi-only adapters or when no combo adapter is connected)." + fi + + echo "" + print_info "Loaded AIC modules:" + lsmod | grep aic || echo " (none)" # Check firmware local fw_count=0 @@ -610,6 +665,15 @@ verify_installation() { if command -v iwconfig &> /dev/null; then iwconfig 2>/dev/null | grep -E "wlan|IEEE" || echo "No wireless interfaces detected (hardware may not be connected)" fi + + print_info "Checking for Bluetooth interfaces on combo adapters..." + if command -v bluetoothctl &> /dev/null; then + bluetoothctl list 2>/dev/null || echo "No Bluetooth interfaces detected (normal for Wi-Fi-only adapters)" + elif command -v hciconfig &> /dev/null; then + hciconfig 2>/dev/null || echo "No Bluetooth interfaces detected (normal for Wi-Fi-only adapters)" + else + echo "Bluetooth tools not installed (install BlueZ to manage a combo adapter)" + fi } ############################################################################# @@ -624,13 +688,14 @@ show_final_instructions() { echo "" echo -e "${CYAN}Important Information:${NC}" echo "" - echo "✓ Driver installed via DKMS" + echo "✓ Wi-Fi driver and firmware loader installed via DKMS" + echo "✓ Combo adapters use the standard Linux btusb driver" echo "✓ Automatic rebuild enabled for kernel updates" echo "✓ Firmware installed in /lib/firmware/" echo "" echo -e "${CYAN}Next Steps:${NC}" echo "" - echo "1. Connect your AIC8800D80 USB WiFi adapter" + echo "1. Connect your AIC8800 USB Wi-Fi or Wi-Fi/Bluetooth adapter" echo "" echo "2. Check if the adapter is detected:" echo " ${BLUE}lsusb | grep -i aic${NC}" @@ -639,32 +704,36 @@ show_final_instructions() { echo "" echo "3. View kernel messages about the driver:" echo " ${BLUE}sudo dmesg | grep aic8800${NC}" + echo " ${BLUE}sudo dmesg | grep -iE 'bluetooth|btusb|hci'${NC}" echo "" echo "4. Connect to a WiFi network:" echo " ${BLUE}nmcli device wifi list${NC}" echo " ${BLUE}nmcli device wifi connect \"SSID\" password \"PASSWORD\"${NC}" echo "" + echo "5. For a combo adapter, check Bluetooth:" + echo " ${BLUE}bluetoothctl list${NC}" + echo " ${BLUE}bluetoothctl scan on${NC}" + echo "" echo -e "${CYAN}Troubleshooting:${NC}" echo "" echo "• Check DKMS status:" echo " ${BLUE}dkms status${NC}" echo "" echo "• Check loaded modules:" - echo " ${BLUE}lsmod | grep aic8800${NC}" + echo " ${BLUE}lsmod | grep -E 'aic|btusb'${NC}" echo "" - echo "• Manually load the module:" + echo "• Manually load the Wi-Fi module and firmware loader:" echo " ${BLUE}sudo modprobe aic8800_fdrv${NC}" echo "" echo "• View detailed logs:" echo " ${BLUE}cat $LOG_FILE${NC}" echo "" echo -e "${YELLOW}Known Limitations:${NC}" - echo "• Bluetooth functionality is not supported" echo "• Secure Boot may prevent module loading (disable in BIOS if needed)" echo "" echo -e "${CYAN}Uninstallation:${NC}" echo " ${BLUE}sudo dkms remove ${DRV_NAME}/${DRV_VERSION} --all${NC}" - echo " ${BLUE}sudo rm -rf /lib/firmware/aic8800D80${NC}" + echo " ${BLUE}sudo rm -rf /lib/firmware/aic8800*${NC}" echo "" } diff --git a/tests/unified-wifi-bt/README.md b/tests/unified-wifi-bt/README.md new file mode 100644 index 0000000..46bf4fd --- /dev/null +++ b/tests/unified-wifi-bt/README.md @@ -0,0 +1,72 @@ +# Unified Wi-Fi and Bluetooth branch test + +This branch tests replacing the separate `main` and `bluetooth` branches with +one driver and installer. The kernel driver, firmware, and DKMS configuration +were already identical on both branches. This test unifies their installer, +migration, diagnostics, packaging description, and documentation. + +The expected architecture is: + +- `aic_load_fw` initializes every supported adapter and uploads firmware. +- `aic8800_fdrv` handles Wi-Fi. +- A combo adapter exposes a Bluetooth HCI USB interface after initialization; + the standard Linux `btusb` driver binds through normal USB device matching. +- A Wi-Fi-only adapter exposes no HCI interface and does not need `btusb`. +- The retired custom `aic_btusb` module is never installed or used. + +The installer deliberately does not force-load `btusb` and does not globally +unblock Bluetooth through rfkill. + +## Install + +```bash +git fetch origin +git switch test/unified-wifi-bt +git pull --ff-only +sudo ./install.sh +sudo reboot +``` + +## Test a Wi-Fi-only adapter + +Confirm that: + +1. The Wi-Fi interface is created. +2. Scanning, association, DHCP, and real traffic work. +3. No `aic_btusb` module is loaded. +4. The absence of `btusb` or an HCI controller is treated as normal. + +## Test a Wi-Fi/Bluetooth combo adapter + +Confirm that: + +1. Wi-Fi scanning, association, DHCP, and real traffic work. +2. `aic_load_fw` uploads the firmware before the HCI interface is used. +3. The Bluetooth USB interface is bound to the standard `btusb` driver. +4. `bluetoothctl` can power on, scan, pair, and exchange real traffic. +5. No `aic_btusb` module, alias, soft dependency, or udev binding rule remains. + +## Collect results + +```bash +git rev-parse --short HEAD +lsusb +lsusb -t +lsmod | grep -E 'aic|btusb|bluetooth' +iw dev +bluetoothctl list +sudo ./diagnose_bt.sh | tee unified-wifi-bt-diagnostic.log +sudo journalctl -k -b --no-pager | tee unified-wifi-bt-kernel.log +``` + +Please attach both logs and identify whether the tested adapter is Wi-Fi-only +or a combo device. + +## Roll back during testing + +```bash +git switch main +git pull --ff-only +sudo ./install.sh +sudo reboot +``` From 268c4f7122cc82d2350f481dc58b8af86b5c7476 Mon Sep 17 00:00:00 2001 From: Shen Mintao Date: Fri, 24 Jul 2026 12:05:34 +0800 Subject: [PATCH 3/6] fix: refresh Bazzite package for unified branch --- bazzite/aic8800d80.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bazzite/aic8800d80.spec b/bazzite/aic8800d80.spec index 31ed88a..68ecc81 100644 --- a/bazzite/aic8800d80.spec +++ b/bazzite/aic8800d80.spec @@ -1,4 +1,4 @@ -%global commit d10bc52903f30a45e49777fd8254765403c9eb64 +%global commit 88dbc0a9531a2515934d11ae1c760ef1c2233d4c %global shortcommit %(echo %{commit} | cut -c1-7) %{!?kver:%global kver %(uname -r)} @@ -70,6 +70,10 @@ cp -a fw/aic8800* %{buildroot}/usr/lib/firmware/ /usr/lib/firmware/aic8800* %changelog +* Fri Jul 24 2026 Shen Mintao - 88dbc0a-1 +- Use the unified Wi-Fi and Bluetooth installer/package description. +- Keep Bluetooth transport on the standard Linux btusb driver. + * Tue Jul 14 2026 Shen Mintao - d10bc52-1 - Build the current main branch without the legacy custom Bluetooth module. - Package all firmware variants and current mode-switch rules. From 6550131e184f91f3218a005d7ddb7ed613ce818f Mon Sep 17 00:00:00 2001 From: Shen Mintao Date: Sat, 18 Jul 2026 18:15:01 +0800 Subject: [PATCH 4/6] test: add standalone btusb ZLP quirk module --- .gitattributes | 8 + tests/issue63-zlp-quirk/Makefile | 12 + tests/issue63-zlp-quirk/README.md | 115 +++++++++ tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh | 231 ++++++++++++++++++ tests/issue63-zlp-quirk/aic_zlp_quirk.c | 228 +++++++++++++++++ tests/issue63-zlp-quirk/dkms.conf | 10 + 6 files changed, 604 insertions(+) create mode 100644 .gitattributes create mode 100644 tests/issue63-zlp-quirk/Makefile create mode 100644 tests/issue63-zlp-quirk/README.md create mode 100755 tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh create mode 100644 tests/issue63-zlp-quirk/aic_zlp_quirk.c create mode 100644 tests/issue63-zlp-quirk/dkms.conf diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..4c3b043 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +/.gitattributes text eol=lf +tests/issue63-btusb-zlp/*.patch -whitespace +tests/issue63-btusb-zlp/*.sh text eol=lf +tests/issue63-zlp-quirk/*.c text eol=lf +tests/issue63-zlp-quirk/*.conf text eol=lf +tests/issue63-zlp-quirk/*.md text eol=lf +tests/issue63-zlp-quirk/*.sh text eol=lf +tests/issue63-zlp-quirk/Makefile text eol=lf diff --git a/tests/issue63-zlp-quirk/Makefile b/tests/issue63-zlp-quirk/Makefile new file mode 100644 index 0000000..26ad7b0 --- /dev/null +++ b/tests/issue63-zlp-quirk/Makefile @@ -0,0 +1,12 @@ +KVER ?= $(shell uname -r) +KDIR ?= /lib/modules/$(KVER)/build + +obj-m += aic_zlp_quirk.o + +.PHONY: all clean + +all: + $(MAKE) -C $(KDIR) M=$(CURDIR) modules + +clean: + $(MAKE) -C $(KDIR) M=$(CURDIR) clean diff --git a/tests/issue63-zlp-quirk/README.md b/tests/issue63-zlp-quirk/README.md new file mode 100644 index 0000000..444cc6a --- /dev/null +++ b/tests/issue63-zlp-quirk/README.md @@ -0,0 +1,115 @@ +# Issue #63: standard `btusb` ZLP companion-module test + +This experiment keeps the normal `aic_load_fw + system btusb` architecture. +It does not install or bind the vendor `aic_btusb` transport, and it does not +replace the distribution's `btusb.ko`. + +The underlying ZLP behavior was confirmed in +[issue #63](https://github.com/shenmintao/aic8800d80/issues/63): AAC playback +that previously stalled after about one minute remained stable for more than +one hour with the standard `btusb` ZLP patch, including after the obsolete +`aic_btusb` module was removed. + +The small `aic_zlp_quirk.ko` module first tries to attach a kretprobe to the +standard `btusb` function that allocates Bluetooth ACL bulk OUT URBs. The +target is module-qualified as `btusb:alloc_bulk_urb`, avoiding similarly named +symbols in unrelated USB drivers. + +Some distribution builds inline that private `btusb` function. When the +preferred hook is unavailable, the same module falls back to the stable +`usb_submit_urb` entry point. The fallback requires all of the following before +changing an URB: + +- USB device `368b:8d81`; +- bulk OUT transfer; +- endpoint declared by Bluetooth interface 0 (`e0/01/01`). + +Both paths add `URB_ZERO_PACKET` before the USB core submits the transfer. The +Wi-Fi interface and unrelated USB devices are left unchanged. + +The hook fails closed: if neither probe can be installed or kprobes are +disabled, the companion module refuses to load and the system `btusb` remains +unchanged. + +## Before installing + +First remove the earlier patched-`btusb` diagnostic build, if installed: + +```bash +cd ../issue63-btusb-zlp +sudo ./btusb-zlp-test.sh remove +``` + +An obsolete `aic_btusb` installation must also be unloaded and removed before +this test. Verify that the AIC Bluetooth interfaces use the system driver: + +```bash +lsusb -t +lsmod | grep -E '^(btusb|aic_btusb)\b' +``` + +## Install + +Install the normal build dependencies. For Fedora: + +```bash +sudo dnf install dkms gcc make kernel-devel-$(uname -r) +``` + +Then install and load the companion module: + +```bash +cd tests/issue63-zlp-quirk +sudo ./aic-zlp-quirk-test.sh install +./aic-zlp-quirk-test.sh status +``` + +Expected status includes: + +```text +quirk loaded: yes +active hook: btusb:alloc_bulk_urb +legacy aic_btusb: not loaded +AIC BT driver: btusb +``` + +`active hook: usb_submit_urb` is also valid when the distribution compiler +inlined the preferred private `btusb` function. + +Select AAC and play audio for at least one hour: + +```bash +bluetoothctl scan off +pactl set-card-profile bluez_card.28_6F_40_46_AB_B1 a2dp-sink-aac +``` + +While audio is playing, the `ZLP injections` counter should increase: + +```bash +./aic-zlp-quirk-test.sh status +sudo dmesg | grep -i aic_zlp_quirk +``` + +## Remove + +```bash +sudo ./aic-zlp-quirk-test.sh remove +./aic-zlp-quirk-test.sh status +``` + +Removal unloads only `aic_zlp_quirk.ko`. The distribution `btusb.ko` was never +overwritten and remains the Bluetooth transport throughout the test. + +## Kernel requirements + +- matching kernel headers; +- `CONFIG_KPROBES=y` and kretprobe support; +- standard `btusb` plus either its `alloc_bulk_urb` symbol or the USB core + `usb_submit_urb` symbol; +- a valid module signature when Secure Boot policy requires one. + +The `alloc_bulk_urb` function is present with the same signature in Linux +5.15, 6.1, 6.6, 6.12, 6.18, and 7.1.3, although compilers may inline it. The +fallback avoids depending on that implementation detail. DKMS compiles a +separate binary for each installed kernel while the repository maintains one +small source file. diff --git a/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh b/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh new file mode 100755 index 0000000..acd64ac --- /dev/null +++ b/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh @@ -0,0 +1,231 @@ +#!/usr/bin/env bash +set -euo pipefail + +PACKAGE_NAME="aic-zlp-quirk" +PACKAGE_VERSION="0.1" +MODULE_NAME="aic_zlp_quirk" +KERNEL_RELEASE="${KERNEL_RELEASE:-$(uname -r)}" +KERNEL_BUILD_DIR="/lib/modules/${KERNEL_RELEASE}/build" +SOURCE_DIR="/usr/src/${PACKAGE_NAME}-${PACKAGE_VERSION}" +MODULES_LOAD_FILE="/etc/modules-load.d/${PACKAGE_NAME}.conf" +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" + +log() { + printf '[aic-zlp-quirk-test] %s\n' "$*" +} + +die() { + printf '[aic-zlp-quirk-test] ERROR: %s\n' "$*" >&2 + exit 1 +} + +require_root() { + [ "$(id -u)" -eq 0 ] || die "run this command as root" +} + +require_command() { + command -v "$1" >/dev/null 2>&1 || die "required command not found: $1" +} + +stop_bluetooth() { + if command -v systemctl >/dev/null 2>&1; then + systemctl stop bluetooth.service 2>/dev/null || true + fi +} + +start_bluetooth() { + if command -v systemctl >/dev/null 2>&1; then + systemctl start bluetooth.service 2>/dev/null || true + fi +} + +module_loaded() { + [ -d "/sys/module/$1" ] +} + +legacy_btusb_loaded() { + module_loaded aic_btusb +} + +patched_btusb_installed() { + dkms status -m btusb-aic-zlp -v 0.1 2>/dev/null | grep -q . +} + +copy_sources() { + install -d "${SOURCE_DIR}" + install -m 0644 "${SCRIPT_DIR}/aic_zlp_quirk.c" "${SOURCE_DIR}/" + install -m 0644 "${SCRIPT_DIR}/Makefile" "${SOURCE_DIR}/" + install -m 0644 "${SCRIPT_DIR}/dkms.conf" "${SOURCE_DIR}/" +} + +rollback_install() { + log "rolling back the ZLP companion module" + rm -f -- "${MODULES_LOAD_FILE}" + modprobe -r "${MODULE_NAME}" >/dev/null 2>&1 || true + dkms remove -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" --all >/dev/null 2>&1 || true + rm -rf -- "${SOURCE_DIR}" + depmod -a "${KERNEL_RELEASE}" >/dev/null 2>&1 || true + start_bluetooth +} + +verify_standard_btusb() { + if legacy_btusb_loaded; then + die "obsolete aic_btusb is loaded; run 'sudo modprobe -r aic_btusb' and remove its old autoload configuration first" + fi + + if patched_btusb_installed; then + die "the patched btusb test package is still installed; remove it before testing the companion module" + fi + + modprobe btusb || die "could not load the system btusb module" +} + +install_module() { + require_root + require_command dkms + require_command make + require_command modprobe + require_command depmod + + [ -r "${KERNEL_BUILD_DIR}/Makefile" ] || \ + die "kernel build tree not found: ${KERNEL_BUILD_DIR}" + + if command -v lsusb >/dev/null 2>&1 && ! lsusb -d 368b:8d81 >/dev/null 2>&1; then + die "this test is restricted to USB device 368b:8d81, which is not connected" + fi + + verify_standard_btusb + + if module_loaded "${MODULE_NAME}"; then + log "unloading the earlier companion module" + if ! modprobe -r "${MODULE_NAME}"; then + die "could not unload the earlier ${MODULE_NAME} module" + fi + fi + + trap rollback_install ERR + + if dkms status -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" 2>/dev/null | grep -q .; then + log "removing an earlier companion-module build" + dkms remove -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" --all + fi + + rm -rf -- "${SOURCE_DIR}" + copy_sources + + log "building the ZLP companion module for ${KERNEL_RELEASE}" + dkms add -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" + dkms build -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" -k "${KERNEL_RELEASE}" + dkms install -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" \ + -k "${KERNEL_RELEASE}" --force + depmod -a "${KERNEL_RELEASE}" + + printf '%s\n' "${MODULE_NAME}" > "${MODULES_LOAD_FILE}" + + stop_bluetooth + if ! modprobe "${MODULE_NAME}"; then + trap - ERR + rollback_install + die "the companion module could not attach; the system btusb was left unchanged" + fi + start_bluetooth + trap - ERR + + log "loaded module: $(modinfo -n "${MODULE_NAME}")" + log "system btusb remains active; test AAC playback for at least one hour" +} + +remove_module() { + require_root + require_command dkms + require_command modprobe + require_command depmod + + stop_bluetooth + rm -f -- "${MODULES_LOAD_FILE}" + if module_loaded "${MODULE_NAME}" && ! modprobe -r "${MODULE_NAME}"; then + start_bluetooth + die "could not unload ${MODULE_NAME}; no files were removed" + fi + if dkms status -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" 2>/dev/null | grep -q .; then + if ! dkms remove -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" --all; then + start_bluetooth + die "DKMS removal failed; source files were left in place" + fi + fi + rm -rf -- "${SOURCE_DIR}" + depmod -a "${KERNEL_RELEASE}" + start_bluetooth + + log "removed the companion module; the distribution btusb was never replaced" +} + +show_aic_binding() { + local device + local driver + + for device in /sys/bus/usb/devices/*; do + [ -r "${device}/idVendor" ] || continue + [ -r "${device}/idProduct" ] || continue + [ "$(cat "${device}/idVendor")" = "368b" ] || continue + [ "$(cat "${device}/idProduct")" = "8d81" ] || continue + + driver="not bound" + if [ -L "${device}:1.0/driver" ]; then + driver="$(basename "$(readlink -f "${device}:1.0/driver")")" + fi + + printf 'AIC BT driver: %s\n' "${driver}" + return + done + + printf 'AIC BT driver: device not found\n' +} + +show_status() { + local loaded="no" + local injections="unavailable" + local hook="unavailable" + local dkms_status + + if module_loaded "${MODULE_NAME}"; then + loaded="yes" + if [ -r "/sys/module/${MODULE_NAME}/parameters/injections" ]; then + injections="$(cat "/sys/module/${MODULE_NAME}/parameters/injections")" + fi + if [ -r "/sys/module/${MODULE_NAME}/parameters/hook" ]; then + hook="$(cat "/sys/module/${MODULE_NAME}/parameters/hook")" + fi + fi + + dkms_status="$(dkms status -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" 2>/dev/null || true)" + if [ -z "${dkms_status}" ]; then + dkms_status="not installed" + fi + + printf 'kernel: %s\n' "${KERNEL_RELEASE}" + printf 'btusb module: %s\n' "$(modinfo -n btusb 2>/dev/null || printf 'not found')" + printf 'quirk module: %s\n' "$(modinfo -n "${MODULE_NAME}" 2>/dev/null || printf 'not found')" + printf 'quirk loaded: %s\n' "${loaded}" + printf 'active hook: %s\n' "${hook}" + printf 'ZLP injections:%s\n' " ${injections}" + printf 'legacy aic_btusb: %s\n' "$(legacy_btusb_loaded && printf 'loaded' || printf 'not loaded')" + printf 'dkms status: %s\n' "${dkms_status}" + show_aic_binding +} + +case "${1:-}" in + install) + install_module + ;; + remove) + remove_module + ;; + status) + show_status + ;; + *) + printf 'Usage: %s {install|remove|status}\n' "$0" >&2 + exit 2 + ;; +esac diff --git a/tests/issue63-zlp-quirk/aic_zlp_quirk.c b/tests/issue63-zlp-quirk/aic_zlp_quirk.c new file mode 100644 index 0000000..f3fc322 --- /dev/null +++ b/tests/issue63-zlp-quirk/aic_zlp_quirk.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#define AIC_USB_VENDOR_ID 0x368b +#define AIC_USB_PRODUCT_ID 0x8d81 +#define USB_BT_SUBCLASS 0x01 +#define USB_BT_PROTOCOL 0x01 + +static atomic64_t injection_count = ATOMIC64_INIT(0); +static const char *hook_name = "none"; + +static int injections_get(char *buffer, const struct kernel_param *kp) +{ + (void)kp; + + return scnprintf(buffer, PAGE_SIZE, "%lld\n", + (long long)atomic64_read(&injection_count)); +} + +static const struct kernel_param_ops injections_ops = { + .get = injections_get, +}; + +module_param_cb(injections, &injections_ops, NULL, 0444); +MODULE_PARM_DESC(injections, "Number of AIC ACL bulk OUT URBs modified"); + +static int hook_get(char *buffer, const struct kernel_param *kp) +{ + (void)kp; + + return scnprintf(buffer, PAGE_SIZE, "%s\n", hook_name); +} + +static const struct kernel_param_ops hook_ops = { + .get = hook_get, +}; + +module_param_cb(hook, &hook_ops, NULL, 0444); +MODULE_PARM_DESC(hook, "Active injection hook"); + +#if IS_ENABLED(CONFIG_KPROBES) + +enum aic_zlp_hook { + AIC_ZLP_HOOK_NONE, + AIC_ZLP_HOOK_BTUSB_RETURN, + AIC_ZLP_HOOK_USB_SUBMIT, +}; + +static enum aic_zlp_hook active_hook; + +static bool is_aic_bulk_out(const struct urb *urb) +{ + const struct usb_device *udev; + + if (!urb) + return false; + + udev = urb->dev; + if (!udev) + return false; + + if (le16_to_cpu(udev->descriptor.idVendor) != AIC_USB_VENDOR_ID || + le16_to_cpu(udev->descriptor.idProduct) != AIC_USB_PRODUCT_ID) + return false; + + return usb_pipetype(urb->pipe) == PIPE_BULK && + usb_pipeout(urb->pipe); +} + +static bool is_bluetooth_acl_endpoint(const struct urb *urb) +{ + const struct usb_endpoint_descriptor *ep; + struct usb_host_interface *alt; + struct usb_interface *intf; + unsigned int endpoint; + int i; + + if (!is_aic_bulk_out(urb)) + return false; + + intf = usb_ifnum_to_if(urb->dev, 0); + if (!intf) + return false; + + alt = READ_ONCE(intf->cur_altsetting); + if (!alt || + alt->desc.bInterfaceClass != USB_CLASS_WIRELESS_CONTROLLER || + alt->desc.bInterfaceSubClass != USB_BT_SUBCLASS || + alt->desc.bInterfaceProtocol != USB_BT_PROTOCOL) + return false; + + endpoint = usb_pipeendpoint(urb->pipe); + for (i = 0; i < alt->desc.bNumEndpoints; i++) { + ep = &alt->endpoint[i].desc; + if (usb_endpoint_is_bulk_out(ep) && + usb_endpoint_num(ep) == endpoint) + return true; + } + + return false; +} + +static void enable_zlp(struct urb *urb) +{ + long long count; + + if (urb->transfer_flags & URB_ZERO_PACKET) + return; + + urb->transfer_flags |= URB_ZERO_PACKET; + count = atomic64_inc_return(&injection_count); + + if (count == 1) + pr_info("enabled ZLP on the first 368b:8d81 ACL bulk OUT URB\n"); +} + +static int alloc_bulk_urb_ret_handler(struct kretprobe_instance *ri, + struct pt_regs *regs) +{ + struct urb *urb; + + (void)ri; + + urb = (struct urb *)regs_return_value(regs); + if (!is_aic_bulk_out(urb)) + return 0; + + enable_zlp(urb); + return 0; +} + +static struct kretprobe alloc_bulk_urb_probe = { + .kp.symbol_name = "btusb:alloc_bulk_urb", + .handler = alloc_bulk_urb_ret_handler, +}; + +static int usb_submit_urb_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct urb *urb; + + (void)p; + + urb = (struct urb *)regs_get_kernel_argument(regs, 0); + if (is_bluetooth_acl_endpoint(urb)) + enable_zlp(urb); + + return 0; +} + +static struct kprobe usb_submit_urb_probe = { + .symbol_name = "usb_submit_urb", + .pre_handler = usb_submit_urb_pre_handler, +}; + +static int __init aic_zlp_quirk_init(void) +{ + int ret; + + ret = register_kretprobe(&alloc_bulk_urb_probe); + if (!ret) { + active_hook = AIC_ZLP_HOOK_BTUSB_RETURN; + hook_name = "btusb:alloc_bulk_urb"; + pr_info("attached to system btusb for USB device 368b:8d81\n"); + return 0; + } + + pr_warn("btusb return hook unavailable (%d), trying USB submit fallback\n", + ret); + + ret = register_kprobe(&usb_submit_urb_probe); + if (ret) { + pr_err("cannot attach to usb_submit_urb: %d\n", ret); + return ret; + } + + active_hook = AIC_ZLP_HOOK_USB_SUBMIT; + hook_name = "usb_submit_urb"; + pr_info("attached USB submit fallback for device 368b:8d81 interface 0\n"); + return 0; +} + +static void __exit aic_zlp_quirk_exit(void) +{ + unsigned long missed = 0; + + if (active_hook == AIC_ZLP_HOOK_BTUSB_RETURN) { + unregister_kretprobe(&alloc_bulk_urb_probe); + missed = alloc_bulk_urb_probe.nmissed; + } else if (active_hook == AIC_ZLP_HOOK_USB_SUBMIT) { + unregister_kprobe(&usb_submit_urb_probe); + missed = usb_submit_urb_probe.nmissed; + } + + pr_info("detached %s after %lld injections (%lu missed hits)\n", + hook_name, (long long)atomic64_read(&injection_count), missed); +} + +#else + +static int __init aic_zlp_quirk_init(void) +{ + pr_err("CONFIG_KPROBES is disabled in this kernel\n"); + return -EOPNOTSUPP; +} + +static void __exit aic_zlp_quirk_exit(void) +{ +} + +#endif + +module_init(aic_zlp_quirk_init); +module_exit(aic_zlp_quirk_exit); + +MODULE_AUTHOR("Shen Mintao "); +MODULE_DESCRIPTION("AIC 8800D80 standard btusb ACL bulk TX ZLP quirk"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); +MODULE_SOFTDEP("pre: btusb"); diff --git a/tests/issue63-zlp-quirk/dkms.conf b/tests/issue63-zlp-quirk/dkms.conf new file mode 100644 index 0000000..1795467 --- /dev/null +++ b/tests/issue63-zlp-quirk/dkms.conf @@ -0,0 +1,10 @@ +PACKAGE_NAME="aic-zlp-quirk" +PACKAGE_VERSION="0.1" + +MAKE[0]="make KVER=${kernelver}" +CLEAN="make KVER=${kernelver} clean" + +BUILT_MODULE_NAME[0]="aic_zlp_quirk" +DEST_MODULE_LOCATION[0]="/updates/dkms" + +AUTOINSTALL="yes" From 13baa9b0b1692f94233bcf6e752060b408062026 Mon Sep 17 00:00:00 2001 From: Shen Mintao Date: Sat, 25 Jul 2026 15:49:53 +0800 Subject: [PATCH 5/6] feat: unify Bluetooth support and add ZLP quirk --- .gitattributes | 5 +- INSTALL_SCRIPT.md | 5 +- README.md | 26 ++- bazzite/README.md | 4 +- bazzite/aic8800d80.spec | 11 +- diagnose_bt.sh | 35 +++- dkms.conf | 5 + drivers/aic8800/Makefile | 7 + drivers/aic8800/aic_zlp_quirk/Makefile | 18 ++ .../aic8800/aic_zlp_quirk}/aic_zlp_quirk.c | 3 +- install.sh | 64 +++++++ tests/issue63-zlp-quirk/README.md | 156 +++++++++--------- tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh | 4 +- tests/unified-wifi-bt/README.md | 25 ++- 14 files changed, 267 insertions(+), 101 deletions(-) create mode 100644 drivers/aic8800/aic_zlp_quirk/Makefile rename {tests/issue63-zlp-quirk => drivers/aic8800/aic_zlp_quirk}/aic_zlp_quirk.c (98%) diff --git a/.gitattributes b/.gitattributes index 4c3b043..b6a4e28 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,6 @@ /.gitattributes text eol=lf -tests/issue63-btusb-zlp/*.patch -whitespace -tests/issue63-btusb-zlp/*.sh text eol=lf -tests/issue63-zlp-quirk/*.c text eol=lf +drivers/aic8800/aic_zlp_quirk/*.c text eol=lf +drivers/aic8800/aic_zlp_quirk/Makefile text eol=lf tests/issue63-zlp-quirk/*.conf text eol=lf tests/issue63-zlp-quirk/*.md text eol=lf tests/issue63-zlp-quirk/*.sh text eol=lf diff --git a/INSTALL_SCRIPT.md b/INSTALL_SCRIPT.md index 90017c9..8ed3c41 100644 --- a/INSTALL_SCRIPT.md +++ b/INSTALL_SCRIPT.md @@ -4,13 +4,16 @@ This automated installation script (`install.sh`) installs the AIC8800 Wi-Fi driver and firmware loader on Linux systems. Wi-Fi/Bluetooth combo adapters use -the standard kernel `btusb` driver after firmware initialization. +the standard kernel `btusb` driver after firmware initialization. For USB +device `368b:8d81`, it also installs a device-scoped ACL bulk TX ZLP companion +module without replacing the distribution's `btusb.ko`. - Automatic Secure Boot detection - Automatic dependency installation - Automatic driver compilation and installation - Automatic module loading on boot - Automatic cleanup of obsolete `aic_btusb` configuration +- Automatic `aic_zlp_quirk` handling for the validated `368b:8d81` device - Wi-Fi-only and Wi-Fi/Bluetooth combo adapter support from the same branch - Comprehensive error handling - Colored output and logging diff --git a/README.md b/README.md index c12a507..41beec4 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ This driver is for the AIC8800D80 chipset, supported by devices such as the Tend > to avoid the deterministic firmware upload timeout at `0x170400`. Use > `main` when `chip_mcu_id=0` or when the MCU revision is unknown. > -> Hardware revision takes precedence over the Bluetooth feature branch. MCU1 -> devices should remain on `legacy-mcu1`, which initializes Bluetooth for the +> Hardware revision determines the firmware branch. MCU1 devices should use +> `legacy-mcu1`, which also initializes Bluetooth for the > kernel's standard `btusb` driver. After switching branches, rerun > `sudo ./install.sh` and reboot; switching the Git branch alone does not > replace the firmware already installed under `/lib/firmware`. @@ -25,6 +25,13 @@ adapters. On combo devices, `aic_load_fw` uploads the AIC firmware and the standard Linux `btusb` driver handles the Bluetooth HCI interface. The obsolete custom `aic_btusb` module is not used. +USB device `368b:8d81` also uses the bundled `aic_zlp_quirk` companion module. +It adds the Bluetooth ACL bulk TX zero-length-packet behavior validated in +[issue #63](https://github.com/shenmintao/aic8800d80/issues/63), while leaving +the distribution's original `btusb.ko` installed and bound to the device. The +quirk is filtered to that VID:PID and fails closed when the required kernel +probe support is unavailable. + ### Disclaimer I did not develop this software, The code is sourced from the Tenda U11 driver. I only made some modifications to the code to adapt it to newer kernel versions. Apart from compilation issues, I am unable to address other problems. @@ -126,7 +133,7 @@ interface, so the Bluetooth path remains inactive. Verify the expected modules and controller with: ```bash -lsmod | grep -E 'aic_load_fw|aic8800_fdrv|btusb' +lsmod | grep -E 'aic_load_fw|aic8800_fdrv|aic_zlp_quirk|btusb' lsusb -t bluetoothctl list ``` @@ -152,3 +159,16 @@ The installer removes active references to the retired `aic_btusb` integration. It does not force-load `btusb` or globally change the Bluetooth rfkill state; normal kernel device matching and the user's system policy remain in control. +For `368b:8d81`, verify the ZLP hook and its injection counter while Bluetooth +traffic is active: + +```bash +cat /sys/module/aic_zlp_quirk/parameters/hook +cat /sys/module/aic_zlp_quirk/parameters/injections +``` + +The Wi-Fi-reset recovery behavior tracked in +[issue #53](https://github.com/shenmintao/aic8800d80/issues/53) remains a known +limitation: after an airplane-mode or hotspot reset, Bluetooth may require a +physical unplug/replug of the adapter. + diff --git a/bazzite/README.md b/bazzite/README.md index 5d56e68..6efd2b0 100644 --- a/bazzite/README.md +++ b/bazzite/README.md @@ -58,7 +58,9 @@ sudo systemctl reboot After reboot, the Wi-Fi module and firmware loader will be available. On combo adapters, Bluetooth is handled by the standard `btusb` kernel module after -firmware initialization. +firmware initialization. USB device `368b:8d81` also autoloads the packaged +`aic_zlp_quirk` companion module for its required Bluetooth ACL bulk TX zero +packet behavior; the distribution's `btusb` module is not replaced. This RPM is built for the kernel reported by `uname -r`. Rebuild and reinstall it after a Bazzite kernel upgrade. diff --git a/bazzite/aic8800d80.spec b/bazzite/aic8800d80.spec index 68ecc81..464d61a 100644 --- a/bazzite/aic8800d80.spec +++ b/bazzite/aic8800d80.spec @@ -5,7 +5,7 @@ Name: aic8800d80 Version: %{shortcommit} Release: 1%{?dist} -Summary: AIC8800 USB Wi-Fi and Bluetooth firmware driver +Summary: AIC8800 USB Wi-Fi, Bluetooth firmware, and ZLP quirk driver License: GPL-2.0-only URL: https://github.com/shenmintao/aic8800d80 @@ -24,7 +24,9 @@ Requires(postun): /usr/sbin/depmod %description Out-of-tree AIC8800 USB driver with Wi-Fi support, Bluetooth firmware loading, udev mode-switch rules, and all firmware variants shipped by the upstream -repository. Combo adapters use the standard Linux btusb transport driver. +repository. Combo adapters use the standard Linux btusb transport driver. A +device-scoped companion module supplies the required ACL bulk TX ZLP behavior +for USB device 368b:8d81 without replacing the distribution btusb module. %prep %autosetup -n %{name}-%{commit} @@ -44,6 +46,10 @@ install -Dpm0644 \ drivers/aic8800/aic_load_fw/aic_load_fw.ko \ %{buildroot}/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic_load_fw.ko +install -Dpm0644 \ + drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.ko \ + %{buildroot}/usr/lib/modules/%{kver}/kernel/drivers/bluetooth/aic8800/aic_zlp_quirk.ko + install -Dpm0644 \ aic.rules \ %{buildroot}/usr/lib/udev/rules.d/90-aic8800-mode-switch.rules @@ -65,6 +71,7 @@ cp -a fw/aic8800* %{buildroot}/usr/lib/firmware/ %dir /usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800 /usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic8800_fdrv.ko /usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic_load_fw.ko +/usr/lib/modules/%{kver}/kernel/drivers/bluetooth/aic8800/aic_zlp_quirk.ko /usr/lib/udev/rules.d/90-aic8800-mode-switch.rules %config(noreplace) /etc/usb_modeswitch.d/1111:1111 /usr/lib/firmware/aic8800* diff --git a/diagnose_bt.sh b/diagnose_bt.sh index c7ff142..ef0e200 100644 --- a/diagnose_bt.sh +++ b/diagnose_bt.sh @@ -19,6 +19,7 @@ echo "" echo "2. USB interfaces and bound drivers:" bt_interface_found=false btusb_bound=false +zlp_target_found=false for dev in /sys/bus/usb/devices/*; do [ -f "$dev/idVendor" ] || continue [ -f "$dev/idProduct" ] || continue @@ -31,6 +32,9 @@ for dev in /sys/bus/usb/devices/*; do esac echo " Device: $vid:$pid" + if [ "$vid" = "368b" ] && [ "$pid" = "8d81" ]; then + zlp_target_found=true + fi for intf in "$dev"/*:*; do [ -d "$intf" ] || continue class=$(cat "$intf/bInterfaceClass" 2>/dev/null) @@ -50,7 +54,7 @@ done echo "" echo "3. Relevant kernel modules (combo expectation: aic_load_fw + btusb):" -lsmod | grep -E '^(aic_load_fw|aic8800_fdrv|aic_btusb|btusb|bluetooth)[[:space:]]' || \ +lsmod | grep -E '^(aic_load_fw|aic8800_fdrv|aic_zlp_quirk|aic_btusb|btusb|bluetooth)[[:space:]]' || \ echo " No related module is currently loaded" echo "" @@ -64,8 +68,8 @@ else fi echo "" -echo "5. Firmware, btusb, and HCI log messages:" -dmesg 2>/dev/null | grep -iE 'fw_patch|fw_adid|aicbt|bluetooth|btusb|hci' | tail -80 || true +echo "5. Firmware, btusb, ZLP quirk, and HCI log messages:" +dmesg 2>/dev/null | grep -iE 'fw_patch|fw_adid|aicbt|aic_zlp_quirk|bluetooth|btusb|hci' | tail -80 || true echo "" echo "6. Bluetooth rfkill state:" @@ -110,6 +114,27 @@ if [ "$legacy_refs_found" = false ]; then fi echo "" +echo "8. Device-scoped Bluetooth ACL ZLP quirk:" +if [ "$zlp_target_found" = true ]; then + if [ -d /sys/module/aic_zlp_quirk ]; then + zlp_hook="unknown" + zlp_injections="unavailable" + [ -r /sys/module/aic_zlp_quirk/parameters/hook ] && \ + zlp_hook=$(cat /sys/module/aic_zlp_quirk/parameters/hook) + [ -r /sys/module/aic_zlp_quirk/parameters/injections ] && \ + zlp_injections=$(cat /sys/module/aic_zlp_quirk/parameters/injections) + echo " Target 368b:8d81 present" + echo " aic_zlp_quirk loaded: yes" + echo " active hook: $zlp_hook" + echo " ZLP injections: $zlp_injections" + else + echo " Target 368b:8d81 present, but aic_zlp_quirk is not loaded" + fi +else + echo " Target 368b:8d81 not present; quirk is not required" +fi +echo "" + echo "=== Assessment ===" if ! lsmod | awk '{print $1}' | grep -qx 'aic_load_fw'; then echo "- aic_load_fw is not loaded; run: sudo modprobe aic8800_fdrv" @@ -125,5 +150,9 @@ fi if [ "$bt_interface_found" = false ]; then echo "- No Bluetooth HCI USB interface was found. This is normal for a Wi-Fi-only adapter." fi +if [ "$zlp_target_found" = true ] && [ ! -d /sys/module/aic_zlp_quirk ]; then + echo "- Device 368b:8d81 requires the ACL ZLP quirk, but the module is not loaded." + echo " Try: sudo modprobe aic_zlp_quirk" +fi echo "=== Diagnostics complete ===" diff --git a/dkms.conf b/dkms.conf index ca060ed..4332d39 100644 --- a/dkms.conf +++ b/dkms.conf @@ -13,4 +13,9 @@ BUILT_MODULE_NAME[1]="aic_load_fw" BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw" DEST_MODULE_LOCATION[1]="/updates/dkms" +# Device-scoped standard-btusb ACL bulk TX ZLP quirk (368b:8d81 only) +BUILT_MODULE_NAME[2]="aic_zlp_quirk" +BUILT_MODULE_LOCATION[2]="drivers/aic8800/aic_zlp_quirk" +DEST_MODULE_LOCATION[2]="/updates/dkms" + AUTOINSTALL="yes" diff --git a/drivers/aic8800/Makefile b/drivers/aic8800/Makefile index 54e658f..ee68eee 100644 --- a/drivers/aic8800/Makefile +++ b/drivers/aic8800/Makefile @@ -1,8 +1,10 @@ CONFIG_AIC_LOADFW_SUPPORT := m CONFIG_AIC8800_WLAN_SUPPORT := m +CONFIG_AIC_ZLP_QUIRK := m obj-$(CONFIG_AIC_LOADFW_SUPPORT) += aic_load_fw/ obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/ +obj-$(CONFIG_AIC_ZLP_QUIRK) += aic_zlp_quirk/ ########## config option ########## export CONFIG_USE_FW_REQUEST = n @@ -51,6 +53,7 @@ KVER ?= $(shell uname -r) KDIR ?= /lib/modules/$(KVER)/build PWD = $(shell pwd) MODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800 +BTMODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/bluetooth/aic8800 SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/ -e s/loongarch64/loongarch/ -e s/loong64/loongarch/ -e s/riscv64/riscv/) ARCH ?= $(SUBARCH) CROSS_COMPILE ?= @@ -78,16 +81,20 @@ modules: install: mkdir -p $(MODDESTDIR) + mkdir -p $(BTMODDESTDIR) install -p -m 644 aic_load_fw/aic_load_fw.ko $(MODDESTDIR)/ install -p -m 644 aic8800_fdrv/aic8800_fdrv.ko $(MODDESTDIR)/ + install -p -m 644 aic_zlp_quirk/aic_zlp_quirk.ko $(BTMODDESTDIR)/ /sbin/depmod -a ${KVER} uninstall: rm -rfv $(MODDESTDIR)/aic_load_fw.ko rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko + rm -rfv $(BTMODDESTDIR)/aic_zlp_quirk.ko /sbin/depmod -a ${KVER} clean: cd aic_load_fw/;make clean;cd .. cd aic8800_fdrv/;make clean;cd .. + cd aic_zlp_quirk/;make clean;cd .. rm -rf modules.order Module.symvers .modules.order.cmd .Module.symvers.cmd .tmp_versions/ diff --git a/drivers/aic8800/aic_zlp_quirk/Makefile b/drivers/aic8800/aic_zlp_quirk/Makefile new file mode 100644 index 0000000..8595f58 --- /dev/null +++ b/drivers/aic8800/aic_zlp_quirk/Makefile @@ -0,0 +1,18 @@ +ifneq ($(KERNELRELEASE),) + +obj-m += aic_zlp_quirk.o + +else + +KVER ?= $(shell uname -r) +KDIR ?= /lib/modules/$(KVER)/build + +.PHONY: all clean + +all: + $(MAKE) -C $(KDIR) M=$(CURDIR) modules + +clean: + $(MAKE) -C $(KDIR) M=$(CURDIR) clean + +endif diff --git a/tests/issue63-zlp-quirk/aic_zlp_quirk.c b/drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.c similarity index 98% rename from tests/issue63-zlp-quirk/aic_zlp_quirk.c rename to drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.c index f3fc322..122bb68 100644 --- a/tests/issue63-zlp-quirk/aic_zlp_quirk.c +++ b/drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.c @@ -224,5 +224,6 @@ module_exit(aic_zlp_quirk_exit); MODULE_AUTHOR("Shen Mintao "); MODULE_DESCRIPTION("AIC 8800D80 standard btusb ACL bulk TX ZLP quirk"); MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); +MODULE_VERSION("1.0"); MODULE_SOFTDEP("pre: btusb"); +MODULE_ALIAS("usb:v368Bp8D81d*dc*dsc*dp*ic*isc*ip*in*"); diff --git a/install.sh b/install.sh index ce2a4f1..4ddad4c 100755 --- a/install.sh +++ b/install.sh @@ -326,6 +326,7 @@ check_kernel_build_tree() { cleanup_legacy_bluetooth_config() { local legacy_conf="/etc/modprobe.d/aic8800-bt.conf" local legacy_udev="/etc/udev/rules.d/90-aic8800-mode-switch.rules" + local legacy_package local changed=false if [ -f "$legacy_conf" ] && grep -Eq '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' "$legacy_conf"; then @@ -358,6 +359,21 @@ cleanup_legacy_bluetooth_config() { fi fi + # Remove the two issue #63 diagnostic DKMS packages before the production + # quirk is installed as part of aic8800/1.0.0. A patched btusb may remain + # active in memory until reboot, but DKMS restores the distribution module + # on disk when its test package is removed. + for legacy_package in "btusb-aic-zlp/0.1" "aic-zlp-quirk/0.1"; do + if dkms status 2>/dev/null | grep -q "^${legacy_package},"; then + print_info "Removing superseded test package ${legacy_package}..." + if dkms remove "$legacy_package" --all >> "$LOG_FILE" 2>&1; then + changed=true + else + print_warning "Could not remove ${legacy_package}; remove it manually before reboot." + fi + fi + done + if [ "$changed" = true ]; then print_success "Legacy Bluetooth configuration cleaned up." fi @@ -460,6 +476,11 @@ BUILT_MODULE_NAME[1]="aic_load_fw" BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw" DEST_MODULE_LOCATION[1]="/updates/dkms" +# Quirk ZLP para Bluetooth ACL bulk TX (somente 368b:8d81) +BUILT_MODULE_NAME[2]="aic_zlp_quirk" +BUILT_MODULE_LOCATION[2]="drivers/aic8800/aic_zlp_quirk" +DEST_MODULE_LOCATION[2]="/updates/dkms" + AUTOINSTALL="yes" EOF @@ -569,6 +590,20 @@ refresh_initramfs() { # Module Loading ############################################################################# +aic_zlp_target_present() { + local device + + for device in /sys/bus/usb/devices/*; do + [ -r "$device/idVendor" ] || continue + [ -r "$device/idProduct" ] || continue + [ "$(cat "$device/idVendor")" = "368b" ] || continue + [ "$(cat "$device/idProduct")" = "8d81" ] || continue + return 0 + done + + return 1 +} + load_module() { print_step "Loading kernel modules..." @@ -611,6 +646,19 @@ load_module() { fi print_info "Combo adapters use the standard btusb driver when their Bluetooth interface appears." + + # The module has a USB alias and normally autoloads when 368b:8d81 appears. + # Explicitly load it here as well when that device was already present before + # DKMS installation and therefore did not generate a new modalias event. + if aic_zlp_target_present; then + print_info "Loading the 368b:8d81 Bluetooth ACL ZLP quirk..." + if modprobe aic_zlp_quirk >> "$LOG_FILE" 2>&1; then + print_success "Device-scoped Bluetooth ZLP quirk is active." + else + print_warning "The ZLP quirk could not attach; system btusb remains unchanged." + print_info "Check CONFIG_KPROBES, Secure Boot, and: sudo dmesg | grep aic_zlp_quirk" + fi + fi } ############################################################################# @@ -643,6 +691,20 @@ verify_installation() { print_info "No Bluetooth controller is present (normal for Wi-Fi-only adapters or when no combo adapter is connected)." fi + if aic_zlp_target_present; then + if lsmod | awk '{print $1}' | grep -qx 'aic_zlp_quirk'; then + local zlp_hook="unknown" + if [ -r /sys/module/aic_zlp_quirk/parameters/hook ]; then + zlp_hook=$(cat /sys/module/aic_zlp_quirk/parameters/hook) + fi + print_success "Bluetooth ACL ZLP quirk is loaded (hook: $zlp_hook)." + else + print_warning "USB device 368b:8d81 is present but aic_zlp_quirk is not loaded." + fi + else + print_info "Bluetooth ZLP quirk is installed but inactive (no 368b:8d81 device present)." + fi + echo "" print_info "Loaded AIC modules:" lsmod | grep aic || echo " (none)" @@ -690,6 +752,7 @@ show_final_instructions() { echo "" echo "✓ Wi-Fi driver and firmware loader installed via DKMS" echo "✓ Combo adapters use the standard Linux btusb driver" + echo "✓ Device-scoped Bluetooth ACL ZLP quirk installed for 368b:8d81" echo "✓ Automatic rebuild enabled for kernel updates" echo "✓ Firmware installed in /lib/firmware/" echo "" @@ -721,6 +784,7 @@ show_final_instructions() { echo "" echo "• Check loaded modules:" echo " ${BLUE}lsmod | grep -E 'aic|btusb'${NC}" + echo " ${BLUE}cat /sys/module/aic_zlp_quirk/parameters/{hook,injections}${NC}" echo "" echo "• Manually load the Wi-Fi module and firmware loader:" echo " ${BLUE}sudo modprobe aic8800_fdrv${NC}" diff --git a/tests/issue63-zlp-quirk/README.md b/tests/issue63-zlp-quirk/README.md index 444cc6a..7d62b3c 100644 --- a/tests/issue63-zlp-quirk/README.md +++ b/tests/issue63-zlp-quirk/README.md @@ -1,104 +1,100 @@ -# Issue #63: standard `btusb` ZLP companion-module test +# Issue #63: standard `btusb` ACL ZLP support -This experiment keeps the normal `aic_load_fw + system btusb` architecture. -It does not install or bind the vendor `aic_btusb` transport, and it does not -replace the distribution's `btusb.ko`. +The `aic_zlp_quirk` companion module supplies the Bluetooth ACL bulk TX +zero-length-packet behavior confirmed in +[issue #63](https://github.com/shenmintao/aic8800d80/issues/63). It is now part +of the normal `aic8800` DKMS build rather than a replacement for the +distribution's Bluetooth driver. -The underlying ZLP behavior was confirmed in -[issue #63](https://github.com/shenmintao/aic8800d80/issues/63): AAC playback -that previously stalled after about one minute remained stable for more than -one hour with the standard `btusb` ZLP patch, including after the obsolete -`aic_btusb` module was removed. +The validated failure was specific and reproducible: AAC playback through USB +device `368b:8d81` stalled after about one minute, while SBC remained stable. +Adding `URB_ZERO_PACKET` to the ACL bulk OUT URBs kept AAC connected for more +than one hour. The standalone module was then verified with the system +`btusb`, no loaded `aic_btusb`, and 2,113 observed ZLP injections. -The small `aic_zlp_quirk.ko` module first tries to attach a kretprobe to the -standard `btusb` function that allocates Bluetooth ACL bulk OUT URBs. The -target is module-qualified as `btusb:alloc_bulk_urb`, avoiding similarly named -symbols in unrelated USB drivers. +## Architecture and scope -Some distribution builds inline that private `btusb` function. When the -preferred hook is unavailable, the same module falls back to the stable -`usb_submit_urb` entry point. The fallback requires all of the following before -changing an URB: +The module first tries to attach a kretprobe to the standard `btusb` function +that allocates ACL bulk OUT URBs. The target is module-qualified as +`btusb:alloc_bulk_urb`, avoiding similarly named symbols in unrelated USB +drivers. -- USB device `368b:8d81`; -- bulk OUT transfer; -- endpoint declared by Bluetooth interface 0 (`e0/01/01`). +Some distribution builds inline that private function. When the preferred hook +is unavailable, the module falls back to the stable `usb_submit_urb` entry +point. The fallback changes an URB only when all of these checks pass: -Both paths add `URB_ZERO_PACKET` before the USB core submits the transfer. The -Wi-Fi interface and unrelated USB devices are left unchanged. +- USB device is exactly `368b:8d81`; +- the transfer is bulk OUT; +- the endpoint belongs to Bluetooth interface 0 (`e0/01/01`). -The hook fails closed: if neither probe can be installed or kprobes are -disabled, the companion module refuses to load and the system `btusb` remains -unchanged. +Both paths add only `URB_ZERO_PACKET`. Wi-Fi interfaces and unrelated USB +devices are unchanged. If neither probe can be installed or kprobes are +disabled, the module refuses to load and system `btusb` remains unchanged. -## Before installing +The module carries a USB modalias for `368b:8d81`, so it is inactive on other +hardware and normally autoloads only when the validated device appears. -First remove the earlier patched-`btusb` diagnostic build, if installed: +## Install from the unified branch ```bash -cd ../issue63-btusb-zlp -sudo ./btusb-zlp-test.sh remove +git fetch origin +git switch test/unified-wifi-bt-zlp +git pull --ff-only +sudo ./install.sh +sudo reboot ``` -An obsolete `aic_btusb` installation must also be unloaded and removed before -this test. Verify that the AIC Bluetooth interfaces use the system driver: +The installer removes the earlier `btusb-aic-zlp/0.1` and +`aic-zlp-quirk/0.1` diagnostic DKMS packages when present. To remove them +manually before installation, use: + +```bash +sudo dkms remove btusb-aic-zlp/0.1 --all +sudo dkms remove aic-zlp-quirk/0.1 --all +sudo depmod -a +``` + +The unified installer also removes active configuration left by the obsolete +custom `aic_btusb` transport. + +## Verify + +Confirm that system `btusb` owns Bluetooth interfaces 0/1 and that the quirk is +loaded: ```bash lsusb -t -lsmod | grep -E '^(btusb|aic_btusb)\b' +lsmod | grep -E '^(btusb|aic_zlp_quirk|aic_btusb)\b' +modinfo -n btusb +modinfo -n aic_zlp_quirk +cat /sys/module/aic_zlp_quirk/parameters/hook +cat /sys/module/aic_zlp_quirk/parameters/injections +sudo ./diagnose_bt.sh ``` -## Install - -Install the normal build dependencies. For Fedora: - -```bash -sudo dnf install dkms gcc make kernel-devel-$(uname -r) -``` - -Then install and load the companion module: - -```bash -cd tests/issue63-zlp-quirk -sudo ./aic-zlp-quirk-test.sh install -./aic-zlp-quirk-test.sh status -``` - -Expected status includes: +Expected results include: ```text -quirk loaded: yes -active hook: btusb:alloc_bulk_urb -legacy aic_btusb: not loaded -AIC BT driver: btusb +Bluetooth interfaces 0/1: btusb +aic_btusb: not loaded +aic_zlp_quirk: loaded +active hook: btusb:alloc_bulk_urb ``` -`active hook: usb_submit_urb` is also valid when the distribution compiler -inlined the preferred private `btusb` function. +`active hook: usb_submit_urb` is also valid when the compiler inlined the +preferred function. During Bluetooth traffic, the `injections` value must +increase. -Select AAC and play audio for at least one hour: +For the promotion test, select AAC and play audio for at least one hour while +also confirming that Wi-Fi scan, association, DHCP, and real traffic remain +working. -```bash -bluetoothctl scan off -pactl set-card-profile bluez_card.28_6F_40_46_AB_B1 a2dp-sink-aac -``` +## Isolated retest helper -While audio is playing, the `ZLP injections` counter should increase: - -```bash -./aic-zlp-quirk-test.sh status -sudo dmesg | grep -i aic_zlp_quirk -``` - -## Remove - -```bash -sudo ./aic-zlp-quirk-test.sh remove -./aic-zlp-quirk-test.sh status -``` - -Removal unloads only `aic_zlp_quirk.ko`. The distribution `btusb.ko` was never -overwritten and remains the Bluetooth transport throughout the test. +`aic-zlp-quirk-test.sh` remains available only for isolated issue #63 retests. +It builds the same canonical source from +`drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.c` as a separate DKMS package. A +normal installation should use the repository-level `install.sh` instead. ## Kernel requirements @@ -108,8 +104,6 @@ overwritten and remains the Bluetooth transport throughout the test. `usb_submit_urb` symbol; - a valid module signature when Secure Boot policy requires one. -The `alloc_bulk_urb` function is present with the same signature in Linux -5.15, 6.1, 6.6, 6.12, 6.18, and 7.1.3, although compilers may inline it. The -fallback avoids depending on that implementation detail. DKMS compiles a -separate binary for each installed kernel while the repository maintains one -small source file. +The preferred function has the same signature in Linux 5.15, 6.1, 6.6, 6.12, +6.18, and 7.1.3, although compilers may inline it. DKMS builds one module for +each installed kernel from the single canonical source file. diff --git a/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh b/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh index acd64ac..1e69fa4 100755 --- a/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh +++ b/tests/issue63-zlp-quirk/aic-zlp-quirk-test.sh @@ -9,6 +9,8 @@ KERNEL_BUILD_DIR="/lib/modules/${KERNEL_RELEASE}/build" SOURCE_DIR="/usr/src/${PACKAGE_NAME}-${PACKAGE_VERSION}" MODULES_LOAD_FILE="/etc/modules-load.d/${PACKAGE_NAME}.conf" SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)" +QUIRK_SOURCE="${REPO_ROOT}/drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.c" log() { printf '[aic-zlp-quirk-test] %s\n' "$*" @@ -53,7 +55,7 @@ patched_btusb_installed() { copy_sources() { install -d "${SOURCE_DIR}" - install -m 0644 "${SCRIPT_DIR}/aic_zlp_quirk.c" "${SOURCE_DIR}/" + install -m 0644 "${QUIRK_SOURCE}" "${SOURCE_DIR}/" install -m 0644 "${SCRIPT_DIR}/Makefile" "${SOURCE_DIR}/" install -m 0644 "${SCRIPT_DIR}/dkms.conf" "${SOURCE_DIR}/" } diff --git a/tests/unified-wifi-bt/README.md b/tests/unified-wifi-bt/README.md index 46bf4fd..dc74a5b 100644 --- a/tests/unified-wifi-bt/README.md +++ b/tests/unified-wifi-bt/README.md @@ -1,9 +1,10 @@ -# Unified Wi-Fi and Bluetooth branch test +# Unified Wi-Fi, Bluetooth, and ZLP branch test This branch tests replacing the separate `main` and `bluetooth` branches with -one driver and installer. The kernel driver, firmware, and DKMS configuration -were already identical on both branches. This test unifies their installer, -migration, diagnostics, packaging description, and documentation. +one driver and installer. The Wi-Fi driver and firmware were already identical +on both branches. This test unifies their installer, migration, diagnostics, +packaging, and documentation, and adds the device-scoped ZLP fix from issue +#63 as a third DKMS module. The expected architecture is: @@ -13,6 +14,9 @@ The expected architecture is: the standard Linux `btusb` driver binds through normal USB device matching. - A Wi-Fi-only adapter exposes no HCI interface and does not need `btusb`. - The retired custom `aic_btusb` module is never installed or used. +- USB device `368b:8d81` autoloads `aic_zlp_quirk`, which adds + `URB_ZERO_PACKET` only to its Bluetooth ACL bulk OUT transfers. +- The distribution's original `btusb.ko` is never replaced. The installer deliberately does not force-load `btusb` and does not globally unblock Bluetooth through rfkill. @@ -21,7 +25,7 @@ unblock Bluetooth through rfkill. ```bash git fetch origin -git switch test/unified-wifi-bt +git switch test/unified-wifi-bt-zlp git pull --ff-only sudo ./install.sh sudo reboot @@ -46,6 +50,16 @@ Confirm that: 4. `bluetoothctl` can power on, scan, pair, and exchange real traffic. 5. No `aic_btusb` module, alias, soft dependency, or udev binding rule remains. +## Test the `368b:8d81` ZLP path + +In addition to the combo-adapter checks, confirm that: + +1. `aic_zlp_quirk` loads automatically and system `btusb` owns interfaces 0/1. +2. `hook` reports `btusb:alloc_bulk_urb` or `usb_submit_urb`. +3. The `injections` counter increases during Bluetooth audio traffic. +4. AAC playback remains connected for at least one hour. +5. Wi-Fi scan, association, and traffic remain unaffected during the test. + ## Collect results ```bash @@ -55,6 +69,7 @@ lsusb -t lsmod | grep -E 'aic|btusb|bluetooth' iw dev bluetoothctl list +cat /sys/module/aic_zlp_quirk/parameters/{hook,injections} 2>/dev/null || true sudo ./diagnose_bt.sh | tee unified-wifi-bt-diagnostic.log sudo journalctl -k -b --no-pager | tee unified-wifi-bt-kernel.log ``` From 800a7b93baad27bffef2c572e53c88b7a6ec06c5 Mon Sep 17 00:00:00 2001 From: Shen Mintao Date: Sat, 25 Jul 2026 15:52:29 +0800 Subject: [PATCH 6/6] fix: refresh Bazzite package for unified ZLP branch --- bazzite/aic8800d80.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bazzite/aic8800d80.spec b/bazzite/aic8800d80.spec index 464d61a..eb782e6 100644 --- a/bazzite/aic8800d80.spec +++ b/bazzite/aic8800d80.spec @@ -1,4 +1,4 @@ -%global commit 88dbc0a9531a2515934d11ae1c760ef1c2233d4c +%global commit 13baa9b0b1692f94233bcf6e752060b408062026 %global shortcommit %(echo %{commit} | cut -c1-7) %{!?kver:%global kver %(uname -r)} @@ -77,6 +77,11 @@ cp -a fw/aic8800* %{buildroot}/usr/lib/firmware/ /usr/lib/firmware/aic8800* %changelog +* Sat Jul 25 2026 Shen Mintao - 13baa9b-1 +- Unify Wi-Fi and standard-btusb Bluetooth support in one package. +- Add the device-scoped 368b:8d81 ACL bulk TX ZLP companion module. +- Clean up obsolete aic_btusb and issue #63 diagnostic installations. + * Fri Jul 24 2026 Shen Mintao - 88dbc0a-1 - Use the unified Wi-Fi and Bluetooth installer/package description. - Keep Bluetooth transport on the standard Linux btusb driver.