mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-09-26 17:44:16 +00:00
test: unify legacy Wi-Fi Bluetooth and ZLP support
# Conflicts: # .gitattributes # README.md
This commit is contained in:
@@ -2,3 +2,10 @@ fw/aic8800D80/*.txt text eol=lf
|
|||||||
fw/aic8800D80/*.bin binary
|
fw/aic8800D80/*.bin binary
|
||||||
fw/aic8800DC/*.txt text eol=lf
|
fw/aic8800DC/*.txt text eol=lf
|
||||||
fw/aic8800DC/*.bin binary
|
fw/aic8800DC/*.bin binary
|
||||||
|
/.gitattributes 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
|
||||||
|
tests/issue63-zlp-quirk/Makefile text eol=lf
|
||||||
|
|||||||
+9
-2
@@ -2,12 +2,19 @@
|
|||||||
|
|
||||||
## Overview
|
## 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. 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 Secure Boot detection
|
||||||
- Automatic dependency installation
|
- Automatic dependency installation
|
||||||
- Automatic driver compilation and installation
|
- Automatic driver compilation and installation
|
||||||
- Automatic module loading on boot
|
- 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
|
- Comprehensive error handling
|
||||||
- Colored output and logging
|
- Colored output and logging
|
||||||
- Compatible with Ubuntu, Debian, Fedora, and derivatives (DKMS supported `dkms.conf`)
|
- Compatible with Ubuntu, Debian, Fedora, and derivatives (DKMS supported `dkms.conf`)
|
||||||
@@ -37,4 +44,4 @@ This script is used to diagnose build issues with the AIC8800D80 driver. Useful
|
|||||||
```bash
|
```bash
|
||||||
# Make the script executable and run it
|
# Make the script executable and run it
|
||||||
chmod +x diagnostic_build.sh && sudo ./diagnostic_build.sh
|
chmod +x diagnostic_build.sh && sudo ./diagnostic_build.sh
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# AIC8800 Linux Driver
|
# AIC8800 Linux Wi-Fi and Bluetooth Driver
|
||||||
This driver supports AIC8800-family chipsets used by devices such as the Tenda U11, AX913B, and TP-Link Archer TX1U Nano.
|
This driver supports AIC8800-family chipsets used by devices such as the Tenda U11, AX913B, and TP-Link Archer TX1U Nano.
|
||||||
|
|
||||||
> **Legacy MCU revision 1 branch:** You are viewing `legacy-mcu1`. This branch
|
> **Legacy MCU revision 1 branch:** You are viewing `legacy-mcu1`. This branch
|
||||||
@@ -12,14 +12,26 @@ This driver supports AIC8800-family chipsets used by devices such as the Tenda U
|
|||||||
> `chip_mcu_id=0` hardware or when the MCU revision is unknown. See the
|
> `chip_mcu_id=0` hardware or when the MCU revision is unknown. See the
|
||||||
> [D80](tests/issue58-mcu1-legacy-fw/README.md) and
|
> [D80](tests/issue58-mcu1-legacy-fw/README.md) and
|
||||||
> [DC/DW](tests/issue71-mcu1-v3-profile/README.md) support notes before installing.
|
> [DC/DW](tests/issue71-mcu1-v3-profile/README.md) support notes before installing.
|
||||||
|
>
|
||||||
|
> After switching branches, rerun `sudo ./install.sh` and reboot; switching the
|
||||||
|
> Git branch alone does not replace firmware already installed under
|
||||||
|
> `/lib/firmware`.
|
||||||
|
|
||||||
Added support for devices with Vendor ID 368B (tested).
|
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.
|
Tested on Linux kernel 6.16 with Ubuntu 25.04 and 6.1.0.27 with Debian 12.
|
||||||
|
|
||||||
> **Bluetooth support:** This branch initializes the integrated Bluetooth
|
The same driver supports Wi-Fi-only adapters and Wi-Fi/Bluetooth combo
|
||||||
> controller for the kernel's standard `btusb` driver. It does not contain or
|
adapters. On combo devices, `aic_load_fw` uploads the AIC firmware and the
|
||||||
> install `aic_btusb`.
|
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
|
### 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.
|
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.
|
||||||
@@ -34,18 +46,18 @@ Before installing the driver, delete all aic8800-related folders under /lib/firm
|
|||||||
#### Method 2: Manual Installation
|
#### Method 2: Manual Installation
|
||||||
|
|
||||||
#### Copy udev rules:
|
#### 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
|
```bash
|
||||||
sudo cp aic.rules /lib/udev/rules.d/
|
sudo cp aic.rules /usr/lib/udev/rules.d/
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Copy firmware:
|
#### Copy firmware:
|
||||||
|
|
||||||
Copy the aic8800D80 folder from ./fw to /lib/firmware/:
|
Copy the firmware directories from `./fw` to `/lib/firmware/`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cp -r ./fw/aic8800D80 /lib/firmware/
|
sudo cp -r ./fw/aic8800* /lib/firmware/
|
||||||
```
|
```
|
||||||
#### Navigate to the driver directory:
|
#### Navigate to the driver directory:
|
||||||
|
|
||||||
@@ -112,3 +124,52 @@ If the device is still not active, check the kernel logs for any errors related
|
|||||||
sudo dmesg
|
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|aic_zlp_quirk|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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -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}=="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}=="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"
|
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}=="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}=="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"
|
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'"
|
||||||
|
|||||||
+5
-1
@@ -56,7 +56,11 @@ sudo rpm-ostree install "$rpm_path"
|
|||||||
sudo systemctl reboot
|
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. 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
|
This RPM is built for the kernel reported by `uname -r`. Rebuild and reinstall
|
||||||
it after a Bazzite kernel upgrade.
|
it after a Bazzite kernel upgrade.
|
||||||
|
|||||||
+21
-5
@@ -1,11 +1,11 @@
|
|||||||
%global commit d10bc52903f30a45e49777fd8254765403c9eb64
|
%global commit 13baa9b0b1692f94233bcf6e752060b408062026
|
||||||
%global shortcommit %(echo %{commit} | cut -c1-7)
|
%global shortcommit %(echo %{commit} | cut -c1-7)
|
||||||
%{!?kver:%global kver %(uname -r)}
|
%{!?kver:%global kver %(uname -r)}
|
||||||
|
|
||||||
Name: aic8800d80
|
Name: aic8800d80
|
||||||
Version: %{shortcommit}
|
Version: %{shortcommit}
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: AIC8800D80 USB Wi-Fi driver
|
Summary: AIC8800 USB Wi-Fi, Bluetooth firmware, and ZLP quirk driver
|
||||||
|
|
||||||
License: GPL-2.0-only
|
License: GPL-2.0-only
|
||||||
URL: https://github.com/shenmintao/aic8800d80
|
URL: https://github.com/shenmintao/aic8800d80
|
||||||
@@ -22,9 +22,11 @@ Requires(post): /usr/sbin/depmod
|
|||||||
Requires(postun): /usr/sbin/depmod
|
Requires(postun): /usr/sbin/depmod
|
||||||
|
|
||||||
%description
|
%description
|
||||||
Out-of-tree AIC8800D80 USB Wi-Fi driver with udev mode-switch rules and all
|
Out-of-tree AIC8800 USB driver with Wi-Fi support, Bluetooth firmware loading,
|
||||||
firmware variants shipped by the upstream repository. This main-branch package
|
udev mode-switch rules, and all firmware variants shipped by the upstream
|
||||||
does not install a custom Bluetooth 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
|
%prep
|
||||||
%autosetup -n %{name}-%{commit}
|
%autosetup -n %{name}-%{commit}
|
||||||
@@ -44,6 +46,10 @@ install -Dpm0644 \
|
|||||||
drivers/aic8800/aic_load_fw/aic_load_fw.ko \
|
drivers/aic8800/aic_load_fw/aic_load_fw.ko \
|
||||||
%{buildroot}/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/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 \
|
install -Dpm0644 \
|
||||||
aic.rules \
|
aic.rules \
|
||||||
%{buildroot}/usr/lib/udev/rules.d/90-aic8800-mode-switch.rules
|
%{buildroot}/usr/lib/udev/rules.d/90-aic8800-mode-switch.rules
|
||||||
@@ -65,11 +71,21 @@ cp -a fw/aic8800* %{buildroot}/usr/lib/firmware/
|
|||||||
%dir /usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800
|
%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/aic8800_fdrv.ko
|
||||||
/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic_load_fw.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
|
/usr/lib/udev/rules.d/90-aic8800-mode-switch.rules
|
||||||
%config(noreplace) /etc/usb_modeswitch.d/1111:1111
|
%config(noreplace) /etc/usb_modeswitch.d/1111:1111
|
||||||
/usr/lib/firmware/aic8800*
|
/usr/lib/firmware/aic8800*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sat Jul 25 2026 Shen Mintao <shenmintao@gmail.com> - 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 <shenmintao@gmail.com> - 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 <shenmintao@gmail.com> - d10bc52-1
|
* Tue Jul 14 2026 Shen Mintao <shenmintao@gmail.com> - d10bc52-1
|
||||||
- Build the current main branch without the legacy custom Bluetooth module.
|
- Build the current main branch without the legacy custom Bluetooth module.
|
||||||
- Package all firmware variants and current mode-switch rules.
|
- Package all firmware variants and current mode-switch rules.
|
||||||
|
|||||||
+158
@@ -0,0 +1,158 @@
|
|||||||
|
#!/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
|
||||||
|
zlp_target_found=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"
|
||||||
|
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)
|
||||||
|
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_zlp_quirk|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, 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:"
|
||||||
|
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 "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"
|
||||||
|
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
|
||||||
|
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 ==="
|
||||||
@@ -13,4 +13,9 @@ BUILT_MODULE_NAME[1]="aic_load_fw"
|
|||||||
BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw"
|
BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw"
|
||||||
DEST_MODULE_LOCATION[1]="/updates/dkms"
|
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"
|
AUTOINSTALL="yes"
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
CONFIG_AIC_LOADFW_SUPPORT := m
|
CONFIG_AIC_LOADFW_SUPPORT := m
|
||||||
CONFIG_AIC8800_WLAN_SUPPORT := m
|
CONFIG_AIC8800_WLAN_SUPPORT := m
|
||||||
|
CONFIG_AIC_ZLP_QUIRK := m
|
||||||
|
|
||||||
obj-$(CONFIG_AIC_LOADFW_SUPPORT) += aic_load_fw/
|
obj-$(CONFIG_AIC_LOADFW_SUPPORT) += aic_load_fw/
|
||||||
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
|
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
|
||||||
|
obj-$(CONFIG_AIC_ZLP_QUIRK) += aic_zlp_quirk/
|
||||||
|
|
||||||
########## config option ##########
|
########## config option ##########
|
||||||
export CONFIG_USE_FW_REQUEST = n
|
export CONFIG_USE_FW_REQUEST = n
|
||||||
@@ -51,6 +53,7 @@ KVER ?= $(shell uname -r)
|
|||||||
KDIR ?= /lib/modules/$(KVER)/build
|
KDIR ?= /lib/modules/$(KVER)/build
|
||||||
PWD = $(shell pwd)
|
PWD = $(shell pwd)
|
||||||
MODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
|
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/)
|
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)
|
ARCH ?= $(SUBARCH)
|
||||||
CROSS_COMPILE ?=
|
CROSS_COMPILE ?=
|
||||||
@@ -78,16 +81,20 @@ modules:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
mkdir -p $(MODDESTDIR)
|
mkdir -p $(MODDESTDIR)
|
||||||
|
mkdir -p $(BTMODDESTDIR)
|
||||||
install -p -m 644 aic_load_fw/aic_load_fw.ko $(MODDESTDIR)/
|
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 aic8800_fdrv/aic8800_fdrv.ko $(MODDESTDIR)/
|
||||||
|
install -p -m 644 aic_zlp_quirk/aic_zlp_quirk.ko $(BTMODDESTDIR)/
|
||||||
/sbin/depmod -a ${KVER}
|
/sbin/depmod -a ${KVER}
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -rfv $(MODDESTDIR)/aic_load_fw.ko
|
rm -rfv $(MODDESTDIR)/aic_load_fw.ko
|
||||||
rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko
|
rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko
|
||||||
|
rm -rfv $(BTMODDESTDIR)/aic_zlp_quirk.ko
|
||||||
/sbin/depmod -a ${KVER}
|
/sbin/depmod -a ${KVER}
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
cd aic_load_fw/;make clean;cd ..
|
cd aic_load_fw/;make clean;cd ..
|
||||||
cd aic8800_fdrv/;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/
|
rm -rf modules.order Module.symvers .modules.order.cmd .Module.symvers.cmd .tmp_versions/
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,229 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||||
|
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kprobes.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
|
|
||||||
|
#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 <cx330.shen@autocore.ai>");
|
||||||
|
MODULE_DESCRIPTION("AIC 8800D80 standard btusb ACL bulk TX ZLP quirk");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_VERSION("1.0");
|
||||||
|
MODULE_SOFTDEP("pre: btusb");
|
||||||
|
MODULE_ALIAS("usb:v368Bp8D81d*dc*dsc*dp*ic*isc*ip*in*");
|
||||||
+152
-19
@@ -323,6 +323,62 @@ check_kernel_build_tree() {
|
|||||||
# Firmware Installation
|
# 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 legacy_package
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
}
|
||||||
|
|
||||||
install_firmware() {
|
install_firmware() {
|
||||||
print_step "Installing firmware..."
|
print_step "Installing firmware..."
|
||||||
|
|
||||||
@@ -334,6 +390,8 @@ install_firmware() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
cleanup_legacy_bluetooth_config
|
||||||
|
|
||||||
# Remove old firmware versions
|
# Remove old firmware versions
|
||||||
if [ -d "/lib/firmware" ] && [ -n "$(find /lib/firmware -maxdepth 1 -name 'aic8800*' -type d 2>/dev/null)" ]; then
|
if [ -d "/lib/firmware" ] && [ -n "$(find /lib/firmware -maxdepth 1 -name 'aic8800*' -type d 2>/dev/null)" ]; then
|
||||||
print_info "Removing existing firmware..."
|
print_info "Removing existing firmware..."
|
||||||
@@ -351,6 +409,8 @@ install_firmware() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
print_success "Firmware installed for all supported chip variants."
|
||||||
|
|
||||||
# Install udev rules
|
# Install udev rules
|
||||||
local rules_source="${SCRIPT_DIR}/aic.rules"
|
local rules_source="${SCRIPT_DIR}/aic.rules"
|
||||||
local rules_dest="/usr/lib/udev/rules.d/aic.rules"
|
local rules_dest="/usr/lib/udev/rules.d/aic.rules"
|
||||||
@@ -416,6 +476,11 @@ BUILT_MODULE_NAME[1]="aic_load_fw"
|
|||||||
BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw"
|
BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw"
|
||||||
DEST_MODULE_LOCATION[1]="/updates/dkms"
|
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"
|
AUTOINSTALL="yes"
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@@ -525,23 +590,38 @@ refresh_initramfs() {
|
|||||||
# Module Loading
|
# 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() {
|
load_module() {
|
||||||
print_step "Loading kernel module..."
|
print_step "Loading kernel modules..."
|
||||||
|
|
||||||
# Update module dependencies
|
# Update module dependencies
|
||||||
print_info "Updating module dependencies..."
|
print_info "Updating module dependencies..."
|
||||||
depmod -a >> "$LOG_FILE" 2>&1
|
depmod -a >> "$LOG_FILE" 2>&1
|
||||||
|
|
||||||
# Unload module if already loaded
|
|
||||||
if lsmod | grep -q "$MODULE_NAME"; then
|
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
|
modprobe -r "$MODULE_NAME" >> "$LOG_FILE" 2>&1 || true
|
||||||
fi
|
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..."
|
print_info "Loading $MODULE_NAME..."
|
||||||
if modprobe "$MODULE_NAME" >> "$LOG_FILE" 2>&1; then
|
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
|
# Verify module is loaded
|
||||||
print_info "Waiting for module to initialize..."
|
print_info "Waiting for module to initialize..."
|
||||||
@@ -555,15 +635,30 @@ load_module() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ "$module_loaded" = true ]; then
|
if [ "$module_loaded" = true ]; then
|
||||||
print_success "Module is active in kernel."
|
print_success "Wi-Fi module is active in kernel."
|
||||||
else
|
else
|
||||||
print_warning "Module may not be fully initialized yet."
|
print_warning "Wi-Fi module may not be fully initialized yet."
|
||||||
fi
|
fi
|
||||||
else
|
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 "This may be due to Secure Boot or missing hardware."
|
||||||
print_info "Try rebooting or check: sudo dmesg | grep aic8800"
|
print_info "Try rebooting or check: sudo dmesg | grep aic8800"
|
||||||
fi
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
@@ -583,14 +678,36 @@ verify_installation() {
|
|||||||
print_warning "DKMS status unclear: $dkms_status"
|
print_warning "DKMS status unclear: $dkms_status"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if module is loaded
|
# Check if the Wi-Fi module is loaded
|
||||||
if lsmod | grep -q "$MODULE_NAME"; then
|
if lsmod | grep -q "$MODULE_NAME"; then
|
||||||
print_success "Kernel module is loaded."
|
print_success "Wi-Fi kernel module is loaded."
|
||||||
echo ""
|
|
||||||
lsmod | grep aic
|
|
||||||
else
|
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
|
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
|
||||||
|
|
||||||
|
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)"
|
||||||
|
|
||||||
# Check firmware
|
# Check firmware
|
||||||
local fw_count=0
|
local fw_count=0
|
||||||
@@ -610,6 +727,15 @@ verify_installation() {
|
|||||||
if command -v iwconfig &> /dev/null; then
|
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)"
|
iwconfig 2>/dev/null | grep -E "wlan|IEEE" || echo "No wireless interfaces detected (hardware may not be connected)"
|
||||||
fi
|
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 +750,15 @@ show_final_instructions() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN}Important Information:${NC}"
|
echo -e "${CYAN}Important Information:${NC}"
|
||||||
echo ""
|
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 "✓ Device-scoped Bluetooth ACL ZLP quirk installed for 368b:8d81"
|
||||||
echo "✓ Automatic rebuild enabled for kernel updates"
|
echo "✓ Automatic rebuild enabled for kernel updates"
|
||||||
echo "✓ Firmware installed in /lib/firmware/"
|
echo "✓ Firmware installed in /lib/firmware/"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN}Next Steps:${NC}"
|
echo -e "${CYAN}Next Steps:${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "1. Connect your AIC8800D80 USB WiFi adapter"
|
echo "1. Connect your AIC8800 USB Wi-Fi or Wi-Fi/Bluetooth adapter"
|
||||||
echo ""
|
echo ""
|
||||||
echo "2. Check if the adapter is detected:"
|
echo "2. Check if the adapter is detected:"
|
||||||
echo " ${BLUE}lsusb | grep -i aic${NC}"
|
echo " ${BLUE}lsusb | grep -i aic${NC}"
|
||||||
@@ -639,32 +767,37 @@ show_final_instructions() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo "3. View kernel messages about the driver:"
|
echo "3. View kernel messages about the driver:"
|
||||||
echo " ${BLUE}sudo dmesg | grep aic8800${NC}"
|
echo " ${BLUE}sudo dmesg | grep aic8800${NC}"
|
||||||
|
echo " ${BLUE}sudo dmesg | grep -iE 'bluetooth|btusb|hci'${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "4. Connect to a WiFi network:"
|
echo "4. Connect to a WiFi network:"
|
||||||
echo " ${BLUE}nmcli device wifi list${NC}"
|
echo " ${BLUE}nmcli device wifi list${NC}"
|
||||||
echo " ${BLUE}nmcli device wifi connect \"SSID\" password \"PASSWORD\"${NC}"
|
echo " ${BLUE}nmcli device wifi connect \"SSID\" password \"PASSWORD\"${NC}"
|
||||||
echo ""
|
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 -e "${CYAN}Troubleshooting:${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• Check DKMS status:"
|
echo "• Check DKMS status:"
|
||||||
echo " ${BLUE}dkms status${NC}"
|
echo " ${BLUE}dkms status${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• Check loaded modules:"
|
echo "• Check loaded modules:"
|
||||||
echo " ${BLUE}lsmod | grep aic8800${NC}"
|
echo " ${BLUE}lsmod | grep -E 'aic|btusb'${NC}"
|
||||||
|
echo " ${BLUE}cat /sys/module/aic_zlp_quirk/parameters/{hook,injections}${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• Manually load the module:"
|
echo "• Manually load the Wi-Fi module and firmware loader:"
|
||||||
echo " ${BLUE}sudo modprobe aic8800_fdrv${NC}"
|
echo " ${BLUE}sudo modprobe aic8800_fdrv${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo "• View detailed logs:"
|
echo "• View detailed logs:"
|
||||||
echo " ${BLUE}cat $LOG_FILE${NC}"
|
echo " ${BLUE}cat $LOG_FILE${NC}"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${YELLOW}Known Limitations:${NC}"
|
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 "• Secure Boot may prevent module loading (disable in BIOS if needed)"
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${CYAN}Uninstallation:${NC}"
|
echo -e "${CYAN}Uninstallation:${NC}"
|
||||||
echo " ${BLUE}sudo dkms remove ${DRV_NAME}/${DRV_VERSION} --all${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 ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
# Issue #63: standard `btusb` ACL ZLP support
|
||||||
|
|
||||||
|
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 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.
|
||||||
|
|
||||||
|
## Architecture and scope
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
- USB device is exactly `368b:8d81`;
|
||||||
|
- the transfer is bulk OUT;
|
||||||
|
- the endpoint belongs to Bluetooth interface 0 (`e0/01/01`).
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Install from the unified branch
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git fetch origin
|
||||||
|
git switch test/unified-wifi-bt-zlp
|
||||||
|
git pull --ff-only
|
||||||
|
sudo ./install.sh
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
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_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
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected results include:
|
||||||
|
|
||||||
|
```text
|
||||||
|
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 compiler inlined the
|
||||||
|
preferred function. During Bluetooth traffic, the `injections` value must
|
||||||
|
increase.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## Isolated retest helper
|
||||||
|
|
||||||
|
`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
|
||||||
|
|
||||||
|
- 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 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.
|
||||||
+233
@@ -0,0 +1,233 @@
|
|||||||
|
#!/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)"
|
||||||
|
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' "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
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 "${QUIRK_SOURCE}" "${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
|
||||||
@@ -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"
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# Unified Wi-Fi, Bluetooth, and ZLP branch test
|
||||||
|
|
||||||
|
This branch tests replacing the separate `main` and `bluetooth` branches with
|
||||||
|
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:
|
||||||
|
|
||||||
|
- `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.
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git fetch origin
|
||||||
|
git switch test/unified-wifi-bt-zlp
|
||||||
|
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.
|
||||||
|
|
||||||
|
## 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
|
||||||
|
git rev-parse --short HEAD
|
||||||
|
lsusb
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user