Author SHA1 Message Date
Shen Mintao cbc12c7bdb test: add btusb ZLP quirk for issue 63 2026-07-17 21:00:18 +08:00
Shen Mintao 8006daf6c7 fix: refresh Bazzite package for bluetooth branch
Pin the package to the current code commit, ship both maintained modules and all firmware variants, remove obsolete Bluetooth configuration, and document kernel-specific rebuilds.
2026-07-14 17:39:29 +08:00
Shen Mintao 6b8cb98e96 fix: clean up legacy aic_btusb configuration
Sanitize obsolete modprobe and udev rules during upgrades, unload the removed module when possible, and expand Bluetooth diagnostics for stale configuration. Continues the cleanup for #44 and #53.
2026-07-14 17:30:03 +08:00
Shen Mintao 7dc7569312 fix: improve dependency installation diagnostics
Install mode-switch dependencies, support a69c:572f, avoid redundant generic headers when a usable kernel build tree exists, and discover DKMS logs dynamically. Addresses installer portions of #28, #55, #65, #66, and #68.
2026-07-14 17:23:53 +08:00
Shen Mintao 0ed5afba03 fix: retry DKMS install when existing modules block install 2026-06-25 19:55:34 +08:00
Shen Mintao df8a44bf88 fix: handle Volumio and early firmware loading 2026-06-25 19:48:08 +08:00
Shen Mintao 18d4be4228 fix: write radiotap HE fields without struct copy 2026-06-25 19:38:40 +08:00
Shen Mintao 0c9e2f1bca fix: avoid fortify warning in patch info unpack 2026-06-25 19:32:42 +08:00
Shen Mintao 35c077823c fix: support newer kernel cfg80211 APIs 2026-06-25 19:26:59 +08:00
Shen MintaoandClaude Opus 4.7 7d7d9547b8 clean up stale aic_btusb references on bluetooth branch (#53)
This branch already switched to standard btusb (commit 86aa95f), but
several pieces still pointed back at the removed aic_btusb module:

- drivers/aic8800/aic_btusb/ source tree (no longer in build)
- modprobe/aic8800-bt.conf installed to /etc/modprobe.d/, which
  softdep'd btusb to a nonexistent aic_btusb and aliased AIC BT
  interfaces to it. This caused btusb to load without firmware
  having been uploaded, producing HCI_Reset timeout -110 on hci0.
- install.sh still copied that conf into /etc/modprobe.d/
- diagnose_bt.sh still told users to modprobe aic_btusb

diagnose_bt.sh rewritten to flag the residual /etc/modprobe.d/aic8800-bt.conf
on already-installed systems and to advise the correct flow
(aic_load_fw uploads BT firmware, btusb takes over).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 15:00:10 +08:00
Nurmukhamed Artykaly f40bda47c3 fixed README.md after requests of telegram users. 2026-05-20 13:38:56 +08:00
Nurmukhamed Artykaly f1f825850b fixed error after trying build. 2026-05-20 13:38:56 +08:00
Nurmukhamed Artykaly 7779c8a285 fixed after comment on github. 2026-05-20 13:38:56 +08:00
Nurmukhamed Artykaly 6510278218 refactored, added bluetooth branch. 2026-05-20 13:38:56 +08:00
Nurmukhamed Artykaly bfe239c9af fixed github raw url. 2026-05-20 13:38:56 +08:00
Nurmukhamed Artykaly 43878adc39 small fix. 2026-05-20 13:38:56 +08:00
Nurmukhamed Artykaly 58dff473e8 added Bazzite SRPM instructions. 2026-05-20 13:38:56 +08:00
Vladislav Tatyanin 16b5d4af33 fix: map riscv64 to riscv for kernel ARCH 2026-05-20 13:38:43 +08:00
Shen MintaoandClaude Sonnet 4.5 d8a8048929 Add support for TP-Link/Mercury branded AIC8800D80 USB WiFi adapters
Added USB VID/PID for TP-Link vendor (0x2357) and Mercury product (0x014b)
to support WiFi adapters that re-enumerate with these IDs after firmware
loading. The device is recognized as AIC8800D81 chip with RX aggregation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-05-20 13:38:23 +08:00
toor11 13cccb953c Add USB ID 368b:8d84 (AIC 8800D80 variant)
Device 368b:8d84 is an AIC 8800D80 variant not included in the USB
device table. Add it as AIC8800M80_CUS0 alongside the other M80 CUS
variants; it maps to PRODUCT_ID_AIC8800D81 like its siblings.

Tested on kernel 6.19.8-arch1 with a physical dongle (Bus 001 Device
005: ID 368b:8d84 AICSemi AIC 8800D80).
2026-05-20 13:37:53 +08:00
Shen MintaoandClaude Opus 4.6 52e968e765 fix: add -b bluetooth to git clone command in INSTALL_SCRIPT.md
Closes #48

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 17:01:02 +08:00
Shen Mintao ebab65c042 更新aic_btusb Makefile 2026-03-24 10:47:23 +08:00
Shen Mintao 3e0c941337 更新Makefile配置 2026-03-24 10:40:21 +08:00
Shen Mintao 3aa0191c7e Merge branch 'bluetooth' of https://github.com/shenmintao/aic8800d80 into bluetooth
# Conflicts:
#	drivers/aic8800/Makefile
2026-03-23 22:21:02 +08:00
Shen Mintao 089be7c4ff Merge main into bluetooth: apply KDIR fix and remove aic_btusb
- Apply PR #34 KDIR fix to dkms.conf for correct kernel header usage
- Remove remaining aic_btusb references from Makefile (standard btusb is used)
2026-03-23 22:17:53 +08:00
Shen MintaoandClaude Sonnet 4.5 41b5208909 feat: auto-load btusb driver in install.sh
Add automatic loading of btusb (standard Linux Bluetooth driver) after
WiFi module installation. This enables Bluetooth functionality without
requiring manual intervention.

The aic_load_fw module uploads Bluetooth firmware including ext0 patches,
then btusb driver handles the actual Bluetooth interface.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-11 10:48:42 +08:00
Shen MintaoandClaude Sonnet 4.5 f2e73a92ab fix: add Linux 6.17+ compatibility for get_tx_power callback
Add radio_idx and changed parameters to rwnx_cfg80211_get_tx_power function
to match the updated cfg80211 API signature introduced in Linux 6.17+. This
fixes compilation errors on kernel 6.19 and later versions.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-11 10:33:27 +08:00
Shen MintaoandClaude Sonnet 4.5 6a2d56d055 fix: update install.sh to install all firmware variants
Changes:
- Install firmware for all chip variants (D80, D80N, D80X2, DC, DW, DLN)
- Automatically detect and copy all firmware directories from fw/
- Update verification to check all installed firmware
- Update uninstallation instructions to remove all firmware

This ensures support for all newly added devices:
- AIC8800D80N series
- AIC8800DLN series
- AIC8800D80X2 with extended firmware
- All other chip variants

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-11 10:14:10 +08:00
Shen MintaoandClaude Sonnet 4.5 165a346c4d feat: update to SDK v5.0 with comprehensive kernel and device support
Major updates:
- Add Linux kernel 6.12-6.19 compatibility support
- Add Linux 6.16 timer_container_of and wakelock API support
- Add Debian 6.1.0-26 backport support
- Fix Bluetooth firmware upload for chip_mcu_id == 1 (cache_mem_addr)
- Add USB device ID 368b:8d81 support
- Add AIC8800DW device support
- Add TP-Link Archer TX1U Nano support (USB_VENDOR_ID_TENDA_V2:0x0110)
- Add TENDA series device support (U2, U11, U11 PRO)
- Add AIC8800FC_CUS4/5/6 series support
- Add AIC8800M80_CUS7/8 series support
- Add UGREEN AIC8800D80 adapter support
- Fix CONFIG_USB_BT interface number check (allow 1 or 3 interfaces)
- Update firmware files for all chip variants

Device support:
- AIC8800D80/D81/DC/DW series
- AIC8800D80X2/D81X2/D89X2 series
- AIC8800D80N/D80LN/D80WN/DLN/DWN series
- TENDA U2/U11/U11 PRO/TX1U Nano adapters
- Multiple OEM variants (FC_CUS1-6, M80_CUS1-8)

Kernel compatibility:
- Linux 3.10 - 6.19+
- Debian 6.1.0-26 with backported APIs
- Ubuntu and other distributions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-11 10:10:30 +08:00
Shen Mintao b0787d9989 fix: fix usb_modeswitch message content 2026-03-04 21:55:41 +08:00
Shen Mintao 86aa95ffcb refactor: remove aic_btusb module, use standard btusb driver for Bluetooth 2026-03-04 18:12:08 +08:00
Shen Mintao cf63c8e0ee docs: update README with full Bluetooth support documentation 2026-03-04 16:48:49 +08:00
MinQ f2d9cc9ff0 Merge pull request #35 from bnister/bluetooth
Bluetooth firmware upload fix
2026-03-04 16:37:27 +08:00
bnister f36a0afeb4 Bluetooth fw upload fix: chip_mcu_id == 1 needs cache_mem_addr |= 1 2026-03-04 04:49:04 +03:00
Shen Mintao b771774f40 fix: pass KDIR to DKMS make command for proper kernel build path 2026-02-28 14:37:30 +08:00
Shen Mintao 600cdf5ef4 feat: add Kconfig for aic_btusb module 2026-02-28 14:34:52 +08:00
Shen Mintao 8a5af5cfdb fix: export CONFIG_AIC8800_BTUSB_SUPPORT for aic_btusb module compilation 2026-02-28 14:32:37 +08:00
Shen Mintao 85a412e5b8 feat: add aic_btusb bluetooth module support to install.sh 2026-02-28 14:27:02 +08:00
Shen Mintao 4f288d90b2 fix: fix 2026-02-28 09:11:25 +08:00
Shen Mintao 8b90bd8f45 feat: 添加蓝牙支持及固件更新 2026-02-27 18:19:39 +08:00
Shen Mintao 96e1d9cd3d feat: 增加对Linux 6.13+内核的MODULE_IMPORT_NS支持 2026-02-27 18:17:43 +08:00
43 changed files with 729 additions and 1680 deletions
+2 -7
View File
@@ -1,7 +1,2 @@
/.gitattributes text eol=lf tests/issue63-btusb-zlp/*.patch -whitespace
drivers/aic8800/aic_zlp_quirk/*.c text eol=lf tests/issue63-btusb-zlp/*.sh 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
+3 -10
View File
@@ -2,19 +2,12 @@
## Overview ## Overview
This automated installation script (`install.sh`) installs the AIC8800 Wi-Fi This automated installation script (`install.sh`) simplifies the process of installing the AIC8800D80 WiFi driver on Linux systems.
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`)
@@ -23,7 +16,7 @@ module without replacing the distribution's `btusb.ko`.
```bash ```bash
# Clone the repository and download the script, make the script executable # Clone the repository and download the script, make the script executable
git clone https://github.com/shenmintao/aic8800d80.git && cd aic8800d80 && chmod +x install.sh git clone -b bluetooth https://github.com/shenmintao/aic8800d80.git && cd aic8800d80 && chmod +x install.sh
# Run the installation # Run the installation
sudo ./install.sh sudo ./install.sh
@@ -44,4 +37,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
``` ```
-67
View File
@@ -1,67 +0,0 @@
# Building with OpenWrt backports
OpenWrt's target kernel and wireless stack can have different versions.
For example, [issue #94](https://github.com/shenmintao/aic8800d80/issues/94)
uses Linux **6.12.94** with **backports 6.18.26** on OpenWrt 25.12.5.
The Ubuntu build host's kernel version is not used to select these APIs.
## Package Makefile
Pass `CFG80211_VERSION=6.18.26` to the kernel make invocation for that
combination. Use the `PKG_VERSION` from your OpenWrt
`package/kernel/mac80211/Makefile`, in `major.minor.patch` format. Keep the
backports include paths and symbol versions from the same build:
```make
NOSTDINC_FLAGS := \
$(KERNEL_NOSTDINC_FLAGS) \
-I$(STAGING_DIR)/usr/include/mac80211-backport/uapi \
-I$(STAGING_DIR)/usr/include/mac80211-backport \
-I$(STAGING_DIR)/usr/include/mac80211/uapi \
-I$(STAGING_DIR)/usr/include/mac80211 \
-include backport/backport.h
define Build/Compile
+$(KERNEL_MAKE) $(PKG_JOBS) \
M="$(PKG_BUILD_DIR)/drivers/aic8800" \
KBUILD_EXTRA_SYMBOLS="$(LINUX_DIR)/../symvers/mac80211.symvers" \
NOSTDINC_FLAGS="$(NOSTDINC_FLAGS)" \
CFG80211_VERSION=6.18.26 \
modules
endef
```
The package must depend on `kmod-cfg80211` so its headers and symbol versions
are staged before this driver is built. Keep any additional dependencies,
firmware installation rules and module packaging rules your device needs.
Update the package's pinned source revision to one containing this fix, or
apply the fix as an OpenWrt package patch, then clean and rebuild the package:
```sh
make package/kernel/aic8800d80/clean
make package/kernel/aic8800d80/compile V=sc -j1
```
Changing `CFG80211_VERSION` alone does not update the driver source or the
wireless headers. The value must match the actual wireless stack; do not set
it to the host kernel version or redefine `LINUX_VERSION_CODE`.
## Compatibility scope
The override selects the wireless API changes since Linux 6.12, including
monitor-channel callbacks, radio/link arguments, radar notifications and
newer cfg80211 callbacks. Timer, USB, memory-management and module namespace
checks continue to use the target kernel version. Older target kernels with
newer backports may need additional wireless API adaptations.
Leave `CFG80211_VERSION` unset when building against the kernel's own wireless
stack, as on a regular Ubuntu/Debian installation. The driver then uses the
kernel version as before. Hardware revision still determines whether to use
`main` or `legacy-mcu1`; a wireless API mismatch does not change that choice.
The feeds/Kconfig duplicate definitions and recursive dependencies also
reported in issue #94 belong to the OpenWrt build configuration and require
separate investigation.
See the [build regression recipe](tests/openwrt-backports/README.md) for
the tested kernel/backports combinations and a script to repeat the build.
+37 -89
View File
@@ -1,43 +1,11 @@
# AIC8800 Linux Wi-Fi and Bluetooth Driver # AIC8800D80 Linux Driver
This driver is for the AIC8800D80 chipset, supported by devices such as the Tenda U11 and AX913B. 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 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`.
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.
> [!NOTE] This branch (`bluetooth`) fully supports both **Wi-Fi** and **Bluetooth**.
> **Maintained branches:** This repository now maintains two hardware branches:
> `main` for `chip_mcu_id=0` or an unknown MCU revision, and `legacy-mcu1` for
> `chip_mcu_id=1`. Wi-Fi, the kernel's standard `btusb` Bluetooth path, and the
> device-scoped ZLP support are integrated into both branches. The former
> separate `bluetooth` branch is retired and should no longer be used.
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.
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.
@@ -45,49 +13,25 @@ I did not develop this software, The code is sourced from the Tenda U11 driver.
### Attention ### Attention
Before installing the driver, delete all aic8800-related folders under /lib/firmware. Using an incorrect firmware version may cause the system to freeze. Before installing the driver, delete all aic8800-related folders under /lib/firmware. Using an incorrect firmware version may cause the system to freeze.
#### Pandora 88M80 mode switching
Pandora 88M80 adapters that initially appear as USB device `1111:1111` are
automatically switched to `a69c:8d80` by sending the required `F3` then `F2`
commands. Existing users must rerun `sudo ./install.sh` to replace the installed
usb_modeswitch configuration, then unplug the adapter completely and plug it
back in.
If automatic switching does not occur, try the same sequence manually:
```bash
sudo usb_modeswitch -v 1111 -p 1111 \
-M "555342438765432100000000000010fd0000000000000000000000000000f3" \
-2 "555342438765432100000000000010fd0000000000000000000000000000f2"
```
This only addresses switching from `1111:1111` to `a69c:8d80`. If the device
has reached `a69c:8d80` but firmware startup still fails, see
[issue #79](https://github.com/shenmintao/aic8800d80/issues/79).
### Installation Steps ### Installation Steps
For OpenWrt SDK/buildroot builds, see [OpenWrt build notes](OPENWRT.md).
OpenWrt can use a newer cfg80211 backport than its target kernel; these builds
must pass the wireless stack version separately.
#### Method 1: [Quick Installation](INSTALL_SCRIPT.md) (Recommended) #### Method 1: [Quick Installation](INSTALL_SCRIPT.md) (Recommended)
#### Method 2: Manual Installation #### Method 2: Manual Installation
#### Copy udev rules: #### Copy udev rules:
Copy the aic.rules file to /usr/lib/udev/rules.d/: Copy the aic.rules file to /lib/udev/rules.d/:
```bash ```bash
sudo cp aic.rules /usr/lib/udev/rules.d/ sudo cp aic.rules /lib/udev/rules.d/
``` ```
#### Copy firmware: #### Copy firmware:
Copy the firmware directories from `./fw` to `/lib/firmware/`: Copy the aic8800D80 folder from ./fw to /lib/firmware/:
```bash ```bash
sudo cp -r ./fw/aic8800* /lib/firmware/ sudo cp -r ./fw/aic8800D80 /lib/firmware/
``` ```
#### Navigate to the driver directory: #### Navigate to the driver directory:
@@ -154,52 +98,56 @@ 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
Bluetooth support does not require a separate AIC transport module. After The `aic_load_fw` module loads the Bluetooth firmware during initialization. After the firmware is correctly uploaded, the standard Linux `btusb` driver handles the Bluetooth interface — no custom `aic_btusb` module is needed (see [PR #35](https://github.com/shenmintao/aic8800d80/pull/35) for details).
`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: #### Verify Bluetooth is Working
After loading the driver and plugging in the USB device, check if the Bluetooth HCI device is registered:
```bash ```bash
lsmod | grep -E 'aic_load_fw|aic8800_fdrv|aic_zlp_quirk|btusb' hciconfig -a
lsusb -t
bluetoothctl list
``` ```
To scan after a controller appears: You should see an HCI device (e.g., `hci0`) listed. If the device is down, bring it up:
```bash
sudo hciconfig hci0 up
```
You can also use `bluetoothctl` to scan and connect to Bluetooth devices:
```bash ```bash
bluetoothctl bluetoothctl
# Inside bluetoothctl:
power on power on
scan on scan on
``` ```
If Bluetooth is missing or reports HCI timeouts, run the read-only diagnostic #### Bluetooth Troubleshooting
script and attach its output together with the current boot log:
If Bluetooth is not working, run the diagnostic script:
```bash ```bash
chmod +x diagnose_bt.sh chmod +x diagnose_bt.sh
sudo ./diagnose_bt.sh sudo ./diagnose_bt.sh
sudo journalctl -k -b --no-pager
``` ```
The installer removes active references to the retired `aic_btusb` integration. Common issues and solutions:
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 1. **Firmware not found**: Ensure the firmware files are correctly copied to `/lib/firmware/aic8800D80/`. Key Bluetooth firmware files include:
traffic is active: - `fw_patch_8800d80_u02.bin`
- `fw_patch_table_8800d80_u02.bin`
- `fw_adid_8800d80_u02.bin`
```bash 2. **Check kernel logs** for Bluetooth-related errors:
cat /sys/module/aic_zlp_quirk/parameters/hook ```bash
cat /sys/module/aic_zlp_quirk/parameters/injections sudo dmesg | grep -iE "aicbt|bluetooth|hci|fw_patch"
``` ```
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.
3. **RF-Kill blocking Bluetooth**:
```bash
rfkill list bluetooth
sudo rfkill unblock bluetooth
```
+18 -4
View File
@@ -1,6 +1,5 @@
# AIC8800 USB mass-storage mode switch rules # 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}=="5722", 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"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5725", SYMLINK+="tendaudiskv2", RUN+="/usr/bin/eject /dev/%k" KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5725", SYMLINK+="tendaudiskv2", RUN+="/usr/bin/eject /dev/%k"
@@ -10,5 +9,20 @@ KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572a", SYMLINK+="ten
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. # AIC8800D80 "Pandora" clone adapter - automatic mode switch & driver binding
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'" # Triggers usb_modeswitch when the device is plugged in as 1111:1111
# --- Mode Switch ---
ACTION=="add", ATTRS{idVendor}=="1111", ATTRS{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'"
# --- WiFi Driver Binding ---
# After mode switch, the device re-enumerates as a69c:8d81 (Radxa fw) or a69c:8d83 (Brostrend fw).
# If aic8800_fdrv doesn't auto-bind to the WiFi interface, add the VID:PID dynamically:
ACTION=="add", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'echo a69c 8d81 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'"
ACTION=="add", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", RUN+="/bin/sh -c 'echo a69c 8d83 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'"
ACTION=="add", ATTRS{idVendor}=="368b", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'echo 368b 8d81 > /sys/bus/usb/drivers/aic8800_fdrv/new_id 2>/dev/null || true'"
# Unblock rfkill for Bluetooth
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="8d83", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'"
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="368b", ATTRS{idProduct}=="8d81", RUN+="/bin/sh -c 'rfkill unblock bluetooth 2>/dev/null || true'"
+3 -6
View File
@@ -32,7 +32,7 @@ Copy aic8800d80.spec to rpmbuild/SPECS
~~~bash ~~~bash
cd $HOME/rpmbuild/SPECS cd $HOME/rpmbuild/SPECS
curl -LO -s https://raw.githubusercontent.com/shenmintao/aic8800d80/refs/heads/main/bazzite/aic8800d80.spec curl -LO -s https://raw.githubusercontent.com/shenmintao/aic8800d80/refs/heads/bluetooth/bazzite/aic8800d80.spec
~~~ ~~~
Prepare and download required files. Prepare and download required files.
@@ -56,11 +56,8 @@ sudo rpm-ostree install "$rpm_path"
sudo systemctl reboot sudo systemctl reboot
~~~ ~~~
After reboot, the Wi-Fi module and firmware loader will be available. On combo After reboot, the Wi-Fi module and firmware loader will be available. Bluetooth
adapters, Bluetooth is handled by the standard `btusb` kernel module after 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 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.
+12 -50
View File
@@ -1,16 +1,11 @@
%global commit 3e9a02549bc98d350bff1e0fb0501f841f9d8e55 %global commit 6b8cb98e969b04236f8726f7591393a040171735
%global shortcommit %(echo %{commit} | cut -c1-7) %global shortcommit %(echo %{commit} | cut -c1-7)
%global snapdate 20260924
%global debug_package %{nil}
%{!?kver:%global kver %(uname -r)} %{!?kver:%global kver %(uname -r)}
Name: aic8800d80 Name: aic8800d80
# Versions before 2026-09-24 were bare commit hashes, which rpm does not Version: %{shortcommit}
# order by commit history. Epoch 1 sorts every snapshot version after them.
Epoch: 1
Version: 1.0.0^%{snapdate}git%{shortcommit}
Release: 1%{?dist} Release: 1%{?dist}
Summary: AIC8800 USB Wi-Fi, Bluetooth firmware, and ZLP quirk driver Summary: AIC8800D80 USB Wi-Fi and Bluetooth driver
License: GPL-2.0-only License: GPL-2.0-only
URL: https://github.com/shenmintao/aic8800d80 URL: https://github.com/shenmintao/aic8800d80
@@ -22,16 +17,16 @@ BuildRequires: kernel-devel-uname-r = %{kver}
Requires: kernel-uname-r = %{kver} Requires: kernel-uname-r = %{kver}
Requires: /usr/bin/eject Requires: /usr/bin/eject
Requires: usb_modeswitch Requires: /usr/sbin/usb_modeswitch
Requires: /usr/sbin/rfkill
Requires(post): /usr/sbin/depmod Requires(post): /usr/sbin/depmod
Requires(postun): /usr/sbin/depmod Requires(postun): /usr/sbin/depmod
%description %description
Out-of-tree AIC8800 USB driver with Wi-Fi support, Bluetooth firmware loading, Out-of-tree AIC8800D80 USB driver with Wi-Fi support, Bluetooth firmware
udev mode-switch rules, and all firmware variants shipped by the upstream loading, udev mode-switch rules, and all firmware variants shipped by the
repository. Combo adapters use the standard Linux btusb transport driver. A upstream repository. Bluetooth interfaces are handled by the standard Linux
device-scoped companion module supplies the required ACL bulk TX ZLP behavior btusb driver after aic_load_fw initializes the device.
for USB device 368b:8d81 without replacing the distribution btusb module.
%prep %prep
%autosetup -n %{name}-%{commit} %autosetup -n %{name}-%{commit}
@@ -51,10 +46,6 @@ 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
@@ -76,41 +67,12 @@ 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
* Thu Sep 24 2026 Shen Mintao <shenmintao@gmail.com> - 1:1.0.0^20260924git3e9a025-1 * Tue Jul 14 2026 Shen Mintao <shenmintao@gmail.com> - 6b8cb98-1
- Version snapshots as 1.0.0^<date>git<commit> with Epoch 1. The previous - Build the current bluetooth branch without the removed aic_btusb module.
commit-hash versions do not sort in commit order, so rpm could treat a
newer snapshot as an older package.
* Thu Sep 24 2026 Shen Mintao <shenmintao@gmail.com> - 3e9a025-1
- Build the current main branch, which adds the Linux 7.1+ TDLS discovery
response length fix, the SUN60IW2P1 USB transfer settings, OpenWrt
cfg80211 backport version handling and the 6.12 stable
set_monitor_channel() fix.
* Fri Aug 21 2026 Heyde Moura <moura.heyde@gmail.com> - e93a7d2-1
- Build the current main branch, which carries the Linux 7.2 cfg80211 and
strncpy() fixes needed to compile on Bazzite 44.
* Tue Jul 28 2026 ccyuen1 - 13baa9b-2
- Disable automatic creation of debuginfo packages to fix issue #77.
- Require usb_modeswitch as package dependency instead of file dependency to fix issue #77.
* 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
- 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.
- Remove obsolete Bluetooth-specific configuration from the Wi-Fi package. - Remove the obsolete custom Bluetooth module integration.
+103 -121
View File
@@ -1,160 +1,142 @@
#!/bin/bash #!/bin/bash
# Diagnose Bluetooth on AIC8800 Wi-Fi/Bluetooth combo adapters.
# #
# aic_load_fw initializes the device and uploads the AIC firmware. The # AIC8800D80 Bluetooth Diagnostic Script
# 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. #
# 本分支 (bluetooth) 使用内核标准 btusb 驱动接管蓝牙,
# aic_load_fw 负责把蓝牙固件上传到芯片。
# 不应该再安装/加载 aic_btusb。
#
echo "=== AIC8800 Bluetooth diagnostics ===" echo "=== AIC8800D80 蓝牙诊断 ==="
echo "" echo ""
echo "1. AIC USB devices:" # 1. 检查 USB 设备
if command -v lsusb >/dev/null 2>&1; then echo "1. USB 设备状态:"
lsusb | grep -iE 'a69c|368b|3625' || echo " No known AIC USB ID found" echo " 当前 AIC 设备:"
else lsusb | grep -iE "a69c|368b|1111" || echo " 未找到 AIC 设备"
echo " lsusb is not installed"
fi
echo "" echo ""
echo "2. USB interfaces and bound drivers:" # 2. 检查 USB 接口数量
bt_interface_found=false echo "2. USB 接口详情:"
btusb_bound=false
zlp_target_found=false
for dev in /sys/bus/usb/devices/*; do for dev in /sys/bus/usb/devices/*; do
[ -f "$dev/idVendor" ] || continue if [ -f "$dev/idVendor" ] && [ -f "$dev/idProduct" ]; then
[ -f "$dev/idProduct" ] || continue vid=$(cat "$dev/idVendor" 2>/dev/null)
pid=$(cat "$dev/idProduct" 2>/dev/null)
vid=$(cat "$dev/idVendor" 2>/dev/null) if [[ "$vid" == "a69c" || "$vid" == "368b" ]]; then
pid=$(cat "$dev/idProduct" 2>/dev/null) echo " 设备: $vid:$pid"
case "$vid" in if [ -d "$dev" ]; then
a69c|368b|3625) ;; for intf in "$dev"/*:*; do
*) continue ;; if [ -d "$intf" ]; then
esac class=$(cat "$intf/bInterfaceClass" 2>/dev/null)
subclass=$(cat "$intf/bInterfaceSubClass" 2>/dev/null)
echo " Device: $vid:$pid" protocol=$(cat "$intf/bInterfaceProtocol" 2>/dev/null)
if [ "$vid" = "368b" ] && [ "$pid" = "8d81" ]; then driver=$(basename "$(readlink "$intf/driver" 2>/dev/null)" 2>/dev/null)
zlp_target_found=true echo " 接口: $class/$subclass/$protocol -> 驱动: ${driver:-未绑定}"
fi fi
for intf in "$dev"/*:*; do done
[ -d "$intf" ] || continue fi
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 fi
done fi
done done
echo "" echo ""
echo "3. Relevant kernel modules (combo expectation: aic_load_fw + btusb):" # 3. 检查已加载的模块
lsmod | grep -E '^(aic_load_fw|aic8800_fdrv|aic_zlp_quirk|aic_btusb|btusb|bluetooth)[[:space:]]' || \ echo "3. 已加载的相关模块 (期望: aic_load_fw + btusb):"
echo " No related module is currently loaded" lsmod | grep -E "aic_load_fw|aicwf|aic_btusb|btusb|bluetooth" || echo " 未找到相关模块"
echo "" echo ""
echo "4. Bluetooth controllers:" # 4. 检查 HCI 设备
if command -v bluetoothctl >/dev/null 2>&1; then echo "4. HCI 设备:"
bluetoothctl list 2>/dev/null || echo " No controller reported by bluetoothctl" hciconfig -a 2>/dev/null || echo " 无法获取 HCI 信息 (可能需要 root 权限)"
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 ""
echo "5. Firmware, btusb, ZLP quirk, and HCI log messages:" # 5. 检查蓝牙固件加载日志
dmesg 2>/dev/null | grep -iE 'fw_patch|fw_adid|aicbt|aic_zlp_quirk|bluetooth|btusb|hci' | tail -80 || true echo "5. 蓝牙固件加载日志 (最近 50 行):"
dmesg | grep -iE "fw_patch|fw_adid|aicbt|bluetooth|btusb|hci" | tail -50
echo "" echo ""
echo "6. Bluetooth rfkill state:" # 6. 检查 rfkill 状态
if command -v rfkill >/dev/null 2>&1; then echo "6. RF-Kill 状态:"
rfkill list bluetooth 2>/dev/null || echo " No Bluetooth rfkill entry" rfkill list bluetooth 2>/dev/null || echo " 无法获取 rfkill 信息"
else
echo " rfkill is not installed"
fi
echo "" echo ""
echo "7. Obsolete aic_btusb installation/configuration:" # 7. 检查残留的旧 aic_btusb 配置 (issue #53)
echo "7. 残留旧配置检查:"
legacy_refs_found=false legacy_refs_found=false
mapfile -t legacy_modprobe_files < <( mapfile -t legacy_modprobe_files < <(
grep -RIlE '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' \ grep -RIlE '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' \
/etc/modprobe.d /run/modprobe.d /usr/local/lib/modprobe.d \ /etc/modprobe.d /run/modprobe.d /usr/local/lib/modprobe.d /usr/lib/modprobe.d /lib/modprobe.d \
/usr/lib/modprobe.d /lib/modprobe.d 2>/dev/null | \ 2>/dev/null || true
grep -vE '\.aic8800-backup$' || true
) )
mapfile -t legacy_udev_files < <( mapfile -t legacy_udev_files < <(
grep -RIl 'aic_btusb/new_id' \ grep -RIl 'aic_btusb/new_id' \
/etc/udev/rules.d /run/udev/rules.d \ /etc/udev/rules.d /run/udev/rules.d /usr/lib/udev/rules.d /lib/udev/rules.d \
/usr/lib/udev/rules.d /lib/udev/rules.d 2>/dev/null | \ 2>/dev/null || true
grep -vE '\.aic8800-backup$' || true
) )
for legacy_file in "${legacy_modprobe_files[@]}"; do for legacy_file in "${legacy_modprobe_files[@]}"; do
echo " Obsolete modprobe directive: $legacy_file" echo " ⚠️ 发现旧 modprobe 指令: $legacy_file"
legacy_refs_found=true legacy_refs_found=true
done 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:" for legacy_file in "${legacy_udev_files[@]}"; do
if [ "$zlp_target_found" = true ]; then echo " ⚠️ 发现旧 udev 绑定规则: $legacy_file"
if [ -d /sys/module/aic_zlp_quirk ]; then legacy_refs_found=true
zlp_hook="unknown" done
zlp_injections="unavailable"
[ -r /sys/module/aic_zlp_quirk/parameters/hook ] && \ if lsmod | awk '{print $1}' | grep -qx 'aic_btusb'; then
zlp_hook=$(cat /sys/module/aic_zlp_quirk/parameters/hook) echo " ⚠️ 旧 aic_btusb 模块当前仍已加载"
[ -r /sys/module/aic_zlp_quirk/parameters/injections ] && \ legacy_refs_found=true
zlp_injections=$(cat /sys/module/aic_zlp_quirk/parameters/injections) fi
echo " Target 368b:8d81 present"
echo " aic_zlp_quirk loaded: yes" if modinfo -n aic_btusb >/dev/null 2>&1; then
echo " active hook: $zlp_hook" echo " ⚠️ 系统中仍存在 aic_btusb 模块: $(modinfo -n aic_btusb 2>/dev/null)"
echo " ZLP injections: $zlp_injections" legacy_refs_found=true
else fi
echo " Target 368b:8d81 present, but aic_zlp_quirk is not loaded"
if [ "$legacy_refs_found" = true ]; then
echo " 这些残留会尝试加载已删除的模块, 并干扰标准 btusb 的自动加载/绑定顺序。"
echo " 修复: 拉取最新 bluetooth 分支后重新运行 sudo ./install.sh"
if command -v update-initramfs >/dev/null 2>&1; then
echo " 然后执行: sudo update-initramfs -u"
elif command -v dracut >/dev/null 2>&1; then
echo " 然后执行: sudo dracut -f"
elif command -v mkinitcpio >/dev/null 2>&1; then
echo " 然后执行: sudo mkinitcpio -P"
fi fi
else else
echo " Target 368b:8d81 not present; quirk is not required" echo " 未发现活动的 aic_btusb 配置、规则或模块 (正常)"
fi fi
echo "" echo ""
echo "=== Assessment ===" # 8. 建议
if ! lsmod | awk '{print $1}' | grep -qx 'aic_load_fw'; then echo "=== 诊断建议 ==="
echo "- aic_load_fw is not loaded; run: sudo modprobe aic8800_fdrv" echo ""
fi
if [ "$bt_interface_found" = true ] && [ "$btusb_bound" = false ]; then # 检查 aic_load_fw 是否加载 (它负责上传 WiFi + BT 固件)
echo "- A Bluetooth USB interface exists but is not bound to btusb." if ! lsmod | grep -q "^aic_load_fw"; then
echo " Check for a btusb blacklist, then try: sudo modprobe btusb" echo "⚠️ aic_load_fw 未加载"
fi echo " 该模块负责把蓝牙固件上传到芯片, 必须先于 btusb 工作"
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 " 解决方案: sudo modprobe aic_load_fw"
echo "- HCI timeout detected. Confirm that aic_load_fw uploaded the firmware before btusb bound." echo ""
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 fi
echo "=== Diagnostics complete ===" # 检查 HCI_Reset 超时 (典型症状: 固件未上传却让 btusb 接管)
if dmesg | grep -iE "hci0:.*command (0x|tx) timed out|hci0.*opcode.*0x0c03" | tail -5 | grep -q .; then
echo "⚠️ 检测到 HCI 命令超时 (HCI_Reset/-110)"
echo " 常见原因:"
echo " a) 旧 aic_btusb 配置或 udev 规则残留 (见第 7 项)"
echo " b) aic_load_fw 没有先把蓝牙固件 patch 上传到芯片"
echo " c) usb_modeswitch 没把 1111:1111 切换到真实 VID:PID"
echo " 排查: 看上面第 5 项日志, 应能看到 fw_patch_table_8800d80 / fw_adid 字样"
echo " 临时缓解: 拔插一次设备 (软件复位/飞行模式切换通常无法救活)"
echo ""
fi
# btusb 是否已接管 BT 接口 (这是正常预期)
if lsmod | grep -q "^btusb"; then
echo "✅ btusb 已加载 (正常, 本分支由 btusb 接管蓝牙)"
fi
echo "=== 诊断完成 ==="
-5
View File
@@ -13,9 +13,4 @@ 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"
+2 -7
View File
@@ -1,10 +1,8 @@
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
@@ -53,7 +51,6 @@ 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 ?=
@@ -61,6 +58,8 @@ endif
########################################### ###########################################
MAKEFLAGS +=-j$(shell nproc)
KERNEL_AUTOCONF := $(KDIR)/include/config/auto.conf KERNEL_AUTOCONF := $(KDIR)/include/config/auto.conf
KERNEL_CONFIG := $(KDIR)/.config KERNEL_CONFIG := $(KDIR)/.config
KERNEL_CC_IS_CLANG := $(shell if [ -r "$(KERNEL_AUTOCONF)" ] && grep -q '^CONFIG_CC_IS_CLANG=y' "$(KERNEL_AUTOCONF)"; then echo y; elif [ -r "$(KERNEL_CONFIG)" ] && grep -q '^CONFIG_CC_IS_CLANG=y' "$(KERNEL_CONFIG)"; then echo y; fi) KERNEL_CC_IS_CLANG := $(shell if [ -r "$(KERNEL_AUTOCONF)" ] && grep -q '^CONFIG_CC_IS_CLANG=y' "$(KERNEL_AUTOCONF)"; then echo y; elif [ -r "$(KERNEL_CONFIG)" ] && grep -q '^CONFIG_CC_IS_CLANG=y' "$(KERNEL_CONFIG)"; then echo y; fi)
@@ -79,20 +78,16 @@ 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/
+3 -19
View File
@@ -2,16 +2,6 @@ EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
EXTRA_CFLAGS += -Wno-implicit-fallthrough EXTRA_CFLAGS += -Wno-implicit-fallthrough
#EXTRA_CFLAGS += -Wno-unused-variable #EXTRA_CFLAGS += -Wno-unused-variable
# OpenWrt may build a newer cfg80211 backport on an older kernel.
# Set this to the wireless stack's version, e.g. CFG80211_VERSION=6.18.26.
ifneq ($(strip $(CFG80211_VERSION)),)
aicwf_cfg80211_version := $(subst ., ,$(CFG80211_VERSION))
ifneq ($(words $(aicwf_cfg80211_version)),3)
$(error CFG80211_VERSION must have the form major.minor.patch)
endif
ccflags-y += '-DAICWF_CFG80211_VERSION_CODE=KERNEL_VERSION($(word 1,$(aicwf_cfg80211_version)),$(word 2,$(aicwf_cfg80211_version)),$(word 3,$(aicwf_cfg80211_version)))'
endif
RWNX_VERS_NUM := 6.4.3.0 RWNX_VERS_NUM := 6.4.3.0
CONFIG_AIC8800_WLAN_SUPPORT = m CONFIG_AIC8800_WLAN_SUPPORT = m
@@ -84,11 +74,7 @@ CONFIG_VHT_FOR_OLD_KERNEL = n
CONFIG_COEX = y CONFIG_COEX = y
CONFIG_ALIGN_8BYTES = y CONFIG_ALIGN_8BYTES = y
CONFIG_TXRX_THREAD_PRIO = y CONFIG_TXRX_THREAD_PRIO = y
ifdef CONFIG_ARCH_SUN60IW2P1
CONFIG_USB_ALIGN_DATA = n
else
CONFIG_USB_ALIGN_DATA = y CONFIG_USB_ALIGN_DATA = y
endif
CONFIG_RX_TASKLET = n CONFIG_RX_TASKLET = n
CONFIG_TX_TASKLET = n CONFIG_TX_TASKLET = n
CONFIG_RX_NETIF_RECV_SKB = y CONFIG_RX_NETIF_RECV_SKB = y
@@ -102,11 +88,7 @@ CONFIG_WOWLAN ?= n
CONFIG_USB_RX_AGGR = n CONFIG_USB_RX_AGGR = n
CONFIG_USB_TX_AGGR = n CONFIG_USB_TX_AGGR = n
ifdef CONFIG_ARCH_SUN60IW2P1
CONFIG_USB_NO_TRANS_DMA_MAP = y
else
CONFIG_USB_NO_TRANS_DMA_MAP = n CONFIG_USB_NO_TRANS_DMA_MAP = n
endif
CONFIG_GPIO_WAKEUP = n CONFIG_GPIO_WAKEUP = n
CONFIG_CREATE_TRACE_POINTS = n CONFIG_CREATE_TRACE_POINTS = n
CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y
@@ -172,7 +154,7 @@ CONFIG_RWNX_BCMC ?= y
# Enable Monitor+Data interface support (need FW support) # Enable Monitor+Data interface support (need FW support)
CONFIG_RWNX_MON_DATA =n CONFIG_RWNX_MON_DATA =n
CONFIG_RWNX_MON_XMIT ?= y CONFIG_RWNX_MON_XMIT ?= n
CONFIG_RWNX_MON_RXFILTER ?= n CONFIG_RWNX_MON_RXFILTER ?= n
CONFIG_FILTER_TCP_ACK =y CONFIG_FILTER_TCP_ACK =y
@@ -367,6 +349,8 @@ ccflags-$(CONFIG_TEMP_CONTROL) += -DCONFIG_TEMP_CONTROL
ccflags-$(CONFIG_POWER_LIMIT) += -DCONFIG_POWER_LIMIT ccflags-$(CONFIG_POWER_LIMIT) += -DCONFIG_POWER_LIMIT
ccflags-$(CONFIG_EXT_FEM_8800DCDW) += -DCONFIG_EXT_FEM_8800DCDW ccflags-$(CONFIG_EXT_FEM_8800DCDW) += -DCONFIG_EXT_FEM_8800DCDW
ccflags-$(CONFIG_WOWLAN) += -DCONFIG_WOWLAN ccflags-$(CONFIG_WOWLAN) += -DCONFIG_WOWLAN
MAKEFLAGS +=-j$(shell nproc)
# Platform support list # Platform support list
CONFIG_PLATFORM_ROCKCHIP ?= n CONFIG_PLATFORM_ROCKCHIP ?= n
CONFIG_PLATFORM_ALLWINNER ?= n CONFIG_PLATFORM_ALLWINNER ?= n
+4 -4
View File
@@ -1832,7 +1832,7 @@ void set_vendor_extension_ie(char *command){
} }
#endif//CONFIG_SET_VENDOR_EXTENSION_IE #endif//CONFIG_SET_VENDOR_EXTENSION_IE
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, struct net_device *dev, int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
#else #else
@@ -1840,7 +1840,7 @@ int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
#endif #endif
int rwnx_atoi2(char *value, int c_len); int rwnx_atoi2(char *value, int c_len);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter) void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter)
#else #else
void set_mon_chan(struct rwnx_vif *vif, char *parameter) void set_mon_chan(struct rwnx_vif *vif, char *parameter)
@@ -1867,7 +1867,7 @@ void set_mon_chan(struct rwnx_vif *vif, char *parameter)
chandef->center_freq1 = chandef->chan->center_freq; chandef->center_freq1 = chandef->chan->center_freq;
chandef->center_freq2 = 0; chandef->center_freq2 = 0;
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, dev, chandef); rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, dev, chandef);
#else #else
rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, chandef); rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, chandef);
@@ -2136,7 +2136,7 @@ int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
char *set_parameter; char *set_parameter;
skip = strlen(CMD_SET_MON_FREQ) + 1; skip = strlen(CMD_SET_MON_FREQ) + 1;
set_parameter = command + skip; set_parameter = command + skip;
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
set_mon_chan(vif, net, set_parameter); set_mon_chan(vif, net, set_parameter);
#else #else
set_mon_chan(vif, set_parameter); set_mon_chan(vif, set_parameter);
+1 -1
View File
@@ -62,7 +62,7 @@ int get_cs_info(struct rwnx_vif *vif, u8 *mac_addr, u8 *val);
unsigned int command_strtoul(const char *cp, char **endp, unsigned int base); unsigned int command_strtoul(const char *cp, char **endp, unsigned int base);
int str_starts(const char *str, const char *start); int str_starts(const char *str, const char *start);
int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len); int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter); void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter);
#else #else
void set_mon_chan(struct rwnx_vif *vif, char *parameter); void set_mon_chan(struct rwnx_vif *vif, char *parameter);
@@ -40,8 +40,7 @@ int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw){
char *filename = FW_USERCONFIG_NAME_8800D80; char *filename = FW_USERCONFIG_NAME_8800D80;
#ifndef ANDROID_PLATFORM #ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800D80", sizeof(aic_fw_path)) >= sizeof(aic_fw_path)) sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80");
return -ENAMETOOLONG;
#endif #endif
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename); AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
@@ -41,8 +41,7 @@ int rwnx_plat_userconfig_load_8800d80x2(struct rwnx_hw *rwnx_hw){
char *filename = FW_USERCONFIG_NAME_8800D80X2; char *filename = FW_USERCONFIG_NAME_8800D80X2;
#ifndef ANDROID_PLATFORM #ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800D80X2", sizeof(aic_fw_path)) >= sizeof(aic_fw_path)) sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80X2");
return -ENAMETOOLONG;
#endif #endif
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename); AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
+30 -6
View File
@@ -297,6 +297,18 @@ static void aicwf_usb_rx_complete(struct urb *urb)
aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_buf_put(usb_dev, usb_buf);
if(urb->status < 0){ if(urb->status < 0){
AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status); AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status);
if(g_rwnx_plat->wait_disconnect_cb == false){
g_rwnx_plat->wait_disconnect_cb = true;
if(atomic_read(&aicwf_deinit_atomic) > 0){
atomic_set(&aicwf_deinit_atomic, 0);
down(&aicwf_deinit_sem);
AICWFDBG(LOGINFO, "%s need to wait for disconnect callback \r\n", __func__);
}else{
g_rwnx_plat->wait_disconnect_cb = false;
}
}
return; return;
}else{ }else{
//schedule_work(&usb_dev->rx_urb_work); //schedule_work(&usb_dev->rx_urb_work);
@@ -373,6 +385,18 @@ static void aicwf_usb_rx_complete(struct urb *urb)
aicwf_usb_rx_buf_put(usb_dev, usb_buf); aicwf_usb_rx_buf_put(usb_dev, usb_buf);
if(urb->status < 0){ if(urb->status < 0){
AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status); AICWFDBG(LOGDEBUG, "%s urb->status:%d \r\n", __func__, urb->status);
if(g_rwnx_plat->wait_disconnect_cb == false){
g_rwnx_plat->wait_disconnect_cb = true;
if(atomic_read(&aicwf_deinit_atomic) > 0){
atomic_set(&aicwf_deinit_atomic, 0);
down(&aicwf_deinit_sem);
AICWFDBG(LOGINFO, "%s need to wait for disconnect callback \r\n", __func__);
}else{
g_rwnx_plat->wait_disconnect_cb = false;
}
}
return; return;
}else{ }else{
//schedule_work(&usb_dev->rx_urb_work); //schedule_work(&usb_dev->rx_urb_work);
@@ -1955,6 +1979,10 @@ static void aicwf_usb_bus_stop(struct device *dev)
if (usb_dev->state == USB_DOWN_ST) if (usb_dev->state == USB_DOWN_ST)
return; return;
if(g_rwnx_plat && g_rwnx_plat->wait_disconnect_cb == true){
atomic_set(&aicwf_deinit_atomic, 1);
up(&aicwf_deinit_sem);
}
aicwf_usb_state_change(usb_dev, USB_DOWN_ST); aicwf_usb_state_change(usb_dev, USB_DOWN_ST);
//aicwf_usb_cancel_all_urbs(usb_dev);//AIDEN //aicwf_usb_cancel_all_urbs(usb_dev);//AIDEN
} }
@@ -2313,8 +2341,7 @@ static int aicwf_usb_chipmatch(struct aic_usb_dev *usb_dev, u16_l vid, u16_l pid
usb_dev->chipid = PRODUCT_ID_AIC8801; usb_dev->chipid = PRODUCT_ID_AIC8801;
AICWFDBG(LOGINFO, "%s USE AIC8801\r\n", __func__); AICWFDBG(LOGINFO, "%s USE AIC8801\r\n", __func__);
return 0; return 0;
}else if(pid == USB_PRODUCT_ID_AIC8800DC || pid == USB_PRODUCT_ID_AIC8800DE }else if(pid == USB_PRODUCT_ID_AIC8800DC || pid == USB_PRODUCT_ID_TENDA
|| pid == USB_PRODUCT_ID_TENDA
|| pid == USB_PRODUCT_ID_TENDA_U2 || pid == USB_PRODUCT_ID_AIC8800FC_CUS1 || pid == USB_PRODUCT_ID_TENDA_U2 || pid == USB_PRODUCT_ID_AIC8800FC_CUS1
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS2 || pid == USB_PRODUCT_ID_AIC8800FC_CUS3 || pid == USB_PRODUCT_ID_AIC8800FC_CUS2 || pid == USB_PRODUCT_ID_AIC8800FC_CUS3
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS4 || pid == USB_PRODUCT_ID_AIC8800FC_CUS5 || pid == USB_PRODUCT_ID_AIC8800FC_CUS4 || pid == USB_PRODUCT_ID_AIC8800FC_CUS5
@@ -2333,8 +2360,7 @@ static int aicwf_usb_chipmatch(struct aic_usb_dev *usb_dev, u16_l vid, u16_l pid
|| pid == USB_PRODUCT_ID_AIC8800M80_CUS3 || pid == USB_PRODUCT_ID_AIC8800M80_CUS4 || pid == USB_PRODUCT_ID_AIC8800M80_CUS3 || pid == USB_PRODUCT_ID_AIC8800M80_CUS4
|| pid == USB_PRODUCT_ID_AIC8800M80_CUS5 || pid == USB_PRODUCT_ID_AIC8800M80_CUS6 || pid == USB_PRODUCT_ID_AIC8800M80_CUS5 || pid == USB_PRODUCT_ID_AIC8800M80_CUS6
|| pid == USB_PRODUCT_ID_AIC8800M80_CUS7 || pid == USB_PRODUCT_ID_AIC8800M80_CUS8 || pid == USB_PRODUCT_ID_AIC8800M80_CUS7 || pid == USB_PRODUCT_ID_AIC8800M80_CUS8
|| pid == USB_PRODUCT_ID_AIC8800D80_UGREEN || pid == USB_PRODUCT_ID_MERCURY || pid == USB_PRODUCT_ID_AIC8800D80_UGREEN || pid == USB_PRODUCT_ID_MERCURY){
|| pid == USB_PRODUCT_ID_TP){
usb_dev->chipid = PRODUCT_ID_AIC8800D81; usb_dev->chipid = PRODUCT_ID_AIC8800D81;
aicwf_usb_rx_aggr = true; aicwf_usb_rx_aggr = true;
AICWFDBG(LOGINFO, "%s USE AIC8800D81\r\n", __func__); AICWFDBG(LOGINFO, "%s USE AIC8800D81\r\n", __func__);
@@ -2644,7 +2670,6 @@ static struct usb_device_id aicwf_usb_id_table[] = {
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800D81, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800D81, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800D41, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800D41, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DC, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DC, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DE, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_TENDA_V2, USB_PRODUCT_ID_TENDA_TX1U_NANO, 0xff, 0xff, 0xff)}, {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_TENDA_V2, USB_PRODUCT_ID_TENDA_TX1U_NANO, 0xff, 0xff, 0xff)},
{USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DW)}, {USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DW)},
{USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800M80_CUS1)}, {USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800M80_CUS1)},
@@ -2680,7 +2705,6 @@ static struct usb_device_id aicwf_usb_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS8)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS8)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80_UGREEN)}, {USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80_UGREEN)},
{USB_DEVICE(USB_VENDOR_ID_TP, USB_PRODUCT_ID_MERCURY)}, {USB_DEVICE(USB_VENDOR_ID_TP, USB_PRODUCT_ID_MERCURY)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_TP, USB_PRODUCT_ID_TP, 0xff, 0xff, 0xff)},
#endif #endif
{} {}
}; };
-1
View File
@@ -38,7 +38,6 @@
#else #else
#define USB_PRODUCT_ID_AIC8801 0x8801 #define USB_PRODUCT_ID_AIC8801 0x8801
#define USB_PRODUCT_ID_AIC8800DC 0x88dc #define USB_PRODUCT_ID_AIC8800DC 0x88dc
#define USB_PRODUCT_ID_AIC8800DE 0x88de
#define USB_PRODUCT_ID_AIC8800DW 0x88dd #define USB_PRODUCT_ID_AIC8800DW 0x88dd
#define USB_PRODUCT_ID_AIC8800D81 0x8d81 #define USB_PRODUCT_ID_AIC8800D81 0x8d81
#define USB_PRODUCT_ID_AIC8800D41 0x8d41 #define USB_PRODUCT_ID_AIC8800D41 0x8d41
@@ -23,33 +23,6 @@
#define _RWNX_COMPAT_H_ #define _RWNX_COMPAT_H_
#include <linux/version.h> #include <linux/version.h>
/* Keep wireless API checks separate from timer, USB and other kernel APIs. */
#ifndef AICWF_CFG80211_VERSION_CODE
#define AICWF_CFG80211_VERSION_CODE LINUX_VERSION_CODE
#endif
/*
* cfg80211_ops.set_monitor_channel() gained a "struct net_device *dev"
* parameter. The change went into mainline 6.13, but it was also
* backported to the 6.12 stable series starting with 6.12.101, so a
* plain ">= 6.13.0" test misses 6.12.101 and later. Those kernels then
* compile against the old prototype, which is fatal with
* -Wincompatible-pointer-types:
*
* rwnx_main.c: error: initialization of
* 'int (*)(struct wiphy *, struct net_device *, struct cfg80211_chan_def *)'
* from incompatible pointer type
* 'int (*)(struct wiphy *, struct cfg80211_chan_def *)'
*
* Debian 13 (6.12.107) is one such kernel. The 6.12.101 threshold
* covers both the backport and mainline, and leaves 6.11 and earlier
* 6.12.x on the old prototype. Keep the check in one place so every
* consumer stays in sync.
*/
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 101)
#define AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
#error "Minimum kernel version supported is 3.10" #error "Minimum kernel version supported is 3.10"
#endif #endif
-16
View File
@@ -335,12 +335,6 @@ struct apm_probe_sta {
u8 sta_mac_addr[6]; u8 sta_mac_addr[6];
u8 vif_idx; u8 vif_idx;
u64 probe_id; u64 probe_id;
/*
* 7.3+ only: the cookie cfg80211_ops::probe_peer() was called with,
* echoed back via cfg80211_probe_status() once the probe completes.
* See rwnx_cfg80211_probe_client().
*/
u64 cookie;
struct work_struct apmprobestaWork; struct work_struct apmprobestaWork;
struct workqueue_struct *apmprobesta_wq; struct workqueue_struct *apmprobesta_wq;
}; };
@@ -681,16 +675,6 @@ struct rwnx_roc_elem {
bool mgmt_roc; bool mgmt_roc;
/* Indicate if we have switch on the RoC channel */ /* Indicate if we have switch on the RoC channel */
bool on_chan; bool on_chan;
/*
* The cookie reported to cfg80211 for this RoC, via
* cfg80211_ready_on_channel() / cfg80211_remain_on_channel_expired().
* On 7.3+, for a RoC started directly by cfg80211_ops::remain_on_channel(),
* this is the cookie cfg80211 pre-assigned; on every older kernel, and
* always for the purely-internal RoC started from inside mgmt_tx, it is
* rwnx_hw->roc_cookie_cnt at RoC-start time. See
* rwnx_cfg80211_remain_on_channel_().
*/
u64 cookie;
}; };
/* Structure containing channel survey information received from MAC */ /* Structure containing channel survey information received from MAC */
+69 -209
View File
@@ -1518,30 +1518,18 @@ static int rwnx_close(struct net_device *dev)
RWNX_DBG(RWNX_FN_ENTRY_STR); RWNX_DBG(RWNX_FN_ENTRY_STR);
/* test_counter = waiting_counter;
* A CONNECTING/DISCONNECTING state is only left when the firmware answers while(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING||
* the pending request. If the bus is already down the answer can never atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTING){
* arrive: rwnx_send_msg() silently drops the message and returns 0 AICWFDBG(LOGDEBUG, "%s wifi is connecting or disconnecting, waiting 200ms for state to stable\r\n", __func__);
* (rwnx_msg_tx.c), so the wait below would always run its full timeout and msleep(200);
* fire the spurious WARN_ON() during USB teardown. Skip the wait when the test_counter--;
* bus is down, using the same condition the vif_started path uses below. if(test_counter == 0){
*/ AICWFDBG(LOGERROR, "%s connecting or disconnecting, not finish\r\n", __func__);
if (bus_if && WARN_ON(1);
(usbdev == NULL || (usbdev->bus_if->state != BUS_DOWN_ST && break;
usbdev->state != USB_DOWN_ST))) { }
test_counter = waiting_counter; }
while(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING||
atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTING){
AICWFDBG(LOGDEBUG, "%s wifi is connecting or disconnecting, waiting 200ms for state to stable\r\n", __func__);
msleep(200);
test_counter--;
if(test_counter == 0){
AICWFDBG(LOGERROR, "%s connecting or disconnecting, not finish\r\n", __func__);
WARN_ON(1);
break;
}
}
}
#if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT) #if defined(AICWF_USB_SUPPORT) || defined(AICWF_SDIO_SUPPORT)
if (rwnx_hw->scanning){ if (rwnx_hw->scanning){
@@ -1599,18 +1587,13 @@ static int rwnx_close(struct net_device *dev)
test_counter = waiting_counter; test_counter = waiting_counter;
if(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTED){ if(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTED){
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, RWNX_DRV_STATUS_DISCONNECTING); rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, RWNX_DRV_STATUS_DISCONNECTING);
/* Same reasoning as above: with the bus down the disconnect rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, 3);
* confirmation cannot arrive, so do not wait for it. */ while (atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING) {
if (usbdev->bus_if->state != BUS_DOWN_ST && AICWFDBG(LOGDEBUG, "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", __func__);
usbdev->state != USB_DOWN_ST) { msleep(100);
rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, 3); test_counter--;
while (atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING) { if (test_counter ==0)
AICWFDBG(LOGDEBUG, "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", __func__); break;
msleep(100);
test_counter--;
if (test_counter ==0)
break;
}
} }
} }
} }
@@ -2959,7 +2942,7 @@ bool key_flag = false;
* when adding a group key. * when adding a group key.
*/ */
static int rwnx_cfg80211_add_key(struct wiphy *wiphy, static int rwnx_cfg80211_add_key(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *netdev, struct net_device *netdev,
@@ -2971,7 +2954,7 @@ static int rwnx_cfg80211_add_key(struct wiphy *wiphy,
struct key_params *params) struct key_params *params)
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *vif = netdev_priv(wdev->netdev); struct rwnx_vif *vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *vif = netdev_priv(netdev); struct rwnx_vif *vif = netdev_priv(netdev);
@@ -3083,7 +3066,7 @@ static int rwnx_cfg80211_add_key(struct wiphy *wiphy,
* *
*/ */
static int rwnx_cfg80211_get_key(struct wiphy *wiphy, static int rwnx_cfg80211_get_key(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *netdev, struct net_device *netdev,
@@ -3107,7 +3090,7 @@ static int rwnx_cfg80211_get_key(struct wiphy *wiphy,
* and @key_index, return -ENOENT if the key doesn't exist. * and @key_index, return -ENOENT if the key doesn't exist.
*/ */
static int rwnx_cfg80211_del_key(struct wiphy *wiphy, static int rwnx_cfg80211_del_key(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *netdev, struct net_device *netdev,
@@ -3119,7 +3102,7 @@ static int rwnx_cfg80211_del_key(struct wiphy *wiphy,
u8 key_index, bool pairwise, const u8 *mac_addr) u8 key_index, bool pairwise, const u8 *mac_addr)
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *vif = netdev_priv(wdev->netdev); struct rwnx_vif *vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *vif = netdev_priv(netdev); struct rwnx_vif *vif = netdev_priv(netdev);
@@ -3171,7 +3154,7 @@ static int rwnx_cfg80211_set_default_key(struct wiphy *wiphy,
* @set_default_mgmt_key: set the default management frame key on an interface * @set_default_mgmt_key: set the default management frame key on an interface
*/ */
static int rwnx_cfg80211_set_default_mgmt_key(struct wiphy *wiphy, static int rwnx_cfg80211_set_default_mgmt_key(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *netdev, struct net_device *netdev,
@@ -3266,7 +3249,7 @@ static int rwnx_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
key_params.seq_len = 0; key_params.seq_len = 0;
key_params.cipher = sme->crypto.cipher_group; key_params.cipher = sme->crypto.cipher_group;
rwnx_cfg80211_add_key(wiphy, rwnx_cfg80211_add_key(wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
&rwnx_vif->wdev, &rwnx_vif->wdev,
#else #else
dev, dev,
@@ -3497,7 +3480,7 @@ static int rwnx_cfg80211_external_auth(struct wiphy *wiphy, struct net_device *d
* @add_station: Add a new station. * @add_station: Add a new station.
*/ */
static int rwnx_cfg80211_add_station(struct wiphy *wiphy, static int rwnx_cfg80211_add_station(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *dev, struct net_device *dev,
@@ -3510,7 +3493,7 @@ static int rwnx_cfg80211_add_station(struct wiphy *wiphy,
struct station_parameters *params) struct station_parameters *params)
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev); struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *rwnx_vif = netdev_priv(dev); struct rwnx_vif *rwnx_vif = netdev_priv(dev);
@@ -3606,7 +3589,7 @@ static int rwnx_cfg80211_add_station(struct wiphy *wiphy,
sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
#endif #endif
cfg80211_new_sta( cfg80211_new_sta(
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
&rwnx_vif->wdev, &rwnx_vif->wdev,
#else #else
rwnx_vif->ndev, rwnx_vif->ndev,
@@ -3637,7 +3620,7 @@ static int rwnx_cfg80211_add_station(struct wiphy *wiphy,
(params->sta_flags_set & BIT(NL80211_STA_FLAG_##f) ? "["#f"]" : "") (params->sta_flags_set & BIT(NL80211_STA_FLAG_##f) ? "["#f"]" : "")
netdev_info( netdev_info(
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
wdev->netdev, wdev->netdev,
#else #else
dev, dev,
@@ -3668,7 +3651,7 @@ static int rwnx_cfg80211_add_station(struct wiphy *wiphy,
* @del_station: Remove a station * @del_station: Remove a station
*/ */
static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy, static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *dev, struct net_device *dev,
@@ -3683,7 +3666,7 @@ static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
) )
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev); struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *rwnx_vif = netdev_priv(dev); struct rwnx_vif *rwnx_vif = netdev_priv(dev);
@@ -3728,7 +3711,7 @@ static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
if(found) { if(found) {
netdev_info( netdev_info(
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
wdev->netdev, wdev->netdev,
#else #else
dev, dev,
@@ -3748,7 +3731,7 @@ static int rwnx_cfg80211_del_station_compat(struct wiphy *wiphy,
} }
if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) { if (rwnx_vif->wdev.iftype == NL80211_IFTYPE_AP || rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_GO) {
cfg80211_del_sta( cfg80211_del_sta(
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
&rwnx_vif->wdev, &rwnx_vif->wdev,
#else #else
rwnx_vif->ndev, rwnx_vif->ndev,
@@ -3957,21 +3940,7 @@ void apm_probe_sta_work_process(struct work_struct *work)
spin_unlock_bh(&rwnx_vif->rwnx_hw->cb_lock); spin_unlock_bh(&rwnx_vif->rwnx_hw->cb_lock);
printk("sta %pM found = %d\n", mac, found); printk("sta %pM found = %d\n", mac, found);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
/*
* 7.3 added an MLO link_id parameter between cookie and acked. This
* driver has no MLO support, and -1 is the documented value for
* "non-MLO" (see the cfg80211_probe_status() kerneldoc). The cookie
* source also changes here: sta_probe.cookie is the value cfg80211
* pre-assigned via probe_peer(), which now must be echoed back
* instead of the driver's own probe_id counter -- see
* rwnx_cfg80211_probe_client().
*/
if(found)
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.cookie, -1, 1, 0, false, GFP_ATOMIC);
else
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.cookie, -1, 0, 0, false, GFP_ATOMIC);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)
if(found) if(found)
cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 1, 0, false, GFP_ATOMIC); cfg80211_probe_status(rwnx_vif->ndev, mac, (u64)rwnx_vif->sta_probe.probe_id, 1, 0, false, GFP_ATOMIC);
else else
@@ -3993,7 +3962,7 @@ void apm_probe_sta_work_process(struct work_struct *work)
* cfg80211_check_station_change() to validate the information. * cfg80211_check_station_change() to validate the information.
*/ */
static int rwnx_cfg80211_change_station(struct wiphy *wiphy, static int rwnx_cfg80211_change_station(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *dev, struct net_device *dev,
@@ -4006,7 +3975,7 @@ static int rwnx_cfg80211_change_station(struct wiphy *wiphy,
struct station_parameters *params) struct station_parameters *params)
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *vif = netdev_priv(wdev->netdev); struct rwnx_vif *vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *vif = netdev_priv(dev); struct rwnx_vif *vif = netdev_priv(dev);
@@ -4019,7 +3988,7 @@ static int rwnx_cfg80211_change_station(struct wiphy *wiphy,
/* Add the TDLS station */ /* Add the TDLS station */
if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER))
{ {
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev); struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *rwnx_vif = netdev_priv(dev); struct rwnx_vif *rwnx_vif = netdev_priv(dev);
@@ -4095,7 +4064,7 @@ static int rwnx_cfg80211_change_station(struct wiphy *wiphy,
(params->sta_flags_set & BIT(NL80211_STA_FLAG_##f) ? "["#f"]" : "") (params->sta_flags_set & BIT(NL80211_STA_FLAG_##f) ? "["#f"]" : "")
netdev_info( netdev_info(
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
wdev->netdev, wdev->netdev,
#else #else
dev, dev,
@@ -4384,7 +4353,7 @@ static int rwnx_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
/* delete any remaining STA*/ /* delete any remaining STA*/
while (!list_empty(&rwnx_vif->ap.sta_list)) { while (!list_empty(&rwnx_vif->ap.sta_list)) {
rwnx_cfg80211_del_station_compat(wiphy, rwnx_cfg80211_del_station_compat(wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
&rwnx_vif->wdev, &rwnx_vif->wdev,
#else #else
dev, dev,
@@ -4451,7 +4420,7 @@ cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
} }
#endif #endif
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy, struct net_device *dev, static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
#else #else
@@ -4511,7 +4480,7 @@ static int rwnx_cfg80211_set_monitor_channel(struct wiphy *wiphy,
} }
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
struct cfg80211_chan_def *chandef) struct cfg80211_chan_def *chandef)
@@ -4528,20 +4497,11 @@ int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
/** /**
* @probe_peer: probe an associated client. Before 7.3 the driver returns a * @probe_client: probe an associated client, must return a cookie that it
* cookie of its own and passes the same value to cfg80211_probe_status() * later passes to cfg80211_probe_status().
* later; from 7.3 the cookie is assigned by cfg80211, passed in, and must
* be echoed back unchanged. Renamed from @probe_client upstream; kept as
* rwnx_cfg80211_probe_client() here since only the cfg80211_ops field
* name changed, not this driver's own naming.
*/ */
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 cookie)
#else
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev, int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 *cookie) const u8 *peer, u64 *cookie)
#endif
{ {
//struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); //struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
struct rwnx_vif *vif = netdev_priv(dev); struct rwnx_vif *vif = netdev_priv(dev);
@@ -4565,22 +4525,10 @@ int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
memcpy(vif->sta_probe.sta_mac_addr, peer, 6); memcpy(vif->sta_probe.sta_mac_addr, peer, 6);
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
/*
* 7.3 made this an input parameter: cfg80211 pre-assigns the cookie
* before calling us instead of us inventing one and returning it. Save
* it before queueing the work: the worker may run on another CPU as
* soon as it is queued, and it echoes this value back via
* cfg80211_probe_status() once the probe completes.
*/
vif->sta_probe.cookie = cookie;
#else
*cookie = vif->sta_probe.probe_id;
#endif
queue_work(vif->sta_probe.apmprobesta_wq, &vif->sta_probe.apmprobestaWork); queue_work(vif->sta_probe.apmprobesta_wq, &vif->sta_probe.apmprobestaWork);
*cookie = vif->sta_probe.probe_id;
return 0; return 0;
} }
@@ -4605,7 +4553,7 @@ void rwnx_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
* have changed. The actual parameter values are available in * have changed. The actual parameter values are available in
* struct wiphy. If returning an error, no value should be changed. * struct wiphy. If returning an error, no value should be changed.
*/ */
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, u32 changed) static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, u32 changed)
#else #else
static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) static int rwnx_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
@@ -4626,7 +4574,7 @@ static int rwnx_cfg80211_set_tx_power(struct wiphy *wiphy,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#endif #endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
int radio_idx, int radio_idx,
#endif #endif
enum nl80211_tx_power_setting type, int mbm) enum nl80211_tx_power_setting type, int mbm)
@@ -4663,10 +4611,10 @@ static int rwnx_cfg80211_get_tx_power(struct wiphy *wiphy,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#endif #endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
int radio_idx, int radio_idx,
#endif #endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 14, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 14, 0)
unsigned int link_id, unsigned int link_id,
#endif #endif
int *mbm) int *mbm)
@@ -4780,7 +4728,6 @@ rwnx_cfg80211_remain_on_channel_(struct wiphy *wiphy,
struct wireless_dev *wdev = &rwnx_vif->wdev; struct wireless_dev *wdev = &rwnx_vif->wdev;
#endif #endif
struct rwnx_roc_elem *roc_elem; struct rwnx_roc_elem *roc_elem;
u64 roc_cookie;
struct mm_add_if_cfm add_if_cfm; struct mm_add_if_cfm add_if_cfm;
struct mm_remain_on_channel_cfm roc_cfm; struct mm_remain_on_channel_cfm roc_cfm;
int error; int error;
@@ -4872,34 +4819,6 @@ rwnx_cfg80211_remain_on_channel_(struct wiphy *wiphy,
/* Initialize the OFFCHAN TX queue to allow off-channel transmissions */ /* Initialize the OFFCHAN TX queue to allow off-channel transmissions */
rwnx_txq_offchan_init(rwnx_vif); rwnx_txq_offchan_init(rwnx_vif);
/*
* Decide the cookie before the element is published and the request
* sent: the RX path can deliver the channel-switch indication and
* call cfg80211_ready_on_channel() with roc_elem->cookie before this
* thread resumes, so it must already be the final value by then.
* Taking one snapshot here also keeps that value and the one reported
* back to the caller below identical: rwnx_send_roc() sleeps, and the
* RoC expiry handler increments roc_cookie_cnt, so re-reading the
* counter afterwards could return a different value than the one
* already reported to cfg80211.
*/
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
/*
* mgmt_roc_flag is false only for the direct cfg80211
* .remain_on_channel call path (see rwnx_cfg80211_remain_on_channel()
* below), where on 7.3+ *cookie already holds the value cfg80211
* pre-assigned and must be honored rather than overwritten. The
* purely-internal RoC this function also serves (started from
* inside mgmt_tx, mgmt_roc_flag true) never goes through that
* cfg80211 op, so there is no pre-assigned value to honor there --
* keep inventing one, exactly as on every older kernel.
*/
roc_cookie = mgmt_roc_flag ? (u64)(rwnx_hw->roc_cookie_cnt) : *cookie;
#else
roc_cookie = (u64)(rwnx_hw->roc_cookie_cnt);
#endif
roc_elem->cookie = roc_cookie;
/* Forward the information to the FMAC */ /* Forward the information to the FMAC */
rwnx_hw->roc_elem = roc_elem; rwnx_hw->roc_elem = roc_elem;
error = rwnx_send_roc(rwnx_hw, rwnx_vif, chan, duration, &roc_cfm); error = rwnx_send_roc(rwnx_hw, rwnx_vif, chan, duration, &roc_cfm);
@@ -4908,12 +4827,7 @@ rwnx_cfg80211_remain_on_channel_(struct wiphy *wiphy,
if (error == 0) { if (error == 0) {
/* Set the cookie value */ /* Set the cookie value */
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0) *cookie = (u64)(rwnx_hw->roc_cookie_cnt);
if (mgmt_roc_flag)
*cookie = roc_cookie;
#else
*cookie = roc_cookie;
#endif
if(roc_cfm.status) { if(roc_cfm.status) {
// failed to roc // failed to roc
rwnx_hw->roc_elem = NULL; rwnx_hw->roc_elem = NULL;
@@ -4943,42 +4857,8 @@ rwnx_cfg80211_remain_on_channel(struct wiphy *wiphy,
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
enum nl80211_channel_type channel_type, enum nl80211_channel_type channel_type,
#endif #endif
unsigned int duration, unsigned int duration, u64 *cookie)
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
/*
* 7.3 made this cookie an input parameter: cfg80211
* pre-assigns it before calling us instead of us
* inventing one and returning it. See
* rwnx_cfg80211_remain_on_channel_(). rx_addr is
* unused for the reason given in the 7.2 arm below:
* it is always NULL for this driver.
*/
u64 cookie, const u8 *rx_addr
#elif AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 2, 0)
/*
* 7.2 added an optional receive address filter for the off-channel
* period. cfg80211 refuses a non-NULL one unless the driver sets
* NL80211_EXT_FEATURE_ROC_ADDR_FILTER, which this one does not, so it
* is always NULL here. mac80211 ignores it in the same way.
*/
u64 *cookie, const u8 *rx_addr
#else
u64 *cookie
#endif
)
{ {
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
/*
* 7.3 passes the cookie by value, while the shared helper still takes a
* pointer because its internal caller invents one. Only the argument
* differs, so pick it here and leave the call itself alone.
*/
u64 local_cookie = cookie;
u64 *cookie_ptr = &local_cookie;
#else
u64 *cookie_ptr = cookie;
#endif
return rwnx_cfg80211_remain_on_channel_(wiphy, return rwnx_cfg80211_remain_on_channel_(wiphy,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
wdev, wdev,
@@ -4989,7 +4869,7 @@ rwnx_cfg80211_remain_on_channel(struct wiphy *wiphy,
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
channel_type, channel_type,
#endif #endif
duration, cookie_ptr, false); duration, cookie, false);
} }
/** /**
@@ -5119,7 +4999,7 @@ static int rwnx_cfg80211_get_channel(struct wiphy *wiphy,
if (rwnx_vif->vif_index == rwnx_hw->monitor_vif) if (rwnx_vif->vif_index == rwnx_hw->monitor_vif)
{ {
//retrieve channel from firmware //retrieve channel from firmware
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
rwnx_cfg80211_set_monitor_channel(wiphy, wdev->netdev, NULL); rwnx_cfg80211_set_monitor_channel(wiphy, wdev->netdev, NULL);
#else #else
rwnx_cfg80211_set_monitor_channel(wiphy, NULL); rwnx_cfg80211_set_monitor_channel(wiphy, NULL);
@@ -5167,17 +5047,7 @@ struct ieee80211_channel *rwnx_cfg80211_get_channel(struct wiphy *wiphy)
/** /**
* @mgmt_tx: Transmit a management frame. * @mgmt_tx: Transmit a management frame.
*/ */
#if (AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params,
/*
* 7.3 made this cookie an input parameter: cfg80211
* pre-assigns it before calling us instead of us
* inventing one and returning it. See
* rwnx_start_mgmt_xmit().
*/
u64 cookie)
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params, struct cfg80211_mgmt_tx_params *params,
u64 *cookie) u64 *cookie)
@@ -5192,7 +5062,7 @@ static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
bool dont_wait_for_ack, bool dont_wait_for_ack,
#endif #endif
u64 *cookie) u64 *cookie)
#endif /* AICWF_CFG80211_VERSION_CODE >= 7.3 / LINUX_VERSION_CODE >= 3.14 */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
{ {
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy); struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0))
@@ -5279,8 +5149,7 @@ static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
return -EINVAL; return -EINVAL;
} }
} else { } else {
/* The internal RoC's own cookie; deliberately not the mgmt_tx one. */ u64 cookie;
u64 roc_cookie;
int error; int error;
AICWFDBG(LOGINFO, "mgmt rx remain on chan\n"); AICWFDBG(LOGINFO, "mgmt rx remain on chan\n");
@@ -5288,13 +5157,13 @@ static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
/* Start a ROC procedure for 30ms */ /* Start a ROC procedure for 30ms */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
error = rwnx_cfg80211_remain_on_channel_(wiphy, wdev, channel, error = rwnx_cfg80211_remain_on_channel_(wiphy, wdev, channel,
30, &roc_cookie, true); 30, &cookie, true);
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) #elif (LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)) && (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0))
error = rwnx_cfg80211_remain_on_channel_(wiphy, wdev, channel, NL80211_CHAN_NO_HT, error = rwnx_cfg80211_remain_on_channel_(wiphy, wdev, channel, NL80211_CHAN_NO_HT,
30, &roc_cookie, true); 30, &cookie, true);
#else #else
error = rwnx_cfg80211_remain_on_channel_(wiphy, dev, channel, NL80211_CHAN_NO_HT, error = rwnx_cfg80211_remain_on_channel_(wiphy, dev, channel, NL80211_CHAN_NO_HT,
30, &roc_cookie, true); 30, &cookie, true);
#endif #endif
if (error) { if (error) {
@@ -5311,16 +5180,11 @@ static int rwnx_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
#endif #endif
send_frame: send_frame:
#if (AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
{ return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, params, offchan, cookie);
u64 local_cookie = cookie;
return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, params, offchan, &local_cookie, true);
}
#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, params, offchan, cookie, false);
#else #else
return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, channel, offchan, wait, buf, len, no_cck, dont_wait_for_ack, cookie, false); return rwnx_start_mgmt_xmit(rwnx_vif, rwnx_sta, channel, offchan, wait, buf, len, no_cck, dont_wait_for_ack, cookie);
#endif /* AICWF_CFG80211_VERSION_CODE >= 7.3 / LINUX_VERSION_CODE >= 3.14 */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
} }
/** /**
@@ -5333,7 +5197,7 @@ int rwnx_cfg80211_start_radar_detection(struct wiphy *wiphy,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
, u32 cac_time_ms , u32 cac_time_ms
#endif #endif
#if (AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0))
, int link_id , int link_id
#endif #endif
) )
@@ -6117,7 +5981,7 @@ int rwnx_fill_station_info(struct rwnx_sta *sta, struct rwnx_vif *vif,
* @get_station: get station information for the station identified by @mac * @get_station: get station information for the station identified by @mac
*/ */
static int rwnx_cfg80211_get_station(struct wiphy *wiphy, static int rwnx_cfg80211_get_station(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *dev, struct net_device *dev,
@@ -6129,7 +5993,7 @@ static int rwnx_cfg80211_get_station(struct wiphy *wiphy,
#endif #endif
struct station_info *sinfo) struct station_info *sinfo)
{ {
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *vif = netdev_priv(wdev->netdev); struct rwnx_vif *vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *vif = netdev_priv(dev); struct rwnx_vif *vif = netdev_priv(dev);
@@ -6167,14 +6031,14 @@ static int rwnx_cfg80211_get_station(struct wiphy *wiphy,
* @dump_station: dump station callback -- resume dump at index @idx * @dump_station: dump station callback -- resume dump at index @idx
*/ */
static int rwnx_cfg80211_dump_station(struct wiphy *wiphy, static int rwnx_cfg80211_dump_station(struct wiphy *wiphy,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct wireless_dev *wdev, struct wireless_dev *wdev,
#else #else
struct net_device *dev, struct net_device *dev,
#endif #endif
int idx, u8 *mac, struct station_info *sinfo) int idx, u8 *mac, struct station_info *sinfo)
{ {
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev); struct rwnx_vif *rwnx_vif = netdev_priv(wdev->netdev);
#else #else
struct rwnx_vif *rwnx_vif = netdev_priv(dev); struct rwnx_vif *rwnx_vif = netdev_priv(dev);
@@ -6678,11 +6542,7 @@ static struct cfg80211_ops rwnx_cfg80211_ops = {
.change_beacon = rwnx_cfg80211_change_beacon, .change_beacon = rwnx_cfg80211_change_beacon,
.stop_ap = rwnx_cfg80211_stop_ap, .stop_ap = rwnx_cfg80211_stop_ap,
.set_monitor_channel = rwnx_cfg80211_set_monitor_channel, .set_monitor_channel = rwnx_cfg80211_set_monitor_channel,
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
.probe_peer = rwnx_cfg80211_probe_client,
#else
.probe_client = rwnx_cfg80211_probe_client, .probe_client = rwnx_cfg80211_probe_client,
#endif
// .mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register, // .mgmt_frame_register = rwnx_cfg80211_mgmt_frame_register,
.set_wiphy_params = rwnx_cfg80211_set_wiphy_params, .set_wiphy_params = rwnx_cfg80211_set_wiphy_params,
.set_txq_params = rwnx_cfg80211_set_txq_params, .set_txq_params = rwnx_cfg80211_set_txq_params,
+1 -6
View File
@@ -91,7 +91,7 @@ void aicwf_p2p_alive_timeout(struct timer_list *t);
int rwnx_send_check_p2p(struct cfg80211_scan_request *param); int rwnx_send_check_p2p(struct cfg80211_scan_request *param);
void apm_staloss_work_process(struct work_struct *work); void apm_staloss_work_process(struct work_struct *work);
void apm_probe_sta_work_process(struct work_struct *work); void apm_probe_sta_work_process(struct work_struct *work);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV #if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
@@ -99,13 +99,8 @@ int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef); struct cfg80211_chan_def *chandef);
#endif #endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 3, 0)
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 cookie);
#else
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev, int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 *cookie); const u8 *peer, u64 *cookie);
#endif
void rwnx_cfg80211_mgmt_frame_register(struct wiphy *wiphy, void rwnx_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0))
struct net_device *dev, struct net_device *dev,
+6 -8
View File
@@ -123,13 +123,13 @@ static inline int rwnx_rx_chan_switch_ind(struct rwnx_hw *rwnx_hw,
if (!roc_elem->mgmt_roc) { if (!roc_elem->mgmt_roc) {
/* Inform the host that we have switch on the indicated off-channel */ /* Inform the host that we have switch on the indicated off-channel */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
cfg80211_ready_on_channel(roc_elem->wdev->netdev, roc_elem->cookie, cfg80211_ready_on_channel(roc_elem->wdev->netdev, (u64)(rwnx_hw->roc_cookie_cnt),
roc_elem->chan, NL80211_CHAN_HT20, roc_elem->duration, GFP_ATOMIC); roc_elem->chan, NL80211_CHAN_HT20, roc_elem->duration, GFP_ATOMIC);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
cfg80211_ready_on_channel(roc_elem->wdev, roc_elem->cookie, cfg80211_ready_on_channel(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt),
roc_elem->chan, NL80211_CHAN_HT20, roc_elem->duration, GFP_ATOMIC); roc_elem->chan, NL80211_CHAN_HT20, roc_elem->duration, GFP_ATOMIC);
#else #else
cfg80211_ready_on_channel(roc_elem->wdev, roc_elem->cookie, cfg80211_ready_on_channel(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt),
roc_elem->chan, roc_elem->duration, GFP_ATOMIC); roc_elem->chan, roc_elem->duration, GFP_ATOMIC);
#endif #endif
} }
@@ -245,13 +245,13 @@ static inline int rwnx_rx_remain_on_channel_exp_ind(struct rwnx_hw *rwnx_hw,
/* Inform the host that off-channel period has expired */ /* Inform the host that off-channel period has expired */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
cfg80211_remain_on_channel_expired(roc_elem->wdev->netdev, roc_elem->cookie, cfg80211_remain_on_channel_expired(roc_elem->wdev->netdev, (u64)(rwnx_hw->roc_cookie_cnt),
roc_elem->chan, NL80211_CHAN_HT20, GFP_ATOMIC); roc_elem->chan, NL80211_CHAN_HT20, GFP_ATOMIC);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0) #elif LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
cfg80211_remain_on_channel_expired(roc_elem->wdev, roc_elem->cookie, cfg80211_remain_on_channel_expired(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt),
roc_elem->chan, NL80211_CHAN_HT20, GFP_ATOMIC); roc_elem->chan, NL80211_CHAN_HT20, GFP_ATOMIC);
#else #else
cfg80211_remain_on_channel_expired(roc_elem->wdev, roc_elem->cookie, cfg80211_remain_on_channel_expired(roc_elem->wdev, (u64)(rwnx_hw->roc_cookie_cnt),
roc_elem->chan, GFP_ATOMIC); roc_elem->chan, GFP_ATOMIC);
#endif #endif
} }
@@ -825,9 +825,7 @@ static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw,
#endif #endif
} }
#ifdef CONFIG_USE_WIRELESS_EXT
putbss: putbss:
#endif
if (bss != NULL) if (bss != NULL)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
cfg80211_put_bss(bss); cfg80211_put_bss(bss);
+1 -7
View File
@@ -4849,13 +4849,7 @@ int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg)
return -ENOMEM; return -ENOMEM;
/* Set parameters for the MM_DBG_TRIGGER_REQ message */ /* Set parameters for the MM_DBG_TRIGGER_REQ message */
/* strncpy(req->error, msg, sizeof(req->error));
* strncpy() is gone in 7.2. req->error is a fixed 64-byte field of a
* firmware message that is not NUL-terminated, and the message came
* from kzalloc(), so copying at most the field size is all strncpy()
* did here.
*/
memcpy(req->error, msg, strnlen(msg, sizeof(req->error)));
/* Send the MM_DBG_TRIGGER_REQ message to LMAC FW */ /* Send the MM_DBG_TRIGGER_REQ message to LMAC FW */
return rwnx_send_msg(rwnx_hw, req, 0, -1, NULL); return rwnx_send_msg(rwnx_hw, req, 0, -1, NULL);
+3 -6
View File
@@ -1669,8 +1669,7 @@ static int rwnx_plat_patch_load(struct rwnx_hw *rwnx_hw)
if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DC || if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DW){ rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DW){
#ifndef ANDROID_PLATFORM #ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800DC", sizeof(aic_fw_path)) >= sizeof(aic_fw_path)) sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800DC");
return -ENAMETOOLONG;
#endif #endif
AICWFDBG(LOGINFO, "testmode=%d\n", testmode); AICWFDBG(LOGINFO, "testmode=%d\n", testmode);
if (chip_sub_id == 0) { if (chip_sub_id == 0) {
@@ -1809,8 +1808,7 @@ static int rwnx_plat_patch_load(struct rwnx_hw *rwnx_hw)
} }
} else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N) { } else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N) {
#ifndef ANDROID_PLATFORM #ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800D80N", sizeof(aic_fw_path)) >= sizeof(aic_fw_path)) sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80N");
return -ENAMETOOLONG;
#endif #endif
if (testmode == FW_NORMAL_MODE) { if (testmode == FW_NORMAL_MODE) {
ret = aicwf_plat_patch_load_8800d80n(rwnx_hw); ret = aicwf_plat_patch_load_8800d80n(rwnx_hw);
@@ -1840,8 +1838,7 @@ static int rwnx_plat_patch_load(struct rwnx_hw *rwnx_hw)
} }
else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DLN) { else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DLN) {
#ifndef ANDROID_PLATFORM #ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800DLN", sizeof(aic_fw_path)) >= sizeof(aic_fw_path)) sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800DLN");
return -ENAMETOOLONG;
#endif #endif
if (testmode == FW_NORMAL_MODE) { if (testmode == FW_NORMAL_MODE) {
aicwf_patch_config_8800dln(rwnx_hw); aicwf_patch_config_8800dln(rwnx_hw);
+2 -2
View File
@@ -1475,7 +1475,7 @@ static void rwnx_radar_cac_work(struct work_struct *ws)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
&ctxt->chan_def, &ctxt->chan_def,
#endif #endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0); NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
#else #else
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL); NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
@@ -1617,7 +1617,7 @@ void rwnx_radar_cancel_cac(struct rwnx_radar *radar)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
&ctxt->chan_def, &ctxt->chan_def,
#endif #endif
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0); NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
#else #else
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL); NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+5 -21
View File
@@ -2283,11 +2283,6 @@ u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv)
if(hw_rxhdr->flags_upload) if(hw_rxhdr->flags_upload)
status |= RX_STAT_FORWARD; status |= RX_STAT_FORWARD;
#ifndef CONFIG_RWNX_MON_DATA
if (status & RX_STAT_MONITOR)
status &= ~RX_STAT_FORWARD;
#endif
/* Check if we need to delete the buffer */ /* Check if we need to delete the buffer */
if (status & RX_STAT_DELETE) { if (status & RX_STAT_DELETE) {
/* Remove the SK buffer from the rxbuf_elems table */ /* Remove the SK buffer from the rxbuf_elems table */
@@ -2350,24 +2345,13 @@ u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv)
} else { } else {
#ifdef CONFIG_RWNX_MON_DATA #ifdef CONFIG_RWNX_MON_DATA
skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC); skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC);
if (skb_monitor) { skb_monitor->data += (msdu_offset + 2); //sdio/usb word allign
skb_monitor->data += (msdu_offset + 2); //sdio/usb word allign
//Save frame length //Save frame length
frm_len = le32_to_cpu(hw_rxhdr->hwvect.len); frm_len = le32_to_cpu(hw_rxhdr->hwvect.len);
}
#endif #endif
} }
if (!skb_monitor) {
if (status == RX_STAT_MONITOR) {
dev_kfree_skb(skb);
goto end;
}
goto check_len_update;
}
//skb_reset_tail_pointer(skb); //skb_reset_tail_pointer(skb);
//skb->len = 0; //skb->len = 0;
skb_reset_tail_pointer(skb_monitor); skb_reset_tail_pointer(skb_monitor);
@@ -2410,7 +2394,7 @@ check_len_update:
hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset); hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset);
rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx); rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
if (rwnx_vif) { if (rwnx_vif) {
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, -1, GFP_ATOMIC); cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, -1, GFP_ATOMIC);
#else #else
cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, GFP_ATOMIC); cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, GFP_ATOMIC);
@@ -2757,7 +2741,7 @@ check_len_update:
if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) { if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) {
printk("aicwf: 4addr flag error\n"); printk("aicwf: 4addr flag error\n");
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev, cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev,
sta->mac_addr, -1, GFP_ATOMIC); sta->mac_addr, -1, GFP_ATOMIC);
#else #else
+4 -4
View File
@@ -115,8 +115,8 @@ rwnx_prep_tdls_direct(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
switch (action_code) { switch (action_code) {
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES: case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0) #if LINUX_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
skb_put(skb, 2 + sizeof(mgmt->u.action.tdls_discover_resp)); skb_put(skb, 1 + sizeof(mgmt->u.action.tdls_discover_resp));
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC; mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES; mgmt->u.action.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.tdls_discover_resp.dialog_token = dialog_token; mgmt->u.action.tdls_discover_resp.dialog_token = dialog_token;
@@ -775,9 +775,9 @@ rwnx_tdls_send_mgmt_packet_data(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_v
params.len = skb->len; params.len = skb->len;
params.buf = skb->data; params.buf = skb->data;
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, &params, false, &cookie, false); ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, &params, false, &cookie);
#else #else
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, NULL, false, 0, skb->data, skb->len, false, false, &cookie, false); ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, NULL, false, 0, skb->data, skb->len, false, false, &cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
return ret; return ret;
+24 -56
View File
@@ -1325,7 +1325,6 @@ int intf_tx(struct rwnx_hw *priv,struct msg_buf *msg)
sw_txhdr->rwnx_sta = sta; sw_txhdr->rwnx_sta = sta;
sw_txhdr->rwnx_vif = rwnx_vif; sw_txhdr->rwnx_vif = rwnx_vif;
sw_txhdr->skb = skb; sw_txhdr->skb = skb;
sw_txhdr->cookie = (unsigned long)skb;
sw_txhdr->headroom = headroom; sw_txhdr->headroom = headroom;
sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr);
@@ -1542,7 +1541,6 @@ netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev)
sw_txhdr->rwnx_sta = sta; sw_txhdr->rwnx_sta = sta;
sw_txhdr->rwnx_vif = rwnx_vif; sw_txhdr->rwnx_vif = rwnx_vif;
sw_txhdr->skb = skb; sw_txhdr->skb = skb;
sw_txhdr->cookie = (unsigned long)skb;
sw_txhdr->headroom = headroom; sw_txhdr->headroom = headroom;
sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr);
@@ -1632,12 +1630,7 @@ free:
* @params: Mgmt frame parameters * @params: Mgmt frame parameters
* @offchan: Indicate whether the frame must be send via the offchan TXQ. * @offchan: Indicate whether the frame must be send via the offchan TXQ.
* (is is redundant with params->offchan ?) * (is is redundant with params->offchan ?)
* @cookie: on return, the value cfg80211_mgmt_tx_status() will report for * @cookie: updated with a unique value to identify the frame with upper layer
* this frame: invented here (the skb pointer) unless
* @use_given_cookie is set, in which case *@cookie is kept.
* @use_given_cookie: *@cookie already holds the cookie cfg80211 assigned
* (7.3+, the direct .mgmt_tx path only); honour it instead of
* inventing one. Every other caller passes false.
* *
*/ */
@@ -1645,7 +1638,7 @@ free:
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct cfg80211_mgmt_tx_params *params, bool offchan, struct cfg80211_mgmt_tx_params *params, bool offchan,
u64 *cookie, bool use_given_cookie) u64 *cookie)
#else #else
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct ieee80211_channel *channel, bool offchan, struct ieee80211_channel *channel, bool offchan,
@@ -1656,7 +1649,7 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
bool dont_wait_for_ack, bool dont_wait_for_ack,
#endif #endif
u64 *cookie, bool use_given_cookie) u64 *cookie)
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
{ {
struct rwnx_hw *rwnx_hw = vif->rwnx_hw; struct rwnx_hw *rwnx_hw = vif->rwnx_hw;
@@ -1710,18 +1703,7 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
return -ENOMEM; return -ENOMEM;
} }
/* *cookie = (unsigned long)skb;
* use_given_cookie is true only for the direct cfg80211 .mgmt_tx call
* path on 7.3+, where *cookie already holds the value cfg80211
* pre-assigned and must be echoed back via cfg80211_mgmt_tx_status()
* later -- see rwnx_cfg80211_mgmt_tx(). TDLS's internal reuse of this
* function (use_given_cookie == false) never goes through that cfg80211
* op, so it still gets an invented, locally-unique cookie exactly as
* before this fix, and on every kernel older than 7.3 every caller
* passes use_given_cookie == false, also leaving this unchanged.
*/
if (!use_given_cookie)
*cookie = (unsigned long)skb;
/* /*
* Move skb->data pointer in order to reserve room for rwnx_txhdr * Move skb->data pointer in order to reserve room for rwnx_txhdr
@@ -1791,7 +1773,6 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
sw_txhdr->rwnx_sta = sta; sw_txhdr->rwnx_sta = sta;
sw_txhdr->rwnx_vif = vif; sw_txhdr->rwnx_vif = vif;
sw_txhdr->skb = skb; sw_txhdr->skb = skb;
sw_txhdr->cookie = *cookie;
sw_txhdr->headroom = headroom; sw_txhdr->headroom = headroom;
sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr);
#ifdef CONFIG_RWNX_AMSDUS_TX #ifdef CONFIG_RWNX_AMSDUS_TX
@@ -1943,7 +1924,6 @@ void rwnx_probersp_work(struct work_struct *work)
sw_txhdr->rwnx_sta = sta; sw_txhdr->rwnx_sta = sta;
sw_txhdr->rwnx_vif = rwnx_vif; sw_txhdr->rwnx_vif = rwnx_vif;
sw_txhdr->skb = skb; sw_txhdr->skb = skb;
sw_txhdr->cookie = (unsigned long)skb;
sw_txhdr->headroom = headroom; sw_txhdr->headroom = headroom;
sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr); sw_txhdr->map_len = skb->len - offsetof(struct rwnx_txhdr, hw_hdr);
#ifdef CONFIG_RWNX_AMSDUS_TX #ifdef CONFIG_RWNX_AMSDUS_TX
@@ -2011,7 +1991,7 @@ free_use:
netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev) netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
int rtap_len, ret, idx; int rtap_len, ret, idx, tmp_len;
struct ieee80211_radiotap_header *rtap_hdr; // net/ieee80211_radiotap.h struct ieee80211_radiotap_header *rtap_hdr; // net/ieee80211_radiotap.h
struct ieee80211_radiotap_iterator iterator; // net/cfg80211.h struct ieee80211_radiotap_iterator iterator; // net/cfg80211.h
u8_l *rtap_buf = (u8_l *)skb->data; u8_l *rtap_buf = (u8_l *)skb->data;
@@ -2032,29 +2012,9 @@ netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *d
bool offchan = false; bool offchan = false;
int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX; int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX;
frame_len = skb->len;
if (unlikely(skb->len < sizeof(*rtap_hdr))) {
AICWFDBG(LOGERROR, "%s radiotap header is truncated\n", __func__);
goto free_tag;
}
rtap_hdr = (struct ieee80211_radiotap_header*)(rtap_buf); rtap_hdr = (struct ieee80211_radiotap_header*)(rtap_buf);
if (unlikely(rtap_hdr->it_version)) {
AICWFDBG(LOGERROR, "%s itv \r\n", __func__);
goto free_tag;
}
rtap_len = ieee80211_get_radiotap_len(rtap_buf);//max_length rtap_len = ieee80211_get_radiotap_len(rtap_buf);//max_length
if (unlikely(rtap_len < sizeof(*rtap_hdr))) { frame_len = skb->len;
AICWFDBG(LOGERROR, "%s rtap_len < sizeof(struct ieee80211_radiotap_header) \r\n", __func__);
goto free_tag;
}
if (unlikely(skb->len < rtap_len)) {
AICWFDBG(LOGERROR, "%s skb->len < rtap_len \r\n", __func__);
goto free_tag;
}
AICWFDBG(LOGINFO, "rwnx_start_monitor_if_xmit, skb_len=%d, rtap_len=%d\n", skb->len, rtap_len); AICWFDBG(LOGINFO, "rwnx_start_monitor_if_xmit, skb_len=%d, rtap_len=%d\n", skb->len, rtap_len);
//rwnx_data_dump((char*)__func__, skb->data, skb->len); //rwnx_data_dump((char*)__func__, skb->data, skb->len);
@@ -2063,6 +2023,23 @@ netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *d
g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW) && chip_id < 3)){ g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW) && chip_id < 3)){
nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC; nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC;
} }
if (unlikely(rtap_hdr->it_version)){
AICWFDBG(LOGERROR, "%s itv \r\n", __func__);
goto free_tag;
}
if (unlikely(skb->len < rtap_len)){
AICWFDBG(LOGERROR, "%s skb->len < rtap_len \r\n", __func__);
goto free_tag;
}
if (unlikely(rtap_len < sizeof(struct ieee80211_radiotap_header))){
AICWFDBG(LOGERROR, "%s rtap_len < sizeof(struct ieee80211_radiotap_header) \r\n", __func__);
goto free_tag;
}
frame_len -= rtap_len; frame_len -= rtap_len;
pframe = rtap_buf + rtap_len; pframe = rtap_buf + rtap_len;
@@ -2298,15 +2275,6 @@ netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *d
sw_txhdr->rwnx_sta = sta; sw_txhdr->rwnx_sta = sta;
sw_txhdr->rwnx_vif = vif; sw_txhdr->rwnx_vif = vif;
sw_txhdr->skb = skb_mgmt; sw_txhdr->skb = skb_mgmt;
/*
* Injected frames are flagged TXU_CNTRL_MGMT below and complete through
* the same path as management frames, which reports sw_txhdr->cookie to
* cfg80211_mgmt_tx_status(). There is no cfg80211-assigned cookie for an
* injected frame, so this is the skb-derived value that path reported
* before the field existed. Not gated on 7.3: this path runs on every
* kernel with CONFIG_RWNX_MON_XMIT.
*/
sw_txhdr->cookie = (unsigned long)skb_mgmt;
sw_txhdr->headroom = headroom; sw_txhdr->headroom = headroom;
sw_txhdr->map_len = skb_mgmt->len - offsetof(struct rwnx_txhdr, hw_hdr); sw_txhdr->map_len = skb_mgmt->len - offsetof(struct rwnx_txhdr, hw_hdr);
sw_txhdr->raw_frame = 1; sw_txhdr->raw_frame = 1;
@@ -2418,7 +2386,7 @@ int rwnx_txdatacfm(void *pthis, void *host_id)
#endif #endif
/* Confirm transmission to CFG80211 */ /* Confirm transmission to CFG80211 */
cfg80211_mgmt_tx_status(&sw_txhdr->rwnx_vif->wdev, cfg80211_mgmt_tx_status(&sw_txhdr->rwnx_vif->wdev,
sw_txhdr->cookie, (unsigned long)skb,
(skb->data + sw_txhdr->headroom), (skb->data + sw_txhdr->headroom),
sw_txhdr->frame_len, sw_txhdr->frame_len,
rwnx_txst.acknowledged, rwnx_txst.acknowledged,
+3 -15
View File
@@ -130,17 +130,6 @@ struct rwnx_sw_txhdr {
#endif #endif
u32 need_cfm; u32 need_cfm;
struct sk_buff *skb; struct sk_buff *skb;
/*
* The cookie cfg80211_mgmt_tx_status() reports for this frame. sw_txhdr
* comes from a kmem_cache and is never zeroed, so every allocation site
* sets this: (unsigned long)skb, which is what the completion path
* reported before the field existed, except in rwnx_start_mgmt_xmit(),
* which stores the cfg80211-assigned cookie it was handed on 7.3+ (see
* use_given_cookie there). Only frames flagged TXU_CNTRL_MGMT are ever
* reported, but the field is initialised unconditionally so that filter
* is not what keeps it safe.
*/
u64 cookie;
size_t map_len; size_t map_len;
dma_addr_t dma_addr; dma_addr_t dma_addr;
@@ -169,7 +158,7 @@ netdev_tx_t rwnx_start_xmit(struct sk_buff *skb, struct net_device *dev);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct cfg80211_mgmt_tx_params *params, bool offchan, struct cfg80211_mgmt_tx_params *params, bool offchan,
u64 *cookie, bool use_given_cookie); u64 *cookie);
#else #else
int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta, int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
struct ieee80211_channel *channel, bool offchan, struct ieee80211_channel *channel, bool offchan,
@@ -180,11 +169,10 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0))
bool dont_wait_for_ack, bool dont_wait_for_ack,
#endif #endif
u64 *cookie, bool use_given_cookie); u64 *cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
#ifdef CONFIG_RWNX_MON_XMIT #ifdef CONFIG_RWNX_MON_XMIT
netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, int rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev);
struct net_device *dev);
#endif #endif
int rwnx_txdatacfm(void *pthis, void *host_id); int rwnx_txdatacfm(void *pthis, void *host_id);
-18
View File
@@ -1,18 +0,0 @@
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
@@ -1,233 +0,0 @@
// 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;
#if defined(CONFIG_ARM)
urb = (struct urb *)regs->ARM_r0;
#else
urb = (struct urb *)regs_get_kernel_argument(regs, 0);
#endif
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*");
+57 -104
View File
@@ -326,7 +326,6 @@ check_kernel_build_tree() {
cleanup_legacy_bluetooth_config() { cleanup_legacy_bluetooth_config() {
local legacy_conf="/etc/modprobe.d/aic8800-bt.conf" local legacy_conf="/etc/modprobe.d/aic8800-bt.conf"
local legacy_udev="/etc/udev/rules.d/90-aic8800-mode-switch.rules" local legacy_udev="/etc/udev/rules.d/90-aic8800-mode-switch.rules"
local legacy_package
local changed=false local changed=false
if [ -f "$legacy_conf" ] && grep -Eq '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' "$legacy_conf"; then if [ -f "$legacy_conf" ] && grep -Eq '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' "$legacy_conf"; then
@@ -359,21 +358,6 @@ cleanup_legacy_bluetooth_config() {
fi fi
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 if [ "$changed" = true ]; then
print_success "Legacy Bluetooth configuration cleaned up." print_success "Legacy Bluetooth configuration cleaned up."
fi fi
@@ -409,12 +393,17 @@ install_firmware() {
fi fi
done done
print_success "Firmware installed for all supported chip variants." print_success "Firmware installed for all chip variants:"
print_info " - aic8800D80 (standard)"
print_info " - aic8800D80N (N variant)"
print_info " - aic8800D80X2 (X2 variant)"
print_info " - aic8800DC/DW (DC/DW series)"
print_info " - aic8800DLN (DLN variant)"
# 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"
if [ -f "$rules_source" ]; then if [ -f "$rules_source" ]; then
print_info "Installing udev rules to $rules_dest..." print_info "Installing udev rules to $rules_dest..."
cp "$rules_source" "$rules_dest" >> "$LOG_FILE" 2>&1 cp "$rules_source" "$rules_dest" >> "$LOG_FILE" 2>&1
@@ -425,11 +414,11 @@ install_firmware() {
else else
print_warning "Udev rules file not found: $rules_source" print_warning "Udev rules file not found: $rules_source"
fi fi
# Install usb_modeswitch configuration for AIC8800D80 "Pandora" clone # Install usb_modeswitch configuration
local modeswitch_source="${SCRIPT_DIR}/usb_modeswitch/1111_1111" local modeswitch_source="${SCRIPT_DIR}/usb_modeswitch/1111_1111"
local modeswitch_dest="/etc/usb_modeswitch.d/1111:1111" local modeswitch_dest="/etc/usb_modeswitch.d/1111:1111"
if [ -f "$modeswitch_source" ]; then if [ -f "$modeswitch_source" ]; then
print_info "Installing usb_modeswitch configuration to $modeswitch_dest..." print_info "Installing usb_modeswitch configuration to $modeswitch_dest..."
mkdir -p /etc/usb_modeswitch.d >> "$LOG_FILE" 2>&1 || true mkdir -p /etc/usb_modeswitch.d >> "$LOG_FILE" 2>&1 || true
@@ -438,7 +427,7 @@ install_firmware() {
else else
print_warning "USB modeswitch configuration file not found: $modeswitch_source" print_warning "USB modeswitch configuration file not found: $modeswitch_source"
fi fi
print_success "Firmware installed successfully." print_success "Firmware installed successfully."
} }
@@ -476,11 +465,6 @@ 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
@@ -590,20 +574,6 @@ 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 modules..." print_step "Loading kernel modules..."
@@ -612,16 +582,14 @@ load_module() {
depmod -a >> "$LOG_FILE" 2>&1 depmod -a >> "$LOG_FILE" 2>&1
if lsmod | grep -q "$MODULE_NAME"; then if lsmod | grep -q "$MODULE_NAME"; then
print_info "Wi-Fi module already loaded. Reloading..." print_info "WiFi module already loaded. Reloading..."
modprobe -r "$MODULE_NAME" >> "$LOG_FILE" 2>&1 || true modprobe -r "$MODULE_NAME" >> "$LOG_FILE" 2>&1 || true
fi fi
# aic8800_fdrv depends on aic_load_fw, which initializes both Wi-Fi-only # Load the WiFi module
# 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 "Wi-Fi module loaded successfully." print_success "WiFi 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..."
@@ -635,29 +603,24 @@ load_module() {
done done
if [ "$module_loaded" = true ]; then if [ "$module_loaded" = true ]; then
print_success "Wi-Fi module is active in kernel." print_success "WiFi module is active in kernel."
else else
print_warning "Wi-Fi module may not be fully initialized yet." print_warning "WiFi module may not be fully initialized yet."
fi fi
else else
print_warning "Wi-Fi module installed but could not be loaded immediately." print_warning "WiFi 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." # Load the standard Bluetooth driver (btusb)
# The aic_load_fw module uploads the Bluetooth firmware, then btusb handles the BT interface
# The module has a USB alias and normally autoloads when 368b:8d81 appears. print_info "Loading standard Bluetooth driver (btusb)..."
# Explicitly load it here as well when that device was already present before if modprobe btusb >> "$LOG_FILE" 2>&1; then
# DKMS installation and therefore did not generate a new modalias event. print_success "Bluetooth driver (btusb) loaded successfully."
if aic_zlp_target_present; then else
print_info "Loading the 368b:8d81 Bluetooth ACL ZLP quirk..." print_warning "Could not load btusb driver automatically."
if modprobe aic_zlp_quirk >> "$LOG_FILE" 2>&1; then print_info "You can manually load it with: sudo modprobe btusb"
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 fi
} }
@@ -678,33 +641,21 @@ verify_installation() {
print_warning "DKMS status unclear: $dkms_status" print_warning "DKMS status unclear: $dkms_status"
fi fi
# Check if the Wi-Fi module is loaded # Check if WiFi module is loaded
if lsmod | grep -q "$MODULE_NAME"; then if lsmod | grep -q "$MODULE_NAME"; then
print_success "Wi-Fi kernel module is loaded." print_success "WiFi kernel module is loaded."
else else
print_info "Wi-Fi module not currently loaded (this is OK if no hardware is connected)." print_info "WiFi 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 # Check if Bluetooth is available via standard btusb
print_success "A Bluetooth controller or the standard btusb module is present." if lsmod | grep -q "btusb"; then
print_success "Bluetooth kernel module (btusb) is loaded."
else else
print_info "No Bluetooth controller is present (normal for Wi-Fi-only adapters or when no combo adapter is connected)." print_info "Bluetooth module (btusb) not currently loaded (this is OK if no hardware is connected)."
fi fi
if aic_zlp_target_present; then # Show all loaded AIC modules
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 "" echo ""
print_info "Loaded AIC modules:" print_info "Loaded AIC modules:"
lsmod | grep aic || echo " (none)" lsmod | grep aic || echo " (none)"
@@ -721,20 +672,21 @@ verify_installation() {
else else
print_warning "No firmware found in /lib/firmware/" print_warning "No firmware found in /lib/firmware/"
fi fi
# Check for wireless interfaces # Check for wireless interfaces
print_info "Checking for wireless interfaces..." print_info "Checking for wireless interfaces..."
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..." # Check for Bluetooth interfaces
if command -v bluetoothctl &> /dev/null; then print_info "Checking for Bluetooth interfaces..."
bluetoothctl list 2>/dev/null || echo "No Bluetooth interfaces detected (normal for Wi-Fi-only adapters)" if command -v hciconfig &> /dev/null; then
elif command -v hciconfig &> /dev/null; then hciconfig 2>/dev/null || echo "No Bluetooth interfaces detected (hardware may not be connected)"
hciconfig 2>/dev/null || echo "No Bluetooth interfaces detected (normal for Wi-Fi-only adapters)" elif command -v bluetoothctl &> /dev/null; then
bluetoothctl list 2>/dev/null || echo "No Bluetooth interfaces detected (hardware may not be connected)"
else else
echo "Bluetooth tools not installed (install BlueZ to manage a combo adapter)" echo "Bluetooth tools not installed (install bluez package for Bluetooth support)"
fi fi
} }
@@ -750,15 +702,14 @@ show_final_instructions() {
echo "" echo ""
echo -e "${CYAN}Important Information:${NC}" echo -e "${CYAN}Important Information:${NC}"
echo "" echo ""
echo "✓ Wi-Fi driver and firmware loader installed via DKMS" echo "✓ WiFi driver installed via DKMS"
echo "✓ Combo adapters use the standard Linux btusb driver" echo "✓ Bluetooth supported via standard btusb driver (after firmware upload)"
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 AIC8800 USB Wi-Fi or Wi-Fi/Bluetooth adapter" echo "1. Connect your AIC8800D80 USB WiFi/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}"
@@ -767,14 +718,14 @@ 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 " ${BLUE}sudo dmesg | grep btusb${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 "5. Check Bluetooth status:"
echo " ${BLUE}bluetoothctl list${NC}" echo " ${BLUE}bluetoothctl show${NC}"
echo " ${BLUE}bluetoothctl scan on${NC}" echo " ${BLUE}bluetoothctl scan on${NC}"
echo "" echo ""
echo -e "${CYAN}Troubleshooting:${NC}" echo -e "${CYAN}Troubleshooting:${NC}"
@@ -783,12 +734,14 @@ show_final_instructions() {
echo " ${BLUE}dkms status${NC}" echo " ${BLUE}dkms status${NC}"
echo "" echo ""
echo "• Check loaded modules:" echo "• Check loaded modules:"
echo " ${BLUE}lsmod | grep -E 'aic|btusb'${NC}" echo " ${BLUE}lsmod | grep aic${NC}"
echo " ${BLUE}cat /sys/module/aic_zlp_quirk/parameters/{hook,injections}${NC}"
echo "" echo ""
echo "• Manually load the Wi-Fi module and firmware loader:" echo "• Manually load the WiFi module:"
echo " ${BLUE}sudo modprobe aic8800_fdrv${NC}" echo " ${BLUE}sudo modprobe aic8800_fdrv${NC}"
echo "" echo ""
echo "• Manually load the Bluetooth module:"
echo " ${BLUE}sudo modprobe btusb${NC}"
echo ""
echo "• View detailed logs:" echo "• View detailed logs:"
echo " ${BLUE}cat $LOG_FILE${NC}" echo " ${BLUE}cat $LOG_FILE${NC}"
echo "" echo ""
@@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shen Mintao <cx330.shen@autocore.ai>
Date: Fri, 17 Jul 2026 21:00:00 +0800
Subject: [PATCH] Bluetooth: btusb: add bulk TX ZLP quirk for AIC 8800D80
The AIC 8800D80 controller can stop returning HCI Number Of Completed
Packets events during sustained AAC A2DP traffic when driven by the
generic btusb transport. Once the controller's ACL credits are
exhausted, the connection is terminated by the HCI ACL TX watchdog.
The vendor transport sets URB_ZERO_PACKET on every ACL bulk OUT URB.
Add an equivalent, device-specific quirk to btusb for the 368b:8d81
variant so that the standard kernel driver retains control of the
device.
This is intentionally limited to the USB ID from the reproducer while
the behaviour is validated on additional AIC variants.
Link: https://github.com/shenmintao/aic8800d80/issues/63
Signed-off-by: Shen Mintao <cx330.shen@autocore.ai>
---
drivers/bluetooth/btusb.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 830fefb342c6..97118c095369 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -67,6 +67,7 @@ static bool reset = true;
#define BTUSB_INTEL_NO_WBS_SUPPORT BIT(26)
#define BTUSB_ACTIONS_SEMI BIT(27)
#define BTUSB_BARROT BIT(28)
+#define BTUSB_BULK_TX_ZLP BIT(29)
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -178,5 +179,9 @@ MODULE_DEVICE_TABLE(usb, btusb_table);
static const struct usb_device_id quirks_table[] = {
+ /* AIC Semiconductor AIC 8800D80 */
+ { USB_DEVICE(0x368b, 0x8d81),
+ .driver_info = BTUSB_BULK_TX_ZLP },
+
/* CSR BlueCore devices */
{ USB_DEVICE(0x0a12, 0x0001), .driver_info = BTUSB_CSR },
@@ -949,6 +954,7 @@ struct btusb_data {
unsigned long flags;
bool poll_sync;
+ bool bulk_tx_zlp;
int intr_interval;
struct work_struct work;
struct work_struct waker;
@@ -2138,6 +2144,9 @@ static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
usb_fill_bulk_urb(urb, data->udev, pipe,
skb->data, skb->len, btusb_tx_complete, skb);
+ if (data->bulk_tx_zlp)
+ urb->transfer_flags |= URB_ZERO_PACKET;
+
skb->dev = (void *)hdev;
return urb;
@@ -4100,6 +4109,7 @@ static int btusb_probe(struct usb_interface *intf,
data->udev = interface_to_usbdev(intf);
data->intf = intf;
+ data->bulk_tx_zlp = id->driver_info & BTUSB_BULK_TX_ZLP;
INIT_WORK(&data->work, btusb_work);
INIT_WORK(&data->waker, btusb_waker);
--
2.50.1
+61
View File
@@ -0,0 +1,61 @@
# Issue #63: system `btusb` ZLP test
This test keeps the normal `aic_load_fw + btusb` architecture. It does not
restore or install the vendor `aic_btusb` driver.
The patch adds one quirk to the standard Linux `btusb` source:
- match only AICSemi `368b:8d81`;
- set `URB_ZERO_PACKET` on Bluetooth ACL bulk OUT transfers;
- leave every other `btusb` device and code path unchanged.
The test installer downloads the standard `btusb` source matching the running
kernel's upstream version, applies the patch, and installs the resulting
`btusb.ko` through DKMS. The distribution module is not overwritten and can be
restored by removing the DKMS test package.
## Install the test module
On Fedora, make sure the test build dependencies are installed:
```bash
sudo dnf install dkms gcc make kernel-devel-$(uname -r) curl patch
```
Stop Bluetooth scanning and disconnect Bluetooth devices, then run:
```bash
cd tests/issue63-btusb-zlp
sudo ./btusb-zlp-test.sh install
./btusb-zlp-test.sh status
```
`modinfo -n btusb` should point to an `updates/dkms` path. Secure Boot systems
may require the DKMS module to be signed or enrolled before it can load.
Select AAC again 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
```
Please capture `sudo btmon -w issue63-zlp.btsnoop` and relevant `dmesg` lines if
the connection still stalls.
## Restore the distribution module
```bash
sudo ./btusb-zlp-test.sh remove
./btusb-zlp-test.sh status
```
After removal, `modinfo -n btusb` should point back to the distribution's
`kernel/drivers/bluetooth/btusb.ko` path.
## Scope
This is an A/B diagnostic patch, not a production workaround. If AAC remains
stable, the small kernel patch can be submitted upstream. If it still fails,
the next isolated experiment should add an AIC-specific runtime-PM quirk rather
than replacing the standard Bluetooth driver.
+196
View File
@@ -0,0 +1,196 @@
#!/usr/bin/env bash
set -euo pipefail
PACKAGE_NAME="btusb-aic-zlp"
PACKAGE_VERSION="0.1"
KERNEL_RELEASE="${KERNEL_RELEASE:-$(uname -r)}"
UPSTREAM_VERSION="${UPSTREAM_VERSION:-$(printf '%s' "$KERNEL_RELEASE" | sed -nE 's/^([0-9]+\.[0-9]+\.[0-9]+).*/\1/p')}"
UPSTREAM_TAG="${UPSTREAM_TAG:-v${UPSTREAM_VERSION}}"
KERNEL_BUILD_DIR="/lib/modules/${KERNEL_RELEASE}/build"
SOURCE_DIR="/usr/src/${PACKAGE_NAME}-${PACKAGE_VERSION}"
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
PATCH_FILE="${SCRIPT_DIR}/0001-Bluetooth-btusb-add-AIC-bulk-TX-ZLP-quirk.patch"
BASE_URL="https://raw.githubusercontent.com/gregkh/linux/${UPSTREAM_TAG}/drivers/bluetooth"
log() {
printf '[btusb-zlp-test] %s\n' "$*"
}
die() {
printf '[btusb-zlp-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
}
rollback_test_install() {
log "rolling back to the distribution btusb module"
dkms remove -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" --all >/dev/null 2>&1 || true
rm -rf -- "${SOURCE_DIR}"
depmod -a "${KERNEL_RELEASE}" || true
modprobe btusb || true
start_bluetooth
}
activate_test_module() {
stop_bluetooth
if ! modprobe -r btusb; then
rollback_test_install
die "could not unload btusb; disconnect active Bluetooth devices and retry"
fi
if ! modprobe btusb; then
rollback_test_install
die "the patched btusb could not load; the distribution module was restored"
fi
start_bluetooth
}
write_build_files() {
cat > "${SOURCE_DIR}/Makefile" <<'EOF'
KVER ?= $(shell uname -r)
KDIR ?= /lib/modules/$(KVER)/build
obj-m += btusb.o
btusb-y := drivers/bluetooth/btusb.o
ccflags-y += -I$(src)/drivers/bluetooth
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
EOF
cat > "${SOURCE_DIR}/dkms.conf" <<'EOF'
PACKAGE_NAME="btusb-aic-zlp"
PACKAGE_VERSION="0.1"
MAKE[0]="make KVER=${kernelver}"
CLEAN="make KVER=${kernelver} clean"
BUILT_MODULE_NAME[0]="btusb"
BUILT_MODULE_LOCATION[0]="."
DEST_MODULE_LOCATION[0]="/updates/dkms"
AUTOINSTALL="no"
EOF
}
download_sources() {
local file
install -d "${SOURCE_DIR}/drivers/bluetooth"
for file in btusb.c btintel.h btbcm.h btrtl.h btmtk.h; do
log "downloading ${file} from Linux ${UPSTREAM_TAG}"
curl --fail --location --silent --show-error \
"${BASE_URL}/${file}" \
--output "${SOURCE_DIR}/drivers/bluetooth/${file}"
done
}
install_test_module() {
require_root
require_command curl
require_command dkms
require_command make
require_command modprobe
require_command patch
[ -n "${UPSTREAM_VERSION}" ] || die "could not derive an upstream version from ${KERNEL_RELEASE}"
[ -r "${KERNEL_BUILD_DIR}/Makefile" ] || die "kernel build tree not found: ${KERNEL_BUILD_DIR}"
[ -r "${PATCH_FILE}" ] || die "patch file not found: ${PATCH_FILE}"
if command -v lsusb >/dev/null 2>&1 && ! lsusb -d 368b:8d81 >/dev/null 2>&1; then
die "the test patch is restricted to USB device 368b:8d81, which is not connected"
fi
if dkms status -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" 2>/dev/null | grep -q .; then
log "removing an earlier test build"
dkms remove -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" --all || true
fi
rm -rf -- "${SOURCE_DIR}"
download_sources
write_build_files
log "applying the AIC bulk TX ZLP quirk"
patch --directory "${SOURCE_DIR}" --strip 1 --input "${PATCH_FILE}"
log "building patched system btusb 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}"
activate_test_module
log "loaded module: $(modinfo -n btusb)"
log "test AAC playback for at least one hour; use '$0 remove' to restore the distribution module"
}
remove_test_module() {
require_root
require_command dkms
require_command modprobe
stop_bluetooth
modprobe -r btusb || {
start_bluetooth
die "could not unload btusb; disconnect active Bluetooth devices and retry"
}
dkms remove -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" --all || true
rm -rf -- "${SOURCE_DIR}"
depmod -a "${KERNEL_RELEASE}"
modprobe btusb || {
start_bluetooth
die "the distribution btusb module could not be loaded"
}
start_bluetooth
log "restored module: $(modinfo -n btusb)"
}
show_status() {
printf 'kernel: %s\n' "${KERNEL_RELEASE}"
printf 'upstream tag: %s\n' "${UPSTREAM_TAG}"
printf 'btusb module: %s\n' "$(modinfo -n btusb 2>/dev/null || printf 'not found')"
printf 'dkms status: %s\n' "$(dkms status -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" 2>/dev/null || printf 'not installed')"
}
case "${1:-}" in
install)
install_test_module
;;
remove)
remove_test_module
;;
status)
show_status
;;
*)
printf 'Usage: %s {install|remove|status}\n' "$0" >&2
exit 2
;;
esac
-12
View File
@@ -1,12 +0,0 @@
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
-109
View File
@@ -1,109 +0,0 @@
# 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.
@@ -1,239 +0,0 @@
#!/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 integrated_dkms_status
local standalone_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
standalone_dkms_status="$(dkms status -m "${PACKAGE_NAME}" -v "${PACKAGE_VERSION}" 2>/dev/null || true)"
if [ -z "${standalone_dkms_status}" ]; then
standalone_dkms_status="not installed"
fi
integrated_dkms_status="$(dkms status -m aic8800 -v 1.0.0 2>/dev/null || true)"
if [ -z "${integrated_dkms_status}" ]; then
integrated_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 'integrated DKMS: %s\n' "${integrated_dkms_status}"
printf 'standalone DKMS: %s\n' "${standalone_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
-10
View File
@@ -1,10 +0,0 @@
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"
-44
View File
@@ -1,44 +0,0 @@
# OpenWrt backports build regression
This checks complete module compilation and MODPOST against real kernel and
wireless-stack headers. It requires an already prepared SDK/buildroot with
cfg80211/mac80211 headers and `mac80211.symvers` staged. It does not install
packages or load modules.
For the x86_64 SDK used in issue #94:
```sh
sdk=/path/to/openwrt-sdk
kernel="$sdk/build_dir/target-x86_64_musl/linux-x86_64/linux-6.12.94"
export STAGING_DIR="$sdk/staging_dir/target-x86_64_musl"
export PATH="$sdk/staging_dir/toolchain-x86_64_gcc-14.3.0_musl/bin:$PATH"
bash tests/openwrt-backports/build.sh \
"$kernel" "$STAGING_DIR/usr/include" \
"$kernel/../symvers/mac80211.symvers" 6.18.26 \
ARCH=x86_64 CROSS_COMPILE=x86_64-openwrt-linux-musl-
```
The script copies the current driver into a fresh temporary directory and
checks that all three `.ko` files are produced. Additional make arguments
can select a compiler or architecture. Use matching headers, configuration
and symbol versions throughout; changing only the version argument is not
a substitute for the matching wireless stack.
## Verified on 2026-09-17
- OpenWrt 25.12.5 x86_64 SDK: Linux 6.12.94, GCC 14.3.0, backports 6.18.26
with the mac80211 patches from OpenWrt revision `f5dae5ece4` applied:
all three modules compile and pass MODPOST with the kernel's `-Werror`.
- Original driver revision `9594c5c`, on the same kernel/backports combination:
reproduces both RX argument-count errors and the four incompatible
`set_monitor_channel`, `set_wiphy_params`, `set_tx_power`, `get_tx_power`
callbacks. This comparison uses `-Wno-error=unused-label`, as the issue's
log does, to reach those failures. The fixed build needs no such override.
- Native kernel headers 6.11.0-17, 6.17.0-14 and 7.2.0-070200, with
`CFG80211_VERSION` unset: all three modules compile and pass MODPOST.
The 7.2 check uses GCC 14 and reports compiler/attribute warnings because
those headers were built with GCC 15.
These are build checks. They do not validate an installable OpenWrt package,
firmware loading, Wi-Fi connectivity or Bluetooth operation on hardware.
-41
View File
@@ -1,41 +0,0 @@
#!/usr/bin/env bash
# Compile a source copy against a prepared kernel and staged wireless backport.
# Leaves the build directory for inspection; does not install or load modules.
set -euo pipefail
if [ "$#" -lt 4 ]; then
echo "Usage: $0 KERNEL_BUILD_DIR STAGED_INCLUDE_DIR MAC80211_SYMVERS CFG80211_VERSION [make arguments...]" >&2
exit 2
fi
kernel_dir=$(realpath "$1")
include_dir=$(realpath "$2")
symvers=$(realpath "$3")
wireless_version=$4
shift 4
for required in "$kernel_dir/Makefile" "$kernel_dir/Module.symvers" \
"$include_dir/mac80211/net/cfg80211.h" \
"$include_dir/mac80211-backport/backport/autoconf.h" "$symvers"; do
if [ ! -f "$required" ]; then
echo "Missing build input: $required" >&2
exit 2
fi
done
repo_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)
build_dir=$(mktemp -d "${TMPDIR:-/tmp}/aic8800-backports.XXXXXX")
cp -a "$repo_dir/drivers/aic8800/." "$build_dir/"
echo "Build directory: $build_dir"
make -C "$kernel_dir" M="$build_dir" \
NOSTDINC_FLAGS="-I$include_dir/mac80211-backport/uapi -I$include_dir/mac80211-backport -I$include_dir/mac80211/uapi -I$include_dir/mac80211 -include backport/backport.h" \
KBUILD_EXTRA_SYMBOLS="$symvers" \
CFG80211_VERSION="$wireless_version" \
-j"${JOBS:-2}" "$@" modules
for module in aic_load_fw/aic_load_fw.ko aic8800_fdrv/aic8800_fdrv.ko \
aic_zlp_quirk/aic_zlp_quirk.ko; do
test -s "$build_dir/$module"
done
echo "All three modules built successfully in $build_dir"
-87
View File
@@ -1,87 +0,0 @@
# 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
```
+3 -5
View File
@@ -2,8 +2,8 @@
# Sends vendor-specific SCSI CDB to trigger mode switch from # Sends vendor-specific SCSI CDB to trigger mode switch from
# USB Mass Storage to WiFi+BT mode. # USB Mass Storage to WiFi+BT mode.
# #
# The two 16-byte CDBs end in F3 and F2 respectively. Each is wrapped in a # The 16-byte CDB is: FD 00 00 00 00 00 00 00 00 00 00 00 00 00 00 F2
# standard 31-byte SCSI CBW (Command Block Wrapper), and must be sent in order. # Wrapped in a standard 31-byte SCSI CBW (Command Block Wrapper).
# #
# Install as: /etc/usb_modeswitch.d/1111:1111 # Install as: /etc/usb_modeswitch.d/1111:1111
# (The filename must contain a colon on Linux; this file is named # (The filename must contain a colon on Linux; this file is named
@@ -13,6 +13,4 @@ DefaultVendor=0x1111
DefaultProduct=0x1111 DefaultProduct=0x1111
TargetVendor=0xa69c TargetVendor=0xa69c
TargetProduct=0x8d80 TargetProduct=0x8d80
MessageContent="555342438765432100000000000010fd0000000000000000000000000000f3" MessageContent="555342438765432100000000000010fd0000000000000000000000000000f2"
MessageContent2="555342438765432100000000000010fd0000000000000000000000000000f2"
NeedResponse=1