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 +```