Files
aic8800d80/tests/issue119-8820/test_loader.py
T
Shen Mintao c79f1b9fec fix(legacy-mcu1): preserve Bluetooth patches for product 0x8820
Keep the product-specific syscfg writes and restore all patch uploads, including patch configuration. Derive the syscfg condition from the current product readback without retaining a loader flag.

Update regression checks for full patch uploads on both products and syscfg write failures, and document the reported hardware results and remaining validation.
2026-10-28 20:51:06 +08:00

144 lines
6.0 KiB
Python

#!/usr/bin/env python3
"""Exercise extracted loader paths with mocked USB requests, without hardware."""
from pathlib import Path
import os
import subprocess
import tempfile
ROOT = Path(__file__).resolve().parents[2]
def block(source, signature):
start = source.index(signature)
brace = source.index("{", start)
end, depth = brace + 1, 1
while depth:
depth += (source[end] == "{") - (source[end] == "}")
end += 1
return source[start:end]
loader = (ROOT / "drivers/aic8800/aic_load_fw/aic_compat_8800d80.c").read_text()
header = (ROOT / "drivers/aic8800/aic_load_fw/aic_compat_8800d80.h").read_text()
header = "\n".join(line for line in header.splitlines() if not line.startswith("#include"))
config = block(loader, "int system_config_8800d80(")
normal = block(loader, "if(testmode == FW_NORMAL_MODE)")
connect = (ROOT / "drivers/aic8800/aic8800_fdrv/rwnx_main.c").read_text()
guard = block(connect[connect.index("static int rwnx_cfg80211_connect("):],
"if((int)atomic_read(&rwnx_vif->drv_conn_state) == (int)RWNX_DRV_STATUS_DISCONNECTING")
prelude = r'''
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <errno.h>
typedef uint32_t u32;
typedef uint8_t u8;
#define printk(...) ((void)0)
#define AICWFDBG(...) ((void)0)
#define CHIP_REV_U01 1
#define CHIP_REV_U02 3
#define CHIP_REV_U03 7
#define FW_NORMAL_MODE 0
#define HOST_START_APP_AUTO 0
struct aic_usb_dev {
u32 id, cache;
int syscfg_writes, syscfg_masks, patches, fmacs, starts;
};
struct dbg_mem_read_cfm { u32 memdata; };
struct aicbt_patch_info_t { u32 addr_adid, addr_patch; };
static u8 chip_id, chip_mcu_id;
static int testmode = FW_NORMAL_MODE, fail_read, fail_write, fail_mask;
static u32 fail_write_addr;
static u32 syscfg_tbl_8800d80[0][2], syscfg_tbl_masked_8800d80[0][3];
static int rwnx_send_dbg_mem_read_req(struct aic_usb_dev *dev, u32 addr,
struct dbg_mem_read_cfm *cfm) {
if (fail_read) return -EIO;
cfm->memdata = addr == 0x40500000 ? dev->id : dev->cache; return 0;
}
static int rwnx_send_dbg_mem_write_req(struct aic_usb_dev *dev, u32 addr, u32 val) {
if (fail_write && (!fail_write_addr || addr == fail_write_addr)) return -EIO;
if (addr == 0x40100020) dev->cache = val;
if (addr == 0x40500010) { assert(val == 2); dev->syscfg_writes++; }
return 0;
}
static int rwnx_send_dbg_mem_mask_write_req(struct aic_usb_dev *dev, u32 addr, u32 mask, u32 val) {
assert(addr == 0x40506024 && mask == 0xff && val == 0xdf);
if (fail_mask) return -EIO;
dev->syscfg_masks++; return 0;
}
static int rwnx_plat_bin_fw_upload_android(struct aic_usb_dev *dev, u32 addr, const char *name) {
if (name[0] == 'f' && name[1] == 'm') {
assert(addr == 0x120000); dev->fmacs++;
} else { dev->patches++; }
return 0;
}
static int aicbt_ext_patch_data_load(struct aic_usb_dev *dev, struct aicbt_patch_info_t *info, const char *name) {
dev->patches++; return 0;
}
static int aicbt_patch_table_load(struct aic_usb_dev *dev, void *head) {
dev->patches++; return 0;
}
static int rwnx_send_dbg_start_app_req(struct aic_usb_dev *dev, u32 addr, int mode) {
assert(addr == 0x120000); dev->starts++; return 0;
}
'''
normal_wrapper = r'''
int aicwf_patch_config_8800d80(struct aic_usb_dev *dev) { dev->patches++; return 0; }
static int load_normal(struct aic_usb_dev *usb_dev) {
struct aicbt_patch_info_t patch_info = {0};
void *head = 0;
'''
busy_wrapper = r'''
return 0;
}
enum { RWNX_DRV_STATUS_DISCONNECTED, RWNX_DRV_STATUS_CONNECTING,
RWNX_DRV_STATUS_DISCONNECTING };
struct vif { int drv_conn_state; };
#define atomic_read(p) (*(p))
static void rwnx_set_conn_state(struct vif *vif, int *state, int val) { *state = val; }
static int busy(struct vif *rwnx_vif) {
'''
checks = r'''
return 0;
}
int main(void) {
struct aic_usb_dev m80 = {.id = 0x00078820}, d80 = {.id = 0x00078800};
/* Both products need the full patch layer; only 0x8820 gets extra syscfg. */
assert(system_config_8800d80(&m80) == 0);
assert(system_config_8800d80(&d80) == 0);
assert(load_normal(&m80) == 0 && m80.patches == 5 && m80.fmacs == 1 && m80.starts == 1);
assert(load_normal(&d80) == 0 && d80.patches == 5 && d80.fmacs == 1 && d80.starts == 1);
assert(m80.syscfg_writes == 1 && m80.syscfg_masks == 1 && (m80.cache & 1));
assert(d80.syscfg_writes == 0 && d80.syscfg_masks == 0 && (d80.cache & 1));
/* Re-read the product on reprobe in both directions. */
m80.id = 0x00078800; m80.patches = m80.fmacs = m80.starts = 0;
assert(system_config_8800d80(&m80) == 0);
assert(load_normal(&m80) == 0 && m80.patches == 5 && m80.fmacs == 1 && m80.starts == 1);
assert(m80.syscfg_writes == 1 && m80.syscfg_masks == 1);
d80.id = 0x00078820; d80.patches = d80.fmacs = d80.starts = 0;
assert(system_config_8800d80(&d80) == 0);
assert(load_normal(&d80) == 0 && d80.patches == 5 && d80.fmacs == 1 && d80.starts == 1);
assert(d80.syscfg_writes == 1 && d80.syscfg_masks == 1);
fail_read = 1; assert(system_config_8800d80(&d80) == -EIO);
fail_read = 0; fail_write = 1; assert(system_config_8800d80(&d80) == -EIO);
fail_write_addr = 0x40500010;
assert(system_config_8800d80(&d80) == -EIO);
fail_write = 0; fail_mask = 1;
assert(system_config_8800d80(&d80) == -EIO);
for (int state = RWNX_DRV_STATUS_CONNECTING; state <= RWNX_DRV_STATUS_DISCONNECTING; state++) {
struct vif vif = {.drv_conn_state = state};
assert(busy(&vif) == -EBUSY && vif.drv_conn_state == state);
}
return 0;
}
'''
with tempfile.TemporaryDirectory(prefix="aic-8820-test-") as temp:
c_file, binary = Path(temp) / "loader.c", Path(temp) / "loader"
c_file.write_text(prelude + header + config + normal_wrapper + normal +
busy_wrapper + guard + checks)
subprocess.run([os.environ.get("CC", "cc"), "-std=gnu11", "-o", str(binary),
str(c_file)], check=True)
subprocess.run([str(binary)], check=True)
print("PASS: full patch uploads for both products, per-probe syscfg, MCU1 cache fix, write errors, busy connect state")