Author SHA1 Message Date
Shen MintaoandClaude Opus 5.5 332677e771 docs: document OpenWrt cfg80211 backport builds
27af5ad added the CFG80211_VERSION make variable for OpenWrt builds that
use a newer mac80211 backport than the target kernel, but it is only
described in a Makefile comment. Document how to pass it from an OpenWrt
package Makefile, link the notes from the installation steps, and add
the build script and the kernel/backports combinations verified for
issue #94.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 14:59:53 +08:00
Shen MintaoandClaude Opus 5.5 a86affa3c6 fix: use monotonic snapshot versions for the Bazzite package
The spec used the pinned commit hash as Version, and rpm does not order
hashes by commit history: 51b7b6e sorts after c8327ea, and 13baa9b after
e93a7d2, so a newer snapshot could be treated as an older package.

Version snapshots as 1.0.0^<date>git<commit>, where 1.0.0 is the DKMS
PACKAGE_VERSION, and add Epoch 1 so every snapshot sorts after all of
the earlier hash versions. Checked with rpm 4.18: the spec parses and
the new EVR compares newer than every previous Version.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 14:03:17 +08:00
Shen MintaoandClaude Opus 5.5 6229bf3c7e fix: build the legacy Bazzite package on Linux 7.2
The legacy spec still pins 51b7b6e, which predates 44748e1 ("fix:
support Linux 7.2 cfg80211 API"). Against Linux 7.2 headers that
snapshot fails with an implicit declaration of strncpy() and an
incompatible cfg80211_ops::remain_on_channel initializer, the same
failure dd74ae6 fixed for the main package.

Pin c8327ea, which also carries the fixes synchronized from main, and
reset Release for the new snapshot. The pinned tree builds all three
modules against 7.2.6 headers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 13:42:37 +08:00
Shen Mintao c8327eab5b feat: enable monitor packet injection
Build the existing monitor transmit path by default. Validate the radiotap header before parsing it and align the transmit prototype with netdev_tx_t.

Hardware-tested-by: jkroepke (GitHub)
2026-09-24 13:38:13 +08:00
Lucas Kawatoko b0ef216ed8 fix: handle set_monitor_channel dev parameter on 6.12 stable
cfg80211_ops.set_monitor_channel() gained a "struct net_device *dev"
parameter in mainline 6.13, and the change was backported to the 6.12
stable series starting with 6.12.101. Debian 13 ships 6.12.107, so the
existing ">= 6.13.0" guards select the old prototype there and the build
fails 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 *)'
    [-Wincompatible-pointer-types]

This is the failure reported in #96 for Debian 13 trixie.

Introduce AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV in rwnx_compat.h,
defined at AICWF_CFG80211_VERSION_CODE >= 6.12.101, and gate the nine
set_monitor_channel call sites on it instead of comparing against 6.13.0.
The threshold covers both the 6.12 backport and mainline 6.13, while
kernels 6.11 and earlier 6.12.x keep the old prototype. The check now
lives in one place and follows the existing AICWF_CFG80211_VERSION_CODE
convention, so OpenWrt builds can override it with CFG80211_VERSION.

The MODULE_IMPORT_NS guard at rwnx_main.c that also checks 6.13.0 is
unrelated and is left untouched.

Verified with clean builds against linux-headers 5.15.0-191,
6.1.0-53, 6.8.0-139, 6.11.0-8 and 6.12.107+deb13.
2026-09-24 13:25:15 +08:00
Shen Mintao 0dfe7588fc fix: support OpenWrt cfg80211 backport versions
Allow CFG80211_VERSION to select wireless API signatures independently of the target kernel. Keep native kernel builds on their existing version checks.

Also guard the WEXT-only label and replace overlapping firmware path formatting with bounded appends so OpenWrt builds pass with Werror.

Validated all three modules against OpenWrt Linux 6.12.94 with backports 6.18.26, plus native 6.11, 6.17 and 7.2 headers. Refs #94.
2026-09-24 13:25:15 +08:00
Shen Mintao 40f1d081e9 fix: sync upstream SUN60IW2P1 USB transfer settings
Disable CONFIG_USB_ALIGN_DATA and enable CONFIG_USB_NO_TRANS_DMA_MAP
when CONFIG_ARCH_SUN60IW2P1 is set, following the upstream USB controller
workaround. Preserve the current defaults on other platforms.

Source: radxa-pkg/aic8800 commit 33f19ba,
fix-usbc1-controller-wifi-rate-of-sun60iw2p1.patch.

Validation: GNU make resolves the expected settings for both platform
branches; Linux 6.14, 6.17 and 7.2 module builds succeeded. No SUN60IW2P1
hardware was available for runtime validation.
2026-09-24 13:25:15 +08:00
Shen Mintao 966de5e878 fix: correct TDLS discovery response length on Linux 7.1+
Linux 7.1 moved action_code outside tdls_discover_resp. Reserve both
category and action_code bytes before the response body so appending an
IE does not overwrite the capability field.

Sync the USB hunk from radxa-pkg/aic8800 commit
bd01abe95bc83c4708dd1d117e27424ee41cc747.

Validation: Linux 6.14, 6.17 and 7.2 module builds succeeded. A focused
frame construction check detects the original one-byte overwrite and
passes with this change. Hardware TDLS operation remains untested.
2026-09-24 13:25:15 +08:00
Shen Mintao 4b717f4048 docs: document Pandora mode switching 2026-08-17 01:21:09 +08:00
Shen Mintao 0e56f1a1f8 fix: use two-stage Pandora mode switch 2026-08-17 01:21:09 +08:00
Shen Mintao 8378d2ce34 fix: scope TP-Link AX900 match to Wi-Fi interface 2026-08-11 17:43:14 +08:00
YaQia 2384dbe450 feat: add USB ID for TP-Link AX900 (2357:014e)
This adapter uses the AIC8800D80 chipset and was previously not
matched by the fdrv probe. Add vendor/product IDs so the driver
binds and both Wi-Fi and Bluetooth (via standard btusb) work.

Tested on Linux 7.1.6 with TP-Link AX900 TL-XDN7000H.
2026-08-11 17:43:14 +08:00
Shen Mintao 8cbefea252 feat: add mode switch rule for AIC8800DE 2026-08-09 17:05:11 +08:00
Shen Mintao 655c14f9f3 feat: support AIC8800DE USB variant 2026-08-09 17:05:11 +08:00
Shen Mintao 44748e193a fix: support Linux 7.2 cfg80211 API 2026-08-08 12:22:08 +08:00
Shen Mintao 35f32c238c fix: avoid USB reboot hang after suspend 2026-08-08 12:22:08 +08:00
Shen Mintao 1b7c44ddd4 fix: respect caller build parallelism 2026-08-08 12:22:08 +08:00
Shen Mintao 5ea5196eea fix: prevent monitor RX null dereference
Do not send monitor frames through the normal data path when simultaneous monitor/data support is disabled. Handle monitor skb allocation failures without dereferencing NULL or dropping the original combined-mode frame.

Fixes #83

(cherry picked from commit 531d16c4d6)
2026-08-07 16:15:55 +08:00
Shen Mintao fffad12a26 fix: support ARM32 ZLP kprobe arguments
Read the first kernel argument from ARM_r0 on 32-bit ARM, where regs_get_kernel_argument() is unavailable.

Fixes #82

(cherry picked from commit 40f00e69af)
2026-08-06 16:34:32 +08:00
Shen Mintao 95d889d961 fix: update legacy Bazzite packaging 2026-07-29 09:36:05 +08:00
Shen Mintao 4bae903599 docs: finalize two-branch maintenance model 2026-07-25 19:42:46 +08:00
MinQ 51b8ab8062 Merge pull request #74 from shenmintao/test/legacy-mcu1-unified-bt-zlp
feat: unify legacy Wi-Fi Bluetooth and ZLP support
2026-07-25 19:40:47 +08:00
Shen Mintao ded6920d06 merge: sync validated Bluetooth diagnostics 2026-07-25 19:15:26 +08:00
Shen Mintao eb3aad9e8d fix: clarify integrated Bluetooth diagnostics 2026-07-25 19:15:07 +08:00
Shen Mintao bbc1a04e59 docs: deduplicate legacy retirement notice 2026-07-25 16:07:28 +08:00
Shen Mintao e7b7599ad9 merge: sync unified Bluetooth retirement notice 2026-07-25 16:06:45 +08:00
Shen Mintao b100e7a7ec merge: sync legacy Bluetooth retirement notice 2026-07-25 16:06:35 +08:00
Shen Mintao e53523ba48 merge: sync Bluetooth retirement notice from main
# Conflicts:
#	README.md
2026-07-25 16:06:11 +08:00
Shen Mintao 957b5f5a82 docs: clarify Bluetooth retirement on legacy branch 2026-07-25 16:05:16 +08:00
Shen Mintao 0d7a07e8aa docs: announce Bluetooth branch retirement 2026-07-25 16:04:38 +08:00
Shen Mintao 1358e55a0e fix: refresh Bazzite package for unified legacy branch 2026-07-25 15:54:52 +08:00
Shen Mintao 51b7b6e729 test: unify legacy Wi-Fi Bluetooth and ZLP support
# Conflicts:
#	.gitattributes
#	README.md
2026-07-25 15:54:23 +08:00
Shen Mintao 800a7b93ba fix: refresh Bazzite package for unified ZLP branch 2026-07-25 15:52:29 +08:00
Shen Mintao 13baa9b0b1 feat: unify Bluetooth support and add ZLP quirk 2026-07-25 15:49:53 +08:00
Shen Mintao 6550131e18 test: add standalone btusb ZLP quirk module 2026-07-25 15:40:59 +08:00
Shen Mintao 268c4f7122 fix: refresh Bazzite package for unified branch 2026-07-25 15:38:56 +08:00
Shen Mintao c83ae8b4e6 test: unify Wi-Fi and Bluetooth installation 2026-07-25 15:38:47 +08:00
Shen Mintao 4b31d02392 docs: explain hardware branch selection 2026-07-25 15:29:46 +08:00
Shen Mintao 1f0c3e28ac docs: point issue 71 to maintained legacy commit 2026-07-24 14:28:47 +08:00
Shen Mintao 59e6b00abe docs: add DC/DW support to legacy MCU1 profile 2026-07-24 14:26:48 +08:00
Shen Mintao dbfbfa0c64 test: use complete V3 DC/DW profile for issue 71 2026-07-24 14:24:30 +08:00
Shen Mintao cc2a888d22 docs: promote MCU1 legacy firmware profile 2026-07-24 09:14:27 +08:00
Shen Mintao 027a7a8662 test: restore MCU1 cache fix for V3 firmware 2026-07-23 09:10:43 +08:00
Shen Mintao 7b2541e5c0 test: match D80 loader to legacy firmware 2026-07-22 16:55:44 +08:00
Shen Mintao bff42860ff test: add legacy D80 firmware for issue 58 2026-07-21 19:59:51 +08:00
Shen Mintao 388a0192c7 fix: refresh Bazzite package for main branch
Pin the Wi-Fi package to the current main code commit, ship both maintained modules and all firmware variants, and remove obsolete Bluetooth packaging.
2026-07-14 17:38:28 +08:00
Shen Mintao d10bc52903 fix: improve dependency installation diagnostics
Install mode-switch dependencies, support a69c:572f, avoid redundant generic headers when a usable kernel build tree exists, and discover DKMS logs dynamically. Addresses installer portions of #28, #55, #65, #66, and #68.
2026-07-14 17:18:27 +08:00
Shen Mintao 3f9916b6ff fix: retry DKMS install when existing modules block install 2026-06-25 19:55:41 +08:00
Shen Mintao c5e635bf4c fix: handle Volumio and early firmware loading 2026-06-25 19:48:22 +08:00
Shen Mintao f97281254a fix: write radiotap HE fields without struct copy 2026-06-25 19:38:56 +08:00
Shen Mintao 46f420f8f6 fix: avoid fortify warning in patch info unpack 2026-06-25 19:33:01 +08:00
Shen Mintao 8bf93919e7 fix: support newer kernel cfg80211 APIs 2026-06-25 19:26:34 +08:00
Shen MintaoandClaude Opus 4.7 a5db07c4d4 fix: install all firmware variants and usb_modeswitch config
Follow-up to d66e5cb which shipped fw/aic8800{,D80N,D80X2,DLN} but
forgot to update install.sh — so users still got only aic8800D80
firmware installed and the "Pandora" mode-switch config was missing.

install_firmware:
- Loop over all fw/aic8800* variants instead of hard-coding aic8800D80
- Install usb_modeswitch/1111_1111 to /etc/usb_modeswitch.d/1111:1111

verify_installation: count installed firmware variants instead of
checking for the single aic8800D80 directory.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 14:06:08 +08:00
Shen MintaoandClaude Opus 4.7 d66e5cb859 feat: update to SDK v5.0 with comprehensive kernel and device support
Sync WiFi driver, firmware, and DKMS configuration from the bluetooth
branch (which itself is radxa USB driver_fw + Linux 6.16/6.17/6.19
kernel compat). aic_btusb and Bluetooth-specific install.sh logic
are intentionally excluded from main.

Driver updates:
- Add Linux kernel 6.12-6.19 compatibility support
- Add Linux 6.16 timer_container_of and wakelock API support
- Add Debian 6.1.0-26 backport support
- Add USB device ID 368b:8d81 support
- Add AIC8800DW device support
- Add TP-Link Archer TX1U Nano support (USB_VENDOR_ID_TENDA_V2:0x0110)
- Add TENDA series device support (U2, U11, U11 PRO)
- Add AIC8800FC_CUS1-6 series support
- Add AIC8800M80_CUS0-8 series support
- Add UGREEN AIC8800D80 adapter support
- Add Mercury (TP-Link OEM) support
- Allow 1 or 3 USB interfaces (BT-disabled SKUs report 1)

New compat modules:
- aicwf_compat_8800d80n.{c,h}
- aicwf_compat_8800dln.{c,h}

Firmware:
- New: fw/aic8800/, fw/aic8800D80N/, fw/aic8800D80X2/, fw/aic8800DLN/
- Updated: fw/aic8800D80/, fw/aic8800DC/

install.sh:
- Loop over all fw/aic8800* variants instead of hard-coding aic8800D80
- Install usb_modeswitch/1111_1111 config for "Pandora" clone adapter
- Verify firmware install by counting variants

dkms.conf: pass KDIR explicitly to make for cross-kernel builds.

Excluded from this commit (BT-only, kept on bluetooth branch):
- drivers/aic8800/aic_btusb/
- modprobe/aic8800-bt.conf
- diagnose_bt.sh
- install.sh btusb auto-load / hciconfig / bluez status checks

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 14:02:08 +08:00
MinQ 9a3b01eead Merge pull request #51 from toor11/add-usb-id-368b-8d84
Add USB ID 368b:8d84 (AIC 8800D80 variant)
2026-05-20 09:42:46 +08:00
toor11 0bcec3069e Add USB ID 368b:8d84 (AIC 8800D80 variant)
Device 368b:8d84 is an AIC 8800D80 variant not included in the USB
device table. Add it as AIC8800M80_CUS0 alongside the other M80 CUS
variants; it maps to PRODUCT_ID_AIC8800D81 like its siblings.

