mirror of
https://github.com/shenmintao/aic8800d80.git
synced 2026-09-26 17:44:16 +00:00
Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbc12c7bdb | ||
|
|
8006daf6c7 | ||
|
|
6b8cb98e96 | ||
|
|
7dc7569312 | ||
|
|
0ed5afba03 | ||
|
|
df8a44bf88 | ||
|
|
18d4be4228 | ||
|
|
0c9e2f1bca | ||
|
|
35c077823c | ||
|
|
7d7d9547b8 | ||
|
|
f40bda47c3 | ||
|
|
f1f825850b | ||
|
|
7779c8a285 | ||
|
|
6510278218 | ||
|
|
bfe239c9af | ||
|
|
43878adc39 | ||
|
|
58dff473e8 | ||
|
|
16b5d4af33 | ||
|
|
d8a8048929 | ||
|
|
13cccb953c | ||
|
|
52e968e765 | ||
|
|
ebab65c042 | ||
|
|
3e0c941337 | ||
|
|
3aa0191c7e | ||
|
|
089be7c4ff | ||
|
|
41b5208909 | ||
|
|
f2e73a92ab | ||
|
|
6a2d56d055 | ||
|
|
165a346c4d | ||
|
|
b0787d9989 | ||
|
|
86aa95ffcb | ||
|
|
cf63c8e0ee | ||
|
|
f2d9cc9ff0 | ||
|
|
f36a0afeb4 | ||
|
|
b771774f40 | ||
|
|
600cdf5ef4 | ||
|
|
8a5af5cfdb | ||
|
|
85a412e5b8 | ||
|
|
4f288d90b2 | ||
|
|
8b90bd8f45 | ||
|
|
96e1d9cd3d |
+2
-7
@@ -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
|
|
||||||
|
|||||||
+2
-9
@@ -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
|
||||||
|
|||||||
-67
@@ -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.
|
|
||||||
@@ -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
|
||||||
|
```
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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.
|
||||||
|
|||||||
+95
-113
@@ -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)
|
vid=$(cat "$dev/idVendor" 2>/dev/null)
|
||||||
pid=$(cat "$dev/idProduct" 2>/dev/null)
|
pid=$(cat "$dev/idProduct" 2>/dev/null)
|
||||||
case "$vid" in
|
if [[ "$vid" == "a69c" || "$vid" == "368b" ]]; then
|
||||||
a69c|368b|3625) ;;
|
echo " 设备: $vid:$pid"
|
||||||
*) continue ;;
|
if [ -d "$dev" ]; then
|
||||||
esac
|
|
||||||
|
|
||||||
echo " Device: $vid:$pid"
|
|
||||||
if [ "$vid" = "368b" ] && [ "$pid" = "8d81" ]; then
|
|
||||||
zlp_target_found=true
|
|
||||||
fi
|
|
||||||
for intf in "$dev"/*:*; do
|
for intf in "$dev"/*:*; do
|
||||||
[ -d "$intf" ] || continue
|
if [ -d "$intf" ]; then
|
||||||
class=$(cat "$intf/bInterfaceClass" 2>/dev/null)
|
class=$(cat "$intf/bInterfaceClass" 2>/dev/null)
|
||||||
subclass=$(cat "$intf/bInterfaceSubClass" 2>/dev/null)
|
subclass=$(cat "$intf/bInterfaceSubClass" 2>/dev/null)
|
||||||
protocol=$(cat "$intf/bInterfaceProtocol" 2>/dev/null)
|
protocol=$(cat "$intf/bInterfaceProtocol" 2>/dev/null)
|
||||||
driver=$(basename "$(readlink "$intf/driver" 2>/dev/null)" 2>/dev/null)
|
driver=$(basename "$(readlink "$intf/driver" 2>/dev/null)" 2>/dev/null)
|
||||||
echo " $(basename "$intf"): ${class:-??}/${subclass:-??}/${protocol:-??} -> ${driver:-unbound}"
|
echo " 接口: $class/$subclass/$protocol -> 驱动: ${driver:-未绑定}"
|
||||||
|
|
||||||
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
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
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 "=== 诊断完成 ==="
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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/
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|||||||
@@ -1518,17 +1518,6 @@ static int rwnx_close(struct net_device *dev)
|
|||||||
|
|
||||||
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
RWNX_DBG(RWNX_FN_ENTRY_STR);
|
||||||
|
|
||||||
/*
|
|
||||||
* A CONNECTING/DISCONNECTING state is only left when the firmware answers
|
|
||||||
* the pending request. If the bus is already down the answer can never
|
|
||||||
* arrive: rwnx_send_msg() silently drops the message and returns 0
|
|
||||||
* (rwnx_msg_tx.c), so the wait below would always run its full timeout and
|
|
||||||
* fire the spurious WARN_ON() during USB teardown. Skip the wait when the
|
|
||||||
* bus is down, using the same condition the vif_started path uses below.
|
|
||||||
*/
|
|
||||||
if (bus_if &&
|
|
||||||
(usbdev == NULL || (usbdev->bus_if->state != BUS_DOWN_ST &&
|
|
||||||
usbdev->state != USB_DOWN_ST))) {
|
|
||||||
test_counter = waiting_counter;
|
test_counter = waiting_counter;
|
||||||
while(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING||
|
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){
|
atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTING){
|
||||||
@@ -1541,7 +1530,6 @@ static int rwnx_close(struct net_device *dev)
|
|||||||
break;
|
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,10 +1587,6 @@ 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
|
|
||||||
* confirmation cannot arrive, so do not wait for it. */
|
|
||||||
if (usbdev->bus_if->state != BUS_DOWN_ST &&
|
|
||||||
usbdev->state != USB_DOWN_ST) {
|
|
||||||
rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, 3);
|
rwnx_send_sm_disconnect_req(rwnx_hw, rwnx_vif, 3);
|
||||||
while (atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING) {
|
while (atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING) {
|
||||||
AICWFDBG(LOGDEBUG, "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", __func__);
|
AICWFDBG(LOGDEBUG, "%s wifi is disconnecting, waiting 100ms for state to stable\r\n", __func__);
|
||||||
@@ -1613,7 +1597,6 @@ static int rwnx_close(struct net_device *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#ifdef CONFIG_USE_P2P0
|
#ifdef CONFIG_USE_P2P0
|
||||||
if(!rwnx_vif->is_p2p_vif || ( rwnx_vif->is_p2p_vif && rwnx_hw->is_p2p_alive)){
|
if(!rwnx_vif->is_p2p_vif || ( rwnx_vif->is_p2p_vif && rwnx_hw->is_p2p_alive)){
|
||||||
if (rwnx_vif->is_p2p_vif)
|
if (rwnx_vif->is_p2p_vif)
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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, ¶ms, false, &cookie, false);
|
ret = rwnx_start_mgmt_xmit(rwnx_vif, NULL, ¶ms, 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;
|
||||||
|
|||||||
@@ -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,17 +1703,6 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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;
|
*cookie = (unsigned long)skb;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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*");
|
|
||||||
+46
-93
@@ -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,7 +393,12 @@ 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"
|
||||||
@@ -426,7 +415,7 @@ install_firmware() {
|
|||||||
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"
|
||||||
|
|
||||||
@@ -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
|
|
||||||
print_info "Loading the 368b:8d81 Bluetooth ACL ZLP quirk..."
|
|
||||||
if modprobe aic_zlp_quirk >> "$LOG_FILE" 2>&1; then
|
|
||||||
print_success "Device-scoped Bluetooth ZLP quirk is active."
|
|
||||||
else
|
else
|
||||||
print_warning "The ZLP quirk could not attach; system btusb remains unchanged."
|
print_warning "Could not load btusb driver automatically."
|
||||||
print_info "Check CONFIG_KPROBES, Secure Boot, and: sudo dmesg | grep aic_zlp_quirk"
|
print_info "You can manually load it with: sudo modprobe btusb"
|
||||||
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
|
|
||||||
|
|
||||||
if aic_zlp_target_present; then
|
|
||||||
if lsmod | awk '{print $1}' | grep -qx 'aic_zlp_quirk'; then
|
|
||||||
local zlp_hook="unknown"
|
|
||||||
if [ -r /sys/module/aic_zlp_quirk/parameters/hook ]; then
|
|
||||||
zlp_hook=$(cat /sys/module/aic_zlp_quirk/parameters/hook)
|
|
||||||
fi
|
|
||||||
print_success "Bluetooth ACL ZLP quirk is loaded (hook: $zlp_hook)."
|
|
||||||
else
|
|
||||||
print_warning "USB device 368b:8d81 is present but aic_zlp_quirk is not loaded."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
print_info "Bluetooth ZLP quirk is installed but inactive (no 368b:8d81 device present)."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Show all loaded AIC modules
|
||||||
echo ""
|
echo ""
|
||||||
print_info "Loaded AIC modules:"
|
print_info "Loaded AIC modules:"
|
||||||
lsmod | grep aic || echo " (none)"
|
lsmod | grep aic || echo " (none)"
|
||||||
@@ -728,13 +679,14 @@ verify_installation() {
|
|||||||
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
|
||||||
@@ -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.
|
||||||
Executable
+196
@@ -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
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -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"
|
|
||||||
@@ -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.
|
|
||||||
@@ -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"
|
|
||||||
@@ -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
|
|
||||||
```
|
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user