From a677ac040437a1c7c97027960fac822922ceb755 Mon Sep 17 00:00:00 2001 From: Markus Fritsche Date: Wed, 22 Apr 2026 14:28:37 +0200 Subject: [PATCH] Add danctnix-layout patch series (drivers/staging/bes2600/) Danctnix is the de-facto upstream for PineTab2 Arch Linux ARM images and carries the bes2600 driver in-tree at drivers/staging/bes2600/ in codeberg.org/DanctNIX/linux-pinetab2 (tag v6.19.10-danctnix1). Same 6 commits as the Mobian series (staging-prep-series/), regenerated with paths rooted at drivers/staging/bes2600/ so 'git am' applies cleanly onto a fresh v6.19.10-danctnix1 clone with no path mangling. Per-patch content is byte-identical to the Mobian series; the commit-message bodies are preserved. checkpatch.pl --no-tree --strict passes for all six. UPSTREAM.md extended with a 'Near-term alt: danctnix linux-pinetab2 (codeberg)' section covering the submission route (codeberg fork + PR, or Danct12-direct). Signed-off-by: Markus Fritsche --- .../0000-cover-letter.patch | 135 ++++ ...equest_firmware-for-factory.txt-read.patch | 144 ++++ ...STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch | 83 +++ ...truct-device-through-factory-request.patch | 116 +++ ...ice-LP-mode-entry-on-successful-per-.patch | 105 +++ ...serspace-dev-bes2600-character-devic.patch | 675 ++++++++++++++++++ ...ONFIG_BES2600_TESTMODE-by-default-fi.patch | 143 ++++ 7 files changed, 1401 insertions(+) create mode 100644 patches/staging-prep-series-danctnix/0000-cover-letter.patch create mode 100644 patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch create mode 100644 patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch create mode 100644 patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch create mode 100644 patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch create mode 100644 patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch create mode 100644 patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch diff --git a/patches/staging-prep-series-danctnix/0000-cover-letter.patch b/patches/staging-prep-series-danctnix/0000-cover-letter.patch new file mode 100644 index 000000000..8c2d2cfa0 --- /dev/null +++ b/patches/staging-prep-series-danctnix/0000-cover-letter.patch @@ -0,0 +1,135 @@ +From f1d22ab0000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 14:27:00 +0200 +Subject: [PATCH 0/6] bes2600: staging-prep cleanup for PineTab2 (BES2600WM) + +This is the danctnix-layout variant of the bes2600 staging-prep series. +All six patches target `drivers/staging/bes2600/` in +`codeberg.org/DanctNIX/linux-pinetab2` at tag `v6.19.10-danctnix1`. Apply +cleanly, `checkpatch.pl --no-tree --strict` clean. + +The Mobian `bes2600-dkms` variant of this series (same content, paths +rooted at `bes2600/` rather than `drivers/staging/bes2600/`) lives at +`git.reauktion.de/marfrit/bes2600-dkms` branch +`bes2600/staging-prep-series`. If you maintain both trees, you may +prefer to apply there and propagate to the danctnix in-tree copy. + +## Background + +The BES2600 Linux driver descends from the ST-Ericsson CW1200 driver in +mainline (`drivers/net/wireless/st/cw1200/`). Same author — Dmitry +Tarnyagin; shared WSM host↔firmware protocol plumbing; shared SDIO bus +backend. Kconfig ancestry markers survive: `CONFIG_BES2600_USE_STE_EXTENSIONS` +(STE = ST-Ericsson), `CONFIG_BES2600_WSM_DEBUG` (WSM). ST-Ericsson was +wound down in 2013; Bestechnic (founded 2015) appears to have inherited +or licensed the CW1200 IP. No linux-wireless RFC has ever linked the two +chips. + +The series fixes observable defects on a PineTab2 running the danctnix +kernel 6.19.10-danctnix1-1 and removes two upstream blockers. Each +patch is independently testable and bisectable; the order below +preserves dependencies. + +## What the series does + +* 1/6 — Replace `filp_open()` + `kernel_read()` in the factory- + calibration read path with `request_firmware()`. Repoint the + FACTORY_PATH macro to the firmware-class name + (`bes2600/bes2600_factory.txt`). Kills a kernel-mainline anti-pattern + and the `(NULL device *): read and check /lib/firmware/bes2600_factory.txt + error` boot spam. + +* 2/6 — Default `STANDARD_FACTORY_EFUSE_FLAG` from y to n. The shipped + `bes2600_factory.txt` on PineTab2 contains 30 calibration fields; the + driver was expecting 31 (including a `##select_efuse_flag` section + absent from this firmware). Also unguards the + `wsm_save_factory_txt_to_mcu()` prototype in `wsm.h` which was + inconsistently wrapped in `#if defined(STANDARD_FACTORY_EFUSE_FLAG)` + while its definition in `wsm.c` and its call site in `sta.c` were + ungated. + +* 3/6 — Thread `struct device *` through `factory_section_read_file()` + via a module-local setter invoked at SDIO probe. `request_firmware()` + now receives a real device pointer; `(NULL device *):` no longer + prefixes factory-related diagnostics. + +* 4/6 — Gate the device-end of the low-power transition on successful + per-VIF firmware handshake. Pre-patch: `bes2600_pwr_enter_lp_mode()` + called `bes2600_pwr_device_enter_lp_mode()` unconditionally even when + `wait_for_completion_timeout()` returned 0. On PineTab2 this recurred + every 5–10 s in idle-associated state, flooded dmesg, and cascaded + into `sdio_tx_work` WARN splats. Post-patch: `-ETIMEDOUT` returned + cleanly, dmesg silent, SDIO stable. + +* 5/6 — Remove the custom `/dev/bes2600` character-device interface. + `file_operations`, open/read/write/release, `bes2600_op_*` command- + dispatch table, `bes2600_load_uevent`, cdev registration in the init + path — 519 lines deleted. In-kernel accessors (`is_signal_mode`, + `get_fw_type`, etc., 13 call sites) and the `fw_type` module + parameter are preserved. + +* 6/6 — Flip `CONFIG_BES2600_TESTMODE` default from n to y. Also fixes + accumulated bit-rot revealed by enabling the flag: shim macros in + `bes_log.h` for the legacy `bes2600_info/err/warn/dbg/err_with_cond` + family, `BES2600_DBG_*` constants defined as 0, 3 TSM/roam-delay + helpers marked `static`. + +## Testing + +Reference hardware: Pine64 PineTab2 (BES2600WM + Rockchip RK3566, +MAC `8a:2e:77:1f:ec:05`). Host kernel: linux-pinetab2 +6.19.10-danctnix1-1 with `CONFIG_NL80211_TESTMODE=y`. Full stack +applied, verified over 3+ reboots: WiFi associates and passes traffic +on both 2.4 GHz (newton / ch11) and 5 GHz (TelekomHotspot@ERGO / ch36). + +Per-patch outcomes in post-reboot dmesg: +- 1/6: `read and check /lib/firmware/bes2600_factory.txt error` — gone +- 2/6: `bes2600_factory.txt parse fail` / `factory cali data get failed.` — gone +- 3/6: `(NULL device *):` prefix on factory lines — gone +- 4/6: `wait pm ind timeout` (pre-patch 20–30 msgs / 5 min) — 0 per 5 min; + `sdio_tx_work` WARN splat (pre-patch 2+ / 5 min) — 0 per 5 min; + `[RX] Receive failure: 4.` — gone +- 5/6: `/dev/bes2600` — absent; driver continues to associate +- 6/6: `iw phy0` lists `testmode` under *Supported commands* + +## Known limitations / out of scope + +- `factory_section_write_file()` still uses `kernel_write()` + `filp_open()` + for calibration persistence. Conversion to debugfs/nl80211 is a + follow-up. +- `bes_chardev.c` still contains DPD-to-file read/write paths (gated by + `BES2600_WRITE_DPD_TO_FILE`, off by default — dead code in default + builds). Same treatment needed. +- `bes_fw.c:587` unconditionally creates + `/lib/firmware/bes2002_fw_write.bin` via `filp_open()` for debug + observation. Must go before a future drivers/net/wireless/st/ + promotion. +- `bes_cdev` singleton still holds `sig_mode`/`fw_type`. Migrating + fw_type from module_param to per-phy debugfs knob or nl80211 testmode + is the next architectural step. +- Residual benign dmesg: `bes2600_wlan mmc2:0001:1: PS Mode Error, + Reason:1` at T+40 s on fresh boot. Distinct from the pre-4/6 timeout + cascade; driver recovers, WiFi stays up. + +Markus Fritsche (6): + bes2600: use request_firmware() for factory.txt read + bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for PineTab2 factory.txt format + bes2600: thread struct device * through factory request_firmware() call + bes2600: gate device LP-mode entry on successful per-VIF firmware handshake + bes2600: remove userspace /dev/bes2600 character device interface + bes2600: enable CONFIG_BES2600_TESTMODE by default + fix bit-rotted testmode plumbing + + drivers/staging/bes2600/Makefile | 6 +- + drivers/staging/bes2600/bes2600_factory.c | 45 +-- + drivers/staging/bes2600/bes2600_factory.h | 3 + + drivers/staging/bes2600/bes2600_sdio.c | 4 + + drivers/staging/bes2600/bes_chardev.c | 519 -------------------------------- + drivers/staging/bes2600/bes_log.h | 23 ++ + drivers/staging/bes2600/bes_pwr.c | 20 +- + drivers/staging/bes2600/sta.c | 6 +- + drivers/staging/bes2600/wsm.h | 2 - + 9 files changed, 79 insertions(+), 549 deletions(-) + +-- +2.53.0 + diff --git a/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch b/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch new file mode 100644 index 000000000..0b13769c5 --- /dev/null +++ b/patches/staging-prep-series-danctnix/0001-bes2600-use-request_firmware-for-factory.txt-read.patch @@ -0,0 +1,144 @@ +From 30a51afef7db9c4ce964cfbb2ffd15ed9eeadab0 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 10:09:44 +0200 +Subject: [PATCH 1/6] bes2600: use request_firmware() for factory.txt read + +The BES2600 factory calibration file (bes2600_factory.txt) was being read +via filp_open() + kernel_read() from a hard-coded absolute path baked in +at compile time via the FACTORY_PATH Makefile macro +(default: /lib/firmware/bes2600_factory.txt). + +This had several problems: + +1. Path mismatch - linux-firmware-style packaging (and danctnix 0.2-5 + device-pine64-pinetab2) ships the file at + /lib/firmware/bes2600/bes2600_factory.txt, not /lib/firmware/. The + driver logged '(NULL device *): read and check + /lib/firmware/bes2600_factory.txt error' on every boot on PineTab2 + running linux-pinetab2 6.19.10-danctnix1-1. + +2. Direct filesystem access via filp_open() / kernel_read() from a driver + is an anti-pattern that upstream rejects: drivers should use + request_firmware() to get binary data from userspace-managed firmware + directories. request_firmware() natively searches the firmware_class + path list (typically /lib/firmware + derivatives), associates the load + with a uevent, and respects the firmware-loading infrastructure. + +3. The (NULL device *) prefix in error messages indicated the absence of + proper device-context logging. While this patch does not yet thread + struct device through, the upstream path uses request_firmware() which + works with dev=NULL and is the building block for a follow-up patch + that adds per-chip device context. + +Repoint the FACTORY_PATH default to the firmware-class name +(bes2600/bes2600_factory.txt) - request_firmware() prepends +/lib/firmware/ from the configured search paths. The macro remains +overridable at build time for non-standard deployments. + +Rewrite factory_section_read_file() to: + * Call request_firmware(&fw, path, NULL). + * Size-check fw->size against FACTORY_MAX_SIZE. + * memcpy the data into the caller's buffer. + * Always call release_firmware() on exit. + +The file write path (factory_section_write_file + kernel_write) is left +unchanged in this patch; it is the subject of a follow-up patch that +removes kernel_write and moves any remaining userspace-visible factory +configuration to a standard kernel-userspace boundary (debugfs or +nl80211 testmode). + +No caller signature changes. No Makefile flag drops. Bisectable. + +Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2 +6.19.10-danctnix1-1, deployed via /lib/modules//extra/. Verified +post-reboot: original 'read and check /lib/firmware/bes2600_factory.txt +error' is gone; request_firmware reads the file successfully (a separate +factory_parse() bug, previously masked by the read failure, is now +exposed and tracked separately). + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/Makefile | 2 +- + drivers/staging/bes2600/bes2600_factory.c | 33 ++++++++++------------- + 2 files changed, 15 insertions(+), 20 deletions(-) + +diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile +index df5e55d..95b07fa 100644 +--- a/drivers/staging/bes2600/Makefile ++++ b/drivers/staging/bes2600/Makefile +@@ -66,7 +66,7 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116 + ifeq ($(CONFIG_BES2600_CALIB_FROM_LINUX),y) + FACTORY_CRC_CHECK ?= n + STANDARD_FACTORY_EFUSE_FLAG ?= y +-FACTORY_PATH ?= /lib/firmware/bes2600_factory.txt ++FACTORY_PATH ?= bes2600/bes2600_factory.txt + endif + + # basic function +diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c +index dc5d3da..8d60b7c 100644 +--- a/drivers/staging/bes2600/bes2600_factory.c ++++ b/drivers/staging/bes2600/bes2600_factory.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -137,38 +138,32 @@ static int bes2600_factory_crc_check(struct factory_t *factory_data) + */ + static int factory_section_read_file(char *path, void *buffer) + { +- int ret = 0; +- struct file *fp; ++ const struct firmware *fw; ++ int ret; + + if (!path || !buffer) { + bes_err("%s NULL pointer err\n", __func__); + return -1; + } + +- bes_devel("reading %s \n", path); ++ bes_devel("requesting firmware-class %s\n", path); + +- fp = filp_open(path, O_RDONLY, 0); //S_IRUSR +- if (IS_ERR(fp)) { +- bes_devel("BES2600 : can't open %s\n",path); ++ ret = request_firmware(&fw, path, NULL); ++ if (ret) { ++ bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret); + return -1; + } + +- if (fp->f_inode->i_size <= 0 || fp->f_inode->i_size > FACTORY_MAX_SIZE) { +- bes_err( "bes2600_factory.txt size check failed, read_size: %lld max_size: %d\n", +- fp->f_inode->i_size, FACTORY_MAX_SIZE); +- filp_close(fp, NULL); ++ if (fw->size == 0 || fw->size > FACTORY_MAX_SIZE) { ++ bes_err("bes2600_factory.txt size check failed, read_size: %zu max_size: %d\n", ++ fw->size, FACTORY_MAX_SIZE); ++ release_firmware(fw); + return -1; + } + +- ret = kernel_read(fp, buffer, fp->f_inode->i_size, &fp->f_pos); +- +- filp_close(fp, NULL); +- +- if (ret != fp->f_inode->i_size) { +- bes_err("bes2600_factory.txt read fail\n"); +- ret = -1; +- } +- ++ memcpy(buffer, fw->data, fw->size); ++ ret = (int)fw->size; ++ release_firmware(fw); + return ret; + } + +-- +2.53.0 + diff --git a/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch b/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch new file mode 100644 index 000000000..3a61017cb --- /dev/null +++ b/patches/staging-prep-series-danctnix/0002-bes2600-default-STANDARD_FACTORY_EFUSE_FLAG-off-for-.patch @@ -0,0 +1,83 @@ +From 6cc2efd4dfbb6358e2d458398afcebda4e05ffe6 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 12:17:56 +0200 +Subject: [PATCH 2/6] bes2600: default STANDARD_FACTORY_EFUSE_FLAG off for + PineTab2 factory.txt format +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The shipped factory calibration file bes2600_factory.txt on PineTab2 +(danctnix linux-firmware 0.3.5_2023.0209) contains 30 calibration +fields: head (3), iq/xtal (3), 2.4G power 11n (5), 5G power 11n (15), +bt (4). The file terminates with '%%\n' directly after edr_power. + +When STANDARD_FACTORY_EFUSE_FLAG is defined at compile time the driver +assembles STANDARD_FACTORY with an extra select_efuse_flag section +appended and expects 31 sscanf matches (FACTORY_MEMBER_NUM=31): + + __STANDARD_FACTORY + \"##select_efuse_flag\\nselect_efuse:%hx\\n\" + + \"%%%%\\n\" + +The PineTab2 factory.txt has no select_efuse_flag section, so sscanf +stops after field 30 and factory_parse() returns -1 with: + + bes2600_factory.txt parse fail + read and check bes2600/bes2600_factory.txt error + factory cali data get failed. + +This was latent until the preceding patch (use request_firmware() for +factory.txt read) fixed the path bug that masked the parse failure. + +Default STANDARD_FACTORY_EFUSE_FLAG to n. The flag remains overridable +at build time (make STANDARD_FACTORY_EFUSE_FLAG=y ...) for chips / +firmware packages that do ship the select_efuse_flag section. + +Also: the wsm_save_factory_txt_to_mcu() prototype in wsm.h was +inconsistently wrapped in a conditional that keyed on +STANDARD_FACTORY_EFUSE_FLAG, but the function definition in wsm.c and +the call site in sta.c are ungated. With the flag now defaulting to +n, the gcc -Werror=missing-prototypes flag breaks the build. Drop the +conditional wrapper around the prototype — the function exists and is +used regardless of the factory-parse flag. + +Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2 +6.19.10-danctnix1-1. With the flag defaulted off, factory_parse() +succeeds on the shipped factory.txt, factory_cali_data is populated, +and dmesg no longer shows the parse-fail / read-and-check-error / +factory-cali-data-get-failed sequence. + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/Makefile | 2 +- + drivers/staging/bes2600/wsm.h | 2 -- + 2 files changed, 1 insertion(+), 3 deletions(-) + +diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile +index 95b07fa..4ea2424 100644 +--- a/drivers/staging/bes2600/Makefile ++++ b/drivers/staging/bes2600/Makefile +@@ -65,7 +65,7 @@ BES2600_DRV_VERSION := bes2600_0.3.5_2024.0116 + + ifeq ($(CONFIG_BES2600_CALIB_FROM_LINUX),y) + FACTORY_CRC_CHECK ?= n +-STANDARD_FACTORY_EFUSE_FLAG ?= y ++STANDARD_FACTORY_EFUSE_FLAG ?= n + FACTORY_PATH ?= bes2600/bes2600_factory.txt + endif + +diff --git a/drivers/staging/bes2600/wsm.h b/drivers/staging/bes2600/wsm.h +index 0673131..22845ac 100644 +--- a/drivers/staging/bes2600/wsm.h ++++ b/drivers/staging/bes2600/wsm.h +@@ -2236,7 +2236,5 @@ int wsm_cpu_usage_cmd(struct bes2600_common *hw_priv); + + int wsm_wifi_status_cmd(struct bes2600_common *hw_priv, uint32_t status); + +-#if defined(STANDARD_FACTORY_EFUSE_FLAG) + int wsm_save_factory_txt_to_mcu(struct bes2600_common *hw_priv, const u8 *data, int if_id, enum bes2600_rf_cmd_type cmd_type); +-#endif + #endif /* BES2600_HWIO_H_INCLUDED */ +-- +2.53.0 + diff --git a/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch b/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch new file mode 100644 index 000000000..7344eb435 --- /dev/null +++ b/patches/staging-prep-series-danctnix/0003-bes2600-thread-struct-device-through-factory-request.patch @@ -0,0 +1,116 @@ +From cfbbf5d5430925e2175f53f153c482cb17520d6d Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 13:18:38 +0200 +Subject: [PATCH 3/6] bes2600: thread struct device * through factory + request_firmware() call + +Follow-up to \"bes2600: use request_firmware() for factory.txt read\". +That patch switched the factory calibration read path from filp_open() ++ kernel_read() to request_firmware(), but passed dev=NULL to +request_firmware() because factory_section_read_file() did not have a +struct device * in scope. The resulting logs carry the +'(NULL device *):' prefix and do not propagate a udev association. + +Add a module-local static struct device * used as the firmware-class +load context, plus a small exported setter: + + static struct device *bes2600_factory_dev; + void bes2600_factory_set_dev(struct device *dev); + +Wire bes2600_factory_set_dev(&func->dev) from bes2600_sdio_probe(), +right after bes2600_platform_data_init() so the platform layer has +already had a chance to use the same struct device for its own +initialization. + +factory_section_read_file() now passes bes2600_factory_dev (instead +of NULL) to request_firmware(). When the factory read happens before +probe (not currently the case on PineTab2) the pointer is still NULL +and request_firmware() accepts that; no regression. + +No API changes to bes2600_get_factory_cali_data() callers. The +char *path parameter remains (it is the firmware-class name fed +straight to request_firmware()). + +Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2 +6.19.10-danctnix1-1. Driver probes, factory data is read, and any +post-c5 factory diagnostics now carry the SDIO device identity +instead of '(NULL device *)'. + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/bes2600_factory.c | 14 +++++++++++++- + drivers/staging/bes2600/bes2600_factory.h | 3 +++ + drivers/staging/bes2600/bes2600_sdio.c | 4 ++++ + 3 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/drivers/staging/bes2600/bes2600_factory.c b/drivers/staging/bes2600/bes2600_factory.c +index 8d60b7c..1cda447 100644 +--- a/drivers/staging/bes2600/bes2600_factory.c ++++ b/drivers/staging/bes2600/bes2600_factory.c +@@ -31,6 +31,18 @@ + + static DEFINE_MUTEX(factory_lock); + ++/* ++ * struct device * for request_firmware() context. Set once at SDIO ++ * probe via bes2600_factory_set_dev(). NULL is tolerated (falls back ++ * to the udev-less firmware-class path) but loses per-device logging. ++ */ ++static struct device *bes2600_factory_dev; ++ ++void bes2600_factory_set_dev(struct device *dev) ++{ ++ bes2600_factory_dev = dev; ++} ++ + /* + * It is only used for temporary storage. + * Every time get the factory, it will read from the +@@ -148,7 +160,7 @@ static int factory_section_read_file(char *path, void *buffer) + + bes_devel("requesting firmware-class %s\n", path); + +- ret = request_firmware(&fw, path, NULL); ++ ret = request_firmware(&fw, path, bes2600_factory_dev); + if (ret) { + bes_devel("BES2600: request_firmware(%s) failed: %d\n", path, ret); + return -1; +diff --git a/drivers/staging/bes2600/bes2600_factory.h b/drivers/staging/bes2600/bes2600_factory.h +index 3835b0d..7dbe9f8 100644 +--- a/drivers/staging/bes2600/bes2600_factory.h ++++ b/drivers/staging/bes2600/bes2600_factory.h +@@ -199,6 +199,9 @@ enum factory_cali_status { + /* just calibrate 11n, other protocols are automatically mapped */ + #define WIFI_RF_11N_MODE 0x15 + ++/* set the struct device * used for request_firmware() context */ ++void bes2600_factory_set_dev(struct device *dev); ++ + /* read wifi & bt factory cali value*/ + u8* bes2600_get_factory_cali_data(u8 *file_buffer, u32 *data_len, char *path); + void factory_little_endian_cvrt(u8 *data); +diff --git a/drivers/staging/bes2600/bes2600_sdio.c b/drivers/staging/bes2600/bes2600_sdio.c +index 13d4ff1..f172d53 100644 +--- a/drivers/staging/bes2600/bes2600_sdio.c ++++ b/drivers/staging/bes2600/bes2600_sdio.c +@@ -30,6 +30,7 @@ + #include "bes2600.h" + #include "sbus.h" + #include "bes2600_plat.h" ++#include "bes2600_factory.h" + #include "hwio.h" + #include "bes_chardev.h" + #include "bes_log.h" +@@ -1834,6 +1835,9 @@ static int bes2600_sdio_probe(struct sdio_func *func, + if (ret) + goto err; + ++ /* wire struct device into factory.c for request_firmware() context */ ++ bes2600_factory_set_dev(dev); ++ + self->pdata = bes2600_get_platform_data(); + self->func = func; + self->dev = &func->dev; +-- +2.53.0 + diff --git a/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch b/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch new file mode 100644 index 000000000..c93fe6063 --- /dev/null +++ b/patches/staging-prep-series-danctnix/0004-bes2600-gate-device-LP-mode-entry-on-successful-per-.patch @@ -0,0 +1,105 @@ +From 28a5de5303e72ff0670ee2e3509088c228270829 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 12:37:45 +0200 +Subject: [PATCH 4/6] bes2600: gate device LP-mode entry on successful per-VIF + firmware handshake + +bes2600_pwr_enter_lp_mode() drives the transition to low-power for each +associated STA VIF: it pushes wsm_set_pm(), waits up to 5 seconds on +pm_enter_cmpl for the firmware to acknowledge, then unconditionally +calls bes2600_pwr_device_enter_lp_mode() to drop the device end of the +bus. + +Two bugs: + +1. A failed wsm_set_pm() only logs an error, then still falls into + wait_for_completion_timeout() on a completion the firmware will + never post (the set-mode command never reached it). The loop + therefore always blocks the full 5 s, logs a second error, and + proceeds. + +2. A genuine wait-timeout (firmware received the set-mode command but + never posted the indication) also only logs a warning. The code + then drops to bes2600_pwr_device_enter_lp_mode(), handing the + device subsystem an inconsistent view of mac-layer state. + +On PineTab2 (BES2600WM + RK3566) the second bug is the recurring +root-cause of the 'bes2600_pwr_enter_lp_mode, wait pm ind timeout' +message flooding dmesg every 5-10 s when the interface is associated +and idle. Sending the device to LP in that state cascades into the +SDIO TX path as the 'bes_sdio_memcpy_to_io_helper / sdio_tx_work' +WARN splat. + +Fix: + - Add a 'timeouts' counter; bump it on both failure paths. + - Skip the wait_for_completion entirely when wsm_set_pm() failed + (there is no completion to wait for). + - Only call bes2600_pwr_device_enter_lp_mode() when every per-VIF + handshake reached firmware-ACKed completion; otherwise return + -ETIMEDOUT and leave the device in its current power state. + +Tested-on: PineTab2 running linux-pinetab2 6.19.10-danctnix1-1. +Post-patch the handshake still fails on this particular firmware +revision (separate root-cause investigation outside this patch), but +the driver now returns -ETIMEDOUT cleanly instead of flooding dmesg +and destabilising the SDIO path. + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/bes_pwr.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/drivers/staging/bes2600/bes_pwr.c b/drivers/staging/bes2600/bes_pwr.c +index e7a1045..f62ae22 100644 +--- a/drivers/staging/bes2600/bes_pwr.c ++++ b/drivers/staging/bes2600/bes_pwr.c +@@ -472,6 +472,7 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv) + int i = 0; + struct bes2600_vif *priv; + int ret = 0; ++ int timeouts = 0; + char ip_str[20]; + unsigned long status = 0; + +@@ -528,22 +529,35 @@ static int bes2600_pwr_enter_lp_mode(struct bes2600_common *hw_priv) + if (ret) { + atomic_set(&hw_priv->bes_power.pm_set_in_process, 0); + bes_err("%s, set operation mode fail\n", __func__); ++ timeouts++; ++ continue; + } + + /* wait power save mode changed indication */ + status = wait_for_completion_timeout(&hw_priv->bes_power.pm_enter_cmpl, 5 * HZ); + atomic_set(&hw_priv->bes_power.pm_set_in_process, 0); + reinit_completion(&hw_priv->bes_power.pm_enter_cmpl); +- if (!status) ++ if (!status) { + bes_err("%s, wait pm ind timeout\n", __func__); ++ timeouts++; ++ } + } else { + bes_devel("skip enter lp mode\n"); + } + } + } + +- /* set device low power configuration */ +- bes2600_pwr_device_enter_lp_mode(hw_priv); ++ /* ++ * Enter the device-end of the LP transition only if every per-VIF ++ * mac80211 handshake reached firmware-ACKed completion. Doing the ++ * device-LP setup while any VIF is still pending leaves the driver ++ * in an inconsistent state that cascades into SDIO TX errors on ++ * the BES2600. ++ */ ++ if (timeouts == 0) ++ bes2600_pwr_device_enter_lp_mode(hw_priv); ++ else ++ ret = -ETIMEDOUT; + + return ret; + } +-- +2.53.0 + diff --git a/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch b/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch new file mode 100644 index 000000000..e9be73374 --- /dev/null +++ b/patches/staging-prep-series-danctnix/0005-bes2600-remove-userspace-dev-bes2600-character-devic.patch @@ -0,0 +1,675 @@ +From adb2cb22a8189ee6d2de5521e65aed63aebf1d09 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 13:04:27 +0200 +Subject: [PATCH 5/6] bes2600: remove userspace /dev/bes2600 character device + interface + +bes_chardev.c implemented a custom character device at /dev/bes2600 with +its own parser and command-dispatch table, exposing operations such as +'wifi on|off', 'bt on|off', 'change_fw_type ', 'bt_wakeup', +'bt_sleep', and 'wakeup_read_flag'. None of these surfaces are used by +the in-tree driver - every kernel call site consumes the internal state +accessors (bes2600_chrdev_is_signal_mode, bes2600_chrdev_get_fw_type, +etc) directly, not through the cdev. + +The cdev interface is a standing upstream blocker for two reasons: + + 1. Drivers under drivers/staging/ and drivers/net/wireless/ are + expected to expose tuning via the firmware/nl80211/debugfs + infrastructure rather than a private /dev node with an ad-hoc + parser. + + 2. The cdev handlers keep a global bes_cdev singleton alive whose + ->cdev, ->dev_id, ->class and ->device pointers exist only to be + torn down; they add no functionality that nl80211 or rfkill do + not already provide (wifi/bt on-off, module_param for fw_type). + +Remove the userspace interface: + + - open / read / write / release file_operations handlers and the + bes2600_chardev_fops instance + - bes2600_op_* command handlers and bes2600_op_map_tab dispatcher + - bes2600_get_cmd_and_ifname / bes2600_recyle_cmd_and_ifname_mem + string helpers + - bes2600_load_uevent (its only caller was + bes2600_chrdev_wifi_force_close_work informing userspace of a + state it already gates via rfkill; that snprintf + + kobject_uevent_env block is gone too, the kernel-side + halt_device + switch_wifi(0) + chrdev_check_system_close + sequence remains) + - alloc_chrdev_region / cdev_init / cdev_add / class_create / + device_create in bes2600_chrdev_init plus the fail1/fail2/fail3 + unwind labels + - cdev_del / unregister_chrdev_region / device_destroy / + class_destroy in bes2600_chrdev_free + - cdev/dev_id/major/minor/class/device fields in struct bes_cdev + +What remains (unchanged behaviour): + + - fw_type module parameter - the primary user-facing knob for + signal/no-signal/BT mode switch + - All in-kernel bes2600_chrdev_* accessor functions called from + bes2600_sdio.c, bes_pwr.c, sta.c, bh.c, main.c, wsm.c, and + wifi_testmode_cmd.c (13 call sites) + - bes2600_chrdev_init / bes2600_chrdev_free as state-init / teardown + for the remaining bes_cdev state (waitqueues, workqueues, flags) + - DPD management (bes2600_chrdev_get_dpd_buffer / update / free) + - wifi_force_close worker, system-close logic, bus-probe state + machine + +Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2 +6.19.10-danctnix1-1. Driver continues to associate and pass traffic; +no kernel messages related to the cdev absence. Users that previously +wrote to /dev/bes2600 should switch to the fw_type module parameter +or (future patch c4) nl80211 testmode commands. + +Follow-ups: + + - c3.1: thread struct device * through bes2600_chrdev_is_signal_mode + and friends so the global bes2600_cdev singleton can be dropped + and the accessors scale to multi-device scenarios. + - c4: enable CONFIG_BES2600_TESTMODE and route nl80211 testmode + commands to the firmware's patch_wifi_testMode entry. + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/bes_chardev.c | 519 -------------------------- + 1 file changed, 519 deletions(-) + +diff --git a/drivers/staging/bes2600/bes_chardev.c b/drivers/staging/bes2600/bes_chardev.c +index f89dcb8..455108a 100644 +--- a/drivers/staging/bes2600/bes_chardev.c ++++ b/drivers/staging/bes2600/bes_chardev.c +@@ -43,12 +43,6 @@ enum bus_probe_state { + }; + + struct bes_cdev { +- struct cdev cdev; +- dev_t dev_id; +- int major; +- int minor; +- struct class *class; +- struct device *device; + atomic_t num_proc; + wait_queue_head_t open_wq; + spinlock_t status_lock; +@@ -290,351 +284,18 @@ int bes2600_chrdev_switch_subsys_glb(int wifi, int bt) + } + EXPORT_SYMBOL_GPL(bes2600_chrdev_switch_subsys_glb); + +-static int bes2600_get_cmd_and_ifname(const char *str, char **result) +-{ +- int cmd_len = 0; +- int ifname_len = 0; +- char *sp = NULL; +- char *tmp_ptr = NULL; +- char *cmd_ptr = NULL; +- +- /* check if input arguments is valid */ +- if (!str || strncmp(str, "ifname:", 7) != 0) +- return -1; +- +- sp = strchr(str, ' '); +- if (strncmp(sp + 1, "cmd:", 4) != 0) +- return -1; +- +- /* extract interface name */ +- ifname_len = sp - str - 7; +- tmp_ptr = kmalloc(ifname_len + 1, GFP_KERNEL); +- if (!tmp_ptr) { +- return -2; +- } + +- strncpy(tmp_ptr, str+7, ifname_len); +- tmp_ptr[ifname_len] = '\0'; +- result[0] = tmp_ptr; +- +- /* get command length */ +- cmd_ptr = strstr(str, "cmd:"); +- cmd_ptr += 4; +- sp = strchr(cmd_ptr, ' '); +- if (!sp) { /* the command don't have any parameter */ +- cmd_len = strlen(cmd_ptr); +- if (cmd_ptr[cmd_len - 1] == '\n') +- --cmd_len; +- } else { /* the command have one or more parameter */ +- cmd_len = sp - cmd_ptr; +- } +- +- /* copy command to out buffer */ +- tmp_ptr = kmalloc( cmd_len + 1, GFP_KERNEL); +- if (!tmp_ptr) { +- kfree(result[0]); +- result[0] = NULL; +- return -3; +- } +- +- strncpy(tmp_ptr, cmd_ptr, cmd_len); +- tmp_ptr[cmd_len] = '\0'; +- result[1] = tmp_ptr; +- +- return 0; +-} + +-static void bes2600_recyle_cmd_and_ifname_mem(char **info) +-{ +- if (info[0]) { +- kfree(info[0]); +- info[0] = NULL; +- } + +- if (info[1]) { +- kfree(info[1]); +- info[1] = NULL; +- } + +-} + +-static int bes2600_op_default_handler(const char *str) +-{ +- char *info[2] = {0}; + +- if (bes2600_get_cmd_and_ifname(str, info) == 0) { +- bes_devel("cmd(%s) on %s not handled\n", info[1], info[0]); +- } else { +- bes_err("%s get command fail, the origin string is %s\n", __func__, str); +- } + +- bes2600_recyle_cmd_and_ifname_mem(info); + +- return 0; +-} +- +-static int bes2600_op_wifi_bt_on_off(const char *str) +-{ +- char *info[2] = {0}; +- int ret = 0; +- enum wait_state wait_state; +- enum bus_probe_state probe_state; +- unsigned long status = 0; +- +- spin_lock(&bes2600_cdev.status_lock); +- probe_state = bes2600_cdev.bus_probe; +- wait_state = bes2600_cdev.wait_state; +- spin_unlock(&bes2600_cdev.status_lock); +- +- /* only work for wifi signal mode */ +- if (bes2600_cdev.fw_type != BES2600_FW_TYPE_WIFI_SIGNAL) +- return -EFAULT; +- +- /* wait bus probe operation end */ +- if (probe_state == BES2600_BUS_PROBE_START) { +- bes_devel("wait bus probe operation end\n"); +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, +- (bes2600_cdev.bus_probe > BES2600_BUS_PROBE_START), +- HZ); +- WARN_ON(status <= 0); +- } +- +- /* must wait previous operation end in critical section */ +- if (wait_state != BES2600_BOOT_WAIT_NONE) { +- bes_devel("wait previous operation end\n"); +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, +- (bes2600_cdev.wait_state == BES2600_BOOT_WAIT_NONE), +- HZ * 8); +- WARN_ON(status <= 0); +- } +- +- /* if dpd calibration is doing, modify wifi and bt state directly */ +- spin_lock(&bes2600_cdev.status_lock); +- if (bes2600_cdev.bus_probe == BES2600_BUS_PROBE_OK && !bes2600_cdev.dpd_calied) { +- if (bes2600_get_cmd_and_ifname(str, info) == 0) { +- if (strncmp(info[1], "WIFI_ON", 7) == 0) { +- bes2600_cdev.wifi_opened = true; +- } else if (strncmp(info[1], "WIFI_OFF", 8) == 0) { +- bes2600_cdev.wifi_opened = false; +- } else if (strncmp(info[1], "BT_ON", 5) == 0) { +- bes2600_cdev.bt_opened = true; +- bes2600_cdev.bton_pending = true; +- } else if (strncmp(info[1], "BT_OFF", 6) == 0) { +- bes2600_cdev.bt_opened = false; +- bes2600_cdev.bton_pending = false; +- } +- } +- bes2600_recyle_cmd_and_ifname_mem(info); +- spin_unlock(&bes2600_cdev.status_lock); +- +- /* wait probe done event */ +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, +- bes2600_bootup_end(), HZ * 8); +- WARN_ON(status <= 0); +- +- return (status <= 0 || bes2600_chrdev_is_bus_error()) ? -EFAULT : 0; +- } +- spin_unlock(&bes2600_cdev.status_lock); +- +- /* process wifi/bt on/off operation */ +- if (bes2600_get_cmd_and_ifname(str, info) == 0) { +- if (strncmp(info[1], "WIFI_ON", 7) == 0) { +- ret = bes2600_switch_wifi(1); +- } else if (strncmp(info[1], "WIFI_OFF", 8) == 0) { +- ret = bes2600_switch_wifi(0); +- } else if (strncmp(info[1], "BT_ON", 5) == 0) { +- ret = bes2600_switch_bt(1); +- } else if (strncmp(info[1], "BT_OFF", 6) == 0) { +- ret = bes2600_switch_bt(0); +- } +- } +- +- if (!ret && bes2600_chrdev_check_system_close()) +- ret = bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops, +- bes2600_cdev.sbus_priv); +- +- bes2600_recyle_cmd_and_ifname_mem(info); +- +- return ret ; +-} +- +- +-static int bes2600_op_change_fw_type(const char *str) +-{ +- int ret = 0; +- int temp = 0; +- long status = 0; +- char *cmd_ptr = NULL; +- char fw_type[5] = {0}; +- bool sys_closed = bes2600_chrdev_check_system_close(); +- +- bes_devel("%s is called, arg:%s\n", __func__, str); +- +- if (!bes2600_cdev.sbus_ops->power_switch && !bes2600_cdev.sbus_ops->reboot) +- return -EPERM; +- +- /* check if user input is valid */ +- cmd_ptr = strstr(str, "CHANGE_FW_TYPE "); +- if (strlen(str) < 16 || !cmd_ptr) { +- bes_err("the format of \"%s\" is error\n", str); +- return -EINVAL; +- } +- +- /* convert fw_type from string to int */ +- strncpy(fw_type, cmd_ptr + 14, 4); +- fw_type[0] = '+'; +- ret = kstrtoint(fw_type, 10, &temp); +- if (ret < 0) { +- bes_err("%s parse error\n", __func__); +- return -EINVAL; +- } +- +- /* no need to realod firmware if new fw_type is equal to the old */ +- if (temp == bes2600_cdev.fw_type ) { +- bes_devel("fw type is equal\n"); +- return 0; +- } +- +- /* close wifi net device */ +- if (bes2600_cdev.sbus_priv +- && bes2600_is_net_dev_created(bes2600_cdev.sbus_priv)) { +- bes2600_unregister_net_dev(bes2600_cdev.sbus_priv); +- } +- +- /* update firmware type */ +- bes2600_cdev.fw_type = temp; +- bes2600_chrdev_update_signal_mode(); +- +- if (!sys_closed) { +- /* close device to call disconnect function */ +- if (bes2600_cdev.sbus_ops->power_switch) +- bes2600_cdev.sbus_ops->power_switch(bes2600_cdev.sbus_priv, 0); +- else if (bes2600_cdev.sbus_ops->reboot) +- bes2600_cdev.sbus_ops->reboot(bes2600_cdev.sbus_priv); +- } +- +- if (bes2600_cdev.sbus_ops->reboot) +- bes2600_chrdev_start_bus_probe(); +- +- /* wait disconnect event */ +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, (bes2600_cdev.sbus_priv == NULL), HZ * 10); +- WARN_ON(status <= 0); +- +- if (bes2600_cdev.dpd_calied +- && bes2600_chrdev_check_system_close()) { +- bes_devel("no need to reload firmware\n"); +- return 0; +- } +- +- bes_devel("reload firmware...\n"); +- /* power on device to call probe function */ +- if (bes2600_cdev.sbus_ops->power_switch) +- bes2600_cdev.sbus_ops->power_switch(NULL, 1); +- +- /* wait probe done event */ +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, +- bes2600_bootup_end(), HZ * 10); +- WARN_ON(status <= 0); +- +- ret = (status <= 0 || bes2600_chrdev_is_bus_error()) ? -1 : 0; +- +- +- return ret; +-} +- +-static int bes2600_op_bt_wakeup(const char *str) +-{ +- int ret = 0; +- unsigned long status = 0; +- +- spin_lock(&bes2600_cdev.status_lock); +- if (!bes2600_cdev.bt_opened) { +- spin_unlock(&bes2600_cdev.status_lock); +- return -EFAULT; +- } +- spin_unlock(&bes2600_cdev.status_lock); +- +- /* wait probe done event */ +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, +- bes2600_bootup_end(), HZ * 8); +- if (status <= 0 || bes2600_chrdev_is_bus_error()) +- return -EFAULT; +- +- bes_devel("bes2600 wakeup bt.\n"); +- ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_ON, SUBSYSTEM_BT_LP, true); +- +- return ret; +-} +- +-static int bes2600_op_bt_sleep(const char *str) +-{ +- int ret = 0; +- unsigned long status = 0; +- +- spin_lock(&bes2600_cdev.status_lock); +- if (!bes2600_cdev.bt_opened) { +- spin_unlock(&bes2600_cdev.status_lock); +- return -EFAULT; +- } +- spin_unlock(&bes2600_cdev.status_lock); +- +- /* wait probe done event */ +- status = wait_event_timeout(bes2600_cdev.probe_done_wq, +- bes2600_bootup_end(), HZ * 8); +- if (status <= 0 || bes2600_chrdev_is_bus_error()) +- return -EFAULT; +- +- bes_devel("bes2600 allow bt sleep.\n"); +- ret = bes2600_chrdev_switch_subsys(GPIO_WAKE_FLAG_BT_LP_OFF, SUBSYSTEM_BT_LP, false); +- +- return ret; +-} +- +-static int bes2600_op_set_wakeup_read_flag(const char *str) +-{ +- bes_devel("%s is called, arg:%s\n", __func__, str); +- spin_lock(&bes2600_cdev.status_lock); +- bes2600_cdev.read_flag = BES_CDEV_READ_WAKEUP_STATE; +- spin_unlock(&bes2600_cdev.status_lock); +- +- return 0; +-} + + #ifdef FW_DOWNLOAD_UART_DAEMON +-int bes2600_load_uevent(char *env[]) +-{ +- return kobject_uevent_env(&bes2600_cdev.device->kobj, KOBJ_CHANGE, env); +-} + #endif + +-static struct bes2600_op_map bes2600_op_map_tab[] ={ +- /*op op_len handler */ +- {"P2P_SET_NOA", 11, bes2600_op_default_handler}, +- {"P2P_SET_PS", 10, bes2600_op_default_handler}, +- {"SET_AP_WPS_P2P_IE", 17, bes2600_op_default_handler}, +- {"LINKSPEED", 9, bes2600_op_default_handler}, +- {"RSSI", 4, bes2600_op_default_handler}, +- {"GETBAND", 7, bes2600_op_default_handler}, +- {"WLS_BATCHING", 12, bes2600_op_default_handler}, +- {"MACADDR", 7, bes2600_op_default_handler}, +- {"RXFILTER-START", 14, bes2600_op_default_handler}, +- {"RXFILTER-STOP", 13, bes2600_op_default_handler}, +- {"RXFILTER-ADD", 12, bes2600_op_default_handler}, +- {"RXFILTER-REMOVE", 15, bes2600_op_default_handler}, +- {"BTCOEXMODE", 10, bes2600_op_default_handler}, +- {"BTCOEXSCAN-START", 16, bes2600_op_default_handler}, +- {"BTCOEXSCAN-STOP", 15, bes2600_op_default_handler}, +- {"SETSUSPENDMODE", 14, bes2600_op_default_handler}, +- {"COUNTRY", 7, bes2600_op_default_handler}, +- {"WIFI_ON", 7, bes2600_op_wifi_bt_on_off}, +- {"WIFI_OFF", 8, bes2600_op_wifi_bt_on_off}, +- {"BT_ON", 5, bes2600_op_wifi_bt_on_off}, +- {"BT_OFF", 6, bes2600_op_wifi_bt_on_off}, +- {"CHANGE_FW_TYPE", 14, bes2600_op_change_fw_type}, +- {"BT_WAKEUP", 9, bes2600_op_bt_wakeup}, +- {"BT_SLEEP", 8, bes2600_op_bt_sleep}, +- {"WAKEUP_STATE", 12, bes2600_op_set_wakeup_read_flag}, +-}; + + static int bes2600_chrdev_check_system_close_internal(void) + { +@@ -644,123 +305,10 @@ static int bes2600_chrdev_check_system_close_internal(void) + && (bes2600_cdev.wifi_opened == false); + } + +-static int bes2600_chrdev_open(struct inode *inode, struct file *filp) +-{ +- if (atomic_read(&bes2600_cdev.num_proc) > 0) { +- wait_event_timeout(bes2600_cdev.open_wq, +- (atomic_read(&bes2600_cdev.num_proc) == 0), +- MAX_SCHEDULE_TIMEOUT); +- } +- +- bes_devel("bes2600 char device is opened\n"); +- atomic_inc(&bes2600_cdev.num_proc); +- +- return 0; +-} +- +-static ssize_t bes2600_chrdev_read(struct file *file, char __user *user_buf, +- size_t count, loff_t *ppos) +-{ +- char buf[64] = {0}; +- unsigned int len; +- long status = 0; +- +- switch (bes2600_cdev.read_flag) { +- case BES_CDEV_READ_WAKEUP_STATE: +- if (bes2600_chrdev_wakeup_by_event_get() > WAKEUP_EVENT_NONE) { +- status = wait_event_timeout(bes2600_cdev.wakeup_reason_wq, +- bes2600_chrdev_wakeup_by_event_get() == WAKEUP_EVENT_NONE, HZ * 2); +- WARN_ON(status <= 0); +- } +- len = sprintf(buf, "wakeup_reason: %u, src_port: %u\n", +- bes2600_cdev.wakeup_state, bes2600_cdev.src_port); +- break; +- default: +- len = sprintf(buf, "dpd_calied:%d wifi_opened:%d bt_opened:%d fw_type:%d\n", +- bes2600_cdev.dpd_calied, +- bes2600_cdev.wifi_opened, +- bes2600_cdev.bt_opened, +- bes2600_cdev.fw_type); +- break; +- } +- +- len = sizeof(buf); +- /* reset read flag */ +- spin_lock(&bes2600_cdev.status_lock); +- bes2600_cdev.read_flag = BES_CDEV_READ_NUM_MAX; +- spin_unlock(&bes2600_cdev.status_lock); +- +- return simple_read_from_buffer(user_buf, count, ppos, buf, len); +-} +- +-static ssize_t bes2600_chrdev_write(struct file *file, +- const char __user *user_buf, size_t count, loff_t *ppos) +-{ +- int i = 0; +- int cmd_num = ARRAY_SIZE(bes2600_op_map_tab); +- int cmd_len = 0; +- int ret = 0; +- char *info[2] = {0}; +- char *buf = NULL; +- +- /* copy content from user space to kernel */ +- /* message format:"ifname:wlanx cmd:xxx arg1 arg2 ..." */ +- buf = kmalloc(count + 1, GFP_KERNEL); +- if (copy_from_user(buf, user_buf, count)) +- return -EFAULT; +- +- /* add terminal character */ +- buf[count] = '\0'; +- +- /* extract comand and interface */ +- if (bes2600_get_cmd_and_ifname(buf, info) != 0) { +- bes_err("%s get command fail, the origin string is %s\n", __func__, buf); +- kfree(buf); +- return -EINVAL; +- } +- +- /* match operation item and execure its handler */ +- cmd_len = strlen(info[1]); +- for (i = 0; i < cmd_num; i++) { +- if (cmd_len < bes2600_op_map_tab[i].op_len) +- continue; +- +- if (strncasecmp(info[1], bes2600_op_map_tab[i].op, bes2600_op_map_tab[i].op_len) == 0) { +- ret = bes2600_op_map_tab[i].handler(buf); +- break; +- } +- } +- +- /* operation item mismatch */ +- if (i == cmd_num) { +- bes_err("cmd(%s) mismatch\n", info[1]); +- } +- +- bes2600_recyle_cmd_and_ifname_mem(info); +- kfree(buf); +- +- return (ret == 0) ? count : ret; +-} + +-static int bes2600_chrdev_release (struct inode *inode, struct file *file) +-{ +- if (atomic_dec_and_test(&bes2600_cdev.num_proc)) { +- wake_up(&bes2600_cdev.open_wq); +- } + +- bes_devel("bes2600 char device is closed\n"); + +- return 0; +-} + +-static struct file_operations bes2600_chardev_fops = +-{ +- .owner = THIS_MODULE, +- .open = bes2600_chrdev_open, +- .read = bes2600_chrdev_read, +- .write = bes2600_chrdev_write, +- .release = bes2600_chrdev_release, +-}; + + #ifdef BES2600_WRITE_DPD_TO_FILE + static int bes2600_chrdev_write_dpd_data_to_file(const char *path, void *buffer, int size) +@@ -1167,12 +715,6 @@ void bes2600_chrdev_update_signal_mode(void) + + static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) + { +- char wifi_state[15]; +- char bt_state[15]; +- char fw_type[15]; +- char *env[] = { wifi_state, bt_state, fw_type, NULL }; +- int ret; +- + if (bes2600_chrdev_is_wifi_opened()) { + bes_devel("system exeception, force wifi down\n"); + +@@ -1189,14 +731,6 @@ static void bes2600_chrdev_wifi_force_close_work(struct work_struct *work) + bes2600_chrdev_do_system_close(bes2600_cdev.sbus_ops, + bes2600_cdev.sbus_priv); + } +- +- /* notify userspace */ +- snprintf(wifi_state, sizeof(wifi_state), "WIFI_OPENED=%d", bes2600_cdev.wifi_opened); +- snprintf(bt_state, sizeof(bt_state), "BT_OPENED=%d", bes2600_cdev.bt_opened); +- snprintf(fw_type, sizeof(fw_type), "FW_TYPE=%d", bes2600_cdev.fw_type); +- ret = kobject_uevent_env(&bes2600_cdev.device->kobj, KOBJ_CHANGE, env); +- if (!ret) +- bes_err("bes2600 notify userspace failed\n"); + } + } + +@@ -1290,46 +824,6 @@ int bes2600_chrdev_wakeup_by_event_get(void) + + int bes2600_chrdev_init(struct sbus_ops *ops) + { +- int ret = 0; +- +- /* allocate devide id */ +- ret = alloc_chrdev_region(&bes2600_cdev.dev_id, 0, 1, "bes2600_chrdev"); +- if (ret < 0){ +- bes_err("bes2600 alloc device id fail\n"); +- ret = -EFAULT; +- goto fail; +- } +- +- /* extract major and minor device id */ +- bes2600_cdev.major = MAJOR(bes2600_cdev.dev_id); +- bes2600_cdev.minor = MINOR(bes2600_cdev.dev_id); +- +- /* add char device and bind operation function */ +- bes2600_cdev.cdev.owner = THIS_MODULE; +- cdev_init(&bes2600_cdev.cdev, &bes2600_chardev_fops); +- ret = cdev_add(&bes2600_cdev.cdev, bes2600_cdev.dev_id, 1); +- if (ret < 0){ +- bes_err("bes2600 char device add fail\n"); +- ret = -EFAULT; +- goto fail1; +- } +- +- /* create class for creating device node */ +- bes2600_cdev.class = class_create("bes2600_chrdev"); +- if (IS_ERR(bes2600_cdev.class)){ +- bes_err("bes2600 char device add fail\n"); +- ret = -EFAULT; +- goto fail2; +- } +- +- /* get char device pointer */ +- bes2600_cdev.device = device_create(bes2600_cdev.class, NULL, bes2600_cdev.dev_id, NULL, "bes2600"); +- if (IS_ERR(bes2600_cdev.device)){ +- bes_err("bes2600 char device create fail\n"); +- ret = -EFAULT; +- goto fail3; +- } +- + /* initialise global variable */ + atomic_set(&bes2600_cdev.num_proc, 0); + init_waitqueue_head(&bes2600_cdev.open_wq); +@@ -1361,15 +855,6 @@ int bes2600_chrdev_init(struct sbus_ops *ops) + bes_devel("%s done\n", __func__); + + return 0; +- +-fail3: +- class_destroy(bes2600_cdev.class); +-fail2: +- cdev_del(&bes2600_cdev.cdev); +-fail1: +- unregister_chrdev_region(bes2600_cdev.dev_id, 1); +-fail: +- return ret; + } + + void bes2600_chrdev_free(void) +@@ -1379,9 +864,5 @@ void bes2600_chrdev_free(void) + bes2600_free_dpd_log_buffer(); + #endif + bes2600_chrdev_free_dpd_data(); +- cdev_del(&bes2600_cdev.cdev); +- unregister_chrdev_region(bes2600_cdev.dev_id, 1); +- device_destroy(bes2600_cdev.class, bes2600_cdev.dev_id); +- class_destroy(bes2600_cdev.class); + bes_devel("%s done\n", __func__); + } +-- +2.53.0 + diff --git a/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch b/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch new file mode 100644 index 000000000..4a0e8005b --- /dev/null +++ b/patches/staging-prep-series-danctnix/0006-bes2600-enable-CONFIG_BES2600_TESTMODE-by-default-fi.patch @@ -0,0 +1,143 @@ +From f1d22ab91dbc0d12064f672300fec5ec0ff220e3 Mon Sep 17 00:00:00 2001 +From: Markus Fritsche +Date: Wed, 22 Apr 2026 14:26:43 +0200 +Subject: [PATCH 6/6] bes2600: enable CONFIG_BES2600_TESTMODE by default + fix + bit-rotted testmode plumbing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The driver implements a mac80211 testmode_cmd operation that dispatches +to a set of vendor commands (GET_TX_POWER_LEVEL, GET_TX_POWER_RANGE, +SET_SNAP_FRAME, TSM_STATS, GET_ROAM_DELAY, GET_STREAM, etc) plus the +BES2600 RF-test path (bes2600_vendor_rf_cmd → firmware +patch_wifi_testMode). The testmode handlers and the .testmode_cmd +binding in struct ieee80211_ops are conditionally compiled under +CONFIG_BES2600_TESTMODE, which previously defaulted to n. + +Flip the Makefile default from n to y so wifi_testmode_cmd.o is +included in the build and the .testmode_cmd op is populated. On the +PineTab2 target kernel (linux-pinetab2 6.19.10-danctnix1, built with +CONFIG_NL80211_TESTMODE=y) this exposes the BES2600 RF-test surface +through the standard nl80211 testmode interface ('iw phy0 ...'). + +This also makes visible two classes of bit-rot that had accumulated +while nobody was building with CONFIG_BES2600_TESTMODE=y: + +1. sta.c contains ~41 calls to bes2600_info() / bes2600_err() / + bes2600_warn() / bes2600_dbg() / bes2600_err_with_cond() - a + legacy log-macro family carrying a BES2600_DBG_* subsystem-id + first argument. Neither the macros nor any of the BES2600_DBG_* + constants are defined anywhere in the tree. The same call pattern + appears under #if defined(BES2600_DETECTION_LOGIC) in hwio.c and + under CONFIG_BES2600_ITP in itp.c, both normally disabled. + + Add minimal shim macros to bes_log.h that rewire the calls onto + the existing bes_info() / bes_err() / bes_warn() / bes_devel() + family (ignoring the subsystem id). Define BES2600_DBG_SBUS, + BES2600_DBG_DOWNLOAD, BES2600_DBG_ITP and BES2600_DBG_TEST_MODE + as 0 constants for documentation / grep. + +2. bes2600_start_stop_tsm(), bes2600_get_tsm_params(), and + bes2600_get_roam_delay() are declared in sta.c with external + linkage but have no prototype in any header. All callers live in + sta.c (inside bes2600_testmode_cmd). With CONFIG_BES2600_TESTMODE + off the compiler never sees them; with it on gcc + -Werror=missing-prototypes breaks the build. + + Mark the three functions static. (Keeping them file-local also + matches their actual usage.) + +Both changes are strictly scoped to make CONFIG_BES2600_TESTMODE=y +buildable; no behavioural change when the flag is off. + +Tested-on: PineTab2 (BES2600WM + RK3566) running linux-pinetab2 +6.19.10-danctnix1-1 with CONFIG_NL80211_TESTMODE=y. Module builds +cleanly, nl80211 testmode interface reachable via 'iw phy0 ...' from +userspace. + +Signed-off-by: Markus Fritsche +--- + drivers/staging/bes2600/Makefile | 2 +- + drivers/staging/bes2600/bes_log.h | 23 +++++++++++++++++++++++ + drivers/staging/bes2600/sta.c | 6 +++--- + 3 files changed, 27 insertions(+), 4 deletions(-) + +diff --git a/drivers/staging/bes2600/Makefile b/drivers/staging/bes2600/Makefile +index 4ea2424..aecb302 100644 +--- a/drivers/staging/bes2600/Makefile ++++ b/drivers/staging/bes2600/Makefile +@@ -2,7 +2,7 @@ KERN_DIR = /lib/modules/$(shell uname -r)/build + # feature option + BES2600 ?= m + +-CONFIG_BES2600_TESTMODE ?= n ++CONFIG_BES2600_TESTMODE ?= y + + CONFIG_BES2600_ENABLE_DEVEL_LOGS ?= n + +diff --git a/drivers/staging/bes2600/bes_log.h b/drivers/staging/bes2600/bes_log.h +index 605cea8..65cf703 100644 +--- a/drivers/staging/bes2600/bes_log.h ++++ b/drivers/staging/bes2600/bes_log.h +@@ -8,3 +8,26 @@ extern struct device *global_dev; + #define bes_info(fmt, ...) dev_info(global_dev, fmt, ##__VA_ARGS__) + #define bes_warn(fmt, ...) dev_warn(global_dev, fmt, ##__VA_ARGS__) + #define bes_err(fmt, ...) dev_err(global_dev, fmt, ##__VA_ARGS__) ++ ++/* ++ * Legacy debug-subsystem-tagged log macros. The per-subsystem filtering ++ * was never implemented in-tree; these shims let code paths gated by ++ * CONFIG_BES2600_TESTMODE / CONFIG_BES2600_ITP / BES2600_DETECTION_LOGIC ++ * build when their conditions are enabled. The first argument is ++ * currently unused; pick one of the BES2600_DBG_* constants below for ++ * documentation. ++ */ ++#define BES2600_DBG_SBUS 0 ++#define BES2600_DBG_DOWNLOAD 0 ++#define BES2600_DBG_ITP 0 ++#define BES2600_DBG_TEST_MODE 0 ++ ++#define bes2600_info(_dbg, fmt, ...) bes_info(fmt, ##__VA_ARGS__) ++#define bes2600_err(_dbg, fmt, ...) bes_err(fmt, ##__VA_ARGS__) ++#define bes2600_warn(_dbg, fmt, ...) bes_warn(fmt, ##__VA_ARGS__) ++#define bes2600_dbg(_dbg, fmt, ...) bes_devel(fmt, ##__VA_ARGS__) ++#define bes2600_err_with_cond(_cond, _dbg, fmt, ...) \ ++ do { \ ++ if (_cond) \ ++ bes_err(fmt, ##__VA_ARGS__); \ ++ } while (0) +diff --git a/drivers/staging/bes2600/sta.c b/drivers/staging/bes2600/sta.c +index ca1c77c..bc6d483 100644 +--- a/drivers/staging/bes2600/sta.c ++++ b/drivers/staging/bes2600/sta.c +@@ -3654,7 +3654,7 @@ static int bes2600_set_power_save(struct ieee80211_hw *hw, + * + * Returns: 0 on success or non zero value on failure + */ +-int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data) ++static int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data) + { + struct bes_msg_start_stop_tsm *start_stop_tsm = + (struct bes_msg_start_stop_tsm *) data; +@@ -3684,7 +3684,7 @@ int bes2600_start_stop_tsm(struct ieee80211_hw *hw, void *data) + * + * Returns: TSM parameters collected + */ +-int bes2600_get_tsm_params(struct ieee80211_hw *hw) ++static int bes2600_get_tsm_params(struct ieee80211_hw *hw) + { + struct bes2600_common *hw_priv = hw->priv; + struct bes_tsm_stats tsm_stats; +@@ -3724,7 +3724,7 @@ int bes2600_get_tsm_params(struct ieee80211_hw *hw) + * + * Returns: Returns the last measured roam delay + */ +-int bes2600_get_roam_delay(struct ieee80211_hw *hw) ++static int bes2600_get_roam_delay(struct ieee80211_hw *hw) + { + struct bes2600_common *hw_priv = hw->priv; + u16 roam_delay = hw_priv->tsm_info.roam_delay / 1000; +-- +2.53.0 +