Tested on kernel 6.19.8-arch1 with a physical dongle (Bus 001 Device
005: ID 368b:8d84 AICSemi AIC 8800D80).
2026-05-11 20:14:30 +02:00
MinQ f8df5e741e Merge pull request #45 from Nurmukhamed/main
fixed README.md after requests of telegram users.
2026-04-28 15:27:01 +08:00
Nurmukhamed Artykaly d1b60ff10d fixed README.md after requests of telegram users. 2026-04-11 20:06:20 +05:00
MinQ 05710dff05 Merge pull request #42 from l27001/main
fix: map riscv64 to riscv for kernel ARCH
2026-03-31 09:22:31 +08:00
Vladislav Tatyanin ed0e373a0d fix: map riscv64 to riscv for kernel ARCH 2026-03-30 14:57:59 +04:00
Shen MintaoandClaude Sonnet 4.5 2bf62be7c8 Add support for TP-Link/Mercury branded AIC8800D80 USB WiFi adapters
Added USB VID/PID for TP-Link vendor (0x2357) and Mercury product (0x014b)
to support WiFi adapters that re-enumerate with these IDs after firmware
loading. The device is recognized as AIC8800D81 chip with RX aggregation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-03-13 13:17:46 +08:00
MinQ 6e9be3b658 Merge pull request #38 from Nurmukhamed/main
added Bazzite SRPM instructions.
2026-03-09 17:11:53 +08:00
Nurmukhamed Artykaly 6a37c4224b added missed aic_btusb module. 2026-03-09 13:41:40 +05:00
Nurmukhamed Artykaly 7e420f3745 fixed error after trying build. 2026-03-09 12:43:13 +05:00
Nurmukhamed Artykaly 6c2496a2dc fixed after comment on github. 2026-03-09 12:28:38 +05:00
Nurmukhamed Artykaly 953488c4bd refactored, added bluetooth branch. 2026-03-08 12:11:25 +05:00
Nurmukhamed Artykaly fd0867729f fixed github raw url. 2026-03-07 22:27:30 +05:00
Nurmukhamed Artykaly 31aa18b841 small fix. 2026-03-07 21:24:24 +05:00
Nurmukhamed Artykaly 15a9272867 added Bazzite SRPM instructions. 2026-03-07 21:18:40 +05:00
156 changed files with 6380 additions and 1654 deletions
+11
View File
@@ -0,0 +1,11 @@
fw/aic8800D80/*.txt text eol=lf
fw/aic8800D80/*.bin binary
fw/aic8800DC/*.txt text eol=lf
fw/aic8800DC/*.bin binary
/.gitattributes text eol=lf
drivers/aic8800/aic_zlp_quirk/*.c text eol=lf
drivers/aic8800/aic_zlp_quirk/Makefile text eol=lf
tests/issue63-zlp-quirk/*.conf text eol=lf
tests/issue63-zlp-quirk/*.md text eol=lf
tests/issue63-zlp-quirk/*.sh text eol=lf
tests/issue63-zlp-quirk/Makefile text eol=lf
+8 -1
View File
@@ -2,12 +2,19 @@
## Overview
This automated installation script (`install.sh`) simplifies the process of installing the AIC8800D80 WiFi driver on Linux systems.
This automated installation script (`install.sh`) installs the AIC8800 Wi-Fi
driver and firmware loader on Linux systems. Wi-Fi/Bluetooth combo adapters use
the standard kernel `btusb` driver after firmware initialization. For USB
device `368b:8d81`, it also installs a device-scoped ACL bulk TX ZLP companion
module without replacing the distribution's `btusb.ko`.
- Automatic Secure Boot detection
- Automatic dependency installation
- Automatic driver compilation and installation
- Automatic module loading on boot
- Automatic cleanup of obsolete `aic_btusb` configuration
- Automatic `aic_zlp_quirk` handling for the validated `368b:8d81` device
- Wi-Fi-only and Wi-Fi/Bluetooth combo adapter support from the same branch
- Comprehensive error handling
- Colored output and logging
- Compatible with Ubuntu, Debian, Fedora, and derivatives (DKMS supported `dkms.conf`)
+67
View File
@@ -0,0 +1,67 @@
# 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.
+114 -7
View File
@@ -1,11 +1,45 @@
# AIC8800D80 Linux Driver
This driver is for the AIC8800D80 chipset, supported by devices such as the Tenda U11 and AX913B.
# AIC8800 Linux Wi-Fi and Bluetooth Driver
This driver supports AIC8800-family chipsets used by devices such as the Tenda U11, AX913B, and TP-Link Archer TX1U Nano.
> **Legacy MCU revision 1 branch:** You are viewing `legacy-mcu1`. This branch
> is only for AIC8800D80 or AIC8800DC/DW devices that report
> `chip_id=7, chip_mcu_id=1`. It provides complete matched V3 firmware and
> loader profiles for the D80 upload-limit failure validated in
> [issue #58](https://github.com/shenmintao/aic8800d80/issues/58) and the DC/DW
> V5 main-application timeout validated in
> [issue #71](https://github.com/shenmintao/aic8800d80/issues/71). Use
> [`main`](https://github.com/shenmintao/aic8800d80/tree/main) for newer
> `chip_mcu_id=0` hardware or when the MCU revision is unknown. See the
> [D80](tests/issue58-mcu1-legacy-fw/README.md) and
> [DC/DW](tests/issue71-mcu1-v3-profile/README.md) support notes before installing.
>
> After switching branches, rerun `sudo ./install.sh` and reboot; switching the
> Git branch alone does not replace firmware already installed under
> `/lib/firmware`.
Added support for devices with Vendor ID 368B (tested).
Tested on Linux kernel 6.16 with Ubuntu 25.04 and 6.1.0.27 with Debian 12.
> **Bluetooth Support**: The [`bluetooth`](https://github.com/shenmintao/aic8800d80/tree/bluetooth) branch fully supports Bluetooth. This main branch only provides Wi-Fi functionality. Please switch to the `bluetooth` branch if you need Bluetooth support.
The same driver supports Wi-Fi-only adapters and Wi-Fi/Bluetooth combo
adapters. On combo devices, `aic_load_fw` uploads the AIC firmware and the
standard Linux `btusb` driver handles the Bluetooth HCI interface. The obsolete
custom `aic_btusb` module is not used.
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.
> [!NOTE]
> **Maintained branches:** This repository now maintains only `main` and
> `legacy-mcu1`. You are viewing the branch for `chip_mcu_id=1`; do not switch
> this hardware to the former separate `bluetooth` branch, which is retired.
> Wi-Fi, the kernel's standard `btusb` Bluetooth path, and the device-scoped
> `368b:8d81` ZLP support are integrated here. The ZLP module remains inactive
> on other VID:PID combinations.
### 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.
@@ -13,25 +47,49 @@ I did not develop this software, The code is sourced from the Tenda U11 driver.
### Attention
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
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 2: Manual Installation
#### Copy udev rules:
Copy the aic.rules file to /lib/udev/rules.d/:
Copy the aic.rules file to /usr/lib/udev/rules.d/:
```bash
sudo cp aic.rules /lib/udev/rules.d/
sudo cp aic.rules /usr/lib/udev/rules.d/
```
#### Copy firmware:
Copy the aic8800D80 folder from ./fw to /lib/firmware/:
Copy the firmware directories from `./fw` to `/lib/firmware/`:
```bash
sudo cp -r ./fw/aic8800D80 /lib/firmware/
sudo cp -r ./fw/aic8800* /lib/firmware/
```
#### Navigate to the driver directory:
@@ -98,3 +156,52 @@ If the device is still not active, check the kernel logs for any errors related
sudo dmesg
```
### Bluetooth on Combo Adapters
Bluetooth support does not require a separate AIC transport module. After
`aic_load_fw` initializes a combo adapter, the kernel automatically binds its
Bluetooth interface to `btusb`. A Wi-Fi-only adapter does not expose that
interface, so the Bluetooth path remains inactive.
Verify the expected modules and controller with:
```bash
lsmod | grep -E 'aic_load_fw|aic8800_fdrv|aic_zlp_quirk|btusb'
lsusb -t
bluetoothctl list
```
To scan after a controller appears:
```bash
bluetoothctl
power on
scan on
```
If Bluetooth is missing or reports HCI timeouts, run the read-only diagnostic
script and attach its output together with the current boot log:
```bash
chmod +x diagnose_bt.sh
sudo ./diagnose_bt.sh
sudo journalctl -k -b --no-pager
```
The installer removes active references to the retired `aic_btusb` integration.
It does not force-load `btusb` or globally change the Bluetooth rfkill state;
normal kernel device matching and the user's system policy remain in control.
For `368b:8d81`, verify the ZLP hook and its injection counter while Bluetooth
traffic is active:
```bash
cat /sys/module/aic_zlp_quirk/parameters/hook
cat /sys/module/aic_zlp_quirk/parameters/injections
```
The Wi-Fi-reset recovery behavior tracked in
[issue #53](https://github.com/shenmintao/aic8800d80/issues/53) remains a known
limitation: after an airplane-mode or hotspot reset, Bluetooth may require a
physical unplug/replug of the adapter.
+6
View File
@@ -1,4 +1,6 @@
# 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}=="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}=="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"
@@ -6,3 +8,7 @@ KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5726", SYMLINK+="ten
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="5727", SYMLINK+="tendaudiskv4", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572a", SYMLINK+="tendaudiskv5", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572c", SYMLINK+="cudydiskv2", RUN+="/usr/bin/eject /dev/%k"
KERNEL=="sd*", ATTRS{idVendor}=="a69c", ATTRS{idProduct}=="572f", SYMLINK+="aicudisk572f", RUN+="/usr/bin/eject /dev/%k"
# AIC8800D80 "Pandora" clone: switch 1111:1111 to its operational USB ID.
ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="1111", ATTR{idProduct}=="1111", RUN+="/bin/sh -c 'if [ -x /usr/sbin/usb_modeswitch ]; then exec /usr/sbin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111; elif [ -x /usr/bin/usb_modeswitch ]; then exec /usr/bin/usb_modeswitch -c /etc/usb_modeswitch.d/1111:1111; fi'"
+67
View File
@@ -0,0 +1,67 @@
# Intro
Hello.
Some instructions how to build rpm file and then install rpm file on Bazzite.
I saw video on Youtube about Asrock AMD BC-250, then I bought this motherboard.
On printables I found a case and recomendations about WIFI BT stick.
There is only one problem - Bazzite has read-only filesystem.
# How to build from spec file.
Install the build tools, the development package for the running kernel, and
the runtime mode-switch tools. Reboot once so the layered packages are active.
~~~bash
sudo rpm-ostree install rpm-build rpmdevtools gcc make "kernel-devel-$(uname -r)" usb_modeswitch util-linux
sudo systemctl reboot
~~~
Prepare rpmbuild folder
~~~bash
cd $HOME
rpmdev-setuptree
~~~
Copy aic8800d80.spec to rpmbuild/SPECS
~~~bash
cd $HOME/rpmbuild/SPECS
curl -LO -s https://raw.githubusercontent.com/shenmintao/aic8800d80/refs/heads/main/bazzite/aic8800d80.spec
~~~
Prepare and download required files.
~~~bash
spectool -g -R $HOME/rpmbuild/SPECS/aic8800d80.spec
rpmbuild -bs $HOME/rpmbuild/SPECS/aic8800d80.spec
~~~
Build SRPM package
~~~bash
rpmbuild --define "kver $(uname -r)" -bb $HOME/rpmbuild/SPECS/aic8800d80.spec
~~~
Install RPM package
~~~bash
rpm_path=$(find "$HOME/rpmbuild/RPMS/$(uname -m)" -maxdepth 1 -name 'aic8800d80-*.rpm' -printf '%T@ %p\n' | sort -nr | head -1 | cut -d' ' -f2-)
sudo rpm-ostree install "$rpm_path"
sudo systemctl reboot
~~~
After reboot, the Wi-Fi module and firmware loader will be available. On combo
adapters, Bluetooth is handled by the standard `btusb` kernel module after
firmware initialization. USB device `368b:8d81` also autoloads the packaged
`aic_zlp_quirk` companion module for its required Bluetooth ACL bulk TX zero
packet behavior; the distribution's `btusb` module is not replaced.
This RPM is built for the kernel reported by `uname -r`. Rebuild and reinstall
it after a Bazzite kernel upgrade.
+116
View File
@@ -0,0 +1,116 @@
%global commit c8327eab5be246d4b517afdba034775f00afa988
%global shortcommit %(echo %{commit} | cut -c1-7)
%global snapdate 20260924
%global debug_package %{nil}
%{!?kver:%global kver %(uname -r)}
Name: aic8800d80
# Versions before 2026-09-24 were bare commit hashes, which rpm does not
# order by commit history. Epoch 1 sorts every snapshot version after them.
Epoch: 1
Version: 1.0.0^%{snapdate}git%{shortcommit}
Release: 1%{?dist}
Summary: AIC8800 USB Wi-Fi, Bluetooth firmware, and ZLP quirk driver
License: GPL-2.0-only
URL: https://github.com/shenmintao/aic8800d80
Source0: %{url}/archive/%{commit}/%{name}-%{commit}.tar.gz
BuildRequires: gcc
BuildRequires: make
BuildRequires: kernel-devel-uname-r = %{kver}
Requires: kernel-uname-r = %{kver}
Requires: /usr/bin/eject
Requires: usb_modeswitch
Requires(post): /usr/sbin/depmod
Requires(postun): /usr/sbin/depmod
%description
Out-of-tree AIC8800 USB driver with Wi-Fi support, Bluetooth firmware loading,
udev mode-switch rules, and all firmware variants shipped by the upstream
repository. Combo adapters use the standard Linux btusb transport driver. A
device-scoped companion module supplies the required ACL bulk TX ZLP behavior
for USB device 368b:8d81 without replacing the distribution btusb module.
%prep
%autosetup -n %{name}-%{commit}
%build
make -C drivers/aic8800 KVER=%{kver} KDIR=/usr/src/kernels/%{kver} clean
make -C drivers/aic8800 KVER=%{kver} KDIR=/usr/src/kernels/%{kver}
%install
rm -rf %{buildroot}
install -Dpm0644 \
drivers/aic8800/aic8800_fdrv/aic8800_fdrv.ko \
%{buildroot}/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic8800_fdrv.ko
install -Dpm0644 \
drivers/aic8800/aic_load_fw/aic_load_fw.ko \
%{buildroot}/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic_load_fw.ko
install -Dpm0644 \
drivers/aic8800/aic_zlp_quirk/aic_zlp_quirk.ko \
%{buildroot}/usr/lib/modules/%{kver}/kernel/drivers/bluetooth/aic8800/aic_zlp_quirk.ko
install -Dpm0644 \
aic.rules \
%{buildroot}/usr/lib/udev/rules.d/90-aic8800-mode-switch.rules
install -Dpm0644 \
usb_modeswitch/1111_1111 \
%{buildroot}/etc/usb_modeswitch.d/1111:1111
install -d -m 0755 %{buildroot}/usr/lib/firmware
cp -a fw/aic8800* %{buildroot}/usr/lib/firmware/
%post
/usr/sbin/depmod -a %{kver} || :
%postun
/usr/sbin/depmod -a %{kver} || :
%files
%dir /usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800
/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic8800_fdrv.ko
/usr/lib/modules/%{kver}/kernel/drivers/net/wireless/aic8800/aic_load_fw.ko
/usr/lib/modules/%{kver}/kernel/drivers/bluetooth/aic8800/aic_zlp_quirk.ko
/usr/lib/udev/rules.d/90-aic8800-mode-switch.rules
%config(noreplace) /etc/usb_modeswitch.d/1111:1111
/usr/lib/firmware/aic8800*
%changelog
* Thu Sep 24 2026 Shen Mintao <shenmintao@gmail.com> - 1:1.0.0^20260924gitc8327ea-1
- Version snapshots as 1.0.0^<date>git<commit> with Epoch 1. The previous
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> - c8327ea-1
- Build the current legacy-mcu1 branch, which carries the Linux 7.2
cfg80211 and strncpy() fixes needed to compile on Bazzite 44.
- Include the monitor packet injection path and the 6.12 stable
set_monitor_channel() fix synchronized from main.
* Wed Jul 29 2026 Shen Mintao <shenmintao@gmail.com> - 51b7b6e-2
- Disable automatic debug package generation for Bazzite builds.
- Require usb_modeswitch by package name for rpm-ostree dependency resolution.
* Sat Jul 25 2026 Shen Mintao <shenmintao@gmail.com> - 51b7b6e-1
- Package the unified installer and ZLP quirk with the legacy MCU1 profiles.
- Preserve the matched D80 and DC/DW firmware and loader combinations.
* 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.
- Remove obsolete Bluetooth-specific configuration from the Wi-Fi package.
+160
View File
@@ -0,0 +1,160 @@
#!/bin/bash
# Diagnose Bluetooth on AIC8800 Wi-Fi/Bluetooth combo adapters.
#
# aic_load_fw initializes the device and uploads the AIC firmware. The
# standard in-kernel btusb driver must then bind to the Bluetooth HCI USB
# interface. The removed aic_btusb module must not be installed or loaded.
echo "=== AIC8800 Bluetooth diagnostics ==="
echo ""
echo "1. AIC USB devices:"
if command -v lsusb >/dev/null 2>&1; then
lsusb | grep -iE 'a69c|368b|3625' || echo " No known AIC USB ID found"
else
echo " lsusb is not installed"
fi
echo ""
echo "2. USB interfaces and bound drivers:"
bt_interface_found=false
btusb_bound=false
zlp_target_found=false
for dev in /sys/bus/usb/devices/*; do
[ -f "$dev/idVendor" ] || continue
[ -f "$dev/idProduct" ] || continue
vid=$(cat "$dev/idVendor" 2>/dev/null)
pid=$(cat "$dev/idProduct" 2>/dev/null)
case "$vid" in
a69c|368b|3625) ;;
*) continue ;;
esac
echo " Device: $vid:$pid"
if [ "$vid" = "368b" ] && [ "$pid" = "8d81" ]; then
zlp_target_found=true
fi
for intf in "$dev"/*:*; do
[ -d "$intf" ] || continue
class=$(cat "$intf/bInterfaceClass" 2>/dev/null)
subclass=$(cat "$intf/bInterfaceSubClass" 2>/dev/null)
protocol=$(cat "$intf/bInterfaceProtocol" 2>/dev/null)
driver=$(basename "$(readlink "$intf/driver" 2>/dev/null)" 2>/dev/null)
echo " $(basename "$intf"): ${class:-??}/${subclass:-??}/${protocol:-??} -> ${driver:-unbound}"
if [ "$driver" = "btusb" ]; then
btusb_bound=true
bt_interface_found=true
elif [ "$class" = "e0" ] && [ "$subclass" = "01" ] && [ "$protocol" = "01" ]; then
bt_interface_found=true
fi
done
done
echo ""
echo "3. Relevant kernel modules (combo expectation: aic_load_fw + btusb):"
lsmod | grep -E '^(aic_load_fw|aic8800_fdrv|aic_zlp_quirk|aic_btusb|btusb|bluetooth)[[:space:]]' || \
echo " No related module is currently loaded"
echo ""
echo "4. Bluetooth controllers:"
if command -v bluetoothctl >/dev/null 2>&1; then
bluetoothctl list 2>/dev/null || echo " No controller reported by bluetoothctl"
elif command -v hciconfig >/dev/null 2>&1; then
hciconfig -a 2>/dev/null || echo " No controller reported by hciconfig"
else
echo " BlueZ command-line tools are not installed"
fi
echo ""
echo "5. Firmware, btusb, ZLP quirk, and HCI log messages:"
dmesg 2>/dev/null | grep -iE 'fw_patch|fw_adid|aicbt|aic_zlp_quirk|bluetooth|btusb|hci' | tail -80 || true
echo ""
echo "6. Bluetooth rfkill state:"
if command -v rfkill >/dev/null 2>&1; then
rfkill list bluetooth 2>/dev/null || echo " No Bluetooth rfkill entry"
else
echo " rfkill is not installed"
fi
echo ""
echo "7. Obsolete aic_btusb installation/configuration:"
legacy_refs_found=false
mapfile -t legacy_modprobe_files < <(
grep -RIlE '^[[:space:]]*(softdep|alias)[^#]*aic_btusb([[:space:]]|$)' \
/etc/modprobe.d /run/modprobe.d /usr/local/lib/modprobe.d \
/usr/lib/modprobe.d /lib/modprobe.d 2>/dev/null | \
grep -vE '\.aic8800-backup$' || true
)
mapfile -t legacy_udev_files < <(
grep -RIl 'aic_btusb/new_id' \
/etc/udev/rules.d /run/udev/rules.d \
/usr/lib/udev/rules.d /lib/udev/rules.d 2>/dev/null | \
grep -vE '\.aic8800-backup$' || true
)
for legacy_file in "${legacy_modprobe_files[@]}"; do
echo " Obsolete modprobe directive: $legacy_file"
legacy_refs_found=true
done
for legacy_file in "${legacy_udev_files[@]}"; do
echo " Obsolete udev binding rule: $legacy_file"
legacy_refs_found=true
done
if lsmod | awk '{print $1}' | grep -qx 'aic_btusb'; then
echo " Obsolete aic_btusb module is loaded"
legacy_refs_found=true
fi
if modinfo -n aic_btusb >/dev/null 2>&1; then
echo " Obsolete module file: $(modinfo -n aic_btusb 2>/dev/null)"
legacy_refs_found=true
fi
if [ "$legacy_refs_found" = false ]; then
echo " No active aic_btusb module, directive, or binding rule found (expected)"
fi
echo ""
echo "8. Device-scoped Bluetooth ACL ZLP quirk:"
if [ "$zlp_target_found" = true ]; then
if [ -d /sys/module/aic_zlp_quirk ]; then
zlp_hook="unknown"
zlp_injections="unavailable"
[ -r /sys/module/aic_zlp_quirk/parameters/hook ] && \
zlp_hook=$(cat /sys/module/aic_zlp_quirk/parameters/hook)
[ -r /sys/module/aic_zlp_quirk/parameters/injections ] && \
zlp_injections=$(cat /sys/module/aic_zlp_quirk/parameters/injections)
echo " Target 368b:8d81 present"
echo " aic_zlp_quirk loaded: yes"
echo " active hook: $zlp_hook"
echo " ZLP injections: $zlp_injections"
else
echo " Target 368b:8d81 present, but aic_zlp_quirk is not loaded"
fi
else
echo " Target 368b:8d81 not present; quirk is not required"
fi
echo ""
echo "=== Assessment ==="
if ! lsmod | awk '{print $1}' | grep -qx 'aic_load_fw'; then
echo "- aic_load_fw is not loaded; run: sudo modprobe aic8800_fdrv"
fi
if [ "$bt_interface_found" = true ] && [ "$btusb_bound" = false ]; then
echo "- A Bluetooth USB interface exists but is not bound to btusb."
echo " Check for a btusb blacklist, then try: sudo modprobe btusb"
fi
if dmesg 2>/dev/null | grep -iE 'hci[0-9]+:.*(command|opcode|tx).*timed out|hci[0-9]+: link tx timeout' | tail -1 | grep -q .; then
echo "- HCI timeout detected. Confirm that aic_load_fw uploaded the firmware before btusb bound."
echo " Also check for obsolete aic_btusb configuration above."
fi
if [ "$bt_interface_found" = false ]; then
echo "- No Bluetooth HCI USB interface was found. This is normal for a Wi-Fi-only adapter."
fi
if [ "$zlp_target_found" = true ] && [ ! -d /sys/module/aic_zlp_quirk ]; then
echo "- Device 368b:8d81 requires the ACL ZLP quirk, but the module is not loaded."
echo " Try: sudo modprobe aic_zlp_quirk"
fi
echo "=== Diagnostics complete ==="
+77 -17
View File
@@ -17,6 +17,29 @@ YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
DRV_NAME="aic8800"
DRV_VERSION="1.0.0"
INSTALL_LOG="/tmp/aic8800d80_install.log"
read_dkms_conf_value() {
local key="$1"
local file="$2"
grep -E "^[[:space:]]*${key}[[:space:]]*=" "$file" 2>/dev/null \
| head -1 \
| cut -d= -f2- \
| tr -d "\"'[:space:]"
}
if [ -f "./dkms.conf" ]; then
detected_name="$(read_dkms_conf_value PACKAGE_NAME ./dkms.conf)"
detected_version="$(read_dkms_conf_value PACKAGE_VERSION ./dkms.conf)"
[ -n "$detected_name" ] && DRV_NAME="$detected_name"
[ -n "$detected_version" ] && DRV_VERSION="$detected_version"
fi
mapfile -t DKMS_SOURCE_DIRS < <(find /usr/src -maxdepth 1 -type d -name "${DRV_NAME}-*" -print 2>/dev/null | sort)
print_section() {
echo ""
echo -e "${BLUE}━━━ $1 ━━━${NC}"
@@ -58,46 +81,73 @@ fi
print_section "2. Checking DKMS directory"
if [ -d "/usr/src/aic8800-1.0.0" ]; then
echo -e "${GREEN}✓${NC} /usr/src/aic8800-1.0.0 directory exists"
echo "Detected package: ${DRV_NAME}/${DRV_VERSION}"
if [ "${#DKMS_SOURCE_DIRS[@]}" -gt 0 ]; then
for source_dir in "${DKMS_SOURCE_DIRS[@]}"; do
echo -e "${GREEN}✓${NC} $source_dir directory exists"
echo ""
echo "Content:"
ls -la /usr/src/aic8800-1.0.0/
ls -la "$source_dir/"
echo ""
echo "Checking drivers/aic8800 inside DKMS:"
if [ -d "/usr/src/aic8800-1.0.0/drivers/aic8800" ]; then
if [ -d "$source_dir/drivers/aic8800" ]; then
echo -e "${GREEN}✓${NC} drivers/aic8800 copied to DKMS"
ls -la /usr/src/aic8800-1.0.0/drivers/aic8800/
ls -la "$source_dir/drivers/aic8800/"
else
echo -e "${RED}✗${NC} drivers/aic8800 NOT copied correctly!"
fi
echo ""
done
else
echo -e "${RED}✗${NC} /usr/src/aic8800-1.0.0 directory NOT FOUND"
echo -e "${RED}✗${NC} No /usr/src/${DRV_NAME}-* directory found"
fi
print_section "3. Checking DKMS build logs"
if [ -f "/var/lib/dkms/aic8800/1.0.0/build/make.log" ]; then
echo -e "${GREEN}✓${NC} Build log found"
mapfile -t BUILD_LOGS < <(find "/var/lib/dkms/${DRV_NAME}" -type f -name make.log -print 2>/dev/null | sort)
if [ "${#BUILD_LOGS[@]}" -gt 0 ]; then
for build_log in "${BUILD_LOGS[@]}"; do
echo -e "${GREEN}✓${NC} Build log found: $build_log"
echo ""
echo "Last 50 lines of make.log:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tail -50 /var/lib/dkms/aic8800/1.0.0/build/make.log
tail -50 "$build_log"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
done
else
echo -e "${RED}✗${NC} No make.log found under /var/lib/dkms/${DRV_NAME}/"
echo "The module may not have reached the build step yet, or this DKMS version stores logs elsewhere."
fi
if [ -f "$INSTALL_LOG" ]; then
echo ""
echo -e "${GREEN}✓${NC} Installer log found: $INSTALL_LOG"
echo "Last 50 lines of installer log:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
tail -50 "$INSTALL_LOG"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
else
echo -e "${RED}✗${NC} Build log not found in /var/lib/dkms/aic8800/1.0.0/build/make.log"
echo -e "${YELLOW}!${NC} Installer log not found: $INSTALL_LOG"
fi
print_section "4. Checking dkms.conf"
if [ -f "/usr/src/aic8800-1.0.0/dkms.conf" ]; then
echo -e "${GREEN}✓${NC} dkms.conf found"
if [ "${#DKMS_SOURCE_DIRS[@]}" -gt 0 ]; then
for source_dir in "${DKMS_SOURCE_DIRS[@]}"; do
if [ -f "$source_dir/dkms.conf" ]; then
echo -e "${GREEN}✓${NC} dkms.conf found: $source_dir/dkms.conf"
echo ""
cat "$source_dir/dkms.conf"
echo ""
echo "dkms.conf content:"
cat /usr/src/aic8800-1.0.0/dkms.conf
else
echo -e "${RED}✗${NC} dkms.conf NOT FOUND!"
echo -e "${RED}✗${NC} dkms.conf NOT FOUND in $source_dir"
fi
done
else
echo -e "${RED}✗${NC} No DKMS source directory available to inspect"
fi
if [ -f "./dkms.conf" ]; then
@@ -120,13 +170,23 @@ print_section "6. System information"
echo "Kernel: $(uname -r)"
echo "Architecture: $(uname -m)"
echo ""
echo "GCC version:"
echo "Compiler version:"
if command -v gcc >/dev/null 2>&1; then
gcc --version | head -1
elif command -v clang >/dev/null 2>&1; then
clang --version | head -1
else
echo "No gcc or clang found"
fi
echo ""
echo "Installed kernel headers:"
ls -d /lib/modules/$(uname -r)/build 2>/dev/null && echo "✓ Headers found" || echo "✗ Headers NOT found"
ls -d "/lib/modules/$(uname -r)/build" 2>/dev/null && echo "✓ Headers found" || echo "✗ Headers NOT found"
print_section "7. DKMS status"
echo "DKMS modules registered:"
if command -v dkms >/dev/null 2>&1; then
dkms status
else
echo -e "${RED}✗${NC} dkms command not found"
fi
+7 -2
View File
@@ -1,7 +1,7 @@
PACKAGE_NAME="aic8800"
PACKAGE_VERSION="1.0.0"
MAKE="KVER=${kernelver} 'make' -C drivers/aic8800"
CLEAN="KVER=${kernelver} 'make' -C drivers/aic8800 clean"
MAKE="KVER=${kernelver} KDIR=/lib/modules/${kernelver}/build 'make' -C drivers/aic8800"
CLEAN="KVER=${kernelver} KDIR=/lib/modules/${kernelver}/build 'make' -C drivers/aic8800 clean"
# Main module (aic8800_fdrv)
BUILT_MODULE_NAME[0]="aic8800_fdrv"
@@ -13,4 +13,9 @@ BUILT_MODULE_NAME[1]="aic_load_fw"
BUILT_MODULE_LOCATION[1]="drivers/aic8800/aic_load_fw"
DEST_MODULE_LOCATION[1]="/updates/dkms"
# Device-scoped standard-btusb ACL bulk TX ZLP quirk (368b:8d81 only)
BUILT_MODULE_NAME[2]="aic_zlp_quirk"
BUILT_MODULE_LOCATION[2]="drivers/aic8800/aic_zlp_quirk"
DEST_MODULE_LOCATION[2]="/updates/dkms"
AUTOINSTALL="yes"
+22 -4
View File
@@ -1,13 +1,16 @@
CONFIG_AIC_LOADFW_SUPPORT := m
CONFIG_AIC8800_WLAN_SUPPORT := m
CONFIG_AIC_ZLP_QUIRK := m
obj-$(CONFIG_AIC_LOADFW_SUPPORT) += aic_load_fw/
obj-$(CONFIG_AIC8800_WLAN_SUPPORT) += aic8800_fdrv/
obj-$(CONFIG_AIC_ZLP_QUIRK) += aic_zlp_quirk/
########## config option ##########
export CONFIG_USE_FW_REQUEST = n
export CONFIG_PREALLOC_RX_SKB = y
export CONFIG_PREALLOC_TXQ = y
export CONFIG_WOWLAN = n
###################################
########## platform support list ##########
@@ -47,34 +50,49 @@ endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
KVER ?= $(shell uname -r)
KDIR = /lib/modules/$(KVER)/build
KDIR ?= /lib/modules/$(KVER)/build
PWD = $(shell pwd)
MODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/net/wireless/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/)
BTMODDESTDIR = /lib/modules/$(KVER)/kernel/drivers/bluetooth/aic8800
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/ -e s/loongarch64/loongarch/ -e s/loong64/loongarch/ -e s/riscv64/riscv/)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
endif
###########################################
MAKEFLAGS +=-j$(shell nproc)
KERNEL_AUTOCONF := $(KDIR)/include/config/auto.conf
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)
ifeq ($(KERNEL_CC_IS_CLANG),y)
LLVM ?= 1
endif
ifneq ($(LLVM),)
KBUILD_EXTRA_ARGS += LLVM=$(LLVM)
endif
all: modules
modules:
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) $(KBUILD_EXTRA_ARGS) modules
install:
mkdir -p $(MODDESTDIR)
mkdir -p $(BTMODDESTDIR)
install -p -m 644 aic_load_fw/aic_load_fw.ko $(MODDESTDIR)/
install -p -m 644 aic8800_fdrv/aic8800_fdrv.ko $(MODDESTDIR)/
install -p -m 644 aic_zlp_quirk/aic_zlp_quirk.ko $(BTMODDESTDIR)/
/sbin/depmod -a ${KVER}
uninstall:
rm -rfv $(MODDESTDIR)/aic_load_fw.ko
rm -rfv $(MODDESTDIR)/aic8800_fdrv.ko
rm -rfv $(BTMODDESTDIR)/aic_zlp_quirk.ko
/sbin/depmod -a ${KVER}
clean:
cd aic_load_fw/;make clean;cd ..
cd aic8800_fdrv/;make clean;cd ..
cd aic_zlp_quirk/;make clean;cd ..
rm -rf modules.order Module.symvers .modules.order.cmd .Module.symvers.cmd .tmp_versions/
+34 -7
View File
@@ -2,6 +2,16 @@ EXTRA_CFLAGS += $(USER_EXTRA_CFLAGS)
EXTRA_CFLAGS += -Wno-implicit-fallthrough
#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
CONFIG_AIC8800_WLAN_SUPPORT = m
@@ -74,7 +84,11 @@ CONFIG_VHT_FOR_OLD_KERNEL = n
CONFIG_COEX = y
CONFIG_ALIGN_8BYTES = y
CONFIG_TXRX_THREAD_PRIO = y
ifdef CONFIG_ARCH_SUN60IW2P1
CONFIG_USB_ALIGN_DATA = n
else
CONFIG_USB_ALIGN_DATA = y
endif
CONFIG_RX_TASKLET = n
CONFIG_TX_TASKLET = n
CONFIG_RX_NETIF_RECV_SKB = y
@@ -82,18 +96,22 @@ CONFIG_BR_SUPPORT = n
CONFIG_USB_MSG_OUT_EP = y
CONFIG_USB_MSG_IN_EP = y
CONFIG_USB_RX_REASSEMBLE = n
CONFIG_WOWLAN = n
CONFIG_WOWLAN ?= n
#DCDW support tx aggr, D80 support both
CONFIG_USB_RX_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
endif
CONFIG_GPIO_WAKEUP = n
CONFIG_CREATE_TRACE_POINTS = n
CONFIG_SUPPORT_REALTIME_CHANGE_MAC = y
CONFIG_USE_USB_ZERO_PACKET = y
CONFIG_DEBUG_FS = n
CONFIG_DEBUG_FS ?= n
CONFIG_STA_SCAN_WHEN_P2P_WORKING = y
CONFIG_SET_VENDOR_EXTENSION_IE = n
CONFIG_VENDOR_GPIO = n
@@ -114,6 +132,7 @@ CONFIG_LOFT_CALIB = n
CONFIG_GKI = n
CONFIG_SCHED_SCAN = n
CONFIG_TEMP_COMP = n
CONFIG_TEMP_CONTROL = n
CONFIG_POWER_LIMIT = n
CONFIG_EXT_FEM_8800DCDW = n
# CONFIG_MCC = n for sta and p2p concurrent in same channel.
@@ -122,6 +141,8 @@ CONFIG_LOAD_BT_PATCH_IN_FDRV = n
CONFIG_DYNAMIC_PWR = n
CONFIG_DYNAMIC_PERPWR = n
CONFIG_BAND_STEERING = n
CONFIG_PRBREQ_REPORT = n
CONFIG_SUPPORT_4ADDR = n
#support D80X2 can write rf result to file
CONFIG_WRITE_FILE_D80X2 = n
@@ -151,7 +172,7 @@ CONFIG_RWNX_BCMC ?= y
# Enable Monitor+Data interface support (need FW support)
CONFIG_RWNX_MON_DATA =n
CONFIG_RWNX_MON_XMIT ?= n
CONFIG_RWNX_MON_XMIT ?= y
CONFIG_RWNX_MON_RXFILTER ?= n
CONFIG_FILTER_TCP_ACK =y
@@ -189,7 +210,9 @@ $(MODULE_NAME)-y := \
aic_priv_cmd.o \
aicwf_compat_8800dc.o \
aicwf_compat_8800d80.o \
aicwf_compat_8800d80x2.o
aicwf_compat_8800d80x2.o \
aicwf_compat_8800d80n.o \
aicwf_compat_8800dln.o
$(MODULE_NAME)-$(CONFIG_BAND_STEERING) += aicwf_manager.o \
aicwf_steering.o
@@ -263,6 +286,8 @@ ccflags-$(CONFIG_LOAD_BT_PATCH_IN_FDRV) += -DCONFIG_LOAD_BT_PATCH_IN_FDRV
ccflags-$(CONFIG_DYNAMIC_PWR) += -DCONFIG_DYNAMIC_PWR
ccflags-$(CONFIG_DYNAMIC_PERPWR) += -DCONFIG_DYNAMIC_PERPWR
ccflags-$(CONFIG_BAND_STEERING) += -DCONFIG_BAND_STEERING
ccflags-$(CONFIG_PRBREQ_REPORT) += -DCONFIG_PRBREQ_REPORT
ccflags-$(CONFIG_SUPPORT_4ADDR) += -DCONFIG_SUPPORT_4ADDR
ccflags-$(CONFIG_WRITE_FILE_D80X2) += -DRF_WRITE_FILE
ifeq ($(CONFIG_SDIO_SUPPORT), y)
@@ -338,10 +363,10 @@ ccflags-$(CONFIG_GKI) += -DCONFIG_GKI
ccflags-$(CONFIG_SCHED_SCAN) += -DCONFIG_SCHED_SCAN
ccflags-$(CONFIG_FILTER_TCP_ACK) += -DCONFIG_FILTER_TCP_ACK
ccflags-$(CONFIG_TEMP_COMP) += -DCONFIG_TEMP_COMP
ccflags-$(CONFIG_TEMP_CONTROL) += -DCONFIG_TEMP_CONTROL
ccflags-$(CONFIG_POWER_LIMIT) += -DCONFIG_POWER_LIMIT
ccflags-$(CONFIG_EXT_FEM_8800DCDW) += -DCONFIG_EXT_FEM_8800DCDW
ccflags-$(CONFIG_WOWLAN) += -DCONFIG_WOWLAN
# Platform support list
CONFIG_PLATFORM_ROCKCHIP ?= n
CONFIG_PLATFORM_ALLWINNER ?= n
@@ -380,11 +405,13 @@ KDIR ?= /home/yaya/D/Workspace/CyberQuantum/JinHaoYue/amls905x3/SDK/20191101-0tt
endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
KVER := $(or $(KVER), $(kernelver), $(KERNELRELEASE), $(shell uname -r))
KVER ?= $(shell uname -r)
KDIR ?= /lib/modules/$(KVER)/build
#KDIR ?= ~/D/Workspace/CyberQuantum/Linux/linux-4.15/
PWD ?= $(shell pwd)
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
endif
+59 -19
View File
@@ -1,23 +1,30 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2017 Realtek Corporation.
* Copyright (C) 2019-2021 Aicsemi Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* http://www.apache.org/licenses/LICENSE-2.0
*
*****************************************************************************/
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#define _AIC_BR_EXT_C_
#include <linux/version.h>
#ifdef __KERNEL__
#include <linux/if_arp.h>
#include <net/ip.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
#include <net/ipx.h>
#endif
#include <linux/atalk.h>
#include <linux/udp.h>
#include <linux/if_pppox.h>
@@ -54,6 +61,7 @@
#define MAGIC_CODE_LEN 2
#define WAIT_TIME_PPPOE 5 /* waiting time for pppoe server in sec */
/*-----------------------------------------------------------------
How database records network address:
0 1 2 3 4 5 6 7 8 9 10
@@ -503,7 +511,6 @@ static void __nat25_db_network_insert(struct rwnx_vif *vif,
spin_unlock_bh(&vif->br_ext_lock);
}
static void __nat25_db_print(struct rwnx_vif *vif)
{
spin_lock_bh(&vif->br_ext_lock);
@@ -746,6 +753,22 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
protocol = *((unsigned short *)(skb->data + 2 * ETH_ALEN));
#if 0
printk("nat25_db_handle: DA=%02x%02x%02x%02x%02x%02x SA=%02x%02x%02x%02x%02x%02x\n",
skb->data[0],
skb->data[1],
skb->data[2],
skb->data[3],
skb->data[4],
skb->data[5],
skb->data[6],
skb->data[7],
skb->data[8],
skb->data[9],
skb->data[10],
skb->data[11]);
#endif
/*---------------------------------------------------*/
/* Handle IP frame */
/*---------------------------------------------------*/
@@ -849,7 +872,6 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
case NAT25_LOOKUP: {
printk("NAT25: Lookup ARP\n");
arp_ptr += arp->ar_hln;
sender = (unsigned int *)arp_ptr;
arp_ptr += (arp->ar_hln + arp->ar_pln);
@@ -874,23 +896,34 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
/*---------------------------------------------------*/
/* Handle IPX and Apple Talk frame */
/*---------------------------------------------------*/
else if ((protocol == __constant_htons(ETH_P_IPX)) ||
else if (
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
(protocol == __constant_htons(ETH_P_IPX)) ||
#endif
(protocol == __constant_htons(ETH_P_ATALK)) ||
(protocol == __constant_htons(ETH_P_AARP))) {
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
unsigned char ipx_header[2] = {0xFF, 0xFF};
struct ipxhdr *ipx = NULL;
#endif
struct elapaarp *ea = NULL;
struct ddpehdr *ddp = NULL;
unsigned char *framePtr = skb->data + ETH_HLEN;
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
if (protocol == __constant_htons(ETH_P_IPX)) {
printk("NAT25: Protocol=IPX (Ethernet II)\n");
ipx = (struct ipxhdr *)framePtr;
} else { /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */
} else
#endif
{ /* if(protocol <= __constant_htons(ETH_FRAME_LEN)) */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
if (!memcmp(ipx_header, framePtr, 2)) {
printk("NAT25: Protocol=IPX (Ethernet 802.3)\n");
ipx = (struct ipxhdr *)framePtr;
} else {
} else
#endif
{
unsigned char ipx_8022_type = 0xE0;
unsigned char snap_8022_type = 0xAA;
@@ -900,13 +933,15 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
unsigned char ddp_snap_id[5] = {0x08, 0x00, 0x07, 0x80, 0x9B}; /* Apple Talk DDP SNAP ID */
framePtr += 3; /* eliminate the 802.2 header */
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
if (!memcmp(ipx_snap_id, framePtr, 5)) {
framePtr += 5; /* eliminate the SNAP header */
printk("NAT25: Protocol=IPX (Ethernet SNAP)\n");
ipx = (struct ipxhdr *)framePtr;
} else if (!memcmp(aarp_snap_id, framePtr, 5)) {
} else
#endif
if (!memcmp(aarp_snap_id, framePtr, 5)) {
framePtr += 5; /* eliminate the SNAP header */
ea = (struct elapaarp *)framePtr;
@@ -919,7 +954,9 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
framePtr[1], framePtr[2], framePtr[3], framePtr[4]);
return -1;
}
} else if (*framePtr == ipx_8022_type) {
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
else if (*framePtr == ipx_8022_type) {
framePtr += 3; /* eliminate the 802.2 header */
if (!memcmp(ipx_header, framePtr, 2)) {
@@ -928,9 +965,11 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
} else
return -1;
}
#endif
}
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 15, 0)
/* IPX */
if (ipx != NULL) {
switch (method) {
@@ -997,10 +1036,11 @@ int nat25_db_handle(struct rwnx_vif *vif, struct sk_buff *skb, int method)
default:
return -1;
}
}
}else
#endif
/* AARP */
else if (ea != NULL) {
if (ea != NULL) {
/* Sanity check fields. */
if (ea->hw_len != ETH_ALEN || ea->pa_len != AARP_PA_ALEN) {
printk("NAT25: Appletalk AARP Sanity check fail!\n");
+13 -9
View File
@@ -1,17 +1,21 @@
/******************************************************************************
*
* Copyright(c) 2007 - 2017 Realtek Corporation.
* Copyright (C) 2019-2021 Aicsemi Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* http://www.apache.org/licenses/LICENSE-2.0
*
*****************************************************************************/
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
#ifndef _AIC_BR_EXT_H_
#define _AIC_BR_EXT_H_
+147 -24
View File
@@ -11,8 +11,6 @@
*/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include "rwnx_defs.h"
#include "rwnx_msg_tx.h"
@@ -90,6 +88,7 @@ enum {
EXEC_FLASH_OPER,
RDWR_PWRADD2X,
RDWR_EFUSE_PWRADD2X,
GET_RSSI=0x52,
CHECK_FLASH=0x108,
};
@@ -342,7 +341,7 @@ static int aic_priv_cmd_set_tx (struct rwnx_hw *rwnx_hw, int argc, char *argv[],
AICWFDBG(LOGINFO, "txparam:%d,%d,%d,%d,%d,%d\n", settx_param.chan, settx_param.bw,
settx_param.mode, settx_param.rate, settx_param.length, settx_param.tx_intv_us);
#ifdef CONFIG_POWER_LIMIT
r_idx = get_ccode_region(country_code);
r_idx = get_ccode_region(rwnx_hw->wiphy->regd->alpha2);
txpwr_loss = &txpwr_loss_tmp;
get_userconfig_txpwr_loss(txpwr_loss);
if (txpwr_loss->loss_enable_2g4 == 1)
@@ -797,7 +796,10 @@ static int aic_priv_cmd_rdwr_pwrlvl (struct rwnx_hw *rwnx_hw, int argc, char *ar
AICWFDBG(LOGERROR, "wrong func: %x\n", func);
return -EINVAL;
}
if((dev->chipid == PRODUCT_ID_AIC8800D81) || (dev->chipid == PRODUCT_ID_AIC8800D81X2) || (dev->chipid == PRODUCT_ID_AIC8800D89X2)){
if((dev->chipid == PRODUCT_ID_AIC8800D81)||
(dev->chipid == PRODUCT_ID_AIC8800D81X2) ||
(dev->chipid == PRODUCT_ID_AIC8800D89X2) ||
(dev->chipid == PRODUCT_ID_AIC8800D80N)) {
memcpy(command, &cfm.rftest_result[0], 6 * 12);
return (6 * 12);
} else {
@@ -823,16 +825,19 @@ static int aic_priv_cmd_rdwr_pwrofst (struct rwnx_hw *rwnx_hw, int argc, char *a
if (func == 0) { // read cur
rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, 0, NULL, &cfm);
} else if (func <= 4) { // write 2.4g/5g pwr ofst and ant0/1
if ((argc > 4) && ((dev->chipid == PRODUCT_ID_AIC8800D81) || (dev->chipid == PRODUCT_ID_AIC8800D81X2) || (dev->chipid == PRODUCT_ID_AIC8800D89X2))) {
if ((argc > 4) && ((dev->chipid == PRODUCT_ID_AIC8800D81) ||
(dev->chipid == PRODUCT_ID_AIC8800D81X2) ||
(dev->chipid == PRODUCT_ID_AIC8800D89X2) ||
(dev->chipid == PRODUCT_ID_AIC8800D80N))) {
u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16);
u8_l chgrp = (u8_l)command_strtoul(argv[3], NULL, 16);
s8_l pwrofst = (u8_l)command_strtoul(argv[4], NULL, 10);
s8_l pwrofst = (s8_l)command_strtoul(argv[4], NULL, 10);
u8_l buf[4] = {func, type, chgrp, (u8_l)pwrofst};
AICWFDBG(LOGINFO, "set pwrofst_%s:[%x][%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", type, chgrp, pwrofst);
rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm);
} else if ((argc > 3) && ((dev->chipid == PRODUCT_ID_AIC8801) || (dev->chipid == PRODUCT_ID_AIC8800DW) || (dev->chipid == PRODUCT_ID_AIC8800DC))) {
} else if ((argc > 3) && ((dev->chipid == PRODUCT_ID_AIC8801) || (dev->chipid == PRODUCT_ID_AIC8800DW) || (dev->chipid == PRODUCT_ID_AIC8800DC) || (dev->chipid == PRODUCT_ID_AIC8800DLN))) {
u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10);
u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
AICWFDBG(LOGINFO, "set pwrofst_%s:[%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", chgrp, pwrofst);
rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFST, sizeof(buf), buf, &cfm);
@@ -843,9 +848,9 @@ static int aic_priv_cmd_rdwr_pwrofst (struct rwnx_hw *rwnx_hw, int argc, char *a
AICWFDBG(LOGERROR, "wrong func: %x\n", func);
return -EINVAL;
}
if ((dev->chipid == PRODUCT_ID_AIC8800DC) || (dev->chipid == PRODUCT_ID_AIC8800DW)) { // 3 = 3 (2.4g)
if ((dev->chipid == PRODUCT_ID_AIC8800DC) || (dev->chipid == PRODUCT_ID_AIC8800DW) || (dev->chipid == PRODUCT_ID_AIC8800DLN)) { // 3 = 3 (2.4g)
res_len = 3;
} else if (dev->chipid == PRODUCT_ID_AIC8800D81) { // 3 * 2 (2.4g) + 3 * 6 (5g)
} else if ((dev->chipid == PRODUCT_ID_AIC8800D81) || (dev->chipid == PRODUCT_ID_AIC8800D80N)) { // 3 * 2 (2.4g) + 3 * 6 (5g)
res_len = 3 * 3 + 3 * 6;
} else if ((dev->chipid == PRODUCT_ID_AIC8800D81X2) || (dev->chipid == PRODUCT_ID_AIC8800D89X2)) { // ant0/1
res_len = ( 3 * 3 + 3 * 6 ) * 2;
@@ -868,7 +873,7 @@ static int aic_priv_cmd_rdwr_pwrofstfine (struct rwnx_hw *rwnx_hw, int argc, cha
} else if (func <= 2) { // write 2.4g/5g pwr ofst
if (argc > 3) {
u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10);
u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
AICWFDBG(LOGINFO, "set pwrofstfine:[%x][%x]=%d\r\n", func, chgrp, pwrofst);
rwnx_send_rftest_req(rwnx_hw, RDWR_PWROFSTFINE, sizeof(buf), buf, &cfm);
@@ -930,16 +935,17 @@ static int aic_priv_cmd_rdwr_efuse_pwrofst (struct rwnx_hw *rwnx_hw, int argc, c
if (func == 0) { // read cur
rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, 0, NULL, &cfm);
} else if (func <= 4) { // write 2.4g/5g pwr ofst and ant0/1
if ((argc > 4) && ((dev->chipid == PRODUCT_ID_AIC8800D81) || (dev->chipid == PRODUCT_ID_AIC8800D81X2) || (dev->chipid == PRODUCT_ID_AIC8800D89X2))) {
if ((argc > 4) && ((dev->chipid == PRODUCT_ID_AIC8800D81) || (dev->chipid == PRODUCT_ID_AIC8800D81X2) || (dev->chipid == PRODUCT_ID_AIC8800D89X2)
|| (dev->chipid == PRODUCT_ID_AIC8800D80N))) {
u8_l type = (u8_l)command_strtoul(argv[2], NULL, 16);
u8_l chgrp = (u8_l)command_strtoul(argv[3], NULL, 16);
s8_l pwrofst = (u8_l)command_strtoul(argv[4], NULL, 10);
s8_l pwrofst = (s8_l)command_strtoul(argv[4], NULL, 10);
u8_l buf[4] = {func, type, chgrp, (u8_l)pwrofst};
AICWFDBG(LOGINFO, "set efuse pwrofst_%s:[%x][%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", type, chgrp, pwrofst);
rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm);
} else if ((argc > 3) && ((dev->chipid == PRODUCT_ID_AIC8801) || (dev->chipid == PRODUCT_ID_AIC8800DW) || (dev->chipid == PRODUCT_ID_AIC8800DC))) {
} else if ((argc > 3) && ((dev->chipid == PRODUCT_ID_AIC8801) || (dev->chipid == PRODUCT_ID_AIC8800DW) || (dev->chipid == PRODUCT_ID_AIC8800DC) || (dev->chipid == PRODUCT_ID_AIC8800DLN))) {
u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10);
u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
AICWFDBG(LOGINFO, "set efuse pwrofst_%s:[%x]=%d\r\n", (func == 1) ? "2.4g" : "5g", chgrp, pwrofst);
rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFST, sizeof(buf), buf, &cfm);
@@ -951,9 +957,9 @@ static int aic_priv_cmd_rdwr_efuse_pwrofst (struct rwnx_hw *rwnx_hw, int argc, c
AICWFDBG(LOGERROR, "wrong func: %x\n", func);
return -EINVAL;
}
if ((dev->chipid == PRODUCT_ID_AIC8800DC) || (dev->chipid == PRODUCT_ID_AIC8800DW)) { // 6 = 3 (2.4g) * 2
if ((dev->chipid == PRODUCT_ID_AIC8800DC) || (dev->chipid == PRODUCT_ID_AIC8800DW) || (dev->chipid == PRODUCT_ID_AIC8800DLN)) { // 6 = 3 (2.4g) * 2
res_len = 3 * 2;
} else if (dev->chipid == PRODUCT_ID_AIC8800D81) { // 3 * 2 (2.4g) + 3 * 6 (5g)
} else if ((dev->chipid == PRODUCT_ID_AIC8800D81) || (dev->chipid == PRODUCT_ID_AIC8800D80N)) { // 3 * 2 (2.4g) + 3 * 6 (5g)
res_len = (3 * 3 + 3 * 6) * 2;
} else if((dev->chipid == PRODUCT_ID_AIC8800D81X2) || (dev->chipid == PRODUCT_ID_AIC8800D89X2)) { // 3 * 2 (2.4g) *2 + 3 * 6 (5g) *2
res_len = (3 * 3 + 3 * 6) * 2 * 2;
@@ -976,7 +982,7 @@ static int aic_priv_cmd_rdwr_efuse_pwrofstfine (struct rwnx_hw *rwnx_hw, int arg
} else if (func <= 2) { // write 2.4g/5g pwr ofst
if (argc > 3) {
u8_l chgrp = (u8_l)command_strtoul(argv[2], NULL, 16);
s8_l pwrofst = (u8_l)command_strtoul(argv[3], NULL, 10);
s8_l pwrofst = (s8_l)command_strtoul(argv[3], NULL, 10);
u8_l buf[3] = {func, chgrp, (u8_l)pwrofst};
AICWFDBG(LOGINFO, "set pwrofstfine:[%x][%x]=%d\r\n", func, chgrp, pwrofst);
rwnx_send_rftest_req(rwnx_hw, RDWR_EFUSE_PWROFSTFINE, sizeof(buf), buf, &cfm);
@@ -1273,6 +1279,49 @@ static int aic_priv_cmd_set_pll_test (struct rwnx_hw *rwnx_hw, int argc, char *a
return 0;
}
static int aic_priv_cmd_get_txpwr(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command)
{
s8_l power=0;
power = get_txpwr_max(power);
memcpy(command, &power, 1);
return 1;
}
static int aic_priv_cmd_set_txpwr_loss(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command)
{
s8_l func;
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *dev = g_rwnx_plat->sdiodev;
#endif
#ifdef AICWF_USB_SUPPORT
struct aic_usb_dev *dev = g_rwnx_plat->usbdev;
#endif
if (argc > 1) {
func = (s8_l)command_strtoul(argv[1], NULL, 10);
AICWFDBG(LOGINFO, "set txpwr loss: %d\n", func);
if (dev->chipid == PRODUCT_ID_AIC8800D81 ||
dev->chipid == PRODUCT_ID_AIC8800D80N){
set_txpwr_loss_ofst(func);
rwnx_send_txpwr_lvl_v3_req(dev->rwnx_hw);
}else if(dev->chipid == PRODUCT_ID_AIC8800D81X2 ||
dev->chipid == PRODUCT_ID_AIC8800D89X2){
set_txpwr_loss_ofst(func);
rwnx_send_txpwr_lvl_v4_req(dev->rwnx_hw);
}else if(dev->chipid == PRODUCT_ID_AIC8800DC ||
dev->chipid == PRODUCT_ID_AIC8800DW){
set_txpwr_loss_ofst(func);
rwnx_send_txpwr_lvl_req(dev->rwnx_hw);
}else{
AICWFDBG(LOGINFO, "error:don't support 8800D");
}
} else {
AICWFDBG(LOGERROR, "wrong args\n");
return -EINVAL;
}
return 0;
}
static int aic_priv_cmd_set_ant_mode (struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command)
{
u8_l func = 0;
@@ -1340,6 +1389,12 @@ static int aic_priv_cmd_country_set(struct rwnx_hw *rwnx_hw, int argc,
return -1;
}
if (!rwnx_hw->mod_params->custregd) {
AICWFDBG(LOGERROR, "%s: invalid custregd\n", __func__);
return -1;
}
AICWFDBG(LOGINFO, "cmd country_set: %s\n", argv[1]);
regdomain = getRegdomainFromRwnxDB(rwnx_hw->wiphy, argv[1]);
@@ -1474,6 +1529,58 @@ static int aic_priv_cmd_check_flash(struct rwnx_hw *rwnx_hw, int argc, char *arg
return 8;
}
static int aic_priv_cmd_get_rssi(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command)
{
rwnx_send_rftest_req(rwnx_hw, GET_RSSI, 0, NULL, &cfm);
memcpy(command, &cfm.rftest_result[0], 1);
AICWFDBG(LOGINFO, "get_rssi: %d\n", (char)cfm.rftest_result[0]);
return 1;
}
#ifdef CONFIG_DYNAMIC_PERPWR
static int aic_priv_cmd_set_sta_thd(struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command)
{
int i;
s8_l val;
if (argc < 3) {
AICWFDBG(LOGERROR, "%s: Invalid parameters (argc=%d)\n", __func__, argc);
return -EINVAL;
}
AICWFDBG(LOGDEBUG, "cmd set_sta_thd: %s, %s\n", argv[1], argv[2]);
val = (s8_l)command_strtoul(argv[2], NULL, 10);
struct {
const char *name;
s8_l *target;
size_t name_len;
} thd_map[] = {
{ "rssi_thd_0", &rwnx_hw->pwrth.rssi_thd_0, 10 },
{ "rssi_thd_1", &rwnx_hw->pwrth.rssi_thd_1, 10 },
{ "rssi_thd_2", &rwnx_hw->pwrth.rssi_thd_2, 10 },
{ "pwr_loss_lvl_0", &rwnx_hw->pwrth.pwr_loss_lvl_0, 14 },
{ "pwr_loss_lvl_1", &rwnx_hw->pwrth.pwr_loss_lvl_1, 14 },
{ "pwr_loss_lvl_2", &rwnx_hw->pwrth.pwr_loss_lvl_2, 14 },
{ "pwr_loss_lvl_3", &rwnx_hw->pwrth.pwr_loss_lvl_3, 14 },
};
for (i = 0; i < ARRAY_SIZE(thd_map); i++) {
if (strncmp(argv[1], thd_map[i].name, thd_map[i].name_len) == 0) {
*thd_map[i].target = val;
AICWFDBG(LOGINFO, "%s: %s = %d\n", __func__, thd_map[i].name, val);
return 0;
}
}
AICWFDBG(LOGERROR, "%s: Unknown parameter '%s'\n", __func__, argv[1]);
return -EINVAL;
}
#endif
static int aic_priv_cmd_help (struct rwnx_hw *rwnx_hw, int argc, char *argv[], char *command)
{
print_help(argc > 0 ? argv[0] : NULL);
@@ -1575,6 +1682,10 @@ static const struct aic_priv_cmd aic_priv_commands[] = {
"= off usb configure before usb disconnect" },
{ "set_pll_test", aic_priv_cmd_set_pll_test,
"<func> <freq> <tx_pwr> = use pll test to measure saturation power" },
{ "get_txpwr", aic_priv_cmd_get_txpwr,
"= get userconfig max txpwr" },
{ "set_txpwr_loss",aic_priv_cmd_set_txpwr_loss,
"<val> = txpwr will change ,val can be negative" },
{ "set_ant", aic_priv_cmd_set_ant_mode,
"<val> = 0/ant0, 1/ant1, 2/both" },
{ "rdwr_bt_efuse_pwrofst", aic_priv_cmd_rdwr_bt_efuse_pwrofst,
@@ -1589,6 +1700,11 @@ static const struct aic_priv_cmd aic_priv_commands[] = {
"a value is added for both 2.4G and 5G to achieve overall power adjustment of the band, write to efuse"},
{"check_flash", aic_priv_cmd_check_flash,
"check bin crc in flash" },
{"get_rssi", aic_priv_cmd_get_rssi, "get rssi"},
#ifdef CONFIG_DYNAMIC_PERPWR
{"set_sta_thd", aic_priv_cmd_set_sta_thd,
"set per_sta power threshold, (set_sta_thd rssi_thd_0 value; set_sta_thd pwr_loss_lvl_0 value)"},
#endif
//Reserve for new aic_priv_cmd.
{ "help", aic_priv_cmd_help,
@@ -1716,7 +1832,7 @@ void set_vendor_extension_ie(char *command){
}
#endif//CONFIG_SET_VENDOR_EXTENSION_IE
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_chan_def *chandef);
#else
@@ -1724,7 +1840,7 @@ int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef);
#endif
int rwnx_atoi2(char *value, int c_len);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter)
#else
void set_mon_chan(struct rwnx_vif *vif, char *parameter)
@@ -1751,7 +1867,7 @@ void set_mon_chan(struct rwnx_vif *vif, char *parameter)
chandef->center_freq1 = chandef->chan->center_freq;
chandef->center_freq2 = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, dev, chandef);
#else
rwnx_cfg80211_set_monitor_channel_(vif->rwnx_hw->wiphy, chandef);
@@ -1794,7 +1910,7 @@ int get_cs_info(struct rwnx_vif *vif, u8 *mac_addr, u8 *val)
}
memset(&cs_info, 0, sizeof(struct aicwf_cs_info));
memcpy(cs_info.countrycode, country_code, 4);
memcpy(cs_info.countrycode, vif->rwnx_hw->wiphy->regd->alpha2, 2);
if((sta == NULL) && (RWNX_VIF_TYPE(vif) == NL80211_IFTYPE_AP)) {
sta = &vif->rwnx_hw->sta_table[vif->ap.bcmc_index];
@@ -1940,6 +2056,11 @@ int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
strncasecmp(command, "country_set", strlen("country_set"))) {
skip = strlen(CMD_SET_COUNTRY) + 1;
country = command + skip;
if (!vif->rwnx_hw->mod_params->custregd) {
AICWFDBG(LOGERROR, "%s: invalid custregd\n", __func__);
ret = -EINVAL;
goto exit;
}
if (!country || strlen(country) < RWNX_COUNTRY_CODE_LEN) {
AICWFDBG(LOGERROR, "%s: invalid country code\n", __func__);
ret = -EINVAL;
@@ -1991,9 +2112,11 @@ int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
if(g_rwnx_plat && g_rwnx_plat->usbdev->rwnx_hw){
if (g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW ||
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DC) ||
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DLN) ||
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D81) ||
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D81X2) ||
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D89X2)){
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D89X2) ||
(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D80N)){
set_testmode(!testmode);
rwnx_send_reboot(g_rwnx_plat->usbdev->rwnx_hw);
}
@@ -2013,7 +2136,7 @@ int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
char *set_parameter;
skip = strlen(CMD_SET_MON_FREQ) + 1;
set_parameter = command + skip;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0))
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
set_mon_chan(vif, net, set_parameter);
#else
set_mon_chan(vif, set_parameter);
@@ -59,6 +59,14 @@ typedef struct _compat_android_wifi_priv_cmd {
int android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd);
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);
int str_starts(const char *str, const char *start);
int handle_private_cmd(struct net_device *net, char *command, u32 cmd_len);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
void set_mon_chan(struct rwnx_vif *vif, struct net_device *dev, char *parameter);
#else
void set_mon_chan(struct rwnx_vif *vif, char *parameter);
#endif
#endif /* _AIC_PRIV_CMD_H_ */
@@ -323,6 +323,13 @@ static int aicwf_vendor_subcmd_set_country_code(struct wiphy *wiphy, struct wire
const struct nlattr *iter;
struct ieee80211_regdomain *regdomain;
struct rwnx_hw *rwnx_hw = wiphy_priv(wiphy);
if (!rwnx_hw->mod_params->custregd) {
AICWFDBG(LOGERROR, "%s: invalid custregd\n", __func__);
return -EINVAL;
}
nla_for_each_attr(iter, data, len, rem) {
type = nla_type(iter);
switch (type) {
@@ -2,6 +2,7 @@
#define _AIC_VENDOR_H
#include <linux/types.h>
#include "rwnx_defs.h"
#define GOOGLE_OUI 0x001A11
#define BRCM_OUI 0x001018
@@ -342,5 +343,10 @@ typedef struct wl_mkeep_alive_pkt {
u8 data[1];
} wl_mkeep_alive_pkt_t;
int aic_dev_start_mkeep_alive(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
u8 mkeep_alive_id, u8 *ip_pkt, u16 ip_pkt_len, u8 *src_mac, u8 *dst_mac, u32 period_msec);
int aic_dev_stop_mkeep_alive(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, u8 mkeep_alive_id);
int aicwf_vendor_init(struct wiphy *wiphy);
#endif /* _AIC_VENDOR_H */
@@ -1,11 +1,9 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#include "aicwf_compat_8800d80.h"
#define FW_USERCONFIG_NAME_8800D80 "aic_userconfig_8800d80.txt"
#define FW_USERCONFIG_NAME_8800D80_U11 "aic_userconfig_8800d80_u11.txt"
#define FW_USERCONFIG_NAME_8800D80_U11_PRO "aic_userconfig_8800d80_u11_pro.txt"
#define FW_USERCONFIG_NAME_8800D80_U11_CUS "aic_userconfig_8800d80_u11_cus.txt"
#define FW_POWERLIMIT_NAME_8800D80 "aic_powerlimit_8800d80.txt"
extern char aic_fw_path[200];
@@ -40,23 +38,10 @@ int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800D80;
if (rwnx_hw->usbdev->pid == USB_PRODUCT_ID_TENDA_U11
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS1
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS4
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS7) {
filename = FW_USERCONFIG_NAME_8800D80_U11;
} else if (rwnx_hw->usbdev->pid == USB_PRODUCT_ID_TENDA_U11_PRO
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS3
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS5
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS6
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS8) {
filename = FW_USERCONFIG_NAME_8800D80_U11_PRO;
} else if (rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800M80_CUS2) {
filename = FW_USERCONFIG_NAME_8800D80_U11_CUS;
}
#ifndef ANDROID_PLATFORM
sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80");
if (strlcat(aic_fw_path, "/aic8800D80", sizeof(aic_fw_path)) >= sizeof(aic_fw_path))
return -ENAMETOOLONG;
#endif
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
@@ -102,7 +87,7 @@ int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw)
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* parsing the file */
rwnx_plat_powerlimit_parsing((char *)dst, size, country_code);
rwnx_plat_powerlimit_parsing((char *)dst, size);
rwnx_release_firmware_common(&dst);
@@ -111,3 +96,37 @@ int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw)
}
#endif
int system_config_8800d80(struct rwnx_hw *rwnx_hw)
{
int ret;
const u32 mem_addr = 0x40500000;
const u32 read_mem_addr = 0x40241014;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGINFO, "%x rd fail: %d\n", mem_addr, ret);
return ret;
}
if (((rd_mem_addr_cfm.memdata >> 25) & 0x01UL) == 0x00UL) {
chip_mcu_id = 1;
}
chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16);
AICWFDBG(LOGINFO, "chip_id=%x, chip_mcu_id = %d\n", chip_id, chip_mcu_id);
if (testmode == 1 && (IS_CHIP_ID_H()))
{
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, read_mem_addr, &rd_mem_addr_cfm);
AICWFDBG(LOGINFO, "%s 0x%08x=0x%08x\n", __func__, read_mem_addr, rd_mem_addr_cfm.memdata);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", read_mem_addr, ret);
return ret;
} else {
if (rd_mem_addr_cfm.memdata != 1) {
AICWFDBG(LOGERROR, "check fail: %x\n", rd_mem_addr_cfm.memdata);
return -1;
}
}
}
return 0;
}
@@ -5,5 +5,5 @@ int rwnx_plat_userconfig_load_8800d80(struct rwnx_hw *rwnx_hw);
int rwnx_plat_powerlimit_load_8800d80(struct rwnx_hw *rwnx_hw);
#endif
int aicwf_set_rf_config_8800d80(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
int system_config_8800d80(struct rwnx_hw *rwnx_hw);
@@ -0,0 +1,560 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#include "rwnx_platform.h"
#include "aicwf_compat_8800d80n.h"
#define FW_USERCONFIG_NAME_8800D80N "aic_userconfig_8800d80n.txt"
#define FW_POWERLIMIT_NAME_8800D80N "aic_powerlimit_8800d80n.txt"
#define RWNX_MAC_FW_RF_BASE_NAME_8800D80N "lmacfw_rf_8800d80n.bin"
#define RWNX_MAC_FW_INITVAR_NAME_8800D80N "fmacfw_initvar_8800d80n.bin"
#define RWNX_MAC_FW_GAINTBL_NAME_8800D80N "fmacfw_gaintbl_8800d80n.bin"
#define RWNX_MAC_FW_CINIT_NAME_8800D80N_U02 "fmacfw_cinit_8800d80n_u02.bin"
#define RWNX_MAC_FW_CALIB_NAME_8800D80N_U02 "fmacfw_calib_8800d80n_u02.bin"
#define RWNX_MAC_PATCH_NAME_8800D80N_U02 "fmacfw_patch_8800d80n_u02.bin"
#define RWNX_MAC_PATCHTBL_NAME_8800D80N_U02 "fmacfw_patch_tbl_8800d80n_u02.bin"
#define RAM_LMAC_FW_RF_ADDR_8800D80N 0x00132C00
#define ROM_FMAC_CINIT_ADDR_8800D80N_U02 0x00133000
#define ROM_FMAC_CALIB_ADDR_8800D80N_U02 0x00138000
#define ROM_FMAC_PATCH_ADDR_8800D80N_U02 0x00188000
#define CHIP_INFO_FLAG_CINIT_BEGIN (0x01U << 12)
#define CHIP_INFO_FLAG_CINIT_DONE (0x01U << 13)
#define PATCH_VAR_FLAG_CALIB_BEGIN (0x01U << 0)
#define PATCH_VAR_FLAG_CALIB_DONE (0x01U << 1)
#define WF_RXGAIN_TBL_IDX_MAX 20
#define WF_RXGAIN_TBL_SIZE 256
#define WF_TXGAIN_TBL_IDX_MAX 21
#define WF_TXGAIN_TBL_SIZE 128
extern char aic_fw_path[200];
int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename);
int rwnx_plat_bin_fw_upload_2_with_version(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename, char *version_str, int version_size);
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
u32** buffer, const char *filename);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
void rwnx_release_firmware_common(u32** buffer);
extern int get_adap_test(void);
typedef u32 (*array2_tbl_t)[2];
typedef u32 (*array3_tbl_t)[3];
u32 syscfg_tbl_masked_8800d80n[][3] = {
// {Address, mask, value}
#if DEF_PATCH_METHOD_VER_1 // moved to cinit.bin
// anareg1, u01 only
{0x4050201C, (0x7 << 0), (0x7 << 0)},
// pmic_pmu_init
{0x70001024, ((0x1F << 0) | (0x1 << 14) | (0x1 << 15)),
((0x08 << 0) | (0x1 << 14) | (0x1 << 15))},
{0x70001044, (0xF << 20), (0x4 << 20)},
{0x70001084, ((0xF << 23) | (0x1 << 27) | (0x1 << 31)),
((0x4 << 23) | (0x0 << 27) | (0x1 << 31))},
{0x70002118, (0x3 << 0), (0x0 << 0)},
{0x7000211C, (0x3 << 2), (0x0 << 2)},
{0x700021D8, (0x3 << 4), (0x0 << 4)},
{0x700021D0, ((0x1 << 5) | (0x1 << 6)),
((0x1 << 5) | (0x1 << 6))},
#if defined(CONFIG_VRF_DCDC_MODE)
{0x70001000, (0x1 << 0), (0x1 << 0)},
#else
{0x70001000, (0x1 << 0), (0x0 << 0)},
#endif
// cm_rf_init
{0x4050500C, ((0x7 << 27) | (0x3 << 30)),
((0x3 << 27) | (0x3 << 30))},
{0x40505008, ((0x3 << 11) | (0xF << 15)),
((0x1 << 11) | (0x4 << 15))},
#endif
{0x00000000, 0x00000000, 0x00000000}, // last one
};
u32 patch_tbl_wifisetting_8800d80n[][2] =
{
//{0x00b8, 0x00009d08 | (0x01U << 13)}, // debug_mask, bit13: CALIB_BIT
};
//adap test
u32 adaptivity_patch_tbl_8800d80n[][2] = {
};
u32 patch_tbl_rf_func_8800d80n[][2] =
{
};
extern int testmode;
extern u8 chip_id;
extern u8 chip_mcu_id;
void system_config_8800d80n(struct rwnx_hw *rwnx_hw)
{
int syscfg_num;
array3_tbl_t p_syscfg_msk_tbl;
int ret, cnt;
const u32 mem_addr = 0x40500000;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", mem_addr, ret);
return;
}
chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16);
//printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
if (((rd_mem_addr_cfm.memdata >> 25) & 0x01UL) == 0x00UL) {
chip_mcu_id = 1;
}
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, 0x00000020, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "[0x00000020] rd fail: %d\n", ret);
return;
}
chip_sub_id = (u8)(rd_mem_addr_cfm.memdata);
//printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
AICWFDBG(LOGINFO, "chip_id=%x, chip_sub_id=%x\n", chip_id, chip_sub_id);
syscfg_num = sizeof(syscfg_tbl_masked_8800d80n) / sizeof(u32) / 3;
p_syscfg_msk_tbl = syscfg_tbl_masked_8800d80n;
for (cnt = 0; cnt < syscfg_num; cnt++) {
if (p_syscfg_msk_tbl[cnt][0] == 0x00000000) {
break;
}
ret = rwnx_send_dbg_mem_mask_write_req(rwnx_hw,
p_syscfg_msk_tbl[cnt][0], p_syscfg_msk_tbl[cnt][1], p_syscfg_msk_tbl[cnt][2]);
if (ret) {
AICWFDBG(LOGERROR, "%x mask write fail: %d\n", p_syscfg_msk_tbl[cnt][0], ret);
return;
}
}
}
int aicwf_plat_patch_load_8800d80n(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
char patch_ver_str[128];
//wifi patch
ret = rwnx_plat_bin_fw_upload_2_with_version(rwnx_hw,
ROM_FMAC_PATCH_ADDR_8800D80N_U02, RWNX_MAC_PATCH_NAME_8800D80N_U02, patch_ver_str, sizeof(patch_ver_str));
if (ret) {
AICWFDBG(LOGERROR, "load patch bin fail: %d\n", ret);
return ret;
}
AICWFDBG(LOGINFO, "PatchVer: %s", patch_ver_str);
return ret;
}
int aicwf_plat_patch_table_load_8800d80n(struct rwnx_hw *rwnx_hw)
{
int err = 0;
unsigned int i, size;
u32 *dst = NULL;
char *filename = RWNX_MAC_PATCHTBL_NAME_8800D80N_U02;
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Upload %s \n", filename);
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (!dst) {
AICWFDBG(LOGERROR, "No such file or directory\n");
return -1;
}
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
err = -1;
}
AICWFDBG(LOGINFO, "tbl size = %d \n", size);
if (!err) {
for (i = 0; i < (size / 4); i += 2) {
if ((dst[i] == 0x0) || (dst[i] == 0xFFFFFFFF)) {
break; // end of tbl
}
AICWFDBG(LOGERROR, "patch_tbl: %x %x\n", dst[i], dst[i+1]);
err = rwnx_send_dbg_mem_write_req(rwnx_hw, dst[i], dst[i+1]);
}
if (err) {
AICWFDBG(LOGERROR, "tbl bin upload fail: %x, err:%d\r\n", dst[i], err);
}
}
if (dst) {
rwnx_release_firmware_common(&dst);
}
return err;
}
void aicwf_patch_config_8800d80n(struct rwnx_hw *rwnx_hw)
{
#ifdef CONFIG_ROM_PATCH_EN
int ret = 0;
int cnt = 0;
//adap test
int adap_test = 0;
int adap_patch_num = 0;
adap_test = get_adap_test();
//adap test
if (testmode == 0) {
const u32 cfg_base = 0x10170;
struct dbg_mem_read_cfm cfm;
//int i;
u32 wifisetting_cfg_addr;
u32 agc_cfg_addr;
u32 txgain_cfg_24g_addr, txgain_cfg_5g_addr;
u32 jump_tbl_addr = 0;
u32 patch_tbl_wifisetting_num = sizeof(patch_tbl_wifisetting_8800d80n)/sizeof(u32)/2;
//u32 jump_tbl_size = 0;
//u32 patch_tbl_func_num = 0;
//array2_tbl_t jump_tbl_base = NULL;
//array2_tbl_t patch_tbl_func_base = NULL;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base, &cfm))) {
AICWFDBG(LOGERROR, "setting base[0x%x] rd fail: %d\n", cfg_base, ret);
}
wifisetting_cfg_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 4, &cfm))) {
AICWFDBG(LOGERROR, "jump_tbl base[0x%x] rd fail: %d\n", cfg_base + 4, ret);
}
jump_tbl_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x10, &cfm))) {
AICWFDBG(LOGERROR, "agc_cfg base[0x%x] rd fail: %d\n", cfg_base + 0xc, ret);
}
agc_cfg_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm))) {
AICWFDBG(LOGERROR, "txgain_cfg_24g base[0x%x] rd fail: %d\n", cfg_base + 0x10, ret);
}
txgain_cfg_24g_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x18, &cfm))) {
AICWFDBG(LOGERROR, "txgain_cfg_5g base[0x%x] rd fail: %d\n", cfg_base + 0x10, ret);
}
txgain_cfg_5g_addr = cfm.memdata;
AICWFDBG(LOGINFO, "wifisetting_cfg_addr=%x, jump_tbl_addr=%x, agc_cfg_addr=%x, txgain_cfg_24g_addr=%x, txgain_cfg_5g_addr=%x\n",
wifisetting_cfg_addr, jump_tbl_addr, agc_cfg_addr, txgain_cfg_24g_addr, txgain_cfg_5g_addr);
for (cnt = 0; cnt < patch_tbl_wifisetting_num; cnt++) {
if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + patch_tbl_wifisetting_8800d80n[cnt][0], patch_tbl_wifisetting_8800d80n[cnt][1]))) {
AICWFDBG(LOGERROR, "wifisetting %x write fail\n", patch_tbl_wifisetting_8800d80n[cnt][0]);
}
}
//adap test
if (adap_test) {
adap_patch_num = sizeof(adaptivity_patch_tbl_8800d80n)/sizeof(u32)/2;
for(cnt = 0; cnt < adap_patch_num; cnt++)
{
if((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + adaptivity_patch_tbl_8800d80n[cnt][0], adaptivity_patch_tbl_8800d80n[cnt][1]))) {
AICWFDBG(LOGERROR, "%x write fail\n", wifisetting_cfg_addr + adaptivity_patch_tbl_8800d80n[cnt][0]);
}
}
}
//adap test
#if DEF_PATCH_METHOD_VER_1
ret = aicwf_plat_initvar_load_8800d80n(rwnx_hw, txgain_cfg_24g_addr);
if (ret) {
AICWFDBG(LOGERROR, "initvar load fail: %d\n", ret);
return;
}
#endif
}
else {
u32 patch_tbl_rf_func_num = sizeof(patch_tbl_rf_func_8800d80n)/sizeof(u32)/2;
for (cnt = 0; cnt < patch_tbl_rf_func_num; cnt++) {
if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, patch_tbl_rf_func_8800d80n[cnt][0], patch_tbl_rf_func_8800d80n[cnt][1]))) {
AICWFDBG(LOGERROR, "patch_tbl_rf_func %x write fail\n", patch_tbl_rf_func_8800d80n[cnt][0]);
}
}
}
#endif
}
int aicwf_plat_rftest_load_8800d80n(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, RAM_LMAC_FW_RF_ADDR_8800D80N, RWNX_MAC_FW_RF_BASE_NAME_8800D80N);
if (ret) {
AICWFDBG(LOGINFO, "load rftest bin fail: %d\n", ret);
return ret;
}
return ret;
}
int aicwf_plat_rftest_exec_8800d80n(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
uint32_t fw_addr, boot_type;
uint32_t rst_hdlr_addr = RAM_LMAC_FW_RF_ADDR_8800D80N + 0x04;
uint32_t rst_hdlr_val;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, rst_hdlr_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", rst_hdlr_addr, ret);
return ret;
}
rst_hdlr_val = rd_mem_addr_cfm.memdata;
if ((rst_hdlr_val & ~0x03FF) == RAM_LMAC_FW_RF_ADDR_8800D80N) {
AICWFDBG(LOGINFO, "rftest loaded, hdlr=%x\n", rst_hdlr_val);
}
/* fw start */
fw_addr = RAM_LMAC_FW_RF_ADDR_8800D80N;
boot_type = HOST_START_APP_AUTO;
AICWFDBG(LOGINFO, "Start app: %08x, %d\n", fw_addr, boot_type);
ret = rwnx_send_dbg_start_app_req(rwnx_hw, fw_addr, boot_type);
if (ret) {
AICWFDBG(LOGERROR, "start app fail: %d\n", ret);
return ret;
}
return ret;
}
#if DEF_PATCH_METHOD_VER_1
int aicwf_plat_initvar_load_8800d80n(struct rwnx_hw *rwnx_hw, u32 var_base_addr)
{
int ret = 0;
ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, var_base_addr, RWNX_MAC_FW_INITVAR_NAME_8800D80N);
if (ret) {
AICWFDBG(LOGERROR, "load initvar bin fail: %d\n", ret);
return ret;
}
return ret;
}
int aicwf_plat_gain_table_load_8800d80n(struct rwnx_hw *rwnx_hw)
{
int size, desired_size, idx, ret;
u32 *dst=NULL;
u8_l *tbl_base;
char *filename = RWNX_MAC_FW_GAINTBL_NAME_8800D80N;
AICWFDBG(LOGINFO, "gaintbl file path:%s\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
desired_size = WF_RXGAIN_TBL_IDX_MAX * WF_RXGAIN_TBL_SIZE + WF_TXGAIN_TBL_IDX_MAX * WF_TXGAIN_TBL_SIZE;
if ((size <= 0) || (size != desired_size)) {
AICWFDBG(LOGERROR, "wrong size of firmware file, desired=%d, size=%d\n", desired_size, size);
if (dst) {
rwnx_release_firmware_common(&dst);
dst = NULL;
}
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* RX gain */
tbl_base = (u8_l *)dst;
for (idx = 0; idx < WF_RXGAIN_TBL_IDX_MAX; idx++) {
u16_l ofst = idx * 16;
u8_l *tbl_ptr = tbl_base + idx * WF_RXGAIN_TBL_SIZE;
ret = rwnx_send_rf_config_v2_req(rwnx_hw, ofst, 0, tbl_ptr, WF_RXGAIN_TBL_SIZE);
if (ret) {
AICWFDBG(LOGERROR, "rx gain rf_config_req fail, ret=%d, ofst=%d\n", ret, ofst);
break;
}
}
/* TX gain */
tbl_base = (u8_l *)dst + WF_RXGAIN_TBL_IDX_MAX * WF_RXGAIN_TBL_SIZE;
for (idx = 0; idx < WF_TXGAIN_TBL_IDX_MAX; idx++) {
u16_l ofst = idx * 16;
u8_l *tbl_ptr = tbl_base + idx * WF_TXGAIN_TBL_SIZE;
ret = rwnx_send_rf_config_v2_req(rwnx_hw, ofst, 2, tbl_ptr, WF_TXGAIN_TBL_SIZE);
if (ret) {
AICWFDBG(LOGERROR, "tx gain rf_config_req fail, ret=%d, ofst=%d\n", ret, ofst);
break;
}
}
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "gaintbl download complete\n\n");
return 0;
}
#endif
#if DEF_PATCH_METHOD_VER_2
int aicwf_plat_cinit_exec_8800d80n(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
uint32_t fw_addr, boot_type;
uint32_t mem_addr = 0x40500184;
uint32_t mem_val;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", mem_addr, ret);
return ret;
}
mem_val = rd_mem_addr_cfm.memdata;
if (mem_val & CHIP_INFO_FLAG_CINIT_BEGIN) {
// wait done
while (!(mem_val & CHIP_INFO_FLAG_CINIT_DONE)) {
AICWFDBG(LOGINFO, "cinit rd chipinfo=%x\n", mem_val);
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", mem_addr, ret);
return ret;
}
mem_val = rd_mem_addr_cfm.memdata;
}
AICWFDBG(LOGINFO, "cinit executed, chipinfo=%x\n", mem_val);
return ret;
}
ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, ROM_FMAC_CINIT_ADDR_8800D80N_U02, RWNX_MAC_FW_CINIT_NAME_8800D80N_U02);
if (ret) {
AICWFDBG(LOGERROR, "load cinit bin fail: %d\n", ret);
return ret;
}
/* fw start */
fw_addr = ROM_FMAC_CINIT_ADDR_8800D80N_U02 + 0x0009;
boot_type = HOST_START_APP_FNCALL;
AICWFDBG(LOGINFO, "Start app: %08x, %d\n", fw_addr, boot_type);
ret = rwnx_send_dbg_start_app_req(rwnx_hw, fw_addr, boot_type);
if (ret) {
AICWFDBG(LOGERROR, "start app fail: %d\n", ret);
return ret;
}
return ret;
}
int aicwf_plat_calib_exec_8800d80n(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
uint32_t fw_addr, boot_type;
uint32_t patch_var_flags_addr = ROM_FMAC_PATCH_ADDR_8800D80N_U02 + 0x08;
uint32_t patch_var_flags_val;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, patch_var_flags_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", patch_var_flags_addr, ret);
return ret;
}
patch_var_flags_val = rd_mem_addr_cfm.memdata;
if (patch_var_flags_val & (PATCH_VAR_FLAG_CALIB_BEGIN | PATCH_VAR_FLAG_CALIB_DONE)) {
AICWFDBG(LOGINFO, "calib executed, var_flags=%x\n", patch_var_flags_val);
return ret;
}
ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, ROM_FMAC_CALIB_ADDR_8800D80N_U02, RWNX_MAC_FW_CALIB_NAME_8800D80N_U02);
if (ret) {
AICWFDBG(LOGERROR, "load calib bin fail: %d\n", ret);
return ret;
}
/* fw start */
fw_addr = ROM_FMAC_CALIB_ADDR_8800D80N_U02 + 0x0009;
boot_type = HOST_START_APP_FNCALL;
AICWFDBG(LOGINFO, "Start app: %08x, %d\n", fw_addr, boot_type);
ret = rwnx_send_dbg_start_app_req(rwnx_hw, fw_addr, boot_type);
if (ret) {
AICWFDBG(LOGERROR, "start app fail: %d\n", ret);
return ret;
}
return ret;
}
#endif
int aicwf_set_rf_config_8800d80n(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
{
int ret = 0;
if ((ret = rwnx_send_txpwr_lvl_v3_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_lvl_adj_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_ofst2x_req(rwnx_hw))) {
return -1;
}
#if DEF_PATCH_METHOD_VER_1
if (testmode == FW_NORMAL_MODE) {
aicwf_plat_gain_table_load_8800d80n(rwnx_hw);
}
#endif
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
return -1;
}
return 0 ;
}
int rwnx_plat_userconfig_load_8800d80n(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800D80N;
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
rwnx_plat_userconfig_parsing((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}
#ifdef CONFIG_POWER_LIMIT
extern char country_code[];
int rwnx_plat_powerlimit_load_8800d80n(struct rwnx_hw *rwnx_hw)
{
int size;
u32 *dst=NULL;
char *filename = FW_POWERLIMIT_NAME_8800D80N;
AICWFDBG(LOGINFO, "powerlimit file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of cfg file\n");
dst = NULL;
return 0;
}
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* parsing the file */
rwnx_plat_powerlimit_parsing((char *)dst, size, country_code);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "powerlimit download complete\n\n");
return 0;
}
#endif
@@ -0,0 +1,32 @@
#include <linux/types.h>
#define DEF_PATCH_METHOD_VER_1 0 // deprecated
#define DEF_PATCH_METHOD_VER_2 1 // in used
void system_config_8800d80n(struct rwnx_hw *rwnx_hw);
int aicwf_plat_patch_load_8800d80n(struct rwnx_hw *rwnx_hw);
int aicwf_plat_patch_table_load_8800d80n(struct rwnx_hw *rwnx_hw);
void aicwf_patch_config_8800d80n(struct rwnx_hw *rwnx_hw);
int aicwf_plat_rftest_load_8800d80n(struct rwnx_hw *rwnx_hw);
int aicwf_plat_rftest_exec_8800d80n(struct rwnx_hw *rwnx_hw);
#if DEF_PATCH_METHOD_VER_1
int aicwf_plat_initvar_load_8800d80n(struct rwnx_hw *rwnx_hw, u32 var_base_addr);
int aicwf_plat_gain_table_load_8800d80n(struct rwnx_hw *rwnx_hw);
#endif
#if DEF_PATCH_METHOD_VER_2
int aicwf_plat_cinit_exec_8800d80n(struct rwnx_hw *rwnx_hw);
int aicwf_plat_calib_exec_8800d80n(struct rwnx_hw *rwnx_hw);
#endif
int rwnx_plat_userconfig_load_8800d80n(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_POWER_LIMIT
int rwnx_plat_powerlimit_load_8800d80n(struct rwnx_hw *rwnx_hw);
#endif
int aicwf_set_rf_config_8800d80n(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
@@ -1,6 +1,7 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#include "aicwf_compat_8800d80x2.h"
#define FW_USERCONFIG_NAME_8800D80X2 "aic_userconfig_8800d80x2.txt"
#define FW_POWERLIMIT_NAME_8800D80X2 "aic_powerlimit_8800d80x2.txt"
@@ -40,7 +41,8 @@ int rwnx_plat_userconfig_load_8800d80x2(struct rwnx_hw *rwnx_hw){
char *filename = FW_USERCONFIG_NAME_8800D80X2;
#ifndef ANDROID_PLATFORM
sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800D80X2");
if (strlcat(aic_fw_path, "/aic8800D80X2", sizeof(aic_fw_path)) >= sizeof(aic_fw_path))
return -ENAMETOOLONG;
#endif
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
@@ -86,7 +88,7 @@ int rwnx_plat_powerlimit_load_8800d80x2(struct rwnx_hw *rwnx_hw)
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* parsing the file */
rwnx_plat_powerlimit_parsing((char *)dst, size, country_code);
rwnx_plat_powerlimit_parsing((char *)dst, size);
rwnx_release_firmware_common(&dst);
@@ -3047,14 +3047,18 @@ int aicwf_misc_ram_valid_check_8800dc(struct rwnx_hw *rwnx_hw, int *valid_out)
*valid_out = 0;
}
AICWFDBG(LOGINFO, "issue71: checking legacy V3 DPD result\n");
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, boot_argc_read_addr, &cfm);
if (ret) {
AICWFDBG(LOGERROR, "boot argc [0x%x] rd fail: %d\n", boot_argc_read_addr, ret);
return ret;
}
printk("boot argc %x\n", cfm.memdata);
AICWFDBG(LOGINFO, "issue71: boot argc=0x%x\n", cfm.memdata);
if (cfm.memdata & 0x10) {
if (valid_out) {
*valid_out = 1;
}
AICWFDBG(LOGINFO, "issue71: boot arguments mark DPD result valid\n");
return ret;
}
if (chip_mcu_id) {
@@ -3064,7 +3068,6 @@ int aicwf_misc_ram_valid_check_8800dc(struct rwnx_hw *rwnx_hw, int *valid_out)
return ret;
}
flash_size = cfm.memdata & 0xff;
printk("flash size %x\n", flash_size);
if (flash_size == 0x16) {
dpd_info_read_addr += 0x4300000;
} else if (flash_size == 0x15) {
@@ -3079,10 +3082,14 @@ int aicwf_misc_ram_valid_check_8800dc(struct rwnx_hw *rwnx_hw, int *valid_out)
AICWFDBG(LOGERROR, "dpd info [0x%x] rd fail: %d\n", dpd_info_read_addr, ret);
return ret;
}
AICWFDBG(LOGINFO,
"issue71: flash size=0x%x, DPD info [0x%x]=0x%x\n",
flash_size, dpd_info_read_addr, cfm.memdata);
if (cfm.memdata & (1<<7)) {
if (valid_out) {
*valid_out = 1;
}
AICWFDBG(LOGINFO, "issue71: legacy V3 flash DPD result is valid\n");
}
} else {
if (testmode == FW_RFTEST_MODE) {
@@ -3510,16 +3517,17 @@ int rwnx_plat_userconfig_load_8800dc(struct rwnx_hw *rwnx_hw){
int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
u16 pid = le16_to_cpu(rwnx_hw->usbdev->udev->descriptor.idProduct);
char *filename = FW_USERCONFIG_NAME_8800DW;
if (rwnx_hw->usbdev->pid == USB_PRODUCT_ID_TENDA
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800FC_CUS3
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800FC_CUS5
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800FC_CUS6) {
if (pid == USB_PRODUCT_ID_TENDA
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS3
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS5
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS6) {
filename = FW_USERCONFIG_NAME_8800DW_W311;
} else if (rwnx_hw->usbdev->pid == USB_PRODUCT_ID_TENDA_U2
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800FC_CUS1
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800FC_CUS2
|| rwnx_hw->usbdev->pid == USB_PRODUCT_ID_AIC8800FC_CUS4) {
} else if (pid == USB_PRODUCT_ID_TENDA_U2
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS1
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS2
|| pid == USB_PRODUCT_ID_AIC8800FC_CUS4) {
filename = FW_USERCONFIG_NAME_8800DW_U2;
}
@@ -3666,7 +3674,10 @@ void system_config_8800dc(struct rwnx_hw *rwnx_hw){
}
chip_sub_id = (u8)(rd_mem_addr_cfm.memdata);
//printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
AICWFDBG(LOGINFO, "chip_id=%x, chip_sub_id=%x\n", chip_id, chip_sub_id);
AICWFDBG(LOGINFO, "chip_id=%x, chip_mcu_id=%x, chip_sub_id=%x\n",
chip_id, chip_mcu_id, chip_sub_id);
AICWFDBG(LOGINFO,
"issue71: using complete pre-SDK-V5/V3 DC/DW firmware and loader profile\n");
//Crystal provided by CPU (start)
@@ -60,3 +60,6 @@ int rwnx_plat_userconfig_load_8800dw(struct rwnx_hw *rwnx_hw);
int rwnx_plat_powerlimit_load_8800dcdw(struct rwnx_hw *rwnx_hw, uint16_t chip_id);
#endif
void system_config_8800dc(struct rwnx_hw *rwnx_hw);
int aicwf_patch_var_config_8800dc(struct rwnx_hw *rwnx_hw);
int set_bbpll_config(struct rwnx_hw *rwnx_hw);
@@ -0,0 +1,330 @@
#include "rwnx_main.h"
#include "rwnx_msg_tx.h"
#include "reg_access.h"
#include "rwnx_platform.h"
#include "aicwf_compat_8800dln.h"
#define FW_USERCONFIG_NAME_8800DLN "aic_userconfig_8800dln.txt"
#define FW_POWERLIMIT_NAME_8800DLN "aic_powerlimit_8800dln.txt"
#define RWNX_MAC_FW_RF_BASE_NAME_8800DLN "lmacfw_rf_8800dln.bin"
#define RWNX_MAC_FW_INITVAR_NAME_8800DLN "fmacfw_initvar_8800dln.bin"
#define RWNX_MAC_FW_GAINTBL_NAME_8800DLN "fmacfw_gaintbl_8800dln.bin"
#define WF_RXGAIN_TBL_IDX_MAX 20
#define WF_RXGAIN_TBL_SIZE 256
#define WF_TXGAIN_TBL_IDX_MAX 21
#define WF_TXGAIN_TBL_SIZE 128
extern char aic_fw_path[200];
int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename);
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw,
u32** buffer, const char *filename);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
void rwnx_release_firmware_common(u32** buffer);
extern int get_adap_test(void);
typedef u32 (*array2_tbl_t)[2];
typedef u32 (*array3_tbl_t)[3];
u32 syscfg_tbl_masked_8800dln[][3] = {
// {Address, mask, value}
{0x00000000, 0x00000000, 0x00000000}, // last one
};
u32 patch_tbl_wifisetting_8800dln[][2] =
{
};
//adap test
u32 adaptivity_patch_tbl_8800dln[][2] = {
};
u32 patch_tbl_rf_func_8800dln[][2] =
{
};
extern int testmode;
extern u8 chip_id;
extern u8 chip_mcu_id;
void system_config_8800dln(struct rwnx_hw *rwnx_hw)
{
int syscfg_num;
array3_tbl_t p_syscfg_msk_tbl;
int ret, cnt;
const u32 mem_addr = 0x40500000;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, mem_addr, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "%x rd fail: %d\n", mem_addr, ret);
return;
}
chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16);
//printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
if (((rd_mem_addr_cfm.memdata >> 25) & 0x01UL) == 0x00UL) {
chip_mcu_id = 1;
}
ret = rwnx_send_dbg_mem_read_req(rwnx_hw, 0x00000020, &rd_mem_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "[0x00000020] rd fail: %d\n", ret);
return;
}
chip_sub_id = (u8)(rd_mem_addr_cfm.memdata);
//printk("%x=%x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
AICWFDBG(LOGINFO, "chip_id=%x, chip_sub_id=%x\n", chip_id, chip_sub_id);
syscfg_num = sizeof(syscfg_tbl_masked_8800dln) / sizeof(u32) / 3;
p_syscfg_msk_tbl = syscfg_tbl_masked_8800dln;
for (cnt = 0; cnt < syscfg_num; cnt++) {
if (p_syscfg_msk_tbl[cnt][0] == 0x00000000) {
break;
}
ret = rwnx_send_dbg_mem_mask_write_req(rwnx_hw,
p_syscfg_msk_tbl[cnt][0], p_syscfg_msk_tbl[cnt][1], p_syscfg_msk_tbl[cnt][2]);
if (ret) {
AICWFDBG(LOGERROR, "%x mask write fail: %d\n", p_syscfg_msk_tbl[cnt][0], ret);
return;
}
}
}
void aicwf_patch_config_8800dln(struct rwnx_hw *rwnx_hw)
{
#ifdef CONFIG_ROM_PATCH_EN
int ret = 0;
int cnt = 0;
//adap test
int adap_test = 0;
int adap_patch_num = 0;
adap_test = get_adap_test();
//adap test
if (testmode == 0) {
const u32 cfg_base = 0x8150;
struct dbg_mem_read_cfm cfm;
u32 wifisetting_cfg_addr;
u32 agc_cfg_addr;
u32 txgain_cfg_24g_addr;
u32 jump_tbl_addr = 0;
u32 patch_tbl_num;
//array2_tbl_t jump_tbl_base = NULL;
array2_tbl_t patch_tbl_base = NULL;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base, &cfm))) {
AICWFDBG(LOGERROR, "setting base[0x%x] rd fail: %d\n", cfg_base, ret);
}
wifisetting_cfg_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 4, &cfm))) {
AICWFDBG(LOGERROR, "jump_tbl base[0x%x] rd fail: %d\n", cfg_base + 4, ret);
}
jump_tbl_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x10, &cfm))) {
AICWFDBG(LOGERROR, "agc_cfg base[0x%x] rd fail: %d\n", cfg_base + 0xc, ret);
}
agc_cfg_addr = cfm.memdata;
if ((ret = rwnx_send_dbg_mem_read_req(rwnx_hw, cfg_base + 0x14, &cfm))) {
AICWFDBG(LOGERROR, "txgain_cfg_24g base[0x%x] rd fail: %d\n", cfg_base + 0x10, ret);
}
txgain_cfg_24g_addr = cfm.memdata;
AICWFDBG(LOGINFO, "wifisetting_cfg_addr=%x, jump_tbl_addr=%x, agc_cfg_addr=%x, txgain_cfg_24g_addr=%x\n",
wifisetting_cfg_addr, jump_tbl_addr, agc_cfg_addr, txgain_cfg_24g_addr);
patch_tbl_num = sizeof(patch_tbl_wifisetting_8800dln)/sizeof(u32)/2;
patch_tbl_base = patch_tbl_wifisetting_8800dln;
for (cnt = 0; cnt < patch_tbl_num; cnt++) {
if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + patch_tbl_base[cnt][0], patch_tbl_base[cnt][1]))) {
AICWFDBG(LOGERROR, "wifisetting %x write fail\n", patch_tbl_base[cnt][0]);
}
}
//adap test
if (adap_test) {
adap_patch_num = sizeof(adaptivity_patch_tbl_8800dln)/sizeof(u32)/2;
patch_tbl_base = adaptivity_patch_tbl_8800dln;
for(cnt = 0; cnt < adap_patch_num; cnt++)
{
if((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, wifisetting_cfg_addr + patch_tbl_base[cnt][0], patch_tbl_base[cnt][1]))) {
AICWFDBG(LOGERROR, "%x write fail\n", wifisetting_cfg_addr + patch_tbl_base[cnt][0]);
}
}
}
//adap test
ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, txgain_cfg_24g_addr, RWNX_MAC_FW_INITVAR_NAME_8800DLN);
if (ret) {
AICWFDBG(LOGINFO, "load initvar bin fail: %d\n", ret);
return;
}
}
else {
u32 patch_tbl_rf_func_num = sizeof(patch_tbl_rf_func_8800dln)/sizeof(u32)/2;
for (cnt = 0; cnt < patch_tbl_rf_func_num; cnt++) {
if ((ret = rwnx_send_dbg_mem_write_req(rwnx_hw, patch_tbl_rf_func_8800dln[cnt][0], patch_tbl_rf_func_8800dln[cnt][1]))) {
AICWFDBG(LOGERROR, "patch_tbl_rf_func %x write fail\n", patch_tbl_rf_func_8800dln[cnt][0]);
}
}
}
#endif
}
int aicwf_plat_rftest_load_8800dln(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
ret = rwnx_plat_bin_fw_upload_2(rwnx_hw, RAM_LMAC_FW_ADDR, RWNX_MAC_FW_RF_BASE_NAME_8800DLN);
if (ret) {
AICWFDBG(LOGINFO, "load rftest bin fail: %d\n", ret);
return ret;
}
return ret;
}
int aicwf_plat_gain_table_load_8800dln(struct rwnx_hw *rwnx_hw)
{
int size, desired_size, idx, ret;
u32 *dst=NULL;
u8_l *tbl_base;
char *filename = RWNX_MAC_FW_GAINTBL_NAME_8800DLN;
AICWFDBG(LOGINFO, "gaintbl file path:%s\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
desired_size = WF_RXGAIN_TBL_IDX_MAX * WF_RXGAIN_TBL_SIZE + WF_TXGAIN_TBL_IDX_MAX * WF_TXGAIN_TBL_SIZE;
if ((size <= 0) || (size != desired_size)) {
AICWFDBG(LOGERROR, "wrong size of firmware file, desired=%d, size=%d\n", desired_size, size);
if (dst) {
rwnx_release_firmware_common(&dst);
dst = NULL;
}
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* RX gain */
tbl_base = (u8_l *)dst;
for (idx = 0; idx < WF_RXGAIN_TBL_IDX_MAX; idx++) {
u16_l ofst = idx * 16;
u8_l *tbl_ptr = tbl_base + idx * WF_RXGAIN_TBL_SIZE;
ret = rwnx_send_rf_config_v2_req(rwnx_hw, ofst, 0, tbl_ptr, WF_RXGAIN_TBL_SIZE);
if (ret) {
AICWFDBG(LOGERROR, "rx gain rf_config_req fail, ret=%d, ofst=%d\n", ret, ofst);
break;
}
}
/* TX gain */
tbl_base = (u8_l *)dst + WF_RXGAIN_TBL_IDX_MAX * WF_RXGAIN_TBL_SIZE;
for (idx = 0; idx < WF_TXGAIN_TBL_IDX_MAX; idx++) {
u16_l ofst = idx * 16;
u8_l *tbl_ptr = tbl_base + idx * WF_TXGAIN_TBL_SIZE;
ret = rwnx_send_rf_config_v2_req(rwnx_hw, ofst, 2, tbl_ptr, WF_TXGAIN_TBL_SIZE);
if (ret) {
AICWFDBG(LOGERROR, "tx gain rf_config_req fail, ret=%d, ofst=%d\n", ret, ofst);
break;
}
}
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "gaintbl download complete\n\n");
return 0;
}
int aicwf_set_rf_config_8800dln(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm)
{
int ret = 0;
if ((ret = rwnx_send_txpwr_lvl_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_lvl_adj_v2_req(rwnx_hw))) {
return -1;
}
if ((ret = rwnx_send_txpwr_ofst2x_v3_req(rwnx_hw))) {
return -1;
}
if (testmode == FW_NORMAL_MODE) {
aicwf_plat_gain_table_load_8800dln(rwnx_hw);
}
if ((ret = rwnx_send_rf_calib_req(rwnx_hw, cfm))) {
return -1;
}
return 0 ;
}
int rwnx_plat_userconfig_load_8800dln(struct rwnx_hw *rwnx_hw){
int size;
u32 *dst=NULL;
char *filename = FW_USERCONFIG_NAME_8800DLN;
AICWFDBG(LOGINFO, "userconfig file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
return 0;
}
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
rwnx_plat_userconfig_parsing((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "userconfig download complete\n\n");
return 0;
}
#ifdef CONFIG_POWER_LIMIT
extern char country_code[];
int rwnx_plat_powerlimit_load_8800dln(struct rwnx_hw *rwnx_hw)
{
int size;
u32 *dst=NULL;
char *filename = FW_POWERLIMIT_NAME_8800DLN;
AICWFDBG(LOGINFO, "powerlimit file path:%s \r\n", filename);
/* load file */
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of cfg file\n");
dst = NULL;
return 0;
}
AICWFDBG(LOGINFO, "### Load file done: %s, size=%d\n", filename, size);
/* parsing the file */
rwnx_plat_powerlimit_parsing((char *)dst, size);
rwnx_release_firmware_common(&dst);
AICWFDBG(LOGINFO, "powerlimit download complete\n\n");
return 0;
}
#endif
@@ -0,0 +1,17 @@
#include <linux/types.h>
void system_config_8800dln(struct rwnx_hw *rwnx_hw);
void aicwf_patch_config_8800dln(struct rwnx_hw *rwnx_hw);
int aicwf_plat_rftest_load_8800dln(struct rwnx_hw *rwnx_hw);
int aicwf_plat_gain_table_load_8800dln(struct rwnx_hw *rwnx_hw);
int rwnx_plat_userconfig_load_8800dln(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_POWER_LIMIT
int rwnx_plat_powerlimit_load_8800dln(struct rwnx_hw *rwnx_hw);
#endif
int aicwf_set_rf_config_8800dln(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
+1 -5
View File
@@ -1,5 +1,3 @@
#define RWNX_FN_ENTRY_STR ">>> %s()\n", __func__
@@ -11,6 +9,7 @@
#define LOGDEBUG 0x0008
#define LOGDATA 0x0010
#define LOGSTEER 0x0020
#define LOGFW 0x0200
extern int aicwf_dbg_level;
void rwnx_data_dump(char* tag, void* data, unsigned long len);
@@ -48,6 +47,3 @@ do { \
} \
} while (0)
#endif
+4 -4
View File
@@ -49,7 +49,7 @@ static int freq_to_channel(int freq)
} else if (freq >= FREQ_6G_MIN && freq <= FREQ_6G_MAX) {
return (freq - 5950) / 5;
} else {
AICWFDBG(LOGERROR, MANAGER_STR"aic Unsupported frequency: %d MHz\n", freq);
AICWFDBG(LOGERROR, MANAGER_STR"Unsupported frequency: %d MHz\n", freq);
return -1;
}
}
@@ -91,7 +91,7 @@ void aicwf_nl_recv_msg(struct sk_buff *skb)
rwnx_hook = nl_hook[band][ssid];
if (!rwnx_hook) {
AICWFDBG(LOGSTEER, MANAGER_STR"%s, !rwnx_hook, %d,%d\n", __func__, band, ssid);
AICWFDBG(LOGSTEER, MANAGER_STR"%s, search for the next rwnx_hook, %d,%d\n", __func__, band, ssid);
continue;
}
if (rwnx_vif == NULL || rwnx_vif->up == false) {
@@ -144,7 +144,7 @@ void aicwf_nl_recv_msg(struct sk_buff *skb)
rwnx_hook = nl_hook[band][ssid];
if (!rwnx_hook) {
AICWFDBG(LOGSTEER, MANAGER_STR"rwnx_hook is null p1.\n");
//AICWFDBG(LOGSTEER, MANAGER_STR"Not this driver's msg p1.\n");
break;
}
if (rwnx_vif == NULL || rwnx_vif->up == false) {
@@ -185,7 +185,7 @@ void aicwf_nl_recv_msg(struct sk_buff *skb)
rwnx_hook = nl_hook[band][ssid];
if (!rwnx_hook) {
AICWFDBG(LOGERROR, MANAGER_STR"rwnx_hook is null p2.\n");
//AICWFDBG(LOGERROR, MANAGER_STR"Not this driver's msg p2.\n");
break;
}
if (rwnx_vif == NULL || rwnx_vif->up == false) {
+2 -9
View File
@@ -527,11 +527,7 @@ static void aicwf_sdio_bus_stop(struct device *dev)
aicwf_sdio_pwrctl_timer(sdiodev, 0);
if(timer_pending(&sdiodev->rwnx_hw->p2p_alive_timer)){
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0)
ret = timer_delete(&sdiodev->rwnx_hw->p2p_alive_timer);}
#else
ret = del_timer(&sdiodev->rwnx_hw->p2p_alive_timer);}
#endif
sdio_dbg("%s\n",__func__);
if (sdiodev->pwrctl_tsk) {
complete(&sdiodev->pwrctrl_trgg);
@@ -1001,7 +997,8 @@ static void aicwf_sdio_bus_pwrctl(struct timer_list *t)
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *) data;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6, 16, 0)
struct aic_sdio_dev *sdiodev = timer_container_of(sdiodev, t, timer);#else
struct aic_sdio_dev *sdiodev = timer_container_of(sdiodev, t, timer);
#else
struct aic_sdio_dev *sdiodev = from_timer(sdiodev, t, timer);
#endif
@@ -1085,11 +1082,7 @@ void aicwf_sdio_pwrctl_timer(struct aic_sdio_dev *sdiodev, uint duration)
spin_lock_bh(&sdiodev->pwrctl_lock);
if (!duration) {
if (timer_pending(&sdiodev->timer))
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0)
timer_delete_sync(&sdiodev->timer);
#else
del_timer_sync(&sdiodev->timer);
#endif
} else {
sdiodev->active_duration = duration;
timeout = msecs_to_jiffies(sdiodev->active_duration);
@@ -8,6 +8,7 @@
#include <linux/moduleparam.h>
#include <net/tcp.h>
#include <linux/timer.h>
#include <linux/version.h>
#define TCP_ACK_NUM 32
@@ -89,4 +90,29 @@ int filter_send_tcp_ack(struct rwnx_hw *priv, struct msg_buf *msgbuf,unsigned ch
void filter_rx_tcp_ack(struct rwnx_hw *priv,unsigned char *buf, unsigned plen);
void move_tcpack_msg(struct rwnx_hw *priv, struct msg_buf * msg);
void intf_tcp_drop_msg(struct rwnx_hw *priv, struct msg_buf *msg);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
void tcp_ack_timeout(unsigned long data);
#else
void tcp_ack_timeout(struct timer_list *t);
#endif
int tcp_check_quick_ack(unsigned char *buf, struct tcp_ack_msg *msg);
int tcp_check_ack(unsigned char *buf,
struct tcp_ack_msg *msg,
unsigned short *win_scale);
int tcp_ack_match(struct tcp_ack_manage *ack_m, struct tcp_ack_msg *ack_msg);
void tcp_ack_update(struct tcp_ack_manage *ack_m);
int tcp_ack_alloc_index(struct tcp_ack_manage *ack_m);
int tcp_ack_handle(struct msg_buf *new_msgbuf,
struct tcp_ack_manage *ack_m,
struct tcp_ack_info *ack_info,
struct tcp_ack_msg *ack_msg,
int type);
int tcp_ack_handle_new(struct msg_buf *new_msgbuf,
struct tcp_ack_manage *ack_m,
struct tcp_ack_info *ack_info,
struct tcp_ack_msg *ack_msg,
int type);
#endif
+3 -2
View File
@@ -23,7 +23,7 @@
#define DATA_BUF_MAX 2048
#define TXPKT_BLOCKSIZE 512
#define MAX_AGGR_TXPKT_LEN (1536*64)
#define CMD_TX_TIMEOUT 2000
#define CMD_TX_TIMEOUT 5000
#define TX_ALIGNMENT 4
#ifdef CONFIG_USB_TX_AGGR
@@ -155,7 +155,7 @@ struct aicwf_tx_priv {
#define DEFRAG_MAX_WAIT 40 //100
#ifdef AICWF_RX_REORDER
#define MAX_REORD_RXFRAME 250
#define REORDER_UPDATE_TIME 500//50
#define REORDER_UPDATE_TIME 50
#define AICWF_REORDER_WINSIZE 64
//SN_LESS(a, b) a-b<0 is ture
#define SN_LESS(a, b) (((a-b)&0x800)!=0)
@@ -307,6 +307,7 @@ void aicwf_rxframe_queue_init_2(struct rx_frame_queue *pq, int max_len);
void rxbuff_free(struct rx_buff *rxbuff);
struct rx_buff *rxbuff_dequeue(struct rx_frame_queue *pq);
bool aicwf_rxbuff_enqueue(struct device *dev, struct rx_frame_queue *rxq, struct rx_buff *pkt);
struct rx_buff *rxbuff_queue_penq(struct rx_frame_queue *pq, struct rx_buff *p);
extern struct aicwf_rx_buff_list aic_rx_buff_list;
#endif
+56 -60
View File
@@ -155,22 +155,24 @@ static void aicwf_usb_msg_rx_buf_put(struct aic_usb_dev *usb_dev, struct aicwf_u
}
#endif
void rwnx_stop_sta_all_queues(struct rwnx_sta *sta, struct rwnx_hw *rwnx_hw)
void rwnx_stop_sta_all_queues(void *sta, struct rwnx_hw *rwnx_hw)
{
u8 tid;
struct rwnx_txq *txq;
struct rwnx_sta *sta_tmp = (struct rwnx_sta *)sta;
for(tid=0; tid<8; tid++) {
txq = rwnx_txq_sta_get(sta, tid, rwnx_hw);
txq = rwnx_txq_sta_get(sta_tmp, tid, rwnx_hw);
netif_stop_subqueue(txq->ndev, txq->ndev_idx);
}
}
void rwnx_wake_sta_all_queues(struct rwnx_sta *sta, struct rwnx_hw *rwnx_hw)
void rwnx_wake_sta_all_queues(void *sta, struct rwnx_hw *rwnx_hw)
{
u8 tid;
struct rwnx_txq *txq;
struct rwnx_sta *sta_tmp = (struct rwnx_sta *)sta;
for(tid=0; tid<8; tid++) {
txq = rwnx_txq_sta_get(sta, tid, rwnx_hw);
txq = rwnx_txq_sta_get(sta_tmp, tid, rwnx_hw);
netif_wake_subqueue(txq->ndev, txq->ndev_idx);
}
}
@@ -200,7 +202,7 @@ static void usb_txc_sta_flowctrl(struct aicwf_usb_buf *usb_buf, struct aic_usb_d
usb_dev->rwnx_hw->sta_flowctrl[sta_idx].flowctrl) {
//AICWFDBG(LOGDEBUG, "sta 0x%x:0x%x, %d pending %d, wake\n", sta->mac_addr[4], sta->mac_addr[5], sta->sta_idx, atomic_read(&usb_dev->rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt));
if(!usb_dev->tbusy)
rwnx_wake_sta_all_queues(sta, usb_dev->rwnx_hw);
rwnx_wake_sta_all_queues((void *)sta, usb_dev->rwnx_hw);
usb_dev->rwnx_hw->sta_flowctrl[sta_idx].flowctrl = 0;
}
}
@@ -295,18 +297,6 @@ static void aicwf_usb_rx_complete(struct urb *urb)
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
if(urb->status < 0){
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;
}else{
//schedule_work(&usb_dev->rx_urb_work);
@@ -383,18 +373,6 @@ static void aicwf_usb_rx_complete(struct urb *urb)
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
if(urb->status < 0){
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;
}else{
//schedule_work(&usb_dev->rx_urb_work);
@@ -781,7 +759,7 @@ static int aicwf_usb_submit_rx_urb(struct aic_usb_dev *usb_dev,
aicwf_prealloc_rxbuff_free(rx_buff, &usb_dev->rx_priv->rxbuff_lock);
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
msleep(100);
mdelay(100);
return -1;
}else{
atomic_inc(&rx_urb_cnt);
@@ -840,7 +818,7 @@ static int aicwf_usb_submit_rx_urb(struct aic_usb_dev *usb_dev,
usb_buf->skb = NULL;
aicwf_usb_rx_buf_put(usb_dev, usb_buf);
msleep(100);
mdelay(100);
return -1;
}else{
atomic_inc(&rx_urb_cnt);
@@ -913,7 +891,7 @@ static int aicwf_usb_submit_msg_rx_urb(struct aic_usb_dev *usb_dev,
usb_buf->skb = NULL;
aicwf_usb_msg_rx_buf_put(usb_dev, usb_buf);
msleep(100);
mdelay(100);
}
return 0;
}
@@ -1214,9 +1192,6 @@ fail:
usb_buf->skb = NULL;
aicwf_usb_tx_queue(usb_dev, &usb_dev->tx_free_list, usb_buf,
&usb_dev->tx_free_count, &usb_dev->tx_free_lock);
if (ret == -ENODEV) {
break;
}
#endif
}
}
@@ -1677,7 +1652,7 @@ static void usb_tx_flow_ctrl(struct rwnx_txhdr *txhdr, struct aic_usb_dev *usb_d
rwnx_hw->sta_flowctrl[sta_idx].flowctrl) {
//AICWFDBG(LOGDEBUG, "sta 0x%x:0x%x, %d pending %d, stop\n", sta->mac_addr[4], sta->mac_addr[5], sta->sta_idx, atomic_read(&rwnx_hw->sta_flowctrl[sta_idx].tx_pending_cnt));
if(!usb_dev->tbusy)
rwnx_stop_sta_all_queues(sta, usb_dev->rwnx_hw);
rwnx_stop_sta_all_queues((void *)sta, usb_dev->rwnx_hw);
rwnx_hw->sta_flowctrl[sta_idx].flowctrl = 1;
}
}
@@ -1903,15 +1878,14 @@ static int aicwf_usb_bus_start(struct device *dev)
aicwf_usb_state_change(usb_dev, USB_UP_ST);
usb_dev->rx_prepare_ready = false;
aicwf_usb_rx_prepare(usb_dev);
aicwf_usb_tx_prepare(usb_dev);
#ifdef CONFIG_USB_MSG_IN_EP
if(usb_dev->msg_in_pipe){
aicwf_usb_msg_rx_prepare(usb_dev);
} else {
aicwf_usb_rx_prepare(usb_dev);
}
#endif
if(!usb_dev->msg_in_pipe && !usb_dev->rx_prepare_ready){
if(!usb_dev->rx_prepare_ready){
AICWFDBG(LOGERROR, "%s rx prepare fail\r\n", __func__);
return -1;
}else{
@@ -1981,10 +1955,6 @@ static void aicwf_usb_bus_stop(struct device *dev)
if (usb_dev->state == USB_DOWN_ST)
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_cancel_all_urbs(usb_dev);//AIDEN
}
@@ -2154,12 +2124,13 @@ static int aicwf_parse_usb(struct aic_usb_dev *usb_dev, struct usb_interface *in
AICWFDBG(LOGERROR, "AIC8800DC change to AIC8800DW\n");
usb_dev->chipid = PRODUCT_ID_AIC8800DW;
}else if (usb_dev->chipid == PRODUCT_ID_AIC8800DW) {
AICWFDBG(LOGINFO, "AIC8800DW\n");}
else if (usb_dev->chipid == PRODUCT_ID_AIC8800D81) {
AICWFDBG(LOGINFO, "AIC8800D80\n");
AICWFDBG(LOGINFO, "AIC8800DW\n");
} else if (usb_dev->chipid == PRODUCT_ID_AIC8800D80N) {
AICWFDBG(LOGERROR, "AIC8800D80N change to AIC8800D80WN\n");
} else if (usb_dev->chipid == PRODUCT_ID_AIC8800DLN) {
AICWFDBG(LOGERROR, "AIC8800DLN change to AIC8800DWN\n");
}else if(usb_dev->chipid == PRODUCT_ID_AIC8800D81X2 ||
usb_dev->chipid == PRODUCT_ID_AIC8800D89X2 ||
usb_dev->chipid == PRODUCT_ID_AIC8800D81){
usb_dev->chipid == PRODUCT_ID_AIC8800D89X2){
//TODO
}else{
ret = -ENODEV;
@@ -2342,7 +2313,8 @@ static int aicwf_usb_chipmatch(struct aic_usb_dev *usb_dev, u16_l vid, u16_l pid
usb_dev->chipid = PRODUCT_ID_AIC8801;
AICWFDBG(LOGINFO, "%s USE AIC8801\r\n", __func__);
return 0;
}else if(pid == USB_PRODUCT_ID_AIC8800DC || pid == USB_PRODUCT_ID_TENDA
}else if(pid == USB_PRODUCT_ID_AIC8800DC || pid == USB_PRODUCT_ID_AIC8800DE
|| pid == USB_PRODUCT_ID_TENDA
|| 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_CUS4 || pid == USB_PRODUCT_ID_AIC8800FC_CUS5
@@ -2356,11 +2328,13 @@ static int aicwf_usb_chipmatch(struct aic_usb_dev *usb_dev, u16_l vid, u16_l pid
return 0;
}else if(pid == USB_PRODUCT_ID_AIC8800D81 || pid == USB_PRODUCT_ID_AIC8800D41
|| pid == USB_PRODUCT_ID_TENDA_U11 || pid == USB_PRODUCT_ID_TENDA_U11_PRO
|| pid == USB_PRODUCT_ID_AIC8800M80_CUS1 || pid == USB_PRODUCT_ID_AIC8800M80_CUS2
|| pid == USB_PRODUCT_ID_AIC8800M80_CUS0 || pid == USB_PRODUCT_ID_AIC8800M80_CUS1
|| pid == USB_PRODUCT_ID_AIC8800M80_CUS2
|| 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_CUS7 || pid == USB_PRODUCT_ID_AIC8800M80_CUS8
|| pid == USB_PRODUCT_ID_AIC8800D80_UGREEN){
|| pid == USB_PRODUCT_ID_AIC8800D80_UGREEN || pid == USB_PRODUCT_ID_MERCURY
|| pid == USB_PRODUCT_ID_TP){
usb_dev->chipid = PRODUCT_ID_AIC8800D81;
aicwf_usb_rx_aggr = true;
AICWFDBG(LOGINFO, "%s USE AIC8800D81\r\n", __func__);
@@ -2393,6 +2367,22 @@ static int aicwf_usb_chipmatch(struct aic_usb_dev *usb_dev, u16_l vid, u16_l pid
}
AICWFDBG(LOGINFO, "%s USE AIC8800D89X2\r\n", __func__);
return 0;
} else if ((pid == USB_PRODUCT_ID_AIC8800D80N) ||
(pid == USB_PRODUCT_ID_AIC8800D80LN) ||
(pid == USB_PRODUCT_ID_AIC8800D80WN) ||
(pid == USB_PRODUCT_ID_AIC8800D40N) ||
(pid == USB_PRODUCT_ID_AIC8800D40LN) ||
(pid == USB_PRODUCT_ID_AIC8800D40WN)) {
usb_dev->chipid = PRODUCT_ID_AIC8800D80N;
aicwf_usb_rx_aggr = true;
AICWFDBG(LOGINFO, "%s USE AIC8800D80N\r\n", __func__);
return 0;
} else if ((pid == USB_PRODUCT_ID_AIC8800DLN) ||
(pid == USB_PRODUCT_ID_AIC8800DWN)) {
usb_dev->chipid = PRODUCT_ID_AIC8800DLN;
aicwf_usb_rx_aggr = true;
AICWFDBG(LOGINFO, "%s USE AIC8800DLN\r\n", __func__);
return 0;
} else{
return -1;
}
@@ -2457,9 +2447,6 @@ static int aicwf_usb_probe(struct usb_interface *intf, const struct usb_device_i
usb_dev->dev = &usb->dev;
usb_set_intfdata(intf, usb_dev);
usb_dev->vid = id->idVendor;
usb_dev->pid = id->idProduct;
ret = aicwf_usb_chipmatch(usb_dev, id->idVendor, id->idProduct);
if (ret < 0) {
@@ -2531,9 +2518,6 @@ static int aicwf_usb_probe(struct usb_interface *intf, const struct usb_device_i
AICWFDBG(LOGERROR, "aicwf_rwnx_usb_platform_init err %d\n", ret);
goto out_free_bus;
}
if(usb_dev->msg_in_pipe){
aicwf_usb_rx_prepare(usb_dev);
}
aicwf_hostif_ready();
#ifdef CONFIG_GPIO_WAKEUP
@@ -2602,7 +2586,9 @@ static int aicwf_usb_suspend(struct usb_interface *intf, pm_message_t state)
AICWFDBG(LOGINFO, "%s enter\r\n", __func__);
#ifdef CONFIG_WOWLAN
#ifndef ANDROID_PLATFORM
rwnx_send_dummy_reboot(usb_dev->rwnx_hw);
#endif
#endif
list_for_each_entry_safe(rwnx_vif, tmp, &usb_dev->rwnx_hw->vifs, list) {
if (rwnx_vif->ndev){
@@ -2634,6 +2620,7 @@ static int aicwf_usb_resume(struct usb_interface *intf)
if (usb_dev->state != USB_UP_ST){
aicwf_bus_start(usb_dev->bus_if);
g_rwnx_plat->wait_disconnect_cb = false;
}
list_for_each_entry_safe(rwnx_vif, tmp, &usb_dev->rwnx_hw->vifs, list) {
@@ -2641,9 +2628,6 @@ static int aicwf_usb_resume(struct usb_interface *intf)
netif_tx_wake_all_queues(rwnx_vif->ndev);
}
}
if(usb_dev->msg_in_pipe){
aicwf_usb_rx_prepare(usb_dev);
}
return 0;
}
@@ -2660,11 +2644,20 @@ 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_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_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(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800DW)},
{USB_DEVICE(USB_VENDOR_ID_AIC, USB_PRODUCT_ID_AIC8800M80_CUS1)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D81X2, 0xff, 0xff, 0xff)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D89X2)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80N, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80LN, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D80WN, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D40N, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D40LN, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800D40WN, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800DLN, 0xff, 0xff, 0xff)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800DWN, 0xff, 0xff, 0xff)},
{USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA)},
{USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA_U2)},
{USB_DEVICE(USB_VENDOR_ID_TENDA, USB_PRODUCT_ID_TENDA_U11)},
@@ -2676,6 +2669,7 @@ static struct usb_device_id aicwf_usb_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS4)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS5)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800FC_CUS6)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS0)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS1)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS2)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS3)},
@@ -2685,6 +2679,8 @@ static struct usb_device_id aicwf_usb_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_PRODUCT_ID_AIC8800M80_CUS7)},
{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_TP, USB_PRODUCT_ID_MERCURY)},
{USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_TP, USB_PRODUCT_ID_TP, 0xff, 0xff, 0xff)},
#endif
{}
};
+23 -7
View File
@@ -16,11 +16,17 @@
/* USB Device ID */
#define USB_VENDOR_ID_AIC 0xA69C
#define USB_VENDOR_ID_AIC_V2 0x368B
#define USB_VENDOR_ID_TP 0x2357
#define USB_VENDOR_ID_TENDA 0x2604
#define USB_VENDOR_ID_TENDA_V2 0x3625
#define USB_VENDOR_ID_AIC_V2 0x368B
#define USB_PRODUCT_ID_TP 0x014e
#define USB_PRODUCT_ID_MERCURY 0x014b
#define USB_PRODUCT_ID_FAST 0x014f
#define USB_PRODUCT_ID_TENDA_U11 0x001f
#define USB_PRODUCT_ID_TENDA_U11_PRO 0x0020
#ifndef CONFIG_USB_BT
#define USB_PRODUCT_ID_AIC8800 0x8800
#define USB_PRODUCT_ID_AIC8801 0x8801
@@ -32,15 +38,22 @@
#else
#define USB_PRODUCT_ID_AIC8801 0x8801
#define USB_PRODUCT_ID_AIC8800DC 0x88dc
#define USB_PRODUCT_ID_AIC8800DE 0x88de
#define USB_PRODUCT_ID_AIC8800DW 0x88dd
#define USB_PRODUCT_ID_AIC8800D81 0x8d81
#define USB_PRODUCT_ID_AIC8800D41 0x8d41
#define USB_PRODUCT_ID_AIC8800D81X2 0x8d91
#define USB_PRODUCT_ID_AIC8800D89X2 0x8d99
#define USB_PRODUCT_ID_AIC8800D80N 0x8d45
#define USB_PRODUCT_ID_AIC8800D80LN 0x8d46
#define USB_PRODUCT_ID_AIC8800D80WN 0x8d47
#define USB_PRODUCT_ID_AIC8800D40N 0x8d48
#define USB_PRODUCT_ID_AIC8800D40LN 0x8d49
#define USB_PRODUCT_ID_AIC8800D40WN 0x8d4a
#define USB_PRODUCT_ID_AIC8800DWN 0x8870
#define USB_PRODUCT_ID_AIC8800DLN 0x8871
#define USB_PRODUCT_ID_TENDA 0x0013
#define USB_PRODUCT_ID_TENDA_U2 0x0014
#define USB_PRODUCT_ID_TENDA_U11 0x001f
#define USB_PRODUCT_ID_TENDA_U11_PRO 0x0020
#define USB_PRODUCT_ID_TENDA_TX1U_NANO 0x0110
#define USB_PRODUCT_ID_AIC8800FC_CUS1 0x88df
#define USB_PRODUCT_ID_AIC8800FC_CUS2 0x88E0
@@ -49,6 +62,7 @@
#define USB_PRODUCT_ID_AIC8800FC_CUS5 0x88E3
#define USB_PRODUCT_ID_AIC8800FC_CUS6 0x88E5
#define USB_PRODUCT_ID_AIC8800M80_CUS0 0x8D84
#define USB_PRODUCT_ID_AIC8800M80_CUS1 0x8D83
#define USB_PRODUCT_ID_AIC8800M80_CUS2 0x8D85
#define USB_PRODUCT_ID_AIC8800M80_CUS3 0x8D86
@@ -64,6 +78,8 @@ enum AICWF_IC{
PRODUCT_ID_AIC8801 = 0,
PRODUCT_ID_AIC8800DC,
PRODUCT_ID_AIC8800DW,
PRODUCT_ID_AIC8800DLN,
PRODUCT_ID_AIC8800D80N,
PRODUCT_ID_AIC8800D81,
PRODUCT_ID_AIC8800D81X2,
PRODUCT_ID_AIC8800D89X2
@@ -78,7 +94,7 @@ enum AICWF_IC{
#define TXQLEN (2048*4)
#define AICWF_USB_TX_URBS (50)
#else
#define AICWF_USB_TX_URBS 50//(100)
#define AICWF_USB_TX_URBS 200//(100)
#endif
#define AICWF_USB_TX_LOW_WATER (AICWF_USB_TX_URBS/4)//25%
#define AICWF_USB_TX_HIGH_WATER (AICWF_USB_TX_LOW_WATER*3)//75%
@@ -202,8 +218,6 @@ struct aic_usb_dev {
#endif
u16 chipid;
bool tbusy;
u16_l vid;
u16_l pid;
};
extern void aicwf_usb_exit(void);
@@ -214,7 +228,9 @@ int usb_msg_busrx_thread(void *data);
#endif
int usb_bustx_thread(void *data);
int usb_busrx_thread(void *data);
void rwnx_stop_sta_all_queues(void *sta, struct rwnx_hw *rwnx_hw);
void rwnx_wake_sta_all_queues(void *sta, struct rwnx_hw *rwnx_hw);
void aicwf_usb_cancel_all_urbs(struct aic_usb_dev *usb_dev);
extern void aicwf_hostif_ready(void);
@@ -400,7 +400,7 @@ static char *aicwf_get_iwe_stream_mac_addr(struct rwnx_hw* rwnx_hw,
iwe->cmd = SIOCGIWAP;
iwe->u.ap_addr.sa_family = ARPHRD_ETHER;
if(scan_re->bss && &scan_re->bss->bssid[0]){
if(scan_re->bss){
memcpy(iwe->u.ap_addr.sa_data, scan_re->bss->bssid, ETH_ALEN);
}
@@ -616,8 +616,10 @@ static inline char *aicwf_get_iwe_stream_rate(struct rwnx_hw* rwnx_hw,
u16 vht_data_rate = 0;
u16 he_cap = false;
u8 he_ch_width_set = 0;
u8 he_bw = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)|| defined(CONFIG_HE_FOR_OLD_KERNEL)
u8 he_ch_width_set = 0;
#endif
/* parsing HT_CAP_IE */
ie_content = NULL;
@@ -8,4 +8,6 @@ struct scanu_result_wext{
void aicwf_set_wireless_ext( struct net_device *ndev, struct rwnx_hw *rwnx_hw);
void aicwf_scan_complete_event(struct net_device *dev);
int aic_get_sec_ie(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len, u8 *wpa_ie, u16 *wpa_len);
u8 aicwf_get_is_wps_ie(u8 *ie_ptr, uint *wps_ielen);
+57 -33
View File
@@ -413,6 +413,13 @@ enum mm_msg_tag
MM_SET_TXPWR_PER_STA_REQ,
MM_SET_TXPWR_PER_STA_CFM,
MM_GET_STATISTIC_REQ,
MM_GET_STATISTIC_CFM,
MM_VENDOR_SWCONFIG_IND,
MM_FW_PANIC_IND,
MM_FW_ASSERT_IND,
/// MAX number of messages
MM_MAX,
};
@@ -892,6 +899,7 @@ struct mm_ba_add_cfm
u8_l tid;
/// Status of ba establishment
u8_l status;
u8_l alligned;
};
/// Structure containing the parameters of the @ref MM_BA_DEL_REQ message.
@@ -1345,6 +1353,12 @@ struct mm_get_sta_info_req
u8_l sta_idx;
};
struct mm_get_sta_info_compat_req
{
u8_l sta_idx;
char pattern[3];
};
struct mm_get_sta_info_cfm
{
u32_l rate_info;
@@ -1412,6 +1426,12 @@ typedef struct
s8_l pwrlvl_adj_tbl_5g[6];
} txpwr_lvl_adj_conf_t;
typedef struct
{
u8_l enable;
s8_l pwrlvl_adj_tbl_2g4[3];
} txpwr_lvl_adj_conf_v2_t;
struct mm_set_txpwr_lvl_req
{
union {
@@ -1424,7 +1444,10 @@ struct mm_set_txpwr_lvl_req
struct mm_set_txpwr_lvl_adj_req
{
union {
txpwr_lvl_adj_conf_t txpwr_lvl_adj;
txpwr_lvl_adj_conf_v2_t txpwr_lvl_adj_v2;
};
};
typedef struct
@@ -1538,12 +1561,33 @@ typedef struct
s8_l pwrofst2x_tbl_6g_ant1[15];
} txpwr_ofst2x_conf_v2_t;
/*
* pwrofst2x_tbl_2g4[3][3]:
* +---------------+----------+----------+----------+
* | RateTyp\ChGrp | CH_1_4 | CH_5_9 | CH_10_13 |
* +---------------+----------+----------+----------+
* | DSSS | [0][0] | [0][1] | [0][2] |
* +---------------+----------+----------+----------+
* | OFDM_HIGHRATE | [1][0] | [1][1] | [1][2] |
* +---------------+----------+----------+----------+
* | OFDM_LOWRATE | [2][0] | [2][1] | [2][2] |
* +---------------+----------+----------+----------+
*/
typedef struct
{
u8_l enable;
s8_l pwrofst2x_tbl_2g4[3][3];
u8_l RESERVED[2];
} txpwr_ofst2x_conf_v3_t;
struct mm_set_txpwr_ofst_req
{
union {
txpwr_ofst_conf_t txpwr_ofst;
txpwr_ofst2x_conf_t txpwr_ofst2x;
txpwr_ofst2x_conf_v2_t txpwr_ofst2x_v2;
txpwr_ofst2x_conf_v3_t txpwr_ofst2x_v3;
};
};
@@ -1664,6 +1708,18 @@ struct mm_csa_traffic_ind
bool_l enable;
};
struct fw_panic_info_ind
{
uint32_t len;
uint8_t info[384];
};
struct fw_assert_info_ind
{
uint32_t len;
uint8_t info[384];
};
/// Structure containing the parameters of the @ref MM_MU_GROUP_UPDATE_REQ message.
/// Size allocated for the structure depends of the number of group
struct mm_mu_group_update_req
@@ -2038,6 +2094,7 @@ struct me_sta_add_cfm
u8_l status;
/// PM state of the station
u8_l pm_state;
u8_l alligned;
};
/// Structure containing the parameters of the @ref ME_STA_DEL_REQ message.
@@ -3463,37 +3520,4 @@ struct mm_set_wakeup_info_req {
u16_l length;
u8_l mask_and_pattern[];
};
struct dbg_pwm_init_req
{
/// PWM_CHANNEL_GPIO
u8 pwm_gpidx;
/// 0 normal 1 breath
u8 mode;
/// 0 config only 1 run after config
u8 run;
u32 tmr_cnt;
u32 dty_cnt;
u32 step_val;
/// 0 disable 1 enable
u8 gpio_en;
/// 0 input 1 output
u8 gpio_dir;
/// 0 low 1 high
u8 gpio_val;
};
struct dbg_pwm_deinit_req
{
/// PWM_CHANNEL_GPIO
u8 pwm_gpidx;
/// 0 disable 1 enable
u8 gpio_en;
/// 0 input 1 output
u8 gpio_dir;
/// 0 low 1 high
u8 gpio_val;
};
#endif // LMAC_MSG_H_
File diff suppressed because it is too large Load Diff
+13 -11
View File
@@ -139,9 +139,13 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
#endif
if(cmd->e2a_msg != NULL) {
do {
if(cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED)
break;
spin_lock_bh(&cmd_mgr->lock);
if(cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
AICWFDBG(LOGERROR, "cmd queue crashed\n");
cmd->result = -EPIPE;
spin_unlock_bh(&cmd_mgr->lock);
return -EPIPE;
}
empty = list_empty(&cmd_mgr->cmds);
if(!empty) {
spin_unlock_bh(&cmd_mgr->lock);
@@ -156,15 +160,13 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
} while(!empty);//wait for cmd queue empty
} else {
spin_lock_bh(&cmd_mgr->lock);
}
if (cmd_mgr->state == RWNX_CMD_MGR_STATE_CRASHED) {
printk(KERN_CRIT"cmd queue crashed\n");
cmd->result = -EPIPE;
spin_unlock_bh(&cmd_mgr->lock);
return -EPIPE;
}
}
#ifndef CONFIG_RWNX_FHOST
if (!list_empty(&cmd_mgr->cmds)) {
@@ -221,8 +223,9 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
//printk("defer push: tkn=%d\r\n", cmd->tkn);
}
spin_unlock_bh(&cmd_mgr->lock);
//spin_unlock_bh(&cmd_mgr->lock);
if (!defer_push) {
spin_unlock_bh(&cmd_mgr->lock);
AICWFDBG(LOGTRACE, "queue:id=%x, param_len=%u\n",cmd->a2e_msg->id, cmd->a2e_msg->param_len);
#ifdef AICWF_SDIO_SUPPORT
@@ -235,7 +238,10 @@ static int cmd_mgr_queue(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd)
kfree(cmd->a2e_msg);
} else {
if(cmd_mgr->queue_sz <= 1) {
spin_unlock_bh(&cmd_mgr->lock);
WAKE_CMD_WORK(cmd_mgr);
} else {
spin_unlock_bh(&cmd_mgr->lock);
}
return 0;
}
@@ -559,7 +565,6 @@ void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
{
u8 *buffer = NULL;
u16 index = 0;
int ret = 0;
#ifdef AICWF_SDIO_SUPPORT
struct aic_sdio_dev *sdiodev = (struct aic_sdio_dev *)dev;
struct aicwf_bus *bus = sdiodev->bus_if;
@@ -594,9 +599,6 @@ void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
index += 2;
memcpy(&buffer[index], (u8 *)msg->param, msg->param_len);
ret = aicwf_bus_txmsg(bus, buffer, len + 8);
if (ret == -EIO) {
ret = aicwf_bus_txmsg(bus, buffer, len + 8);
}
aicwf_bus_txmsg(bus, buffer, len + 8);
}
+1
View File
@@ -116,5 +116,6 @@ void rwnx_cmd_mgr_init(struct rwnx_cmd_mgr *cmd_mgr);
void rwnx_cmd_mgr_deinit(struct rwnx_cmd_mgr *cmd_mgr);
int cmd_mgr_queue_force_defer(struct rwnx_cmd_mgr *cmd_mgr, struct rwnx_cmd *cmd);
void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len);
void cmd_mgr_task_process(struct work_struct *work);
#endif /* _RWNX_CMDS_H_ */
+29 -1
View File
@@ -23,6 +23,33 @@
#define _RWNX_COMPAT_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)
#error "Minimum kernel version supported is 3.10"
#endif
@@ -41,7 +68,7 @@
#define IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_MASK IEEE80211_HE_MAC_CAP3_MAX_A_AMPDU_LEN_EXP_MASK
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 18, 0)
#if LINUX_VERSION_CODE > KERNEL_VERSION(5, 15, 60)
#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
#endif
@@ -380,6 +407,7 @@ enum {
rwnx_ops_hw_scan(hw, vif, struct cfg80211_scan_request *req)
#endif
u16 rwnx_select_txq(struct rwnx_vif *rwnx_vif, struct sk_buff *skb);
/* NET */
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
#define rwnx_select_queue(dev, skb, sb_dev) \
+4 -5
View File
@@ -1777,7 +1777,7 @@ static ssize_t rwnx_dbgfs_dbg_level_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
//struct rwnx_hw *priv = file->private_data;
char buf[32];
int ret;
ssize_t read;
@@ -1796,7 +1796,7 @@ static ssize_t rwnx_dbgfs_dbg_level_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct rwnx_hw *priv = file->private_data;
//struct rwnx_hw *priv = file->private_data;
char buf[32];
int val;
size_t len = min_t(size_t, count, sizeof(buf) - 1);
@@ -2019,7 +2019,7 @@ static void idx_to_rate_cfg1(unsigned int formatmod,
case FORMATMOD_NON_HT:
{
r_cfg->formatModTx = formatmod;
r_cfg->giAndPreTypeTx = 1;
r_cfg->giAndPreTypeTx = 2;
r_cfg->mcsIndexTx = mcs;
break;
}
@@ -2236,8 +2236,7 @@ static ssize_t rwnx_dbgfs_rc_fixed_rate_idx_write(struct file *file,
/* Get the station index from MAC address */
sscanf(file->f_path.dentry->d_parent->d_iname, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
if (&mac[0] == NULL)
return 0;
sta = rwnx_get_sta(priv, mac);
if (sta == NULL)
return 0;
@@ -198,6 +198,7 @@ static inline void rwnx_dbgfs_register_rc_stat(struct rwnx_hw *rwnx_hw, struct r
static inline void rwnx_dbgfs_unregister_rc_stat(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta) {}
#endif
#endif /* CONFIG_RWNX_DEBUGFS */
void _rwnx_dbgfs_rc_stat_write(struct rwnx_debugfs *rwnx_debugfs, uint8_t sta_idx);
#endif /* _RWNX_DEBUGFS_H_ */
+33 -11
View File
@@ -79,20 +79,11 @@
#if LINUX_VERSION_CODE >= HIGH_KERNEL_VERSION
#ifndef IEEE80211_MAX_AMPDU_BUF
#define IEEE80211_MAX_AMPDU_BUF IEEE80211_MAX_AMPDU_BUF_HE
#endif
#ifndef IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB
#define IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB
#endif
#ifndef IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB
#define IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMER_FB IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB
#endif
#ifndef IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA IEEE80211_HE_PHY_CAP3_RX_PARTIAL_BW_SU_IN_20MHZ_MU
#endif
#endif
#ifndef IEEE80211_MAX_AMPDU_BUF
#define IEEE80211_MAX_AMPDU_BUF 0x100
@@ -107,6 +98,7 @@
#define IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA 0x40
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0) || defined(CONFIG_VHT_FOR_OLD_KERNEL)
enum nl80211_ac {
NL80211_AC_VO,
@@ -237,6 +229,7 @@ struct tmp_feature_sta {
u8_l supported_band;
};
#if 0
#define MAX_PENDING_PROBES 3
struct ap_probe_rsp {
u8_l da[6];
@@ -244,6 +237,7 @@ struct ap_probe_rsp {
bool in_use;
};
#endif
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
#define NL80211_MESHCONF_POWER_MODE 26
@@ -388,6 +382,18 @@ enum rwnx_ap_flags {
RWNX_AP_ISOLATE = BIT(0),
};
#ifdef CONFIG_DYNAMIC_PERPWR
struct sta_pwrthd {
s8_l rssi_thd_0; //rssi 0 (dBm)
s8_l rssi_thd_1; //rssi 1 (dBm)
s8_l rssi_thd_2; //rssi 2 (dBm)
s8_l pwr_loss_lvl_0; //RSSI > RSSI_THD_0
s8_l pwr_loss_lvl_1; //RSSI_THD_1 < RSSI <= RSSI_THD_0
s8_l pwr_loss_lvl_2; //RSSI_THD_2 < RSSI <= RSSI_THD_1
s8_l pwr_loss_lvl_3; //RSSI <= RSSI_THD_2
};
#endif
/*
* Structure used to save information relative to the managed interfaces.
* This is also linked within the rwnx_hw vifs list.
@@ -402,6 +408,7 @@ struct rwnx_vif {
struct rwnx_key key[6];
unsigned long drv_flags;
atomic_t drv_conn_state;
spinlock_t conn_state_lock;
u8 drv_vif_index; /* Identifier of the VIF in driver */
u8 vif_index; /* Identifier of the station in FW */
u8 ch_index; /* Channel context identifier */
@@ -458,6 +465,7 @@ struct rwnx_vif {
u32_l freq;
bool start;
#endif
u32_l ap_freq;
enum nl80211_mesh_power_mode mesh_pm; /* mesh power save mode currently set in firmware */
enum nl80211_mesh_power_mode next_mesh_pm; /* mesh power save mode for next peer */
} ap;
@@ -487,12 +495,14 @@ struct rwnx_vif {
struct br_ext_info ethBrExtInfo;
#endif /* CONFIG_BR_SUPPORT */
#ifdef CONFIG_BAND_STEERING
struct workqueue_struct *rsp_wq;
struct timer_list steer_timer;
struct work_struct steer_work;
struct b_steer_priv bsteerpriv;
#if 0
struct workqueue_struct *rsp_wq;
struct ap_probe_rsp pb_pool[MAX_PENDING_PROBES];
#endif
#endif
};
@@ -724,7 +734,7 @@ struct amsdu_subframe_hdr {
};
/* rwnx driver status */
void rwnx_set_conn_state(atomic_t *drv_conn_state, int state);
void rwnx_set_conn_state(struct rwnx_vif *vif, atomic_t *drv_conn_state, int state);
enum rwnx_drv_connect_status {
RWNX_DRV_STATUS_DISCONNECTED = 0,
@@ -885,6 +895,7 @@ struct rwnx_hw {
char wext_essid[33];
int support_freqs[SCAN_CHANNEL_MAX];
int support_freqs_number;
#endif
#ifdef CONFIG_DYNAMIC_PWR
struct timer_list pwrloss_timer;
struct work_struct pwrloss_work;
@@ -892,11 +903,22 @@ struct rwnx_hw {
s8 pwrloss_lvl;
u8 sta_rssi_idx;
#endif
#ifdef CONFIG_TEMP_CONTROL
struct timer_list tc_timer;
struct work_struct tc_work;
s8 tc_range;
#endif
#ifdef CONFIG_BAND_STEERING
u8_l iface_idx;
struct tmp_feature_sta feature_table[NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX];
#endif
#ifdef CONFIG_DYNAMIC_PERPWR
struct sta_pwrthd pwrth;
#endif
ktime_t last_time;
char last_alpha2[3];
};
u8 *rwnx_build_bcn(struct rwnx_bcn *bcn, struct cfg80211_beacon_data *new);
+2
View File
@@ -16,5 +16,7 @@
int rwnx_dini_platform_init(struct pci_dev *pci_dev,
struct rwnx_plat **rwnx_plat);
int rwnx_cfpga_irq_enable(struct rwnx_hw *rwnx_hw);
int rwnx_cfpga_irq_disable(struct rwnx_hw *rwnx_hw);
#endif /* _RWNX_DINI_H_ */
+1 -1
View File
@@ -12,7 +12,7 @@
#include "rwnx_defs.h"
#include "ipc_host.h"
#include "rwnx_prof.h"
#include "rwnx_irqs.h"
/**
* rwnx_irq_hdlr - IRQ handler
*
File diff suppressed because it is too large Load Diff
+60 -2
View File
@@ -37,6 +37,21 @@ extern u8 chip_mcu_id;
#define PWR_LOSS_LVL3 (0)//(2) //RSSI <RSSI_THD_2
#define PWR_DELAY_TIME (10 * 1000) //pwr reduced latency time (ms)
#define PWR_FAST_SWITCH_PROTECT_TIME (2 * 1000) //quickly switch protection time (ms)
#define RSSI_HYSTERESIS_OFFSET 2 //buffer zone (dB)
#define RSSI_HYSTERESIS_THRESHOLD 2 //range of signal variation (dB)
#ifdef CONFIG_TEMP_CONTROL
#define TEMP_GET_INTERVAL (10 * 1000) //time interval
#define TEMP_THD_0 (110) //℃
#define TEMP_THD_1 (95) //℃
#define TEMP_THD_2 (85) //℃
#define TC_LOSS_LVL0 (-10) //TEMP >= TEMP_THD_0
#define TC_LOSS_LVL1 (-5) //TEMP_THD_1 < TEMP <= TEMP_THD_0
#define TC_LOSS_LVL2 (-2) //TEMP_THD_2 < TEMP <= TEMP_THD_1
#define TC_LOSS_LVL3 (0) //TEMP <= TEMP_THD_2
#endif
struct rwnx_sta *rwnx_retrieve_sta(struct rwnx_hw *rwnx_hw,
struct rwnx_vif *rwnx_vif, u8 *addr,
@@ -53,13 +68,56 @@ void aicwf_steering_timeout(struct timer_list *t);
#endif
#ifdef CONFIG_DYNAMIC_PERPWR
void rssi_update_txpwrloss(struct rwnx_sta *sta, s8_l rssi);
void rssi_update_txpwrloss(struct rwnx_sta *sta, s8_l rssi, struct rwnx_vif *vif);
void aicwf_txpwer_per_sta_worker(struct work_struct *work);
#endif
#ifdef CONFIG_DYNAMIC_PWR
void set_txpwrloss_ctrl(struct rwnx_hw *rwnx_hw, s8 value);
#ifdef CONFIG_DYNAMIC_PWR
void aicwf_pwrloss_worker(struct work_struct *work);
#endif
#ifdef CONFIG_TEMP_CONTROL
void aicwf_tcloss_worker(struct work_struct *work);
#endif
void rwnx_skb_align_8bytes(struct sk_buff *skb);
void rwnx_frame_parser(char* tag, char* data, unsigned long len);
void rwnx_update_mesh_power_mode(struct rwnx_vif *vif);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
void aicwf_p2p_alive_timeout(ulong data);
#else
void aicwf_p2p_alive_timeout(struct timer_list *t);
#endif
int rwnx_send_check_p2p(struct cfg80211_scan_request *param);
void apm_staloss_work_process(struct work_struct *work);
void apm_probe_sta_work_process(struct work_struct *work);
#ifdef AICWF_CFG80211_SET_MONITOR_CHANNEL_HAS_DEV
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_chan_def *chandef);
#else
int rwnx_cfg80211_set_monitor_channel_(struct wiphy *wiphy,
struct cfg80211_chan_def *chandef);
#endif
int rwnx_cfg80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
const u8 *peer, u64 *cookie);
void rwnx_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0))
struct net_device *dev,
#else
struct wireless_dev *wdev,
#endif
u16 frame_type, bool reg);
int rwnx_cfg80211_channel_switch(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_csa_settings *params);
int rwnx_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev,
struct bss_parameters *params);
int rwnx_ic_system_init(struct rwnx_hw *rwnx_hw);
int rwnx_ic_rf_init(struct rwnx_hw *rwnx_hw);
void aic_ipc_setting(struct rwnx_vif *rwnx_vif);
u16 rwnx_select_queue(struct net_device *dev, struct sk_buff *skb,
struct net_device *sb_dev);
#endif /* _RWNX_MAIN_H_ */
+11 -2
View File
@@ -55,6 +55,7 @@ struct rwnx_mod_params rwnx_mod_params = {
COMMON_PARAM(mutx, true, true)
COMMON_PARAM(mutx_on, true, true)
COMMON_PARAM(use_80, true, true)
/* false: use crda(iw reg set CN); true: drive self-management(wifi_test wlan0 country_set CN) */
COMMON_PARAM(custregd, true, true)
COMMON_PARAM(custchan, false, false)
COMMON_PARAM(roc_dur_max, 500, 500)
@@ -1781,6 +1782,8 @@ int rwnx_handle_dynparams(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
if(rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D81 &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D81X2 &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D89X2 &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D80N &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800DLN &&
rwnx_hw->mod_params->he_mcs_map > IEEE80211_HE_MCS_SUPPORT_0_9){
rwnx_hw->mod_params->he_mcs_map = IEEE80211_HE_MCS_SUPPORT_0_9;
} else {
@@ -1791,6 +1794,7 @@ int rwnx_handle_dynparams(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
if(rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D81 &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D81X2 &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D89X2 &&
rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800D80N &&
rwnx_hw->mod_params->use_80 == true){
rwnx_hw->mod_params->use_80 = false;
} else {
@@ -1837,11 +1841,13 @@ void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
wiphy->regulatory_flags |= REGULATORY_IGNORE_STALE_KICKOFF;
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
#endif
if (!rwnx_hw->mod_params->custregd)
return;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED;
rtnl_lock();
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)
if (regulatory_set_wiphy_regd_sync(wiphy, getRegdomainFromRwnxDB(wiphy, default_ccode))){
@@ -1852,6 +1858,7 @@ void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
wiphy_err(wiphy, "Failed to set custom regdomain\n");
}
#endif
else{
wiphy_err(wiphy,"\n"
"*******************************************************\n"
@@ -1860,4 +1867,6 @@ void rwnx_custregd(struct rwnx_hw *rwnx_hw, struct wiphy *wiphy)
}
rtnl_unlock();
#endif
}
@@ -71,6 +71,8 @@ struct ieee80211_regdomain *getRegdomainFromRwnxDB(struct wiphy *wiphy,
struct ieee80211_regdomain *getRegdomainFromRwnxDBIndex(struct wiphy *wiphy,
int index);
void rwnx_get_countrycode_channels(struct wiphy *wiphy,
struct ieee80211_regdomain *regdomain);
#endif /* _RWNX_MOD_PARAM_H_ */
+90 -8
View File
@@ -28,6 +28,8 @@
#ifdef CONFIG_USE_WIRELESS_EXT
#include "aicwf_wext_linux.h"
#endif
#include "rwnx_msg_rx.h"
void rwnx_cfg80211_unlink_bss(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif);
static int rwnx_freq_to_idx(struct rwnx_hw *rwnx_hw, int freq)
@@ -790,7 +792,15 @@ static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw,
#ifdef CONFIG_USE_WIRELESS_EXT
if(rwnx_hw->wext_scan){
if (!bss ) {
AICWFDBG(LOGERROR, "%s: Invalid BSS structure\n", __func__);
goto putbss;
}
list_for_each_entry(scan_re_wext, &rwnx_hw->wext_scanre_list, scanu_re_list) {
if (!scan_re_wext || !scan_re_wext->bss ) {
AICWFDBG(LOGDEBUG, "%s: Corrupted list entry detected\n", __func__);
continue;
}
if (!memcmp(scan_re_wext->bss->bssid, bss->bssid, ETH_ALEN)) {
AICWFDBG(LOGDEBUG, "%s: BSSID already exists, no need to add again\r\n", __func__);
goto putbss;
@@ -815,7 +825,9 @@ static inline int rwnx_rx_scanu_result_ind(struct rwnx_hw *rwnx_hw,
#endif
}
#ifdef CONFIG_USE_WIRELESS_EXT
putbss:
#endif
if (bss != NULL)
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
cfg80211_put_bss(bss);
@@ -1043,9 +1055,9 @@ static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw,
rwnx_vif->wep_auth_err = true;
AICWFDBG(LOGINFO, "con ind wep_auth_err %d\n", rwnx_vif->wep_auth_err);
}
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
}else{
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
}
@@ -1067,9 +1079,13 @@ static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw,
ind->assoc_rsp_ie_len, ind->status_code,
GFP_ATOMIC);
if (ind->status_code == 0) {
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_CONNECTED);
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_CONNECTED);
} else {
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
if(atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_CONNECTED) {
AICWFDBG(LOGINFO, "%s roaming fail no roamed ind \r\n", __func__);
cfg80211_disconnected(dev, 0, NULL, 0, 1, GFP_ATOMIC);
}
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
rwnx_external_auth_disable(rwnx_vif);
}
AICWFDBG(LOGINFO, "%s cfg80211_connect_result pass, rwnx_vif->drv_conn_state:%d\r\n", __func__, (int)atomic_read(&rwnx_vif->drv_conn_state));
@@ -1078,7 +1094,7 @@ static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw,
if(ind->status_code != 0){
AICWFDBG(LOGINFO, "%s roaming fail to notify disconnect \r\n", __func__);
cfg80211_disconnected(dev, 0, NULL, 0,1, GFP_ATOMIC);
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
rwnx_external_auth_disable(rwnx_vif);
}else{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
@@ -1116,7 +1132,7 @@ static inline int rwnx_rx_sm_connect_ind(struct rwnx_hw *rwnx_hw,
, ind->assoc_rsp_ie_len
, GFP_ATOMIC);
#endif /*LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)*/
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_CONNECTED);
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_CONNECTED);
}
rwnx_vif->sta.is_roam = false;
}
@@ -1263,7 +1279,7 @@ static inline int rwnx_rx_sm_disconnect_ind(struct rwnx_hw *rwnx_hw,
//msleep(200);
if (rwnx_vif->sta.is_roam == false) {
rwnx_set_conn_state(&rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
rwnx_set_conn_state(rwnx_vif, &rwnx_vif->drv_conn_state, (int)RWNX_DRV_STATUS_DISCONNECTED);
}
return 0;
@@ -1577,6 +1593,68 @@ static inline int rwnx_rx_dbg_error_ind(struct rwnx_hw *rwnx_hw,
return 0;
}
struct fault_ctxt {
uint32_t reg_i[13];
uint32_t SP;
uint32_t LR;
uint32_t PC;
uint32_t xPSR;
uint32_t PSP;
uint32_t MSP;
uint32_t EXC_RETURN;
uint32_t CONTROL;
};
static inline int rwnx_fw_panic_ind(struct rwnx_hw *rwnx_hw,
struct rwnx_cmd *cmd,
struct ipc_e2a_msg *msg)
{
struct fw_panic_info_ind *ind = (struct fw_panic_info_ind *)msg->param;
uint8_t version[36];
struct fault_ctxt fault;
uint32_t msp[64];
uint8_t i;
memcpy(version, ind->info, 36);
version[35] = '\0';
memcpy(&fault, &ind->info[36], sizeof(struct fault_ctxt));
memcpy(msp, &ind->info[36+sizeof(struct fault_ctxt)], 64*4);
printk("fw_panic: len=%d\n", ind->len);
printk("firmware: %s\n", version);
for(i=0; i<13; i++)
printk("REG %d = [%x]\n", i, fault.reg_i[i]);
printk("SP = [%x]\n", fault.SP);
printk("LR = [%x]\n", fault.LR);
printk("PC = [%x]\n", fault.PC);
printk("PSP = [%x]\n", fault.PSP);
printk("xPSR = [%x]\n", fault.xPSR);
printk("EXC_RETURN = [%x]\n", fault.EXC_RETURN);
printk("CONTROL = [%x]\n", fault.CONTROL);
printk("STACK:\n");
for(i=0; i<64; i+=4) {
printk("%08x, %08x, %08x, %08x\n", msp[i], msp[i+1], msp[i+2], msp[i+3]);
}
return 0;
}
static inline int rwnx_fw_assert_ind(struct rwnx_hw *rwnx_hw,
struct rwnx_cmd *cmd,
struct ipc_e2a_msg *msg)
{
struct fw_assert_info_ind *ind = (struct fw_assert_info_ind *)msg->param;
uint8_t buffer[256];
memcpy(buffer, ind->info, ind->len);
buffer[ind->len] = '\0';
printk("%s: %s\n", __func__, buffer);
return 0;
}
#ifdef CONFIG_RWNX_FULLMAC
static msg_cb_fct mm_hdlrs[MSG_I(MM_MAX)] = {
@@ -1595,6 +1673,8 @@ static msg_cb_fct mm_hdlrs[MSG_I(MM_MAX)] = {
[MSG_I(MM_PKTLOSS_IND)] = rwnx_rx_pktloss_notify_ind,
[MSG_I(MM_APM_STALOSS_IND)] = rwnx_apm_staloss_ind,
[MSG_I(MM_RADAR_DETECT_IND)] = rwnx_radar_detect_ind,
[MSG_I(MM_FW_PANIC_IND)] = rwnx_fw_panic_ind,
[MSG_I(MM_FW_ASSERT_IND)] = rwnx_fw_assert_ind,
};
static msg_cb_fct scan_hdlrs[MSG_I(SCANU_MAX)] = {
@@ -1669,12 +1749,14 @@ void rwnx_rx_handle_print(struct rwnx_hw *rwnx_hw, u8 *msg, u32 len)
u8 *data_end = NULL;
(void)data_end;
msg[len-1] = '\0';
if (!rwnx_hw || !rwnx_hw->fwlog_en) {
pr_err("FWLOG-OVFL: %s", msg);
return;
}
printk("FWLOG: %s", msg);
AICWFDBG(LOGFW, "%s", msg);
#ifdef CONFIG_RWNX_DEBUGFS
data_end = rwnx_hw->debugfs.fw_log.buf.dataend;
+207 -68
View File
@@ -205,6 +205,7 @@ void rwnx_cmd_free(struct rwnx_cmd *cmd){
spin_lock_irqsave(&cmd_array_lock, flags);
cmd->used = 0;
cmd->flags = 0;
AICWFDBG(LOGTRACE, "%s cmd_array[%d]:%p \r\n", __func__, cmd->array_id, cmd);
spin_unlock_irqrestore(&cmd_array_lock, flags);
}
@@ -1150,6 +1151,34 @@ int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8_l ofst, u8_l sel, u8_l *
return (error);
}
int rwnx_send_rf_config_v2_req(struct rwnx_hw *rwnx_hw, u16_l ofst, u8_l sel, u8_l *tbl, u16_l len)
{
struct mm_set_rf_config_req *rf_config_req;
int error;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_RF_CONFIG_REQ message */
rf_config_req = rwnx_msg_zalloc(MM_SET_RF_CONFIG_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_set_rf_config_req));
if (!rf_config_req) {
return -ENOMEM;
}
rf_config_req->table_sel = sel;
rf_config_req->table_ofst = 0;
rf_config_req->table_num = 16;
rf_config_req->deft_page = ofst / 16;
memcpy(rf_config_req->data, tbl, len);
/* Send the MM_SET_RF_CONFIG_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, rf_config_req, 1, MM_SET_RF_CONFIG_CFM, NULL);
return (error);
}
#ifdef RF_WRITE_FILE
#define FW_PATH_MAX_LEN_RF 200
@@ -1271,6 +1300,9 @@ int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D89X2){
rf_calib_req->cal_cfg_24g = 0x0f8f;
rf_calib_req->cal_cfg_5g = 0x0f0f;
}else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N){
rf_calib_req->cal_cfg_24g = 0x0f8f;
rf_calib_req->cal_cfg_5g = 0x0f0f;
}
rf_calib_req->param_alpha = 0x0c34c008;
@@ -1444,6 +1476,9 @@ int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D89X2){
rf_calib_req->cal_cfg_24g = 0x0f8f;
rf_calib_req->cal_cfg_5g = 0x0f0f;
} else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N){
rf_calib_req->cal_cfg_24g = 0x0f8f;
rf_calib_req->cal_cfg_5g = 0x0f0f;
}
rf_calib_req->param_alpha = 0x0c34c008;
@@ -1494,8 +1529,23 @@ int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw, struct mm_get_mac_addr_cf
int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_get_sta_info_cfm *cfm)
{
struct mm_get_sta_info_req *get_info_req;
struct mm_get_sta_info_compat_req *get_info_compat_req;
int error;
if(rwnx_hw->usbdev->chipid < PRODUCT_ID_AIC8800D81X2) {
/* Build the MM_GET_STA_INFO_REQ message */
get_info_compat_req = rwnx_msg_zalloc(MM_GET_STA_INFO_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_get_sta_info_compat_req));
if (!get_info_compat_req) {
return -ENOMEM;
}
get_info_compat_req->sta_idx = sta_idx;
memcpy(get_info_compat_req->pattern, "sta", 3);
/* Send the MM_GET_STA_INFO_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, get_info_compat_req, 1, MM_GET_STA_INFO_CFM, cfm);
} else {
/* Build the MM_GET_STA_INFO_REQ message */
get_info_req = rwnx_msg_zalloc(MM_GET_STA_INFO_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_get_sta_info_req));
@@ -1508,7 +1558,7 @@ int rwnx_send_get_sta_info_req(struct rwnx_hw *rwnx_hw, u8_l sta_idx, struct mm_
/* Send the MM_GET_STA_INFO_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, get_info_req, 1, MM_GET_STA_INFO_CFM, cfm);
}
return error;
};
@@ -1709,6 +1759,7 @@ int rwnx_send_vendor_hwconfig_req(struct rwnx_hw *rwnx_hw, uint32_t hwconfig_id,
printk("get_chip_temp err=%d\n", error);
}
}
break;
case CUSTOMIZED_FREQ_REQ:
/* Build the CUSTOMIZED_FREQ_REQ message */
req5 = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID, sizeof(struct mm_set_customized_freq_req));
@@ -2386,7 +2437,8 @@ int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw)
txpwr_lvl_v2->pwrlvl_11ax_2g4[i] -= txpwr_loss->loss_value_2g4;
}
if ((testmode == 0) && (chip_sub_id == 0)) {
if ((rwnx_hw->usbdev->chipid != PRODUCT_ID_AIC8800DLN) &&
(testmode == 0) && (chip_sub_id == 0)) {
txpwr_lvl_req->txpwr_lvl.enable = txpwr_lvl_v2->enable;
txpwr_lvl_req->txpwr_lvl.dsss = txpwr_lvl_v2->pwrlvl_11b_11ag_2g4[3]; // 11M
txpwr_lvl_req->txpwr_lvl.ofdmlowrate_2g4= txpwr_lvl_v2->pwrlvl_11ax_2g4[4]; // MCS4
@@ -2753,6 +2805,45 @@ int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw)
}
}
int rwnx_send_txpwr_lvl_adj_v2_req(struct rwnx_hw *rwnx_hw)
{
struct mm_set_txpwr_lvl_adj_req *txpwr_lvl_adj_req;
txpwr_lvl_adj_conf_v2_t txpwr_lvl_adj_v2_tmp;
txpwr_lvl_adj_conf_v2_t *txpwr_lvl_adj_v2;
int error;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_TXPWR_LVL_REQ message */
txpwr_lvl_adj_req = rwnx_msg_zalloc(MM_SET_TXPWR_LVL_ADJ_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_set_txpwr_lvl_adj_req));
if (!txpwr_lvl_adj_req) {
return -ENOMEM;
}
txpwr_lvl_adj_v2 = &txpwr_lvl_adj_v2_tmp;
get_userconfig_txpwr_lvl_adj_v2_in_fdrv(txpwr_lvl_adj_v2);
if (txpwr_lvl_adj_v2->enable == 0) {
rwnx_msg_free(rwnx_hw, txpwr_lvl_adj_req);
return 0;
} else {
AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_adj_v2->enable);
AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_1_4:%d\r\n", __func__, txpwr_lvl_adj_v2->pwrlvl_adj_tbl_2g4[0]);
AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_5_9:%d\r\n", __func__, txpwr_lvl_adj_v2->pwrlvl_adj_tbl_2g4[1]);
AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_10_13:%d\r\n", __func__, txpwr_lvl_adj_v2->pwrlvl_adj_tbl_2g4[2]);
txpwr_lvl_adj_req->txpwr_lvl_adj_v2 = *txpwr_lvl_adj_v2;
/* Send the MM_SET_TXPWR_LVL_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, txpwr_lvl_adj_req, 1, MM_SET_TXPWR_LVL_ADJ_CFM, NULL);
return (error);
}
}
extern void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst);
int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw)
@@ -2839,6 +2930,8 @@ int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw)
} else if (rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D81X2 ||
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D89X2){
get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x);
} else if (rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N) {
get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x);
}
if (txpwr_ofst2x->enable){
AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_ofst2x->enable);
@@ -2922,6 +3015,53 @@ int rwnx_send_txpwr_ofst2x_v2_req(struct rwnx_hw *rwnx_hw)
return (error);
}
int rwnx_send_txpwr_ofst2x_v3_req(struct rwnx_hw *rwnx_hw)
{
struct mm_set_txpwr_ofst_req *txpwr_ofst_req;
txpwr_ofst2x_conf_v3_t *txpwr_ofst2x_v3;
int error = 0;
int type, ch_grp;
RWNX_DBG(RWNX_FN_ENTRY_STR);
/* Build the MM_SET_TXPWR_OFST_REQ message */
txpwr_ofst_req = rwnx_msg_zalloc(MM_SET_TXPWR_OFST_REQ, TASK_MM, DRV_TASK_ID,
sizeof(struct mm_set_txpwr_ofst_req));
if (!txpwr_ofst_req) {
return -ENOMEM;
}
txpwr_ofst2x_v3 = &txpwr_ofst_req->txpwr_ofst2x_v3;
txpwr_ofst2x_v3->enable = 0;
for (type = 0; type < 3; type++) {
for (ch_grp = 0; ch_grp < 3; ch_grp++) {
txpwr_ofst2x_v3->pwrofst2x_tbl_2g4[type][ch_grp] = 0;
}
}
get_userconfig_txpwr_ofst2x_v3_in_fdrv(txpwr_ofst2x_v3);
if (txpwr_ofst2x_v3->enable){
AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_ofst2x_v3->enable);
AICWFDBG(LOGINFO, "pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n"
" chan=" "\t1-4" "\t5-9" "\t10-13");
for (type = 0; type < 3; type++) {
AICWFDBG(LOGINFO, "\n [%d] =", type);
for (ch_grp = 0; ch_grp < 3; ch_grp++) {
AICWFDBG(LOGINFO, "\t%d", txpwr_ofst2x_v3->pwrofst2x_tbl_2g4[type][ch_grp]);
}
}
AICWFDBG(LOGINFO, "\n");
/* Send the MM_SET_TXPWR_OFST_REQ message to UMAC FW */
error = rwnx_send_msg(rwnx_hw, txpwr_ofst_req, 1, MM_SET_TXPWR_OFST_CFM, NULL);
}else{
AICWFDBG(LOGINFO, "%s:Do not use txpwr_ofst2x_v3\r\n", __func__);
rwnx_msg_free(rwnx_hw, txpwr_ofst_req);
}
return (error);
}
int rwnx_send_set_filter(struct rwnx_hw *rwnx_hw, uint32_t filter)
{
struct mm_set_filter_req *set_filter_req_param;
@@ -3279,7 +3419,7 @@ int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw, struct station_parameters *par
#if (defined CONFIG_HE_FOR_OLD_KERNEL) || (defined CONFIG_VHT_FOR_OLD_KERNEL)
struct aic_sta *sta = &rwnx_hw->aic_table[rwnx_vif->ap.aic_index];
printk("assoc_req idx %d, he: %d, vht: %d\n ", rwnx_vif->ap.aic_index, sta->he, sta->vht);
if (rwnx_vif->ap.aic_index < NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX)
if (rwnx_vif->ap.aic_index < (NX_REMOTE_STA_MAX + NX_VIRT_DEV_MAX - 1))
rwnx_vif->ap.aic_index++;
else
rwnx_vif->ap.aic_index = 0;
@@ -3406,8 +3546,13 @@ int rwnx_send_me_sta_add(struct rwnx_hw *rwnx_hw, struct station_parameters *par
req->flags |= STA_MFP_CAPA;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
if (link_sta_params->opmode_notif_used) {
req->opmode = link_sta_params->opmode_notif_used;
#if LINUX_VERSION_CODE < HIGH_KERNEL_VERSION
if (params->opmode_notif_used) {
req->opmode = params->opmode_notif;
#else
if (params->link_sta_params.opmode_notif_used) {
req->opmode = params->link_sta_params.opmode_notif;
#endif//LINUX_VERSION_CODE < HIGH_KERNEL_VERSION
req->flags |= STA_OPMOD_NOTIF;
}
#endif
@@ -4704,7 +4849,13 @@ int rwnx_send_dbg_trigger_req(struct rwnx_hw *rwnx_hw, char *msg)
return -ENOMEM;
/* 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 */
return rwnx_send_msg(rwnx_hw, req, 0, -1, NULL);
@@ -5038,6 +5189,54 @@ int rwnx_send_cfg_rssi_req(struct rwnx_hw *rwnx_hw, u8 vif_index, int rssi_thold
return rwnx_send_msg(rwnx_hw, req, 1, MM_CFG_RSSI_CFM, NULL);
}
int rwnx_send_get_temp_req(struct rwnx_hw *rwnx_hw, s8_l *temp)
{
struct mm_get_chip_temp_req *hwreq;
struct mm_set_vendor_swconfig_req *swreq;
struct mm_set_vendor_hwconfig_cfm hwcfm;
struct mm_set_vendor_swconfig_cfm swcfm;
int ret = 0;
RWNX_DBG(RWNX_FN_ENTRY_STR);
if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DW){
/* Build the CHIP_TEMP_GET_REQ message */
hwreq = rwnx_msg_zalloc(MM_SET_VENDOR_HWCONFIG_REQ, TASK_MM, DRV_TASK_ID, sizeof(struct mm_get_chip_temp_req));
if (!hwreq)
return -ENOMEM;
hwreq->hwconfig_id = CHIP_TEMP_GET_REQ;
/* Send the MM_SET_VENDOR_HWCONFIG_REQ message to UMAC FW */
ret = rwnx_send_msg(rwnx_hw, hwreq, 1, MM_SET_VENDOR_HWCONFIG_CFM, &hwcfm);
if (!ret) {
AICWFDBG(LOGINFO, "get_chip_temp degree=%d\n", hwcfm.chip_temp_cfm.degree);
*temp = hwcfm.chip_temp_cfm.degree;
} else {
AICWFDBG(LOGINFO, "get_chip_temp err=%d\n", ret);
return ret;
}
return ret;
} else if (rwnx_hw->usbdev->chipid >= PRODUCT_ID_AIC8800D80N) {
/* Build the TEMP_COMP_GET_REQ message */
swreq = rwnx_msg_zalloc(MM_SET_VENDOR_SWCONFIG_REQ, TASK_MM, DRV_TASK_ID, sizeof(struct mm_set_vendor_swconfig_req));
if (!swreq) {
AICWFDBG(LOGINFO, "%s msg_alloc fail\n", __func__);
return -ENOMEM;
}
swreq->swconfig_id = TEMP_COMP_GET_REQ;
ret = rwnx_send_msg(rwnx_hw, swreq, 1, MM_SET_VENDOR_SWCONFIG_CFM, &swcfm);
if (!ret) {
AICWFDBG(LOGINFO, "status=%d, temp=%d\n", swcfm.temp_comp_get_cfm.status, swcfm.temp_comp_get_cfm.degree);
*temp = swcfm.temp_comp_get_cfm.degree;
} else {
AICWFDBG(LOGINFO, "%s msg_fail\n", __func__);
return ret;
}
}
return ret;
}
//#ifdef CONFIG_USB_BT
int rwnx_send_reboot(struct rwnx_hw *rwnx_hw)
{
@@ -5049,70 +5248,9 @@ int rwnx_send_reboot(struct rwnx_hw *rwnx_hw)
ret = rwnx_send_dbg_start_app_req(rwnx_hw, delay, HOST_START_APP_REBOOT);
return ret;
}
int rwnx_send_pwm_init_req(struct rwnx_hw *rwnx_hw, u8 pwm_gpidx, u8 mode, u8 run, u32 tmr_cnt,
u32 dty_cnt, u32 step_val, u8 gpio_en, u8 gpio_dir, u8 gpio_val)
{
struct dbg_pwm_init_req *pwm_init_req;
pwm_init_req = rwnx_msg_zalloc(DBG_PWM_INIT_REQ, TASK_DBG, DRV_TASK_ID,
sizeof(struct dbg_pwm_init_req));
if (!pwm_init_req)
return -ENOMEM;
pwm_init_req->pwm_gpidx = pwm_gpidx;
pwm_init_req->mode = mode;
pwm_init_req->run = run;
pwm_init_req->tmr_cnt = tmr_cnt;
pwm_init_req->dty_cnt = dty_cnt;
pwm_init_req->step_val = step_val;
pwm_init_req->gpio_en = gpio_en;
pwm_init_req->gpio_dir = gpio_dir;
pwm_init_req->gpio_val = gpio_val;
return rwnx_send_msg(rwnx_hw, pwm_init_req, 1, DBG_PWM_INIT_CFM, NULL);
}
int rwnx_send_pwm_deinit_req(struct rwnx_hw *rwnx_hw, u8 pwm_gpidx, u8 gpio_en, u8 gpio_dir, u8 gpio_val)
{
struct dbg_pwm_deinit_req *pwm_deinit_req;
pwm_deinit_req = rwnx_msg_zalloc(DBG_PWM_DEINIT_REQ, TASK_DBG, DRV_TASK_ID,
sizeof(struct dbg_pwm_deinit_req));
if (!pwm_deinit_req)
return -ENOMEM;
pwm_deinit_req->pwm_gpidx = pwm_gpidx;
pwm_deinit_req->gpio_en = gpio_en;
pwm_deinit_req->gpio_dir = gpio_dir;
pwm_deinit_req->gpio_val = gpio_val;
return rwnx_send_msg(rwnx_hw, pwm_deinit_req, 1, DBG_PWM_DEINIT_CFM, NULL);
}
u32 pwm_tbl[][2] = {
{0x40504088, 4},
};
void rwnx_set_pwm_tbl(struct rwnx_hw *rwnx_hw)
{
int patch_num = 0;
int cnt = 0;
int ret = 0;
patch_num = sizeof(pwm_tbl) / sizeof(u32) / 2;
for (cnt = 0; cnt < patch_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(rwnx_hw, pwm_tbl[cnt][0], pwm_tbl[cnt][1]);
if (ret) {
break;
}
}
}
//#endif // CONFIG_USB_BT
#ifdef CONFIG_WOWLAN
#ifndef ANDROID_PLATFORM
int rwnx_send_dummy_reboot(struct rwnx_hw *rwnx_hw)
{
int ret = 0;
@@ -5124,3 +5262,4 @@ int rwnx_send_dummy_reboot(struct rwnx_hw *rwnx_hw)
return ret;
}
#endif
#endif
+8 -6
View File
@@ -67,6 +67,7 @@ int rwnx_send_arpoffload_en_req(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_v
u32_l ipaddr, u8_l enable);
#endif
int rwnx_send_rf_config_req(struct rwnx_hw *rwnx_hw, u8_l ofst, u8_l sel, u8_l *tbl, u16_l len);
int rwnx_send_rf_config_v2_req(struct rwnx_hw *rwnx_hw, u16_l ofst, u8_l sel, u8_l *tbl, u16_l len);
int rwnx_send_rf_calib_req(struct rwnx_hw *rwnx_hw, struct mm_set_rf_calib_cfm *cfm);
int rwnx_send_get_macaddr_req(struct rwnx_hw *rwnx_hw, struct mm_get_mac_addr_cfm *cfm);
@@ -184,11 +185,13 @@ int rwnx_send_txpwr_idx_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_ofst_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_ofst2x_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_ofst2x_v2_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_ofst2x_v3_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_set_filter(struct rwnx_hw *rwnx_hw, uint32_t filter);
int rwnx_send_txpwr_lvl_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_v3_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_v4_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_adj_req(struct rwnx_hw *rwnx_hw);
int rwnx_send_txpwr_lvl_adj_v2_req(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_WOWLAN
int rwnx_send_set_pkt_filter_req(struct rwnx_hw *rwnx_hw, u8_l *param);
int rwnx_send_dummy_reboot(struct rwnx_hw *rwnx_hw);
@@ -196,15 +199,14 @@ int rwnx_send_dummy_reboot(struct rwnx_hw *rwnx_hw);
#ifdef CONFIG_DYNAMIC_PERPWR
int rwnx_send_txpwr_per_sta_req(struct rwnx_hw *rwnx_hw, struct rwnx_sta *sta);
#endif
int rwnx_send_get_temp_req(struct rwnx_hw *rwnx_hw, s8_l *temp);
//#ifdef CONFIG_USB_BT
int rwnx_send_reboot(struct rwnx_hw *rwnx_hw);
//#endif // CONFIG_USB_BT
int rwnx_send_pwm_init_req(struct rwnx_hw *rwnx_hw, u8 pwm_gpidx, u8 mode, u8 run, u32 tmr_cnt,
u32 dty_cnt, u32 step_val, u8 gpio_en, u8 gpio_dir, u8 gpio_val);
int rwnx_send_pwm_deinit_req(struct rwnx_hw *rwnx_hw, u8 pwm_gpidx, u8 gpio_en, u8 gpio_dir, u8 gpio_val);
void rwnx_set_pwm_tbl(struct rwnx_hw *rwnx_hw);
struct rwnx_cmd *rwnx_cmd_malloc(void);
void rwnx_cmd_free(struct rwnx_cmd *cmd);
int rwnx_init_cmd_array(void);
void rwnx_free_cmd_array(void);
#endif /* _RWNX_MSG_TX_H_ */
+1
View File
@@ -13,6 +13,7 @@
#include "rwnx_defs.h"
#include "rwnx_dini.h"
#include "rwnx_v7.h"
#include "rwnx_pci.h"
#define PCI_VENDOR_ID_DINIGROUP 0x17DF
#define PCI_DEVICE_ID_DINIGROUP_DNV6_F2PCIE 0x1907
+272 -10
View File
@@ -34,6 +34,8 @@
#include "aicwf_compat_8800dc.h"
#include "aicwf_compat_8800d80.h"
#include "aicwf_compat_8800d80x2.h"
#include "aicwf_compat_8800d80n.h"
#include "aicwf_compat_8800dln.h"
#ifdef CONFIG_USE_FW_REQUEST
#include <linux/firmware.h>
#endif
@@ -190,6 +192,15 @@ userconfig_info_t userconfig_info = {
.pwrofst2x_tbl_6g_ant0 = { 0, }, // ofdm_highrate: 6e_ch7 ~ 6e_ch229
.pwrofst2x_tbl_6g_ant1 = { 0, }, // ofdm_highrate: 6e_ch7 ~ 6e_ch229
},
.txpwr_ofst2x_v3 = {
.enable = 0,
.pwrofst2x_tbl_2g4 =
{ // ch1-4, ch5-9, ch10-13
{ 0, 0, 0 }, // 11b
{ 0, 0, 0 }, // ofdm_highrate
{ 0, 0, 0 }, // ofdm_lowrate
},
},
.xtal_cap = {
.enable = 0,
.xtal_cap = 24,
@@ -248,6 +259,7 @@ reg_table reg_tables[] = {
{.ccode = "CL", .region = REGIONS_ETSI},
{.ccode = "CO", .region = REGIONS_FCC},
{.ccode = "CR", .region = REGIONS_FCC},
{.ccode = "CU", .region = REGIONS_FCC},
{.ccode = "CX", .region = REGIONS_FCC},
{.ccode = "CY", .region = REGIONS_ETSI},
{.ccode = "CZ", .region = REGIONS_ETSI},
@@ -272,7 +284,7 @@ reg_table reg_tables[] = {
{.ccode = "GL", .region = REGIONS_ETSI},
{.ccode = "GP", .region = REGIONS_ETSI},
{.ccode = "GR", .region = REGIONS_ETSI},
{.ccode = "GT", .region = REGIONS_FCC},
{.ccode = "GT", .region = REGIONS_DEFAULT},
{.ccode = "GU", .region = REGIONS_FCC},
{.ccode = "GY", .region = REGIONS_DEFAULT},
{.ccode = "HK", .region = REGIONS_ETSI},
@@ -285,7 +297,7 @@ reg_table reg_tables[] = {
{.ccode = "IL", .region = REGIONS_ETSI},
{.ccode = "IN", .region = REGIONS_ETSI},
{.ccode = "IQ", .region = REGIONS_ETSI},
{.ccode = "IR", .region = REGIONS_JP},
{.ccode = "IR", .region = REGIONS_ETSI},
{.ccode = "IS", .region = REGIONS_ETSI},
{.ccode = "IT", .region = REGIONS_ETSI},
{.ccode = "JM", .region = REGIONS_FCC},
@@ -295,7 +307,7 @@ reg_table reg_tables[] = {
{.ccode = "KH", .region = REGIONS_ETSI},
{.ccode = "KN", .region = REGIONS_ETSI},
{.ccode = "KP", .region = REGIONS_JP},
{.ccode = "KR", .region = REGIONS_ETSI},
{.ccode = "KR", .region = REGIONS_KCC},
{.ccode = "KW", .region = REGIONS_ETSI},
{.ccode = "KY", .region = REGIONS_FCC},
{.ccode = "KZ", .region = REGIONS_DEFAULT},
@@ -339,7 +351,7 @@ reg_table reg_tables[] = {
{.ccode = "PF", .region = REGIONS_ETSI},
{.ccode = "PG", .region = REGIONS_FCC},
{.ccode = "PH", .region = REGIONS_FCC},
{.ccode = "PK", .region = REGIONS_ETSI},
{.ccode = "PK", .region = REGIONS_DEFAULT},
{.ccode = "PL", .region = REGIONS_ETSI},
{.ccode = "PM", .region = REGIONS_ETSI},
{.ccode = "PR", .region = REGIONS_FCC},
@@ -361,7 +373,7 @@ reg_table reg_tables[] = {
{.ccode = "SN", .region = REGIONS_FCC},
{.ccode = "SR", .region = REGIONS_ETSI},
{.ccode = "SV", .region = REGIONS_FCC},
{.ccode = "SY", .region = REGIONS_DEFAULT},
{.ccode = "SY", .region = REGIONS_ETSI},
{.ccode = "TC", .region = REGIONS_FCC},
{.ccode = "TD", .region = REGIONS_ETSI},
{.ccode = "TG", .region = REGIONS_ETSI},
@@ -372,6 +384,7 @@ reg_table reg_tables[] = {
{.ccode = "TR", .region = REGIONS_ETSI},
{.ccode = "TT", .region = REGIONS_FCC},
{.ccode = "TW", .region = REGIONS_FCC},
{.ccode = "TZ", .region = REGIONS_ETSI},
{.ccode = "UA", .region = REGIONS_ETSI},
{.ccode = "UG", .region = REGIONS_FCC},
{.ccode = "UY", .region = REGIONS_FCC},
@@ -382,10 +395,13 @@ reg_table reg_tables[] = {
{.ccode = "VN", .region = REGIONS_JP},
{.ccode = "VU", .region = REGIONS_FCC},
{.ccode = "WF", .region = REGIONS_ETSI},
{.ccode = "WS", .region = REGIONS_ETSI},
{.ccode = "YE", .region = REGIONS_DEFAULT},
{.ccode = "YT", .region = REGIONS_ETSI},
{.ccode = "ZA", .region = REGIONS_ETSI},
{.ccode = "ZM", .region = REGIONS_ETSI},
{.ccode = "FO", .region = REGIONS_ETSI},
{.ccode = "FK", .region = REGIONS_ETSI},
{.ccode = "ZW", .region = REGIONS_ETSI},
};
@@ -417,6 +433,8 @@ u8 get_region_index(char * name)
return REGIONS_ETSI;
else if (strncmp(name, "JP", 2) == 0)
return REGIONS_JP;
else if (strncmp(name, "KCC", 3) == 0)
return REGIONS_KCC;
else if (strncmp(name, "UNSET", 5) == 0)
return REGIONS_DEFAULT;
@@ -424,6 +442,7 @@ u8 get_region_index(char * name)
}
#ifdef CONFIG_POWER_LIMIT
#define POWER_LIMIT_INVALID_VAL POWER_LEVEL_INVALID_VAL
@@ -431,7 +450,7 @@ u8 get_region_index(char * name)
#define MAX_2_4G_BW_NUM 2
#define MAX_5G_BW_NUM 3
#define MAX_REGION_NUM 5
#define MAX_REGION_NUM 6
typedef struct
@@ -685,7 +704,7 @@ static int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *dev
}
/* start to read from firmware file */
buffer = vmalloc(size);
buffer = vmalloc(size + 1);
if (!buffer) {
*fw_buf = NULL;
__putname(path);
@@ -700,6 +719,7 @@ static int rwnx_load_firmware(u32 **fw_buf, const char *name, struct device *dev
rdlen = kernel_read(fp, fp->f_pos, buffer, size);
#endif
*((char*)buffer + size) = 0;
if (size != rdlen) {
AICWFDBG(LOGERROR, "%s: %s file rdlen invalid %d\n", __func__, name, (int)rdlen);
*fw_buf = NULL;
@@ -836,6 +856,69 @@ int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
return err;
}
int rwnx_plat_bin_fw_upload_2_with_version(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename, char *version_str, int version_size)
{
int err = 0;
unsigned int i = 0, size;
u32 *dst = NULL;
/* Copy the file on the Embedded side */
AICWFDBG(LOGINFO, "### Upload %s firmware, @ = %x\n", filename, fw_addr);
size = rwnx_request_firmware_common(rwnx_hw, &dst, filename);
if (!dst) {
AICWFDBG(LOGERROR, "No such file or directory\n");
return -1;
}
if (size <= 0) {
AICWFDBG(LOGERROR, "wrong size of firmware file\n");
dst = NULL;
err = -1;
return -1;
}
AICWFDBG(LOGINFO, "size=%d, dst[0]=%x\n", size, dst[0]);
// get version if exist
if (version_str) {
char *bin_str = (char *)&dst[4];
int char_idx = 0;
for (char_idx = 0; char_idx < version_size; char_idx++) {
version_str[char_idx] = bin_str[char_idx];
if (bin_str[char_idx] == '\0') {
//break;
}
}
if (char_idx == version_size) {
version_str[version_size - 1] = '\0';
}
AICWFDBG(LOGINFO, "version_str=%s\n", version_str);
}
// upload
if (size > 512) {
for (; i < (size - 512); i += 512) {
//printk("wr blk 0: %p -> %x\r\n", dst + i / 4, fw_addr + i);
err = rwnx_send_dbg_mem_block_write_req(rwnx_hw, fw_addr + i, 512, dst + i / 4);
if (err) {
AICWFDBG(LOGERROR, "bin upload fail: %x, err:%d\r\n", fw_addr + i, err);
break;
}
}
}
if (!err && (i < size)) {
//printk("wr blk 1: %p -> %x\r\n", dst + i / 4, fw_addr + i);
err = rwnx_send_dbg_mem_block_write_req(rwnx_hw, fw_addr + i, size - i, dst + i / 4);
if (err) {
AICWFDBG(LOGERROR, "bin upload fail: %x, err:%d\r\n", fw_addr + i, err);
}
}
if (dst) {
rwnx_release_firmware_common(&dst);
}
return err;
}
#ifndef CONFIG_ROM_PATCH_EN
@@ -1586,7 +1669,8 @@ static int rwnx_plat_patch_load(struct rwnx_hw *rwnx_hw)
if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DW){
#ifndef ANDROID_PLATFORM
sprintf(aic_fw_path, "%s/%s", aic_fw_path, "aic8800DC");
if (strlcat(aic_fw_path, "/aic8800DC", sizeof(aic_fw_path)) >= sizeof(aic_fw_path))
return -ENAMETOOLONG;
#endif
AICWFDBG(LOGINFO, "testmode=%d\n", testmode);
if (chip_sub_id == 0) {
@@ -1723,8 +1807,54 @@ static int rwnx_plat_patch_load(struct rwnx_hw *rwnx_hw)
return 1; // exit calib mode
}
}
} else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N) {
#ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800D80N", sizeof(aic_fw_path)) >= sizeof(aic_fw_path))
return -ENAMETOOLONG;
#endif
if (testmode == FW_NORMAL_MODE) {
ret = aicwf_plat_patch_load_8800d80n(rwnx_hw);
if (ret) {
AICWFDBG(LOGERROR, "patch upload fail: %d\n", ret);
return ret;
}
ret = aicwf_plat_patch_table_load_8800d80n(rwnx_hw);
if (ret) {
AICWFDBG(LOGERROR, "patch_tbl upload fail: %d\r\n", ret);
return ret;
}
aicwf_patch_config_8800d80n(rwnx_hw);
#if DEF_PATCH_METHOD_VER_2
aicwf_plat_cinit_exec_8800d80n(rwnx_hw);
aicwf_plat_calib_exec_8800d80n(rwnx_hw);
#endif
}
else if (testmode == FW_RFTEST_MODE) {
AICWFDBG(LOGINFO, "%s load rftest bin\n", __func__);
ret = aicwf_plat_rftest_load_8800d80n(rwnx_hw);
if (ret) {
AICWFDBG(LOGERROR, "load rftest bin fail: %d\n", ret);
return ret;
}
}
}
else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DLN) {
#ifndef ANDROID_PLATFORM
if (strlcat(aic_fw_path, "/aic8800DLN", sizeof(aic_fw_path)) >= sizeof(aic_fw_path))
return -ENAMETOOLONG;
#endif
if (testmode == FW_NORMAL_MODE) {
aicwf_patch_config_8800dln(rwnx_hw);
}
else if (testmode == FW_RFTEST_MODE) {
AICWFDBG(LOGINFO, "%s load rftest bin\n", __func__);
ret = aicwf_plat_rftest_load_8800dln(rwnx_hw);
if (ret) {
AICWFDBG(LOGINFO, "load rftest bin fail: %d\n", ret);
return ret;
}
}
}
return ret;
}
#endif
@@ -2242,6 +2372,16 @@ void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj)
AICWFDBG(LOGINFO, "%s:lvl_adj_5g_chan_155:%d\r\n", __func__, txpwr_lvl_adj->pwrlvl_adj_tbl_5g[5]);
}
void get_userconfig_txpwr_lvl_adj_v2_in_fdrv(txpwr_lvl_adj_conf_v2_t *txpwr_lvl_adj_v2)
{
*txpwr_lvl_adj_v2 = userconfig_info.txpwr_lvl_adj_v2;
AICWFDBG(LOGINFO, "%s:enable:%d\r\n", __func__, txpwr_lvl_adj_v2->enable);
AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_1_4:%d\r\n", __func__, txpwr_lvl_adj_v2->pwrlvl_adj_tbl_2g4[0]);
AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_5_9:%d\r\n", __func__, txpwr_lvl_adj_v2->pwrlvl_adj_tbl_2g4[1]);
AICWFDBG(LOGINFO, "%s:lvl_adj_2g4_chan_10_13:%d\r\n", __func__, txpwr_lvl_adj_v2->pwrlvl_adj_tbl_2g4[2]);
}
void get_userconfig_txpwr_ofst_in_fdrv(txpwr_ofst_conf_t *txpwr_ofst)
{
@@ -2311,6 +2451,23 @@ void get_userconfig_txpwr_ofst2x_v2_in_fdrv(txpwr_ofst2x_conf_v2_t *txpwr_ofst2x
}
AICWFDBG(LOGINFO, "\n");
}
void get_userconfig_txpwr_ofst2x_v3_in_fdrv(txpwr_ofst2x_conf_v3_t *txpwr_ofst2x_v3)
{
int type, ch_grp;
*txpwr_ofst2x_v3 = userconfig_info.txpwr_ofst2x_v3;
AICWFDBG(LOGINFO, "%s:enable :%d\r\n", __func__, txpwr_ofst2x_v3->enable);
AICWFDBG(LOGINFO, "pwrofst2x 2.4g: [0]:11b, [1]:ofdm_highrate, [2]:ofdm_lowrate\n"
" chan=" "\t1-4" "\t5-9" "\t10-13");
for (type = 0; type < 3; type++) {
AICWFDBG(LOGINFO, "\n [%d] =", type);
for (ch_grp = 0; ch_grp < 3; ch_grp++) {
AICWFDBG(LOGINFO, "\t%d", txpwr_ofst2x_v3->pwrofst2x_tbl_2g4[type][ch_grp]);
}
}
AICWFDBG(LOGINFO, "\n");
}
void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss)
{
txpwr_loss->loss_enable_2g4 = userconfig_info.txpwr_loss.loss_enable_2g4;
@@ -2322,6 +2479,101 @@ void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss)
txpwr_loss->loss_enable_2g4, txpwr_loss->loss_value_2g4,
txpwr_loss->loss_enable_5g, txpwr_loss->loss_value_5g);
}
s8_l get_txpwr_max(s8_l power)
{
int i=0;
if(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D81X2 ||
g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D89X2 ){
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[i])
power = userconfig_info.txpwr_lvl_v4.pwrlvl_11b_11ag_2g4[i];
}
for (i = 0; i <= 9; i++){
if(power < userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[i])
power = userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_2g4[i];
}
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[i])
power = userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_2g4[i];
}
for (i = 0; i <= 7; i++){
if(power < userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[i])
power = userconfig_info.txpwr_lvl_v4.pwrlvl_11a_5g[i];
}
for (i = 0; i <= 9; i++){
if(power < userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[i])
power = userconfig_info.txpwr_lvl_v4.pwrlvl_11n_11ac_5g[i];
}
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[i])
power = userconfig_info.txpwr_lvl_v4.pwrlvl_11ax_5g[i];
}
if ((userconfig_info.txpwr_loss.loss_enable_2g4 == 1) ||
(userconfig_info.txpwr_loss.loss_enable_5g == 1)) {
if (userconfig_info.txpwr_loss.loss_value_2g4 <
userconfig_info.txpwr_loss.loss_value_5g)
power += userconfig_info.txpwr_loss.loss_value_5g;
else
power += userconfig_info.txpwr_loss.loss_value_2g4;
}
}
else if (g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D81 ||
g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800D80N){
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i])
power = userconfig_info.txpwr_lvl_v3.pwrlvl_11b_11ag_2g4[i];
}
for (i = 0; i <= 9; i++){
if(power < userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i])
power = userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_2g4[i];
}
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i])
power = userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_2g4[i];
}
for (i = 4; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i])
power = userconfig_info.txpwr_lvl_v3.pwrlvl_11a_5g[i];
}
for (i = 0; i <= 9; i++){
if(power < userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i])
power = userconfig_info.txpwr_lvl_v3.pwrlvl_11n_11ac_5g[i];
}
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i])
power = userconfig_info.txpwr_lvl_v3.pwrlvl_11ax_5g[i];
}
if ((userconfig_info.txpwr_loss.loss_enable_2g4 == 1) ||
(userconfig_info.txpwr_loss.loss_enable_5g == 1)) {
if (userconfig_info.txpwr_loss.loss_value_2g4 <
userconfig_info.txpwr_loss.loss_value_5g)
power += userconfig_info.txpwr_loss.loss_value_5g;
else
power += userconfig_info.txpwr_loss.loss_value_2g4;
}
}else if(g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DC || g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW){
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[i])
power = userconfig_info.txpwr_lvl_v2.pwrlvl_11b_11ag_2g4[i];
}
for (i = 0; i <= 9; i++){
if(power < userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[i])
power = userconfig_info.txpwr_lvl_v2.pwrlvl_11n_11ac_2g4[i];
}
for (i = 0; i <= 11; i++){
if(power < userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[i])
power = userconfig_info.txpwr_lvl_v2.pwrlvl_11ax_2g4[i];
}
}
AICWFDBG(LOGINFO, "%s:txpwr_max:%d \r\n",__func__,power);
return power;
}
void set_txpwr_loss_ofst(s8_l value)
{
userconfig_info.txpwr_loss.loss_enable_2g4 = 1;
@@ -3115,7 +3367,7 @@ int8_t rwnx_plat_powerlimit_save(u8_l band, char *channel, u8_l bw, char *limit,
}
void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc)
void rwnx_plat_powerlimit_parsing(char *buffer, int size)
{
#define LD_STAGE_EXC_MAPPING 0
#define LD_STAGE_TAB_DEFINE 1
@@ -3465,11 +3717,21 @@ static int rwnx_plat_userconfig_load(struct rwnx_hw *rwnx_hw) {
#ifdef CONFIG_POWER_LIMIT
rwnx_plat_powerlimit_load_8800dcdw(rwnx_hw, PRODUCT_ID_AIC8800DW);
#endif
}else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800DLN){
rwnx_plat_userconfig_load_8800dln(rwnx_hw);
#ifdef CONFIG_POWER_LIMIT
rwnx_plat_powerlimit_load_8800dln(rwnx_hw);
#endif
}else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D81){
rwnx_plat_userconfig_load_8800d80(rwnx_hw);
}else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D81X2 ||
rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D89X2){
rwnx_plat_userconfig_load_8800d80x2(rwnx_hw);
}else if(rwnx_hw->usbdev->chipid == PRODUCT_ID_AIC8800D80N){
rwnx_plat_userconfig_load_8800d80n(rwnx_hw);
#ifdef CONFIG_POWER_LIMIT
rwnx_plat_powerlimit_load_8800d80n(rwnx_hw);
#endif
}
return 0;
+19 -1
View File
@@ -71,10 +71,12 @@ typedef struct
txpwr_lvl_conf_v3_t txpwr_lvl_v3;
txpwr_lvl_conf_v4_t txpwr_lvl_v4;
txpwr_lvl_adj_conf_t txpwr_lvl_adj;
txpwr_lvl_adj_conf_v2_t txpwr_lvl_adj_v2;
txpwr_loss_conf_t txpwr_loss;
txpwr_ofst_conf_t txpwr_ofst;
txpwr_ofst2x_conf_t txpwr_ofst2x;
txpwr_ofst2x_conf_v2_t txpwr_ofst2x_v2;
txpwr_ofst2x_conf_v3_t txpwr_ofst2x_v3;
xtal_cap_conf_t xtal_cap;
} userconfig_info_t;
@@ -85,6 +87,7 @@ typedef enum {
REGIONS_FCC,
REGIONS_ETSI,
REGIONS_JP,
REGIONS_KCC,
REGIONS_DEFAULT,
} Regions_code;
@@ -156,10 +159,13 @@ void get_userconfig_txpwr_lvl_v2_in_fdrv(txpwr_lvl_conf_v2_t *txpwr_lvl_v2);
void get_userconfig_txpwr_lvl_v3_in_fdrv(txpwr_lvl_conf_v3_t *txpwr_lvl_v3);
void get_userconfig_txpwr_lvl_v4_in_fdrv(txpwr_lvl_conf_v4_t *txpwr_lvl_v4);
void get_userconfig_txpwr_lvl_adj_in_fdrv(txpwr_lvl_adj_conf_t *txpwr_lvl_adj);
void get_userconfig_txpwr_lvl_adj_v2_in_fdrv(txpwr_lvl_adj_conf_v2_t *txpwr_lvl_adj_v2);
void get_userconfig_txpwr_ofst_in_fdrv(txpwr_ofst_conf_t *txpwr_ofst);
void get_userconfig_txpwr_ofst2x_in_fdrv(txpwr_ofst2x_conf_t *txpwr_ofst2x);
void get_userconfig_txpwr_ofst2x_v2_in_fdrv(txpwr_ofst2x_conf_v2_t *txpwr_ofst2x_v2);
void get_userconfig_txpwr_ofst2x_v3_in_fdrv(txpwr_ofst2x_conf_v3_t *txpwr_ofst2x_v3);
void get_userconfig_txpwr_loss(txpwr_loss_conf_t *txpwr_loss);
s8_l get_txpwr_max(s8_l power);
void set_txpwr_loss_ofst(s8_l value);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
@@ -169,7 +175,7 @@ u8 get_region_index(char * name);
#ifdef CONFIG_POWER_LIMIT
int8_t rwnx_plat_powerlimit_save(u8_l band, char *channel, u8_l bw, char *limit, char *name);
void rwnx_plat_powerlimit_parsing(char *buffer, int size, char *cc);
void rwnx_plat_powerlimit_parsing(char *buffer, int size);
int8_t get_powerlimit_by_freq(uint8_t band, uint16_t freq, uint8_t r_idx);
int8_t get_powerlimit_by_chnum(uint8_t chnum, uint8_t r_idx, uint8_t bw);
#endif
@@ -182,5 +188,17 @@ static inline unsigned int rwnx_platform_get_irq(struct rwnx_plat *rwnx_plat)
{
return rwnx_plat->pci_dev->irq;
}
int rwnx_request_firmware_common(struct rwnx_hw *rwnx_hw, u32** buffer, const char *filename);
void rwnx_release_firmware_common(u32** buffer);
int rwnx_plat_bin_fw_upload_2(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename);
int rwnx_plat_bin_fw_upload_2_with_version(struct rwnx_hw *rwnx_hw, u32 fw_addr,
char *filename, char *version_str, int version_size);
int rwnx_atoi2(char *value, int c_len);
int rwnx_atoi(char *value);
void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap);
void rwnx_plat_nvram_set_value(char *command, char *value);
void rwnx_plat_nvram_set_value_8800d80x2(char *command, char *value);
void rwnx_plat_userconfig_parsing_8800d80x2(char *buffer, int size);
#endif /* _RWNX_PLATFORM_H_ */
+47 -51
View File
@@ -182,28 +182,27 @@ static const struct radar_types fcc_radar_types = {
};
#define JP_PATTERN FCC_PATTERN
//JP_PATTERN(1, 2, 8, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT),
static const struct radar_detector_specs jp_radar_ref_types_riu[] = {
JP_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(1, 2, 8, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(2, 0, 8, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(3, 0, 8, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(4, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
JP_PATTERN(5, 6, 20, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
JP_PATTERN(6, 10, 28, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
JP_PATTERN(7, 50, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
JP_PATTERN(8, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
JP_PATTERN(0, 0, 4, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(1, 0, 4, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(2, 0, 4, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(3, 0, 6, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
JP_PATTERN(4, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
JP_PATTERN(5, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
JP_PATTERN(6, 48, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
JP_PATTERN(7, 0, 4, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
};
static const struct radar_detector_specs jp_radar_ref_types_fcu[] = {
JP_PATTERN(0, 0, 8, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(1, 2, 6, 3846, 3846, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(2, 0, 8, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(3, 2, 2, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(4, 0, 8, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
JP_PATTERN(5, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
JP_PATTERN(6, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
JP_PATTERN(7, 50, 104, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
JP_PATTERN(8, 0, 8, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
JP_PATTERN(0, 0, 4, 1388, 1388, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(1, 0, 4, 1428, 1428, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(2, 0, 4, 4000, 4000, 1, 18, RADAR_WAVEFORM_SHORT),
JP_PATTERN(3, 0, 6, 150, 230, 1, 23, RADAR_WAVEFORM_SHORT),
JP_PATTERN(4, 6, 12, 200, 500, 1, 16, RADAR_WAVEFORM_SHORT),
JP_PATTERN(5, 10, 22, 200, 500, 1, 12, RADAR_WAVEFORM_SHORT),
JP_PATTERN(6, 48, 110, 1000, 2000, 1, 8, RADAR_WAVEFORM_LONG),
JP_PATTERN(7, 0, 4, 333, 333, 1, 9, RADAR_WAVEFORM_SHORT),
};
static const struct radar_types jp_radar_types = {
@@ -219,33 +218,6 @@ static const struct radar_types *dfs_domains[] = {
&jp_radar_types,
};
/**
* struct pri_sequence - sequence of pulses matching one PRI
* @head: list_head
* @pri: pulse repetition interval (PRI) in usecs
* @dur: duration of sequence in usecs
* @count: number of pulses in this sequence
* @count_falses: number of not matching pulses in this sequence
* @first_ts: time stamp of first pulse in usecs
* @last_ts: time stamp of last pulse in usecs
* @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
* @ppb_thresh: Number of pulses to validate detection
* (need for weather radar whose value depends of pri)
*/
struct pri_sequence {
struct list_head head;
u32 pri;
u32 dur;
u32 count;
u32 count_falses;
u64 first_ts;
u64 last_ts;
u64 deadline_ts;
u8 ppb_thresh;
};
/**
* struct pulse_elem - elements in pulse queue
* @ts: time stamp in usecs
@@ -804,9 +776,9 @@ struct pri_sequence *pde_long_add_pulse(struct rwnx_radar *radar, struct pri_det
struct pri_sequence *ps;
const struct radar_detector_specs *rs = pde->rs;
if(radar->status != RWNX_RADAR_CAC_BUSY) {
return NULL;
}
//if(radar->status != RWNX_RADAR_CAC_BUSY) {
// return NULL;
//}
if (list_empty(&pde->sequences)) {
/* First pulse, create a new sequence */
@@ -1407,6 +1379,29 @@ static void rwnx_radar_process_pulse(struct work_struct *ws)
rm->ts[rm->idx] = dpd->last_pulse_ts + pri;
}
rm->idx = (rm->idx + 1) % RWNX_RADARR_DUMP_NB;
if(rm->cnt == 1)
{
struct radar_detector_specs *spc;
int k;
AICWFDBG(LOGINFO, "dpd: en = %d, region = %d, ntype = %d", dpd->enabled, dpd->region, dpd->num_radar_types);
AICWFDBG(LOGINFO, "id wid.{min, max} pri.{min, max, num}, ppb, thd, tlrn, type");
for (k = 0; k < dpd->num_radar_types; k++)
{
spc =(struct radar_detector_specs *)&dpd->radar_spec[k];
AICWFDBG(LOGINFO, "%d %3d, %3d %4d %4d %d %2d %2d %d %d",
spc->type_id,
spc->width_min,
spc->width_max,
spc->pri_min,
spc->pri_max,
spc->num_pri,
spc->ppb,
spc->ppb_thresh,
spc->max_pri_tolerance,
spc->type);
}
}
}
#endif
if((radar->status != RWNX_RADAR_CAC_BUSY) && (radar->status != RWNX_RADAR_INSERVICE_BUSY)) {
@@ -1480,7 +1475,7 @@ static void rwnx_radar_cac_work(struct work_struct *ws)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
&ctxt->chan_def,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
#else
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL);
@@ -1602,6 +1597,7 @@ void rwnx_radar_start_cac(struct rwnx_radar *radar, u32 cac_time_ms,
{
WARN(radar->cac_vif != NULL, "CAC already in progress");
radar->cac_vif = vif;
AICWFDBG(LOGINFO, "%s DFS: cac time = %u ms", __func__, cac_time_ms);
schedule_delayed_work(&radar->cac_work, msecs_to_jiffies(cac_time_ms));
}
@@ -1621,7 +1617,7 @@ void rwnx_radar_cancel_cac(struct rwnx_radar *radar)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)
&ctxt->chan_def,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
NL80211_RADAR_CAC_FINISHED, GFP_KERNEL, 0);
#else
NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
@@ -1714,8 +1710,8 @@ int rwnx_radar_dump_pattern_detector(char *buf, size_t len,
}
size_needed += sizeof(info);
return size_needed;
}
return size_needed;
}
/* */
+31
View File
@@ -32,6 +32,34 @@ enum rwnx_radar_detector {
radar to upper layer. */
};
/**
* struct pri_sequence - sequence of pulses matching one PRI
* @head: list_head
* @pri: pulse repetition interval (PRI) in usecs
* @dur: duration of sequence in usecs
* @count: number of pulses in this sequence
* @count_falses: number of not matching pulses in this sequence
* @first_ts: time stamp of first pulse in usecs
* @last_ts: time stamp of last pulse in usecs
* @deadline_ts: deadline when this sequence becomes invalid (first_ts + dur)
* @ppb_thresh: Number of pulses to validate detection
* (need for weather radar whose value depends of pri)
*/
struct pri_sequence {
struct list_head head;
u32 pri;
u32 dur;
u32 count;
u32 count_falses;
u64 first_ts;
u64 last_ts;
u64 deadline_ts;
u8 ppb_thresh;
};
#ifdef CONFIG_RWNX_RADAR
#include <linux/workqueue.h>
#include <linux/spinlock.h>
@@ -137,6 +165,9 @@ int rwnx_radar_dump_pattern_detector(char *buf, size_t len,
struct rwnx_radar *radar, u8 chain);
int rwnx_radar_dump_radar_detected(char *buf, size_t len,
struct rwnx_radar *radar, u8 chain);
struct pri_detector *pri_detector_init(struct dfs_pattern_detector *dpd,
u16 radar_type, u16 freq);
void print_radar_detect_info(struct pri_detector *pde, struct pri_sequence *ps);
#else
+156 -28
View File
@@ -812,6 +812,7 @@ static void rwnx_rx_mgmt(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
aicwf_nl_send_frame_rpt_msg(rwnx_vif, WIFI_AUTH, mgmt->sa, rxvect->rssi1);
}
#if 0
if (ieee80211_is_probe_req(mgmt->frame_control)) {
if (!rwnx_vif->ap.start)
return;
@@ -830,6 +831,7 @@ static void rwnx_rx_mgmt(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
AICWFDBG(LOGERROR, "usb probe_rsp pool full, drop %pM\n", mgmt->sa);
return;
}
#endif
}
#endif
@@ -1308,7 +1310,7 @@ static void rwnx_rx_add_rtap_hdr(struct rwnx_hw* rwnx_hw,
// Check for HE frames
if (rxvect->format_mod == FORMATMOD_HE_SU) {
struct ieee80211_radiotap_he he;
struct ieee80211_radiotap_he he = {0};
#define HE_PREP(f, val) cpu_to_le16(FIELD_PREP(IEEE80211_RADIOTAP_HE_##f, val))
#define D1_KNOWN(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_##f##_KNOWN)
#define D2_KNOWN(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_##f##_KNOWN)
@@ -1364,8 +1366,18 @@ static void rwnx_rx_add_rtap_hdr(struct rwnx_hw* rwnx_hw,
while ((pos - (u8 *)rtap) & 1)
pos++;
rtap->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_HE);
memcpy(pos, &he, sizeof(he));
pos += sizeof(he);
put_unaligned_le16(le16_to_cpu(he.data1), pos);
pos += 2;
put_unaligned_le16(le16_to_cpu(he.data2), pos);
pos += 2;
put_unaligned_le16(le16_to_cpu(he.data3), pos);
pos += 2;
put_unaligned_le16(le16_to_cpu(he.data4), pos);
pos += 2;
put_unaligned_le16(le16_to_cpu(he.data5), pos);
pos += 2;
put_unaligned_le16(le16_to_cpu(he.data6), pos);
pos += 2;
}
// Rx Chains
@@ -1833,8 +1845,7 @@ bool reord_rxframes_process(struct aicwf_rx_priv *rx_priv, struct reord_ctrl *pr
return bPktInBuf;
}
void reord_rxframes_ind(struct aicwf_rx_priv *rx_priv,
struct reord_ctrl *preorder_ctrl)
void reord_rxframes_ind(struct aicwf_rx_priv *rx_priv, struct reord_ctrl *preorder_ctrl)
{
struct list_head *phead, *plist;
struct recv_msdu *prframe;
@@ -1927,8 +1938,6 @@ int reord_process_unit(struct recv_msdu *pframe, struct aicwf_rx_priv *rx_priv,
struct reord_ctrl_info *reord_info;
struct rwnx_vif *rwnx_vif = (struct rwnx_vif *)rx_priv->rwnx_vif;
struct ethhdr *eh = (struct ethhdr *)(skb->data);
u8 *da = eh->h_dest;
u8 is_mcast = ((*da) & 0x01)? 1 : 0;
#if 0
struct recv_msdu *pframe;
@@ -1949,7 +1958,7 @@ int reord_process_unit(struct recv_msdu *pframe, struct aicwf_rx_priv *rx_priv,
preorder_ctrl = pframe->preorder_ctrl;
pframe->is_amsdu = is_amsdu;
if ((ntohs(eh->h_proto) == ETH_P_PAE) || is_mcast)
if (ntohs(eh->h_proto) == ETH_P_PAE)
return reord_single_frame_ind(rx_priv, pframe);
if((rwnx_vif->wdev.iftype == NL80211_IFTYPE_STATION) || (rwnx_vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT))
@@ -2127,7 +2136,10 @@ void remove_sec_hdr_mgmt_frame(struct hw_rxhdr *hw_rxhdr,struct sk_buff *skb)
if(!hw_rxhdr->hwvect.ga_frame){
if(((skb->data[0] & 0x0C) == 0) && (skb->data[1] & 0x40) == 0x40){ //protect management frame
printk("frame type %x\n",skb->data[0]);
if(hw_rxhdr->hwvect.decr_status == RWNX_RX_HD_DECR_CCMP128){
if((hw_rxhdr->hwvect.decr_status == RWNX_RX_HD_DECR_CCMP128) ||
(hw_rxhdr->hwvect.decr_status == RWNX_RX_HD_DECR_CCMP256) ||
(hw_rxhdr->hwvect.decr_status == RWNX_RX_HD_DECR_GCMP128) ||
(hw_rxhdr->hwvect.decr_status == RWNX_RX_HD_DECR_GCMP256)) {
memcpy(mgmt_header,skb->data,hdr_len);
skb_pull(skb,8);
memcpy(skb->data,mgmt_header,hdr_len);
@@ -2250,7 +2262,14 @@ u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv)
u8 is_amsdu = 0;
bool resend = false, forward = true;
const struct ethhdr *eth;
#ifdef CONFIG_SUPPORT_4ADDR
u8_l b_4addr = 0;
#endif
#ifdef CONFIG_BR_SUPPORT
int vif_idx;
struct rwnx_vif *vif_itr = NULL;
struct rwnx_sta *cur_sta;
#endif
REG_SW_SET_PROFILING(rwnx_hw, SW_PROF_RWNXDATAIND);
hw_rxhdr = (struct hw_rxhdr *)skb->data;
@@ -2264,6 +2283,11 @@ u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv)
if(hw_rxhdr->flags_upload)
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 */
if (status & RX_STAT_DELETE) {
/* Remove the SK buffer from the rxbuf_elems table */
@@ -2326,15 +2350,26 @@ u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv)
} else {
#ifdef CONFIG_RWNX_MON_DATA
skb_monitor = skb_copy_expand(skb, rtap_len, 0, GFP_ATOMIC);
if (skb_monitor) {
skb_monitor->data += (msdu_offset + 2); //sdio/usb word allign
//Save frame length
frm_len = le32_to_cpu(hw_rxhdr->hwvect.len);
}
#endif
}
skb_reset_tail_pointer(skb);
skb->len = 0;
if (!skb_monitor) {
if (status == RX_STAT_MONITOR) {
dev_kfree_skb(skb);
goto end;
}
goto check_len_update;
}
//skb_reset_tail_pointer(skb);
//skb->len = 0;
skb_reset_tail_pointer(skb_monitor);
skb_monitor->len = 0;
skb_put(skb_monitor, frm_len);
@@ -2375,7 +2410,7 @@ check_len_update:
hdr = (struct ieee80211_hdr *)(skb->data + msdu_offset);
rwnx_vif = rwnx_rx_get_vif(rwnx_hw, hw_rxhdr->flags_vif_idx);
if (rwnx_vif) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, -1, GFP_ATOMIC);
#else
cfg80211_rx_spurious_frame(rwnx_vif->ndev, hdr->addr2, GFP_ATOMIC);
@@ -2389,8 +2424,26 @@ check_len_update:
rwnx_rx_vector_convert(rwnx_hw,
&hw_rxhdr->hwvect.rx_vect1,
&hw_rxhdr->hwvect.rx_vect2);
#ifndef CONFIG_SUPPORT_4ADDR
if (hw_rxhdr->flags_is_4addr) {
dev_err(rwnx_hw->dev, "4addr Frame received (%d), skb->len:%u\n", hw_rxhdr->flags_vif_idx, skb->len);
print_hex_dump(KERN_ERR,"4addr ",DUMP_PREFIX_NONE, 16, 1, skb->data, skb->len, false);
dev_kfree_skb(skb);
goto end;
}
#endif
skb_pull(skb, msdu_offset + 2); //+2 since sdio allign 58->60
#define MAC_FCTRL_MOREFRAG 0x0400
#ifdef CONFIG_SUPPORT_4ADDR
if (hw_rxhdr->flags_is_4addr) {
hdr_len += 6;
b_4addr = 1;
}
#endif
frame_ctrl = (skb->data[1] << 8) | skb->data[0];
seq_num = ((skb->data[22] & 0xf0) >> 4) | (skb->data[23] << 4);
frag_num = (skb->data[22] & 0x0f);
@@ -2398,28 +2451,86 @@ check_len_update:
if ((skb->data[0] & 0x0f) == 0x08) {
if ((skb->data[0] & 0x80) == 0x80) {//qos data
hdr_len = 26;
hdr_len += 2;
#ifdef CONFIG_SUPPORT_4ADDR
tid = b_4addr ? (skb->data[30] & 0x0F) : (skb->data[24] & 0x0F);
#else
tid = skb->data[24] & 0x0F;
#endif
is_qos = 1;
#ifdef CONFIG_SUPPORT_4ADDR
if (b_4addr) {
if (skb->data[30] & 0x80)
is_amsdu = 1;
} else {
if (skb->data[24] & 0x80)
is_amsdu = 1;
}
#else
if (skb->data[24] & 0x80)
is_amsdu = 1;
#endif
}
if(skb->data[1] & 0x80)// htc
hdr_len += 4;
if((skb->data[1] & 0x3) == 0x1) {// to ds
memcpy(ra, &skb->data[16], MAC_ADDR_LEN);//destination addr
memcpy(ta, &skb->data[10], MAC_ADDR_LEN);//source addr
} else if((skb->data[1] & 0x3) == 0x2) { //from ds
memcpy(ta, &skb->data[16], MAC_ADDR_LEN);//destination addr
memcpy(ra, &skb->data[4], MAC_ADDR_LEN);//BSSID
#ifdef CONFIG_SUPPORT_4ADDR
if (b_4addr) {
if ((skb->data[1] & 0x3) != 0x3) {
printk("aicwf: 4addr DS error, to_from ds:%d\n", skb->data[1] & 0x3);
print_hex_dump(KERN_ERR,"rx_4addr ",DUMP_PREFIX_NONE, 16, 1, skb->data, skb->len, false);
}
memcpy(ra, &skb->data[16], MAC_ADDR_LEN);
memcpy(ta, &skb->data[24], MAC_ADDR_LEN);
printk("aicwf 4addr: da: %pM, sa: %pM\n", ra, ta);
} else {
//printk("aicwf: to_from ds:%d\n", skb->data[1] & 0x3);
if((skb->data[1] & 0x3) == 0x1) {// to ds
memcpy(ra, &skb->data[16], MAC_ADDR_LEN);
memcpy(ta, &skb->data[10], MAC_ADDR_LEN);
} else if((skb->data[1] & 0x3) == 0x2) { //from ds
memcpy(ta, &skb->data[16], MAC_ADDR_LEN);
memcpy(ra, &skb->data[4], MAC_ADDR_LEN);
}
}
#else
if((skb->data[1] & 0x3) == 0x1) {// to ds
memcpy(ra, &skb->data[16], MAC_ADDR_LEN);
memcpy(ta, &skb->data[10], MAC_ADDR_LEN);
} else if((skb->data[1] & 0x3) == 0x2) { //from ds
memcpy(ta, &skb->data[16], MAC_ADDR_LEN);
memcpy(ra, &skb->data[4], MAC_ADDR_LEN);
}
#endif
#ifdef CONFIG_BR_SUPPORT
if((skb->data[1] & 0x3) == 0x2) {
for (vif_idx = 0; vif_idx < NX_VIRT_DEV_MAX; vif_idx++) {
vif_itr = rwnx_hw->vif_table[vif_idx];
if (vif_itr && vif_itr->up && RWNX_VIF_TYPE(vif_itr) == NL80211_IFTYPE_AP) {
spin_lock_bh(&vif_itr->rwnx_hw->cb_lock);
list_for_each_entry(cur_sta, &vif_itr->ap.sta_list, list) {
if (!memcmp(cur_sta->mac_addr, ta, MAC_ADDR_LEN)) {
//printk("aicwf filter out, %pM\n", ta);
dev_kfree_skb(skb);
spin_unlock_bh(&vif_itr->rwnx_hw->cb_lock);
goto end;
}
}
spin_unlock_bh(&vif_itr->rwnx_hw->cb_lock);
}
}
}
#endif
pull_len += (hdr_len + 8);
switch (hw_rxhdr->hwvect.decr_status) {
case RWNX_RX_HD_DECR_CCMP128:
case RWNX_RX_HD_DECR_CCMP256:
case RWNX_RX_HD_DECR_GCMP128:
case RWNX_RX_HD_DECR_GCMP256:
pull_len += 8;//ccmp_header
//skb_pull(&skb->data[skb->len-8], 8); //ccmp_mic_len
memcpy(ether_type, &skb->data[hdr_len + 6 + 8], 2);
@@ -2441,17 +2552,33 @@ check_len_update:
memcpy(ether_type, &skb->data[hdr_len + 6], 2);
break;
}
if((ether_type[0] == 0x8e && ether_type[1] == 0x88) || (ether_type[0] == 0x88 && ether_type[1] == 0x8e))
printk("rx eapol\n");
if (is_amsdu) {
//Check NETGEAR R7000 router's AMSDU packet format for compliance. start
AICWFDBG(LOGDEBUG, "%s is amsdu pkt pull_len:%d %x %x %x\r\n", __func__,
pull_len, skb->data[pull_len - 8],
skb->data[pull_len - 7],
skb->data[pull_len - 2]);
if (skb->data[pull_len - 8] == 0xAA &&
skb->data[pull_len - 7] == 0xAA &&
skb->data[pull_len - 2] > 0x06){
AICWFDBG(LOGERROR, "%s amsdu pkt not regular \r\n", __func__);
is_amsdu = 0;
}else{
skb_pull(skb, pull_len-8);
}
//Check NETGEAR R7000 router's AMSDU packet format for compliance. end
}
if(is_amsdu)
hw_rxhdr->flags_is_amsdu = 1;
else
hw_rxhdr->flags_is_amsdu = 0;
if((ether_type[0] == 0x8e && ether_type[1] == 0x88) || (ether_type[0] == 0x88 && ether_type[1] == 0x8e))
printk("rx eapol\n");
if (is_amsdu) {
skb_pull(skb, pull_len-8);
}
if (hw_rxhdr->flags_dst_idx != RWNX_INVALID_STA)
sta_idx = hw_rxhdr->flags_dst_idx;
@@ -2629,7 +2756,8 @@ check_len_update:
}
if (hw_rxhdr->flags_is_4addr && !rwnx_vif->use_4addr) {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
printk("aicwf: 4addr flag error\n");
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(6, 17, 0)
cfg80211_rx_unexpected_4addr_frame(rwnx_vif->ndev,
sta->mac_addr, -1, GFP_ATOMIC);
#else
@@ -2675,7 +2803,7 @@ check_len_update:
#ifdef CONFIG_DYNAMIC_PERPWR
sta = &rwnx_hw->sta_table[hw_rxhdr->flags_sta_idx];
rssi_update_txpwrloss(sta, hw_rxhdr->hwvect.rx_vect1.rssi1);
rssi_update_txpwrloss(sta, hw_rxhdr->hwvect.rx_vect1.rssi1, rwnx_vif);
#endif
#ifdef CONFIG_BAND_STEERING
(&rwnx_hw->sta_table[hw_rxhdr->flags_sta_idx])->rssi = hw_rxhdr->hwvect.rx_vect1.rssi1;
+14
View File
@@ -353,10 +353,15 @@ struct DHCPInfo {
u8 options[308]; /* 312 - cookie */
};
int reord_flush_tid(struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u8 tid);
bool reord_rxframes_process(struct aicwf_rx_priv *rx_priv, struct reord_ctrl *preorder_ctrl, int bforced);
u8 rwnx_unsup_rx_vec_ind(void *pthis, void *hostid);
u8 rwnx_rxdataind(void *pthis, void *hostid);
u8 rwnx_rxdataind_aicwf(struct rwnx_hw *rwnx_hw, void *hostid, void *rx_priv);
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv);
void rwnx_rx_data_skb_resend(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif, struct sk_buff *skb);
#ifdef CONFIG_USB_MSG_IN_EP
int aicwf_process_msg_rxframes(struct aicwf_rx_priv *rx_priv);
#endif
@@ -373,11 +378,20 @@ int reord_need_check(struct reord_ctrl *preorder_ctrl, u16 seq_num);
int reord_rxframe_enqueue(struct reord_ctrl *preorder_ctrl, struct recv_msdu *prframe);
void reord_timeout_worker(struct work_struct *work);
int reord_single_frame_ind(struct aicwf_rx_priv *rx_priv, struct recv_msdu *prframe);
void reord_rxframes_ind(struct aicwf_rx_priv *rx_priv, struct reord_ctrl *preorder_ctrl);
void remove_sec_hdr_mgmt_frame(struct hw_rxhdr *hw_rxhdr,struct sk_buff *skb);
int reord_process_unit(struct recv_msdu *pframe, struct aicwf_rx_priv *rx_priv, struct sk_buff *skb, u16 seq_num, u8 tid, u8 forward, u8 is_amsdu);
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,14,0)
void reord_timeout_handler (ulong data);
#else
void reord_timeout_handler (struct timer_list *t);
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
void defrag_timeout_cb(ulong data);
#else
void defrag_timeout_cb(struct timer_list *t);
#endif
#endif
void rwnx_rxdata_process_amsdu(struct rwnx_hw *rwnx_hw, struct sk_buff *skb, u8 vif_idx,
+9
View File
@@ -115,12 +115,21 @@ rwnx_prep_tdls_direct(struct rwnx_hw *rwnx_hw, struct rwnx_vif *rwnx_vif,
switch (action_code) {
case WLAN_PUB_ACTION_TDLS_DISCOVER_RES:
#if AICWF_CFG80211_VERSION_CODE >= KERNEL_VERSION(7, 1, 0)
skb_put(skb, 2 + sizeof(mgmt->u.action.tdls_discover_resp));
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
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.capability =
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
#else
skb_put(skb, 1 + sizeof(mgmt->u.action.u.tdls_discover_resp));
mgmt->u.action.category = WLAN_CATEGORY_PUBLIC;
mgmt->u.action.u.tdls_discover_resp.action_code = WLAN_PUB_ACTION_TDLS_DISCOVER_RES;
mgmt->u.action.u.tdls_discover_resp.dialog_token = dialog_token;
mgmt->u.action.u.tdls_discover_resp.capability =
cpu_to_le16(rwnx_get_tdls_sta_capab(rwnx_vif, status_code));
#endif
break;
default:
return -EINVAL;
+22 -19
View File
@@ -1833,7 +1833,7 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
return 0;
}
#ifdef CONFIG_BAND_STEERING
#if 0//def CONFIG_BAND_STEERING
void rwnx_probersp_work(struct work_struct *work)
{
struct ap_probe_rsp *rsp = container_of(work, struct ap_probe_rsp, rsp_work);
@@ -1841,7 +1841,6 @@ void rwnx_probersp_work(struct work_struct *work)
struct rwnx_hw *rwnx_hw = rwnx_vif->rwnx_hw;
struct sk_buff *skb = NULL;
struct rwnx_bcn *bcn = &rwnx_vif->ap.bcn;
unsigned int len = bcn->len;
u8_l *buf;
struct ieee80211_mgmt *mgmt;
bool robust;
@@ -1852,13 +1851,13 @@ void rwnx_probersp_work(struct work_struct *work)
struct rwnx_sw_txhdr *sw_txhdr;
struct txdesc_api *desc;
headroom = sizeof(struct rwnx_txhdr);
frame_len = len;
frame_len = bcn->len;
if (aicwf_band_steering_block_chk(rwnx_vif, rsp->da)) {
AICWFDBG(LOGSTEER, "usb %s, %d, probe_rsp refuse temp %pM\n", __func__, rwnx_vif->ap.freq, rsp->da);
goto free_use;
}
if (!bcn->head || bcn->head_len == 0 || bcn->head_len > frame_len) {
if (frame_len == 0 || !bcn->head || bcn->head_len == 0 || bcn->head_len > frame_len) {
AICWFDBG(LOGSTEER, "%s bcn head NULL\n", __func__);
goto free_use;
}
@@ -1992,7 +1991,7 @@ free_use:
netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *dev)
{
int rtap_len, ret, idx, tmp_len;
int rtap_len, ret, idx;
struct ieee80211_radiotap_header *rtap_hdr; // net/ieee80211_radiotap.h
struct ieee80211_radiotap_iterator iterator; // net/cfg80211.h
u8_l *rtap_buf = (u8_l *)skb->data;
@@ -2013,34 +2012,37 @@ netdev_tx_t rwnx_start_monitor_if_xmit(struct sk_buff *skb, struct net_device *d
bool offchan = false;
int nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX;
rtap_hdr = (struct ieee80211_radiotap_header*)(rtap_buf);
rtap_len = ieee80211_get_radiotap_len(rtap_buf);//max_length
frame_len = skb->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);
if((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8801) ||
((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW) && chip_id < 3)){
nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC;
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);
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
if (unlikely(rtap_len < sizeof(*rtap_hdr))) {
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;
}
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;
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);
if((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8801) ||
((g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DC ||
g_rwnx_plat->usbdev->chipid == PRODUCT_ID_AIC8800DW) && chip_id < 3)){
nx_off_chan_txq_idx = NX_OFF_CHAN_TXQ_IDX_FOR_OLD_IC;
}
frame_len -= rtap_len;
pframe = rtap_buf + rtap_len;
@@ -2347,7 +2349,8 @@ int rwnx_txdatacfm(void *pthis, void *host_id)
/* Check status in the header. If status is null, it means that the buffer
* was not transmitted and we have to return immediately */
if (rwnx_txst.value == 0) {
return -1;
//return -1;
rwnx_txst.tx_done = 1;
}
#ifdef AICWF_USB_SUPPORT
+6 -2
View File
@@ -17,6 +17,7 @@
#include "ipc_shared.h"
#include "rwnx_txq.h"
#include "hal_desc.h"
#include "aicwf_tcp_ack.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
#define IEEE80211_NUM_TIDS 16
@@ -171,7 +172,8 @@ int rwnx_start_mgmt_xmit(struct rwnx_vif *vif, struct rwnx_sta *sta,
u64 *cookie);
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */
#ifdef CONFIG_RWNX_MON_XMIT
int 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);
#endif
int rwnx_txdatacfm(void *pthis, void *host_id);
@@ -197,6 +199,8 @@ void rwnx_tx_push(struct rwnx_hw *rwnx_hw, struct rwnx_txhdr *txhdr, int flags);
#ifdef CONFIG_BAND_STEERING
void rwnx_probersp_work(struct work_struct *work);
#endif
#ifdef CONFIG_FILTER_TCP_ACK
int intf_tx(struct rwnx_hw *priv,struct msg_buf *msg);
#endif
#endif /* _RWNX_TX_H_ */
+1
View File
@@ -393,5 +393,6 @@ void rwnx_txq_confirm_any(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq,
void rwnx_hwq_init(struct rwnx_hw *rwnx_hw);
void rwnx_hwq_process(struct rwnx_hw *rwnx_hw, struct rwnx_hwq *hwq);
void rwnx_hwq_process_all(struct rwnx_hw *rwnx_hw);
void rwnx_txq_flush(struct rwnx_hw *rwnx_hw, struct rwnx_txq *txq);
#endif /* _RWNX_TXQ_H_ */
@@ -131,6 +131,7 @@ struct rwnx_ipc_rxbuf_elems {
struct sk_buff *skb[RWNX_RXBUFF_MAX];
int idx;
};
int rwnx_init_aic(struct rwnx_hw *rwnx_hw);
#endif /* CONFIG_RWNX_FULLMAC */
#endif /* _RWNX_IPC_UTILS_H_ */
@@ -1,5 +1,5 @@
#define RWNX_VERS_REV "1a4b0054d2M (master)"
#define RWNX_VERS_MOD "6.4.3.0"
#define RWNX_VERS_BANNER "rwnx v6.4.3.0 - 1a4b0054d2M (master)"
#define RELEASE_DATE "2025_1018_71b66e7b"
#define RELEASE_DATE "2026_0123_5f7be68d"
+1
View File
@@ -39,5 +39,6 @@ extern void aicwf_usb_host_txdesc_push(struct usb_host_env_tag *env, const int q
extern void aicwf_usb_host_tx_cfm_handler(struct usb_host_env_tag *env, u32 *data);
extern int aicwf_rwnx_usb_platform_init(struct aic_usb_dev *usbdev);
volatile struct txdesc_host *aicwf_usb_host_txdesc_get(struct usb_host_env_tag *env, const int queue_idx);
#endif
+15 -8
View File
@@ -7,14 +7,16 @@ CONFIG_M2D_OTA_AUTO_SUPPORT = n
CONFIG_LINK_DET_5G = y
CONFIG_FOR_IPCAM = n
CONFIG_USB_SUSPEND_REBOOT_TIME = n
CONFIG_SUPPORT_USB_SUSP = n
CONFIG_RADAR_OR_IR_DETECT =n
CONFIG_LOAD_BT_CONF = n
CONFIG_FLASH_CALRES = n
CONFIG_WOWLAN ?= n
# Need to set fw path in BOARD_KERNEL_CMDLINE
CONFIG_USE_FW_REQUEST ?= n
CONFIG_PREALLOC_RX_SKB ?= n
CONFIG_PREALLOC_TXQ ?= y
CONFIG_BAND_STEERING = n
CONFIG_PRBREQ_REPORT = n
# Platform support list
CONFIG_PLATFORM_ROCKCHIP ?= n
@@ -44,7 +46,11 @@ ccflags-$(CONFIG_PREALLOC_TXQ) += -DCONFIG_PREALLOC_TXQ
ccflags-$(CONFIG_USB_SUSPEND_REBOOT_TIME) += -DCONFIG_USB_SUSPEND_REBOOT_TIME
ccflags-$(CONFIG_SUPPORT_USB_SUSP) += -DCONFIG_SUPPORT_USB_SUSP
ccflags-$(CONFIG_RADAR_OR_IR_DETECT) += -DCONFIG_RADAR_OR_IR_DETECT
ccflags-$(CONFIG_LOAD_BT_CONF) += -DCONFIG_LOAD_BT_CONF
ccflags-$(CONFIG_FLASH_CALRES) += -DCONFIG_FLASH_CALRES
ccflags-$(CONFIG_BAND_STEERING) += -DCONFIG_BAND_STEERING
ccflags-$(CONFIG_PRBREQ_REPORT) += -DCONFIG_PRBREQ_REPORT
ccflags-$(CONFIG_WOWLAN) += -DCONFIG_WOWLAN
obj-$(CONFIG_AIC_LOADFW_SUPPORT) := $(MODULE_NAME).o
$(MODULE_NAME)-y := aic_bluetooth_main.o \
@@ -67,7 +73,7 @@ ccflags-$(CONFIG_PLATFORM_ROCKCHIP) += -DCONFIG_PLATFORM_ROCKCHIP
#ARCH ?= arm
#CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android7/RK3229_ANDROID7.1_v1.01_20170914/rk3229_Android7.1_v1.01_xml0914/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-
KDIR := /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/kernel
ARCH ?=$(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
ARCH ?= arm
CROSS_COMPILE ?= /home/yaya/E/Rockchip/3229/Android9/rk3229_android9.0_box/prebuilts/gcc/linux-x86/arm/gcc-linaro-6.3.1-2017.05-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
#KDIR := /home/yaya/E/Rockchip/3399/rk3399-android-10/kernel
#ARCH ?= arm64
@@ -91,12 +97,13 @@ endif
ifeq ($(CONFIG_PLATFORM_UBUNTU), y)
ccflags-$(CONFIG_PLATFORM_UBUNTU) += -DCONFIG_PLATFORM_UBUNTU
KVER := $(or $(KVER), $(kernelver), $(KERNELRELEASE), $(shell uname -r))
KVER ?= $(shell uname -r)
KDIR ?= /lib/modules/$(KVER)/build
PWD ?= $(shell pwd)
MODDESTDIR ?= /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
CROSS_COMPILE ?=
PWD := $(shell pwd)
MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/aic8800
SUBARCH = $(shell uname -m | sed -e s/i.86/i386/ -e s/armv.l/arm/ -e s/aarch64/arm64/)
ARCH ?= $(SUBARCH)
CROSS_COMPILE :=
endif
@@ -39,27 +39,14 @@ typedef struct {
#define AIC_PATCH_OFST(mem) ((size_t) &((aic_patch_t *)0)->mem)
#define AIC_PATCH_ADDR(mem) ((u32) (aic_patch_str_base + AIC_PATCH_OFST(mem)))
#define USER_PWROFST_COVER_CALIB_FLAG (0x01U << 0)
#define USER_CHAN_MAX_TXPWR_EN_FLAG (0x01U << 1)
#define USER_TX_USE_ANA_F_FLAG (0x01U << 2)
#define USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG (0x01U << 3)
#define USER_HE_MU_EDCA_UPDATE_DISABLE_FLAG (0x01U << 4)
#define CFG_PWROFST_COVER_CALIB 1
#ifdef CONFIG_POWER_LIMIT
#define CFG_USER_CHAN_MAX_TXPWR_EN 1
#else
#define CFG_USER_CHAN_MAX_TXPWR_EN 0
#endif
#define CFG_USER_TX_USE_ANA_F 0
#ifdef CONFIG_BAND_STEERING
#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE 1
#else
#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE 0
#endif
#define CFG_USER_EXT_FLAGS_EN (CFG_PWROFST_COVER_CALIB || CFG_USER_CHAN_MAX_TXPWR_EN || CFG_USER_TX_USE_ANA_F|| CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE)
/*
* Issue #58 legacy-loader test.
*
* Keep this table aligned with the SDK V3 D80 firmware imported from Radxa
* commit 254d47e6a131dbed5ba32131972f4719f3e1c7fe. Newer loader patches use
* different RX aggregation settings and a user_ext_flags field that is not
* part of this firmware generation.
*/
u32 patch_tbl_d80[][2] =
{
#ifdef USE_5G
@@ -67,32 +54,7 @@ u32 patch_tbl_d80[][2] =
#else
{0x00b4, 0xf3010000},
#endif
#ifdef CONFIG_PLATFORM_HI
{0x0170, 0x00010001},//rx aggr counter
#else
{0x0170, 0x0001000A},//rx aggr counter
#endif
#if CFG_USER_EXT_FLAGS_EN
{0x0188, 0x00000000
#if CFG_PWROFST_COVER_CALIB
| USER_PWROFST_COVER_CALIB_FLAG
#endif
#if CFG_USER_CHAN_MAX_TXPWR_EN
| USER_CHAN_MAX_TXPWR_EN_FLAG
#endif
#if CFG_USER_TX_USE_ANA_F
| USER_TX_USE_ANA_F_FLAG
#endif
#if CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE
| USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG
#endif
}, // user_ext_flags
#endif
#ifdef CONFIG_RADAR_OR_IR_DETECT
{0x0019c,0x00000B00},
#endif
{0x0170, 0x00000002},//rx aggr counter
};
//adap test
@@ -113,16 +75,11 @@ u32 syscfg_tbl_8800d80[][2] = {
extern int adap_test;
#define NEW_PATCH_BUFFER_MAP 1
int aicwf_patch_config_8800d80(struct aic_usb_dev *usb_dev)
{
u32 rd_patch_addr;
u32 aic_patch_addr;
u32 config_base, aic_patch_str_base;
#if (NEW_PATCH_BUFFER_MAP)
u32 patch_buff_addr, patch_buff_base, rd_version_addr, rd_version_val;
#endif
uint32_t start_addr = 0x001D7000;
u32 patch_addr = start_addr;
u32 patch_cnt = sizeof(patch_tbl_d80) / 4 / 2;
@@ -159,32 +116,6 @@ int aicwf_patch_config_8800d80(struct aic_usb_dev *usb_dev)
AICWFDBG(LOGERROR, "%x=%x\n", rd_patch_addr_cfm.memaddr, rd_patch_addr_cfm.memdata);
aic_patch_str_base = rd_patch_addr_cfm.memdata;
#if (NEW_PATCH_BUFFER_MAP)
if (chip_id == CHIP_REV_U01) {
rd_version_addr = RAM_FMAC_FW_ADDR_8800D80 + 0x01C;
} else {
rd_version_addr = RAM_FMAC_FW_ADDR_8800D80_U02 + 0x01C;
}
if ((ret = rwnx_send_dbg_mem_read_req(usb_dev, rd_version_addr, &rd_patch_addr_cfm))) {
AICWFDBG(LOGERROR, "version val[0x%x] rd fail: %d\n", rd_version_addr, ret);
return ret;
}
rd_version_val = rd_patch_addr_cfm.memdata;
AICWFDBG(LOGINFO, "rd_version_val=%08X\n", rd_version_val);
usb_dev->fw_version_uint = rd_version_val;
if (rd_version_val > 0x06090100) {
patch_buff_addr = rd_patch_addr + 12;
ret = rwnx_send_dbg_mem_read_req(usb_dev, patch_buff_addr, &rd_patch_addr_cfm);
if (ret) {
AICWFDBG(LOGERROR, "patch buf rd fail\n");
return ret;
}
AICWFDBG(LOGINFO, "%x=%x\n", rd_patch_addr_cfm.memaddr, rd_patch_addr_cfm.memdata);
patch_buff_base = rd_patch_addr_cfm.memdata;
patch_addr = start_addr = patch_buff_base;
}
#endif
if ((ret = rwnx_send_dbg_mem_write_req(usb_dev, AIC_PATCH_ADDR(magic_num), AIC_PATCH_MAGIG_NUM))) {
AICWFDBG(LOGERROR, "maigic_num[0x%x] write fail: %d\n", AIC_PATCH_ADDR(magic_num), ret);
return ret;
@@ -303,6 +234,7 @@ int system_config_8800d80(struct aic_usb_dev *usb_dev){
int syscfg_num;
int ret, cnt;
const u32 mem_addr = 0x40500000;
const u32 cache_mem_addr = 0x40100020;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
ret = rwnx_send_dbg_mem_read_req(usb_dev, mem_addr, &rd_mem_addr_cfm);
if (ret) {
@@ -314,6 +246,21 @@ int system_config_8800d80(struct aic_usb_dev *usb_dev){
}
chip_id = (u8)(rd_mem_addr_cfm.memdata >> 16);
printk("chip_id=%x, chip_mcu_id = %d\n", chip_id, chip_mcu_id);
printk("AIC8800D80 legacy: using Radxa SDK V3 loader profile\n");
if (chip_mcu_id == 1) {
ret = rwnx_send_dbg_mem_read_req(usb_dev, cache_mem_addr, &rd_mem_addr_cfm);
if (ret) {
printk("%x rd fail: %d\n", cache_mem_addr, ret);
return ret;
}
rd_mem_addr_cfm.memdata |= 0x01;
ret = rwnx_send_dbg_mem_write_req(usb_dev, cache_mem_addr, rd_mem_addr_cfm.memdata);
if (ret) {
printk("%x write fail: %d\n", cache_mem_addr, ret);
return ret;
}
printk("AIC8800D80 MCU1: enabled Bluetooth cache fix\n");
}
#if 1
syscfg_num = sizeof(syscfg_tbl_8800d80) / sizeof(u32) / 2;
for (cnt = 0; cnt < syscfg_num; cnt++) {
@@ -337,7 +284,7 @@ int system_config_8800d80(struct aic_usb_dev *usb_dev){
}
static int aicbt_ext_patch_data_load(struct aic_usb_dev *usb_dev, struct aicbt_patch_info_t *patch_info)
static int aicbt_ext_patch_data_load(struct aic_usb_dev *usb_dev, struct aicbt_patch_info_t *patch_info, const char *filename)
{
int ret = 0;
uint32_t ext_patch_nb = patch_info->ext_patch_nb;
@@ -354,7 +301,7 @@ static int aicbt_ext_patch_data_load(struct aic_usb_dev *usb_dev, struct aicbt_p
addr = *(patch_info->ext_patch_param + (index * 2) + 1);
memset(ext_patch_file_name, 0, sizeof(ext_patch_file_name));
sprintf(ext_patch_file_name,"%s%d.bin",
FW_PATCH_BASE_NAME_8800D80_U02_EXT,
filename,
id);
AICWFDBG(LOGDEBUG, "%s ext_patch_file_name:%s ext_patch_id:%x ext_patch_addr:%x \r\n",
__func__,ext_patch_file_name, id, addr);
@@ -386,7 +333,6 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
int i = 0;
#if 0
if (chip_id == CHIP_REV_U01) {
head = aicbt_patch_table_alloc(usb_dev, FW_PATCH_TABLE_NAME_8800D80);
} else {
@@ -414,11 +360,10 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
}
printk("addr_adid 0x%x, addr_patch 0x%x\n", patch_info.addr_adid, patch_info.addr_patch);
#endif
if(testmode == FW_NORMAL_MODE){
if (chip_id != CHIP_REV_U01){
#if 0
if(rwnx_plat_bin_fw_upload_android(usb_dev, patch_info.addr_adid, FW_ADID_BASE_NAME_8800D80_U02)) {
return -1;
}
@@ -426,14 +371,13 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
return -1;
}
if (aicbt_ext_patch_data_load(usb_dev, &patch_info)) {
if (aicbt_ext_patch_data_load(usb_dev, &patch_info, FW_PATCH_BASE_NAME_8800D80_U02_EXT)) {
return -1;
}
if (aicbt_patch_table_load(usb_dev, head)) {
return -1;
}
#endif
if (IS_CHIP_ID_H()){
if(rwnx_plat_bin_fw_upload_android(usb_dev, RAM_FMAC_FW_ADDR_8800D80_U02, FW_BASE_NAME_8800D80_H_U02))
@@ -456,7 +400,6 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
return -1;
}
}else {
#if 0
if(rwnx_plat_bin_fw_upload_android(usb_dev, patch_info.addr_adid, FW_ADID_BASE_NAME_8800D80)) {
return -1;
}
@@ -472,7 +415,6 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
return -1;
}
#endif
#endif
if(rwnx_plat_bin_fw_upload_android(usb_dev, RAM_FMAC_FW_ADDR_8800D80, FW_BASE_NAME_8800D80)) {
return -1;
}
@@ -482,7 +424,7 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
}
}else if(testmode == FW_TEST_MODE){
if (chip_id != CHIP_REV_U01){
#if 0
if(rwnx_plat_bin_fw_upload_android(usb_dev, patch_info.addr_adid, FW_ADID_BASE_NAME_8800D80_U02)) {
return -1;
}
@@ -491,7 +433,7 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
return -1;
}
if (aicbt_ext_patch_data_load(usb_dev, &patch_info)) {
if (aicbt_ext_patch_data_load(usb_dev, &patch_info, FW_PATCH_BASE_NAME_8800D80_U02_EXT)) {
return -1;
}
@@ -508,7 +450,7 @@ int aicfw_download_fw_8800d80(struct aic_usb_dev *usb_dev)
return -1;
}
}
#endif
if(rwnx_plat_bin_fw_upload_android(usb_dev, RAM_FMAC_RF_FW_ADDR_8800D80_U02, FW_RF_BASE_NAME_8800D80_U02)) {
AICWFDBG(LOGERROR,"%s wifi fw download fail \r\n", __func__);
return -1;
@@ -41,21 +41,32 @@ typedef struct {
#define USER_PWROFST_COVER_CALIB_FLAG (0x01U << 0)
#define USER_CHAN_MAX_TXPWR_EN_FLAG (0x01U << 1)
#define USER_TX_USE_ANA_F_FLAG (0x01U << 2)
#define USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG (0x01U << 3)
#define USER_HE_MU_EDCA_UPDATE_DISABLE_FLAG (0x01U << 4)
#define USER_RF_WITH_SAW_EN_FLAG (0x01U << 10)
#define USER_SETCH_LOFT_CALIB_EN_FLAG (0x01U << 11)
#define USER_SETCH_RXDC_CALIB_EN_FLAG (0x01U << 12)
#ifdef CONFIG_POWER_LIMIT
#define CFG_USER_CHAN_MAX_TXPWR_EN 1
#define USER_EXT_FLAGS_DEFAULT_D80X2 \
(USER_PWROFST_COVER_CALIB_FLAG | \
USER_CHAN_MAX_TXPWR_EN_FLAG | \
USER_SETCH_LOFT_CALIB_EN_FLAG)
#define CFG_USER_PWROFST_COVER_CALIB_EN (1)
#if (defined(CONFIG_POWER_LIMIT))
#define CFG_USER_CHAN_MAX_TXPWR_EN (1)
#else
#define CFG_USER_CHAN_MAX_TXPWR_EN 0
#define CFG_USER_CHAN_MAX_TXPWR_EN (0)
#endif
#define CFG_USER_TX_USE_ANA_F 0
#ifdef CONFIG_BAND_STEERING
#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE 1
#if (defined(CONFIG_PRBREQ_REPORT))
#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE (1)
#else
#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE 0
#define CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE (0)
#endif
#define CFG_USER_HE_MU_EDCA_UPDATE_DISABLE (0)
#define CFG_USER_RF_WITH_SAW_EN (0)
#define CFG_USER_SETCH_LOFT_CALIB_EN (1)
#define CFG_USER_SETCH_RXDC_CALIB_EN (0)
u32 patch_tbl_d80x2[][2] =
{
@@ -71,29 +82,35 @@ u32 patch_tbl_d80x2[][2] =
{0x0228, 0x50000a00},//ss aggr
#endif
#if 0
#ifdef USE_5G
{0x00b4, 0xf3010001},
#else
{0x00b4, 0xf3010000},
#endif
#ifdef CONFIG_PLATFORM_HI
{0x0170, 0x00000001},//rx aggr counter
#else
{0x0170, 0x0000000A},//rx aggr counter
#endif
#ifdef CONFIG_FLASH_CALRES
{0x0234, 0x0000004F}, // cal_res_stored_in_flash_flags
#endif
{0x01f0, 0x00000001
#if CFG_USER_CHAN_MAX_TXPWR_EN
| USER_CHAN_MAX_TXPWR_EN_FLAG
#endif
#if CFG_USER_TX_USE_ANA_F
| USER_TX_USE_ANA_F_FLAG
#endif
{0x01f0,
(USER_EXT_FLAGS_DEFAULT_D80X2 |
#if CFG_USER_APM_PRBRSP_OFFLOAD_DISABLE
| USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG
USER_APM_PRBRSP_OFFLOAD_DISABLE_FLAG |
#endif
#if CFG_USER_HE_MU_EDCA_UPDATE_DISABLE
USER_HE_MU_EDCA_UPDATE_DISABLE_FLAG |
#endif
#if CFG_USER_RF_WITH_SAW_EN
USER_RF_WITH_SAW_EN_FLAG |
#endif
#if CFG_USER_SETCH_RXDC_CALIB_EN
USER_SETCH_RXDC_CALIB_EN_FLAG |
#endif
0) & ~(
#if !CFG_USER_PWROFST_COVER_CALIB_EN
USER_PWROFST_COVER_CALIB_FLAG |
#endif
#if !CFG_USER_CHAN_MAX_TXPWR_EN
USER_CHAN_MAX_TXPWR_EN_FLAG |
#endif
#if !CFG_USER_SETCH_LOFT_CALIB_EN
USER_SETCH_LOFT_CALIB_EN_FLAG |
#endif
0)
}, // user_ext_flags
};
@@ -301,7 +318,39 @@ int system_config_8800d80x2(struct aic_usb_dev *usb_dev){
int ret, cnt;
const u32 mem_addr = 0x40500000;
const u32 mem_addr2 = 0x40500004;
const u32 mem_addr3 = 0x40800000;
const u32 mem_mask3 = (0x03UL << 24) | (0x01UL << 6) | (0x01UL << 1);
const u32 mem_data3 = (0x02UL << 24) | (0x01UL << 6);
const u32 mem_addr4 = 0x40800014;
const u32 mem_data4 = 0x00000820;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
/* fix usb2.0 rx_err */
ret = rwnx_send_dbg_mem_mask_write_req(usb_dev, mem_addr3, mem_mask3, mem_data3);
if (ret) {
printk("%x mask write fail: %d\n", mem_addr3, ret);
return ret;
}
ret = rwnx_send_dbg_mem_write_req(usb_dev, mem_addr4, mem_data4);
if (ret) {
printk("%x write fail: %d\n", mem_addr4, ret);
return ret;
}
ret = rwnx_send_dbg_mem_read_req(usb_dev, mem_addr3, &rd_mem_addr_cfm);
if (ret) {
printk("%x rd fail: %d\n", mem_addr3, ret);
return ret;
} else {
printk("[%08x]=%08x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
}
ret = rwnx_send_dbg_mem_read_req(usb_dev, mem_addr4, &rd_mem_addr_cfm);
if (ret) {
printk("%x rd fail: %d\n", mem_addr4, ret);
return ret;
} else {
printk("[%08x]=%08x\n", rd_mem_addr_cfm.memaddr, rd_mem_addr_cfm.memdata);
}
ret = rwnx_send_dbg_mem_read_req(usb_dev, mem_addr, &rd_mem_addr_cfm);
if (ret) {
printk("%x rd fail: %d\n", mem_addr, ret);
@@ -319,7 +368,7 @@ int system_config_8800d80x2(struct aic_usb_dev *usb_dev){
}
printk("chip_id=%x, chip_mcu_id = %d\n", chip_id, chip_mcu_id);
#if 1
syscfg_num = sizeof(syscfg_tbl_8800d80x2) / sizeof(u32) / 2;
for (cnt = 0; cnt < syscfg_num; cnt++) {
ret = rwnx_send_dbg_mem_write_req(usb_dev, syscfg_tbl_8800d80x2[cnt][0], syscfg_tbl_8800d80x2[cnt][1]);
@@ -337,13 +386,12 @@ int system_config_8800d80x2(struct aic_usb_dev *usb_dev){
return ret;
}
}
#endif
return 0;
}
static int aicbt_ext_patch_data_load(struct aic_usb_dev *usb_dev, struct aicbt_patch_info_t *patch_info)
static int aicbt_ext_patch_data_load(struct aic_usb_dev *usb_dev, struct aicbt_patch_info_t *patch_info, const char *filename)
{
int ret = 0;
uint32_t ext_patch_nb = patch_info->ext_patch_nb;
@@ -351,16 +399,26 @@ static int aicbt_ext_patch_data_load(struct aic_usb_dev *usb_dev, struct aicbt_p
int index = 0;
uint32_t id = 0;
uint32_t addr = 0;
uint32_t mem_w_add = 0;
uint32_t mem_w_data = 0;
if (ext_patch_nb > 0){
AICWFDBG(LOGDEBUG, "[0x40480000]: 0x00040220\n");
mem_w_add = 0x40580000;
mem_w_data = 0x00040220;
AICWFDBG(LOGDEBUG, "%s addr:0x%x data:0x%x \n", __func__, mem_w_add, mem_w_data);
ret = rwnx_send_dbg_mem_write_req(usb_dev, mem_w_add, mem_w_data);
if (ret) {
printk("%x wr fail: %d\n", mem_w_add, ret);
return ret;
}
for (index = 0; index < patch_info->ext_patch_nb; index++){
id = *(patch_info->ext_patch_param + (index * 2));
addr = *(patch_info->ext_patch_param + (index * 2) + 1);
memset(ext_patch_file_name, 0, sizeof(ext_patch_file_name));
sprintf(ext_patch_file_name,"%s%d.bin",
FW_PATCH_BASE_NAME_8800D80X2_U03_EXT,
filename,
id);
AICWFDBG(LOGDEBUG, "%s ext_patch_file_name:%s ext_patch_id:%x ext_patch_addr:%x \r\n",
__func__,ext_patch_file_name, id, addr);
@@ -393,6 +451,10 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
int i = 0;
#ifdef CONFIG_LOAD_BT_CONF
aicbt_parse_config(usb_dev, FW_BT_CONF_NAME_8800D80X2);
#endif
if (chip_id < CHIP_REV_U05) {
head = aicbt_patch_table_alloc(usb_dev, FW_PATCH_TABLE_NAME_8800D80X2_U03);
} else {
@@ -480,7 +542,7 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
return -1;
}
if (aicbt_ext_patch_data_load(usb_dev, &patch_info)) {
if (aicbt_ext_patch_data_load(usb_dev, &patch_info, FW_PATCH_BASE_NAME_8800D80X2_U03_EXT)) {
return -1;
}
@@ -515,7 +577,7 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
if(rwnx_plat_bin_fw_upload_android(usb_dev, patch_info.addr_patch, FW_PATCH_BASE_NAME_8800D80X2_U05)) {
return -1;
}
if (aicbt_ext_patch_data_load(usb_dev, &patch_info)) {
if (aicbt_ext_patch_data_load(usb_dev, &patch_info, FW_PATCH_BASE_NAME_8800D80X2_U05_EXT)) {
return -1;
}
if (aicbt_patch_table_load(usb_dev, head)) {
@@ -545,7 +607,7 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
return -1;
}
if (aicbt_ext_patch_data_load(usb_dev, &patch_info)) {
if (aicbt_ext_patch_data_load(usb_dev, &patch_info, FW_PATCH_BASE_NAME_8800D80X2_U03_EXT)) {
return -1;
}
@@ -556,15 +618,6 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
mdelay(100);
#endif
if (chip_mcu_id) {
int ret = 0;
ret = rwnx_plat_flash_bin_upload_android(usb_dev, FLASH_BIN_ADDR_8800M80X2, FLASH_BIN_8800M80X2);
if (ret && ret!= ENOENT) {
AICWFDBG(LOGERROR,"%s flash bin download fail \r\n", __func__);
return -1;
}
}
if(rwnx_plat_bin_fw_upload_android(usb_dev, RAM_FMAC_RF_FW_ADDR_8800D80X2, FW_RF_BASE_NAME_8800D80X2)) {
AICWFDBG(LOGERROR,"%s wifi fw download fail \r\n", __func__);
return -1;
@@ -582,7 +635,7 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
return -1;
}
if (aicbt_ext_patch_data_load(usb_dev, &patch_info)) {
if (aicbt_ext_patch_data_load(usb_dev, &patch_info, FW_PATCH_BASE_NAME_8800D80X2_U05_EXT)) {
return -1;
}
@@ -613,7 +666,7 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
data & mask = "0x46 0x00" 0x00 0x00 0x00 0x00 0x00 0x00 0x00 "0x30 0xff 0xff 0x43 0x52 0x45 0x4c 0x42"
using data & mask value condition to wakeup host_wake_bt gpio
*/
int ret;
struct ble_wakeup_param_t* wakeup_param = (struct ble_wakeup_param_t*)kmalloc(sizeof(struct ble_wakeup_param_t), GFP_KERNEL);
uint32_t *write_blocks = (uint32_t *)wakeup_param;
@@ -744,7 +797,6 @@ int aicfw_download_fw_8800d80x2(struct aic_usb_dev *usb_dev)
}
//rwnx_send_dbg_start_app_req(usb_dev, RAM_FW_BLE_SCAN_WAKEUP_ADDR_8800D80, HOST_START_APP_AUTO);
int ret;
ret = rwnx_send_dbg_mem_write_req(usb_dev, 0x40500048, RAM_FW_BLE_SCAN_WAKEUP_ADDR_8800D80);
if (ret) {
printk("%x write fail\n", ret);
@@ -4,6 +4,7 @@
#define USB_DEVICE_ID_AIC_8800D80X2 0x8D90
#define USB_DEVICE_ID_AIC_8800D81X2 0x8D91
#define USB_DEVICE_ID_AIC_8800D89X2 0x8D99
#define USB_DEVICE_ID_AIC_8800D40X2 0x8D92
#ifdef CONFIG_FOR_IPCAM
#define FW_BASE_NAME_8800D80X2 "fmacfw_8800d80x2_ipc.bin"
@@ -22,12 +23,14 @@
#define FW_ADID_BASE_NAME_8800D80X2_U05 "fw_adid_8800d80x2_u05.bin"
#define FW_PATCH_TABLE_NAME_8800D80X2_U05 "fw_patch_table_8800d80x2_u05.bin"
#define FW_BT_CONF_NAME_8800D80X2 "aicbt.conf"
#define FLASH_BIN_8800M80X2 "host_wb_8800m80x2.bin"
#define FW_USERCONFIG_NAME_8800D80X2 "aic_userconfig_8800d80x2.txt"
#define RAM_FMAC_FW_ADDR_8800D80X2 0x120000
#define RAM_FMAC_RF_FW_ADDR_8800D80X2 0x120000
#define RAM_FMAC_FW_ADDR_8800D80X2 0x128000
#define RAM_FMAC_RF_FW_ADDR_8800D80X2 0x128000
#define FW_RAM_ADID_BASE_ADDR_8800D80X2_U03 0x003018f8
#define FW_RAM_PATCH_BASE_ADDR_8800D80X2_U03 0x0030b494
@@ -35,7 +38,7 @@
#define FW_RAM_ADID_BASE_ADDR_8800D80X2_U05 0x003018f8
#define FW_RAM_PATCH_BASE_ADDR_8800D80X2_U05 0x0030b48c
#define FLASH_BIN_ADDR_8800M80X2 0x8000000
#define FLASH_BIN_ADDR_8800M80X2 0x4000000
int aicwf_patch_config_8800d80x2(struct aic_usb_dev *usb_dev);
+1 -1
View File
@@ -18,7 +18,7 @@
#define DATA_BUF_MAX 2048
#define TXPKT_BLOCKSIZE 512
#define MAX_AGGR_TXPKT_LEN (1536*32)
#define CMD_TX_TIMEOUT 2000
#define CMD_TX_TIMEOUT 5000
#define TX_ALIGNMENT 4
#define RX_HWHRD_LEN 60 //58->60 word allined
+171 -41
View File
@@ -20,20 +20,6 @@ extern int flash_erase_len;
int flash_write_size = 0;
u32 flash_write_bin_crc = 0;
typedef struct
{
int8_t enable;
int8_t dsss;
int8_t ofdmlowrate_2g4;
int8_t ofdm64qam_2g4;
int8_t ofdm256qam_2g4;
int8_t ofdm1024qam_2g4;
int8_t ofdmlowrate_5g;
int8_t ofdm64qam_5g;
int8_t ofdm256qam_5g;
int8_t ofdm1024qam_5g;
} txpwr_idx_conf_t;
txpwr_idx_conf_t userconfig_txpwr_idx = {
.enable = 1,
@@ -49,17 +35,6 @@ txpwr_idx_conf_t userconfig_txpwr_idx = {
};
typedef struct
{
int8_t enable;
int8_t chan_1_4;
int8_t chan_5_9;
int8_t chan_10_13;
int8_t chan_36_64;
int8_t chan_100_120;
int8_t chan_122_140;
int8_t chan_142_165;
} txpwr_ofst_conf_t;
txpwr_ofst_conf_t userconfig_txpwr_ofst = {
.enable = 1,
@@ -72,13 +47,6 @@ txpwr_ofst_conf_t userconfig_txpwr_ofst = {
.chan_142_165 = 0
};
typedef struct
{
int8_t enable;
int8_t xtal_cap;
int8_t xtal_cap_fine;
} xtal_cap_conf_t;
xtal_cap_conf_t userconfig_xtal_cap = {
.enable = 0,
@@ -757,7 +725,7 @@ int rwnx_plat_flash_bin_upload_android(struct aic_usb_dev *usbdev, u32 fw_addr,
int err=0;
const u32 mem_addr = fw_addr;
struct dbg_mem_read_cfm rd_mem_addr_cfm;
u32 crc = ~0UL;
u32 crc = (u32)~0UL;
/* load aic firmware */
size = aic_load_firmware(&dst, filename, dev);
@@ -1285,6 +1253,149 @@ static struct aicbt_info_t aicbt_info[] = {
},//PRODUCT_ID_AIC8800D80X2
};
#ifdef CONFIG_LOAD_BT_CONF
static const char *aicbt_find_tag(const u8 *file_data, unsigned int file_size,
const char *tag_name, unsigned int tag_len)
{
unsigned int line_start = 0, tag_name_len = strlen(tag_name);
const char *comment_symbols = "#;";
RWNX_DBG(RWNX_FN_ENTRY_STR);
while (line_start < file_size) {
unsigned int line_end = line_start;
while (line_end < file_size && file_data[line_end] != '\n' && file_data[line_end] != '\r') {
line_end++;
}
if (line_end - line_start >= tag_name_len &&
!strncmp((const char*)&file_data[line_start], tag_name, tag_name_len))
{
const char *value_start = (const char*)&file_data[line_start + tag_name_len];
const char *value_end = (const char*)&file_data[line_end];
while (value_start < value_end && (*value_start == ' ' || *value_start == '=')) {
value_start++;
}
const char *comment_pos = value_start;
while (comment_pos < value_end && !strchr(comment_symbols, *comment_pos)) {
comment_pos++;
}
while (comment_pos > value_start && (*(comment_pos-1) == ' ' || *(comment_pos-1) == '\t')) {
comment_pos--;
}
if (comment_pos > value_start) {
return value_start;
}
}
line_start = line_end;
while (line_start < file_size && (file_data[line_start] == '\n' || file_data[line_start] == '\r')) {
line_start++;
}
}
return NULL;
}
void aicbt_parse_config(struct aic_usb_dev *usbdev, const char *filename)
{
struct device *dev = usbdev->dev;
u32 *dst = NULL;
int size;
const u8 *tag_ptr;
u32 tmp_val;
//char *filename = "aicbt.conf";
RWNX_DBG(RWNX_FN_ENTRY_STR);
size = aic_load_firmware((u32 **)&dst, filename, dev);
if (size <= 0) {
AICWFDBG(LOGERROR, "%s: load %s fail (%d)\n", __func__, filename, size);
return;
}
tag_ptr = aicbt_find_tag((char*)dst, size, "BTMODE=", strlen("0"));
if (tag_ptr) {
if (sscanf(tag_ptr, "%x", &aicbt_info[usbdev->chipid].btmode) != 1 ||
aicbt_info[usbdev->chipid].btmode > AICBT_BTMODE_BT_ONLY_COANT) {
aicbt_info[usbdev->chipid].btmode = AICBT_BTMODE_DEFAULT;
AICWFDBG(LOGERROR, "BTMODE invalid, use default %02X\n", AICBT_BTMODE_DEFAULT);
}
} else {
aicbt_info[usbdev->chipid].btmode = AICBT_BTMODE_DEFAULT;
}
tag_ptr = aicbt_find_tag((char*)dst, size, "BTPORT=", strlen("0"));
if (tag_ptr) {
if (sscanf(tag_ptr, "%x", &aicbt_info[usbdev->chipid].btport) != 1 ||
aicbt_info[usbdev->chipid].btport > AICBT_BTPORT_UART) {
aicbt_info[usbdev->chipid].btport = AICBT_BTPORT_DEFAULT;
}
} else {
aicbt_info[usbdev->chipid].btport = AICBT_BTPORT_DEFAULT;
}
tag_ptr = aicbt_find_tag((char*)dst, size, "UART_BAUD=", 0);
if (tag_ptr) {
if (sscanf(tag_ptr, "%u", &tmp_val) == 1) {
if(tmp_val >= AICBT_UART_BAUD_115200 && tmp_val <= AICBT_UART_BAUD_3_25M) {
aicbt_info[usbdev->chipid].uart_baud = tmp_val;
} else {
aicbt_info[usbdev->chipid].uart_baud = AICBT_UART_BAUD_DEFAULT;
AICWFDBG(LOGERROR, "UART_BAUD %u invalid, use default %d\n", tmp_val, AICBT_UART_BAUD_DEFAULT);
}
} else {
aicbt_info[usbdev->chipid].uart_baud = AICBT_UART_BAUD_DEFAULT;
}
} else {
aicbt_info[usbdev->chipid].uart_baud = AICBT_UART_BAUD_DEFAULT;
}
tag_ptr = aicbt_find_tag((char*)dst, size, "UART_FC=", strlen("0"));
if (tag_ptr) {
if (sscanf(tag_ptr, "%x", &aicbt_info[usbdev->chipid].uart_flowctrl) != 1 ||
aicbt_info[usbdev->chipid].uart_flowctrl > AICBT_UART_FLOWCTRL_ENABLE) {
aicbt_info[usbdev->chipid].uart_flowctrl = AICBT_UART_FC_DEFAULT;
}
} else {
aicbt_info[usbdev->chipid].uart_flowctrl = AICBT_UART_FC_DEFAULT;
}
tag_ptr = aicbt_find_tag((char*)dst, size, "LPM_ENABLE=", strlen("0"));
if (tag_ptr) {
if (sscanf(tag_ptr, "%x", &aicbt_info[usbdev->chipid].lpm_enable) != 1 ||
aicbt_info[usbdev->chipid].lpm_enable > 1) {
aicbt_info[usbdev->chipid].lpm_enable = AICBT_LPM_ENABLE_DEFAULT;
}
} else {
aicbt_info[usbdev->chipid].lpm_enable = AICBT_LPM_ENABLE_DEFAULT;
}
tag_ptr = aicbt_find_tag((char*)dst, size, "TXPWR_LVL=", strlen("0x6F2F"));
if (tag_ptr) {
if (sscanf(tag_ptr, "%08x", &tmp_val) == 1) {
if (tmp_val >= 0 || tmp_val <= 0X7F7F) {
aicbt_info[usbdev->chipid].txpwr_lvl = tmp_val;
} else {
aicbt_info[usbdev->chipid].txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT;
}
} else {
aicbt_info[usbdev->chipid].txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT;
}
} else {
aicbt_info[usbdev->chipid].txpwr_lvl = AICBT_TXPWR_LVL_DEFAULT;
}
vfree(dst);
AICWFDBG(LOGINFO, "%s: btmode %d btport %d uart baud %d uart fc %d lpm %d txpwrlvl %4X\n",
__func__,
aicbt_info[usbdev->chipid].btmode,
aicbt_info[usbdev->chipid].btport,
aicbt_info[usbdev->chipid].uart_baud,
aicbt_info[usbdev->chipid].uart_flowctrl,
aicbt_info[usbdev->chipid].lpm_enable,
aicbt_info[usbdev->chipid].txpwr_lvl);
}
#endif
int aicbt_patch_table_load(struct aic_usb_dev *usbdev, struct aicbt_patch_table *_head)
{
struct aicbt_patch_table *head, *p;
@@ -1308,10 +1419,11 @@ int aicbt_patch_table_load(struct aic_usb_dev *usbdev, struct aicbt_patch_table
*(data + 17) = aicbt_info[usbdev->chipid].txpwr_lvl;
printk("%s bt btmode[%d]:%d\r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].btmode);
printk("%s bt btport[%d]:%d\r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].btport);
printk("%s bt uart_baud[%d]:%d\r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].uart_baud);
printk("%s bt uart_flowctrl[%d]:%d\r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].uart_flowctrl);
printk("%s bt lpm_enable[%d]:%d\r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].lpm_enable);
printk("%s bt tx_pwr[%d]:%d \r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].txpwr_lvl);
printk("%s bt tx_pwr[%d]:%4X\r\n", __func__, usbdev->chipid, aicbt_info[usbdev->chipid].txpwr_lvl);
}
if (p->type == 0x06) {
@@ -1326,7 +1438,8 @@ int aicbt_patch_table_load(struct aic_usb_dev *usbdev, struct aicbt_patch_table
data += 2;
}
if (p->type == AICBT_PT_PWRON)
udelay(500);
mdelay(100);
// udelay(500);
}
aicbt_patch_table_free(head);
return 0;
@@ -1334,7 +1447,6 @@ int aicbt_patch_table_load(struct aic_usb_dev *usbdev, struct aicbt_patch_table
int aicbt_patch_info_unpack(struct aicbt_patch_info_t *patch_info, struct aicbt_patch_table *head_t)
{
uint8_t *patch_info_array = (uint8_t*)patch_info;
int base_len = 0;
int memcpy_len = 0;
@@ -1349,17 +1461,35 @@ int aicbt_patch_info_unpack(struct aicbt_patch_info_t *patch_info, struct aicbt_
patch_info->info_len = head_t->len;
memcpy_len = patch_info->info_len;
}
head_t->len = patch_info->info_len;
AICWFDBG(LOGDEBUG, "%s memcpy_len:%d \r\n", __func__, memcpy_len);
if (patch_info->info_len == 0)
return 0;
memcpy(((patch_info_array) + sizeof(patch_info->info_len)),
head_t->data,
memcpy_len * sizeof(uint32_t) * 2);
if (memcpy_len >= 1) {
patch_info->adid_addrinf = head_t->data[0];
patch_info->addr_adid = head_t->data[1];
}
if (memcpy_len >= 2) {
patch_info->patch_addrinf = head_t->data[2];
patch_info->addr_patch = head_t->data[3];
}
if (memcpy_len >= 3) {
patch_info->reset_addr = head_t->data[4];
patch_info->reset_val = head_t->data[5];
}
if (memcpy_len >= 4) {
patch_info->adid_flag_addr = head_t->data[6];
patch_info->adid_flag = head_t->data[7];
}
if (memcpy_len >= 5) {
patch_info->ext_patch_nb_addr = head_t->data[8];
patch_info->ext_patch_nb = head_t->data[9];
}
AICWFDBG(LOGDEBUG, "%s adid_addrinf:%x addr_adid:%x \r\n", __func__,
((struct aicbt_patch_info_t *)patch_info_array)->adid_addrinf,
((struct aicbt_patch_info_t *)patch_info_array)->addr_adid);
patch_info->adid_addrinf,
patch_info->addr_adid);
if (patch_info->ext_patch_nb > 0){
int index = 0;
@@ -9,6 +9,53 @@ struct aicbt_patch_table {
struct aicbt_patch_table *next;
};
typedef struct
{
int8_t enable;
int8_t dsss;
int8_t ofdmlowrate_2g4;
int8_t ofdm64qam_2g4;
int8_t ofdm256qam_2g4;
int8_t ofdm1024qam_2g4;
int8_t ofdmlowrate_5g;
int8_t ofdm64qam_5g;
int8_t ofdm256qam_5g;
int8_t ofdm1024qam_5g;
} txpwr_idx_conf_t;
typedef struct
{
int8_t enable;
int8_t chan_1_4;
int8_t chan_5_9;
int8_t chan_10_13;
int8_t chan_36_64;
int8_t chan_100_120;
int8_t chan_122_140;
int8_t chan_142_165;
} txpwr_ofst_conf_t;
typedef struct
{
int8_t enable;
int8_t xtal_cap;
int8_t xtal_cap_fine;
} xtal_cap_conf_t;
u32 aic_crc32(u8 *p, u32 len, u32 crc);
void get_fw_path(char* fw_path);
void set_testmode(int val);
int get_testmode(void);
int get_hardware_info(void);
int get_adap_test(void);
int get_flash_bin_size(void);
u32 get_flash_bin_crc(void);
void get_userconfig_xtal_cap(xtal_cap_conf_t *xtal_cap);
void get_userconfig_txpwr_idx(txpwr_idx_conf_t *txpwr_idx);
void get_userconfig_txpwr_ofst(txpwr_ofst_conf_t *txpwr_ofst);
void rwnx_plat_userconfig_set_value(char *command, char *value);
void rwnx_plat_userconfig_parsing(char *buffer, int size);
int aic_bt_platform_init(struct aic_usb_dev *sdiodev);
@@ -30,6 +77,9 @@ int8_t rwnx_atoi(char *value);
uint32_t rwnx_atoli(char *value);
int aicbt_patch_table_free(struct aicbt_patch_table *head);
struct aicbt_patch_table *aicbt_patch_table_alloc(struct aic_usb_dev *usbdev, const char *filename);
#ifdef CONFIG_LOAD_BT_CONF
void aicbt_parse_config(struct aic_usb_dev *usbdev, const char *filename);
#endif
int aicbt_patch_info_unpack(struct aicbt_patch_info_t *patch_info, struct aicbt_patch_table *head_t);
int aicbt_patch_table_load(struct aic_usb_dev *usbdev, struct aicbt_patch_table *_head);
@@ -240,7 +240,6 @@ void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
struct aicwf_bus *bus = usbdev->bus_if;
u8 *buffer = bus->cmd_buf;
u16 index = 0;
int ret = 0;
memset(buffer, 0, CMD_BUF_MAX);
buffer[0] = (len+4) & 0x00ff;
@@ -262,10 +261,7 @@ void aicwf_set_cmd_tx(void *dev, struct lmac_msg *msg, uint len)
index += 2;
memcpy(&buffer[index], (u8 *)msg->param, msg->param_len);
ret = aicwf_bus_txmsg(bus, buffer, len + 8);
if (ret == -EIO) {
ret = aicwf_bus_txmsg(bus, buffer, len + 8);
}
aicwf_bus_txmsg(bus, buffer, len + 8);
}
static inline void *rwnx_msg_zalloc(lmac_msg_id_t const id,
@@ -336,7 +332,10 @@ static int rwnx_send_msg(struct aic_usb_dev *usbdev, const void *msg_params,
}
if(!reqcfm)
{
kfree(cmd);
rwnx_msg_free(msg, msg_params);
}
return ret;
}
@@ -1,5 +1,6 @@
#include <linux/slab.h>
#include "aicwf_debug.h"
#include "aicwf_txq_prealloc.h"
struct prealloc_txq{
int prealloced;
@@ -1,4 +1,7 @@
#ifndef __AICWF_TXQ_PREALLOC_H
#define __AICWF_TXQ_PREALLOC_H
void *aicwf_prealloc_txq_alloc(size_t size);
void aicwf_prealloc_txq_free(void);
#endif
+11 -1
View File
@@ -985,7 +985,7 @@ u32 patch_tbl[][2] ={
#ifdef CONFIG_USB_SUSPEND_REBOOT_TIME
{0x0110, 0x03e80001}//reboot time when usb suspend,0001 enables reboot on suspend, default 0x3e8 = 1000ms reboot
#else
#ifdef CONFIG_SUPPORT_USB_SUSP
#ifdef CONFIG_WOWLAN
//USB SUSP keep working 0x0100:enable 0x0000:disable
{0x0110, 0x00000100}
#endif
@@ -1367,6 +1367,14 @@ static int aicloadfw_chipmatch(struct aic_usb_dev *usb_dev, u16 vid, u16 pid){
usb_dev->chipid = PRODUCT_ID_AIC8800D89X2;
AICWFDBG(LOGINFO, "%s USE AIC8800D89X2\r\n", __func__);
return 0;
}else if(pid == USB_DEVICE_ID_AIC_8800D40X2 && vid == USB_VENDOR_ID_AIC_V2){
usb_dev->chipid = PRODUCT_ID_AIC8800D80X2;
AICWFDBG(LOGINFO, "%s USE AIC8800D40X2\r\n", __func__);
return 0;
}else if(pid == USB_DEVICE_ID_AIC_8800D81 && vid == USB_VENDOR_ID_AIC_V2){
usb_dev->chipid = PRODUCT_ID_AIC8800D81;
AICWFDBG(LOGINFO, "%s USE AIC8800D81 (368b:8d81)\r\n", __func__);
return 0;
}else{
return -1;
}
@@ -1846,6 +1854,8 @@ static struct usb_device_id aicwf_usb_id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_DEVICE_ID_AIC_8800D80X2)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_DEVICE_ID_AIC_8800D81X2)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_DEVICE_ID_AIC_8800D89X2)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_DEVICE_ID_AIC_8800D40X2)},
{USB_DEVICE(USB_VENDOR_ID_AIC_V2, USB_DEVICE_ID_AIC_8800D81)}, /* 368b:8d81 */
{}
};
+4 -1
View File
@@ -42,11 +42,12 @@ enum AICWF_IC{
PRODUCT_ID_AIC8800D80X2,
PRODUCT_ID_AIC8800D81X2,
PRODUCT_ID_AIC8800D89X2,
PRODUCT_ID_AIC8800D40X2,
};
#define AICWF_USB_RX_URBS (20)
#define AICWF_USB_TX_URBS (30)
#define AICWF_USB_TX_URBS (100)
#define AICWF_USB_TX_LOW_WATER (AICWF_USB_TX_URBS/4)
#define AICWF_USB_TX_HIGH_WATER (AICWF_USB_TX_LOW_WATER*3)
#define AICWF_USB_MAX_PKT_SIZE (2048)
@@ -233,6 +234,8 @@ extern void aicwf_usb_tx_flowctrl(struct aic_usb_dev *usb_dev, bool state);
int usb_bustx_thread(void *data);
int usb_busrx_thread(void *data);
int aicwf_process_rxframes(struct aicwf_rx_priv *rx_priv);
int aicfw_download_fw_8800(struct aic_usb_dev *usb_dev);
int aicfw_download_fw(struct aic_usb_dev *usb_dev);
#endif /* AICWF_USB_SUPPORT */
#endif /* _AICWF_USB_H_ */
@@ -1,4 +1,4 @@
#define RWNX_VERS_REV "1a4b0054d2M (master)"
#define RWNX_VERS_MOD "6.4.3.0"
#define RWNX_VERS_BANNER "rwnx v6.4.3.0 - 1a4b0054d2M (master)"
#define RELEASE_DATE "2025_0423_71b66e7b"
#define RELEASE_DATE "2026_0123_5f7be68d"
+18
View File
@@ -0,0 +1,18 @@
ifneq ($(KERNELRELEASE),)
obj-m += aic_zlp_quirk.o
else
KVER ?= $(shell uname -r)
KDIR ?= /lib/modules/$(KVER)/build
.PHONY: all clean
all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules
clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
endif
@@ -0,0 +1,233 @@
// 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*");
+30
View File
@@ -0,0 +1,30 @@
# AIC USERCONFIG 2021/0911/2127
# txpwr_idx
enable=1
dsss=9
ofdmlowrate_2g4=10
ofdm64qam_2g4=10
ofdm256qam_2g4=9
ofdm1024qam_2g4=8
ofdmlowrate_5g=10
ofdm64qam_5g=9
ofdm256qam_5g=9
ofdm1024qam_5g=8
# txpwr_ofst
ofst_enable=0
ofst_chan_1_4=0
ofst_chan_5_9=0
ofst_chan_10_13=0
ofst_chan_36_64=0
ofst_chan_100_120=0
ofst_chan_122_140=0
ofst_chan_142_165=0
# xtal cap
xtal_enable=0
xtal_cap=24
xtal_cap_fine=31
# END
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More