一一

Blog of Yeyiyi
前天看到了小兔,昨天是小鹿,今天是你
  1. 首页
  2. 未分类
  3. 正文

修一台 Kindle Paperwhite 3 的「电池无效 -22」

2026年10月28日 10点热度 0人点赞 0条评论

修一台 Kindle Paperwhite 3 的「电池无效 -22」# 修一台 Kindle Paperwhite 3 的「电池无效 -22」——从误判硬件到自编译内核

记录时间:2026-10-24 ~ 10-27
设备:Kindle Paperwhite 3(7 代,2015),板型 Muscat WFO,i.MX6SoloLite
固件:原 5.16.2.1.1(已被刷为非原厂内核,is_production=0)
结果:成功启动,问题根治


一、问题是什么

机器长按电源后:

  • 指示灯先绿、后橙色闪烁
  • 屏幕刷新一次,背光点亮
  • 随后停在 Your Kindle needs repair. Repair Code 0 + 底部一行 BATTERY INVALID: -22
  • 无限循环重启

串口抓到的关键日志:

[    5.925502] INFO:BATTERY INVALID: -22
[    6.159269] === BATTERY ID IS INVALID. STOPPING BOOT ===

-22 不是「电量低」,而是 Linux 的 EINVAL(Invalid argument)。它发生在内核 initramfs 阶段——比挂载主系统还早。


二、先搞懂机理,否则全是瞎猜

2.1 校验逻辑

Kindle 的 PMIC 是 MAX77696。内核 max77696-battery.c 里有个函数:

static int wario_check_battery(void)
{
    int temp_delta = 0;
    temp_delta = abs(wario_battery_temp_c - display_temp_c);

    if ((temp_delta < BATT_ID_CHECK_TEMP_DELTA) ||        /* 15℃ */
        (strncmp(system_bootmode, "diags", 5) == 0) ||
        (lab126_board_is(BOARD_ID_WARIO) || lab126_board_is(BOARD_ID_WOODY)) ||
        wario_battery_check_disabled) {
        return 1;
    }
    return 0;
}

放行条件是一个「或」链:温差 < 15℃、或进 diags、或特定板型、或校验被禁用。

return 0 之后,内核做两件事:

if (!wario_battery_valid) {
    LLOG_DEVICE_METRIC(...);
    /* Turn OFF charging */
    rc = max77696_charger_set_mode(MAX77696_CHARGER_MODE_OFF);   /* 关充电! */
}

这就是为什么很多人报 -22 后「充不进电」——不是充电坏了,是内核主动关的。

2.2 两个温度从哪来

  • wario_battery_temp_c:电量计 NTC 测的电池温度,约 27~28℃
  • display_temp_c:屏幕温度,由 max77696-adc.c 采 PMIC 的 ADC 得到

如果屏幕温度读不到,内核会硬写一个默认值:

ADC value out of thermistor range! setting display temp to 75 deg C

75℃ − 28℃ = 47℃ > 15℃ → 校验失败 → -22。

2.3 屏幕 NTC 到底在哪

PW3 显示总成后面有 4 条排线:

排线 作用 含 NTC
display cable EPD 面板本体 ✅ 是
touch cable 电容触摸(I²C) ❌
backlit cable 前光 LED ❌
button key cable 按键 ❌

结论:NTC 在显示排线上,不在触摸、不在背光。

依据:E Ink 把 NTC 定义为面板本体的一部分;触摸层和背光层都是后贴的独立层;固件变量名就叫 display_temp_c,用途是补偿墨水在不同温度下的驱动波形(波形文件名 ..._TC.wrf.gz 里的 TC = Temperature Compensation)。


三、第一轮:我的判断全错了

当时我根据论坛帖子,给出的概率分布是:

嫌疑 我估的概率
屏幕热敏电阻 55~65%
电池侧 NTC / 座子 25~30%
主板 PMIC 10~15%

然后实测把这些全推翻了。

3.1 实测:全部正常

测点 结果
主板电池触点各引脚对地反向压降 正常
屏幕排线上 NTC 阻值 约 10 kΩ,正常
NTC 与排线座联通 正常
排线座相关引脚对地反向压降 正常
电池电压 3991 mV(约 70~75%,不是过放)

四条实测把「屏侧」和「电池侧」全都排除了。

⚠️ 这里有个方法论教训:「反向压降正常」只能证明保护二极管/ESD 结构和对地通路没问题,不能证明信号到达了 PMIC 的 ADC 输入端。 这两件事在万用表层面区分不出来。

3.2 换了个思路:diags 也失败

进 diags 模式后:

BOOTMODE OVERRIDE: DIAGS
[    0.331530] max77696-adc max77696-adc.0: adc conversion timed out
[    0.422881] max77696-adc max77696-adc.0: adc conversion timed out
3.0.35-lab126 #1 PREEMPT Mon Jun 1 23:54:30 PDT 2015

diags 下照样超时。

这一点很关键:wario_battery_valid 是靠内核变量计分的,diags 只影响判决,不影响 ADC 驱动本身。之前所有日志都来自 2023 自制内核(builder@eink-builds),存在「是不是自制内核搞坏了驱动」的合理怀疑。现在换了个 2015-06-01 的内核,依然超时。

⇒ 排除内核 bug,坐实是硬件问题。


四、深入 PMIC:一个被「回读残留」坑掉的过程

4.1 MAX77696 是四从地址的复合芯片

从 GPL 源码 drivers/mfd/max77696-i2c.c 找到:

/* MAX77696 I2C Slave Addresses
 *   Real-Time Clock / Energy Harvester  W 0xD0  R 0xD1
 *   USB Interface Circuit               W 0x6A  R 0x6B
 *   Fuel Gauge                          W 0x68  R 0x69
 *   Power Management / GPIO/ other      W 0x78  R 0x79
 */

换算成 7-bit:

模块 7-bit 地址 实测 probe
RTC 0x68 ✅
UIC 0x35 ✅
Fuel Gauge 0x34 ✅
Power Management 0x3C ✅

在 u-boot 的 bist 里跑 i2c probe,返回 Valid chip addresses: 00 34 35 3C 68 —— 四个子模块全部 ACK,芯片是活的。

4.2 寄存器速查(来自官方源码)

include/max77696_registers.h:

寄存器 地址 关键位
ADCCNTL 0x26 bit4 ADCCONV(转换完成自动清零)、bit3:2 ADCAVG、bit1 ADCREFEN、bit0 ADCEN
ADCDLY 0x27 转换延迟,每步 500 µs
ADCSEL0/1 0x28/0x29 通道选择
ADCCHSEL 0x2A 读结果前选通道
ADCDATAL/H 0x2B/0x2C 结果
ADCICNFG 0x30 bit3:2 IADCMUX、bit1:0 IADC(恒流源档位)

IADC 档位编码:

代码 电流
0x03 ≥50 µA
0x02 ≥10 µA
0x01 ≥5 µA
0x00 <5 µA

4.3 屏幕温度读的是 AIN0,AIN2 是接地噪声参考

adc_disp_gettemp_work() 原文:

max77696_adc_read(MAX77696_ADC_CH_AIN0, &data);      /* 真正的屏幕温度 */

if (lab126_board_is(BOARD_ID_MUSCAT_WFO) || ...) {
    u16 noise = 0x0;
    max77696_adc_read(MAX77696_ADC_CH_AIN2, &noise); /* AIN2 = 接地噪声参考 */
    data = abs(data - noise);                        /* 两者相减 */
}
display_temp_c = lkup_temp_data(data);

这解释了两件事:

  1. 为什么 adc conversion timed out 总是成对出现、间隔约 20 ms —— 一次采样要读 AIN0 和 AIN2 各一次,两次都超时就是两条;
  2. 有两条模拟通道参与,都要查。

4.4 踩坑:pmic rd 的读数根本不可信

在 u-boot 里读寄存器,得到一组诡异数据:

pmic rd 3c 26  →  0x80
pmic rd 3c 27  →  0x80
pmic rd 3c 2a  →  0x80
pmic rd 3c 2b  →  0x80
pmic rd 3c 2c  →  0x80

五个功能完全不同的寄存器,读出同一个值。 真实寄存器中 0x27(转换延迟)、0x2A(通道号)、0x2B/2C(数据)取值范围完全不同,不可能全等。

于是做了个决定性的对照实验:

pmic wr 3c 2a 05      ← 写入 0x05
pmic rd 3c 2a         ← 读回 0x05  ✅
pmic rd 3c 26         ← 读回 0x05  ⚠️
pmic rd 3c 27         ← 读回 0x05  ⚠️
pmic rd 3c 2b         ← 读回 0x05  ⚠️
pmic rd 3c 2c         ← 读回 0x05  ⚠️

全部返回最后写入的值。这是「回读残留」——pmic rd 在 0x3C 上返回的是 I²C 总线上的残留值,不是寄存器真实内容。

教训:u-boot 的 pmic rd 在这个从地址上不可信,基于它得出的所有结论都要作废。 后来改用 i2c md 34 20 10 验证(Fuel Gauge 能读出 14 个不同值),证明块读路径是可靠的,只有 0x3C 的单读路径有问题。


五、突破:恒流源是好的,坏的是内核写寄存器的方式

5.1 决定性实验

在 u-boot 里整字节写入:

pmic wr 3c 30 03     ← ADCICNFG:IADC=0x03(50µA), IADCMUX=0(AIN0)

NTC 两端立刻出现 0.38 V。

算一下:0.38 V ÷ 50 µA = 7600 Ω。用 NTC 的 B 值公式(R25=10k,B=3435)反推,7600 Ω 对应 约 32℃ —— 和室温完全吻合。

这证明了:PMIC 的 50 µA 恒流源完全正常,NTC、排线、座子全部完好。

5.2 但重启后又变回 0 V

现象很明确:bist 里写就有电压,一启动内核就没了。

5.3 根因:读-改-写遇到坏读取

max77696_write_masked() 的实现(include/linux/mfd/max77696.h):

static __always_inline int max77696_write_masked(struct max77696_i2c *i2c,
        u8 addr, u8 mask, u8 val)
{
    rc = max77696_read(i2c, addr, &buf);        /* ← 先读当前值 */
    if (unlikely(rc)) return rc;
    buf = ((buf & (~mask)) | (val & mask));     /* ← 只改目标位 */
    return max77696_write(i2c, addr, buf);      /* ← 整个字节写回 */
}

而 max77696_adc_cfgadc_write() 用的是 reg_set_bit,走的就是这条路径:

rc = max77696_adc_reg_set_bit(me, ADCICNFG, IADC, tmp);   /* 读-改-写 */

因果链:

内核 probe → 读 ADCICNFG(读取不可靠)
    → 读到脏值
    → 读-改-写把整个字节写坏(IADC 变 0,或 IADCMUX 切错)
    → 恒流源关闭 / 电流走错通道
    → NTC 上 0 V
    → ADC 读到 0 → 查表得 75℃
    → 温差 47℃ > 15℃
    → wario_battery_valid = 0
    → STOPPING BOOT

而 ADCCNTL 的位分布注定这个缺陷致命:

bit4 = ADCCONV    bit3:2 = ADCAVG    bit1 = ADCREFEN    bit0 = ADCEN

adcavg_write() 的目标掩码只覆盖 bit3:2,ADCEN 和 ADCREFEN 完全依赖读回来的值来保持。读到脏值 → 写回时 ADCEN 变 0 → ADC 被关掉。

5.4 这解释了全部现象

观察 解释
u-boot 写 0x30=0x03 立刻出电压 u-boot 用整字节直写,不读-改-写
内核一启动恒流源消失 内核走读-改-写,读错就写坏
pmic rd 五个寄存器同值 同一批 I²C 读取不可靠
电量计、充电、背光、LED 全正常 它们不依赖这一路 ADC

六、软件方案的两条路

6.1 路线 A:逆向 recovery-util(最后放弃了)

-22 的报错文本在 initramfs 里的 recovery-util(一个 1,021,768 字节的独立静态 ELF,32-bit ARM)。

反汇编后定位到判定代码:

0x8394:  bl    0xca74       ; gasgauge_battery_id_valid()
0x8398:  subs  r6, r0, #0
0x839c:  beq   0x8408       ; ★ r0==0 才继续启动
0x83a0:  mov   r0, #3
0x83a4:  bl    0xbe98
0x83a8:  mov   r1, r6
0x83ac:  ldr   r0, [pc] → "BATTERY INVALID: %d\n"
0x83b0:  bl    0xc464        ; printf
0x83c4:  ldr   r0, [pc] → "=== BATTERY ID IS INVALID. STOPPING BOOT ===\n"

并确认了返回值约定(0xca74 内部):

cb2c: ldr r3, [sp, #4]      ; 读出的 battery_id_valid
cb30: cmp r3, #0
cb34: bne 0xca90            ; 非 0 → 有效
ca90: mov r0, #0            ; ★ return 0   = 有效
...
cb38: mvn r0, #21           ; ★ return -22 = 无效

-22 正是返回值,被 printf("%d") 打出来。

于是补丁就是一个字节:

指令 机器码(小端)
原 beq 0x8408 19 00 00 **0A**
改 b 0x8408 19 00 00 **EA**

文件偏移 0x39F,0x0A → 0xEA。

6.2 两次失败,因为压缩器用错了

第一次重建后,刷入内核:

Starting kernel ...
(之后无任何输出)

内核自解压阶段就挂了。

排查发现 zImage 尾部有 52 字节的绝对偏移索引表:

a4e33600 = 0x0036E3A4
2c460000 = 0x0000462C      ← gzip 起点
98e33600 = 0x0036E398      ← zImage 总长

重压缩后文件变短了 11,971 字节,偏移表全部失效。

第二次改用「填充到等长」策略,还是失败。直到从官方源码包里翻到答案:

scripts/Makefile.lib 第 200 行:

cmd_gzip = (cat (filter-out FORCE,^) | gzip -n -f -9 > $@)

在编译机上验证:

gzip -n -9 -c img.raw > gz_repro.bin
cmp gz_repro.bin gz_orig.bin
# *** 完全相同 ***

用 gzip -n -9 可以逐字节复现原厂 gzip 流。 而 Python 的 gzip.compress(level=9) 生成的是 3,567,221 字节,比原厂少 11,971——根本不是同一种压缩。

压缩方式 结果长度
原厂 3,579,192
Python gzip level=9 3,567,221(差 -11,971)
GNU gzip -n -9 3,579,192(完全一致) ✅

改用正确的压缩器后,新流只比原流小 1 字节,填充 1 个 0x00 即可。

但刷上去还是 Starting kernel 后无输出。

这次放弃了逆向路线。 根本障碍:改 initramfs 一个字节必须重压缩,而 zImage 自解压器对压缩流有自己的校验逻辑,我无法完全掌握。


七、转向编译内核

7.1 源码从哪来

Kindle 内核是 Linux(GPLv2),Amazon 必须开源。官方 GPL 包:

Kindle_src_5.15.1_3889320042.tar.gz   322 MB
└── gplrelease/linux-3.0.35.tar.gz    116 MB   ← 内核源码

包里还有 BUILD_HOW-TO.txt,明确写了:

Kindle Paperwhite (6th & 7th generation)、Kindle Voyage (7th generation)、Kindle (7th generation):
imx60_wario_defconfig

PW3 正是 7th generation。

7.2 编译环境搭建

在 Ubuntu 18.04(12 核、11G、420G 空闲)上:

sudo apt install -y bison flex libncurses-dev libelf-dev gawk \
    git diffstat texinfo chrpath socat libssl-dev u-boot-tools
sudo apt install -y gcc-arm-linux-gnueabi binutils-arm-linux-gnueabi

工具链踩坑记录:

尝试 结果
koxtoolchain 2025.05 预编译 ❌ GLIBC_2.32/2.33/2.34 not found(18.04 只有 2.27)
koxtoolchain 2021.12 ❌ 下载失败
apt 的 gcc-arm-linux-gnueabi 7.5.0 ✅ 可用

apt 版本的前缀 arm-linux-gnueabi- 正好和 Amazon 官方要求一致。

7.3 三个编译错误

① compiler-gcc7.h: No such file or directory

3.0.35 内核只带 compiler-gcc3.h 和 compiler-gcc4.h,而 gcc 7.5 需要 gcc7 的头:

cd include/linux
for v in 5 6 7 8 9 10 11 12 13 14; do
    ln -sf compiler-gcc4.h compiler-gcc${v}.h
done

② timeconst.pl 的 defined(@array)

Can't use 'defined(@array)' (Maybe you should just omit the defined()?)
at kernel/timeconst.pl line 373.

新版 Perl 禁用了 defined(@array),改掉:

- if (!defined(@val)) {
+ if (!@val) {

③ 编译成功,但产物只有 2.28 MB

原厂 uImage 是 3.43 MB。差的那 1.15 MB 是 initramfs。

CONFIG_INITRAMFS_SOURCE=""

空的。 Amazon 的 GPL 包只给代码,不给 initramfs 里的二进制(recovery-util、kinit、.ko 都是闭源产物)。

7.4 initramfs 怎么补——两次试错

第一次:直接指向解包目录

CONFIG_INITRAMFS_SOURCE="/tmp/imx/root"

产物 3.42 MB,结构正确,刷入后:

[0.408721] max77696-adc max77696-adc.0: adc conversion timed out
(然后循环重启)

第二次:用源码包的 initramfs.list

生成清单指向解包目录,产物 3.37 MB,刷入后:

[0.551309] FAT-fs (loop1): bogus number of reserved sectors
[0.573498] ERROR:/dev/loop1:Invalid argument(22)
[0.576901] ERROR:find_file: Failed to open /mnt/wfm/waveform_to_use: error 2
[0.576915] ERROR:insmod(/lib/modules/mxc_epdc_eink.ko): open(2) error: No such file or directory
[0.577494] INFO:Rebooting ...

找到根因:mxc_epdc_eink.ko 没有被带进去。

而 Amazon 自带的 initramfs.list 本身就不完整——它只列了 mxc_epdc_fb.ko,漏了 mxc_epdc_eink.ko(11,924 字节,在原厂 cpio 里是有的):

# eink driver
file /lib/modules/mxc_epdc_fb.ko /initrd/initramfs/lib/mxc_epdc_fb.ko 0755 0 0

7.5 正确的做法:整份原厂 cpio 嵌进去

CONFIG_INITRAMFS_SOURCE="/tmp/orig_initramfs.cpio"

104 个条目一个不少。

结果:framework:started:time=80640 —— 系统起来了。


八、最后一个坑:补丁放错位置

v3 能启动,但日志里有:

[  29.702230] max77696-adc max77696-adc.0: adc conversion timed out
[  60.661781] ...
[  60.691811] ...
[ 120.821775] ...
(每 60 秒一轮,持续不断)

原因:我最早把补丁加在了 wario_check_battery() 里:

static int wario_check_battery(void)
{
    int temp_delta = 0;
    display_temp_c = wario_battery_temp_c;   /* ← 我的补丁在这里 */
    temp_delta = abs(wario_battery_temp_c - display_temp_c);

但这个函数只在启动时调用一次。 而 display_temp_c 每 60 秒会被 ADC 驱动覆盖:

adc_disp_gettemp_work()   ← DISP_ADC_TEMP_THRESHOLD = 60000 ms
    display_temp_c = lkup_temp_data(data);   ← ADC 坏 → data=0 → 返回 75℃

所以:启动时补丁生效(能过校验),运行 60 秒后温度又变回 75℃,波形温补按 75℃ 走。

修正:补丁移到数据源头

static void adc_disp_gettemp_work(struct work_struct *work)
{
    /* PATCH: 屏幕 NTC 通路故障,ADC 每次转换都超时。
     * 原逻辑: 读 AIN0/AIN2 -> lkup_temp_data(0) -> 恒返回 75C
     * 改法  : 直接采用电池温度作为屏幕温度近似值
     */
    extern int wario_battery_temp_c;
    display_temp_c = wario_battery_temp_c;

    schedule_delayed_work(&adc_disp_temp_work, msecs_to_jiffies(DISP_ADC_TEMP_THRESHOLD));
    return;
}

同时把 wario_check_battery() 恢复为原厂实现——理由是:

  • display_temp_c 现在由 ADC 驱动持续维护为合理值,源头已正确;
  • wario_check_battery() 只是消费者,自然通过校验:abs(27−28) = 1 < 15;
  • 如果在消费者端也改,反而会掩盖问题:将来 ADC 修好,display_temp_c 会变成真实屏幕温度,
    而那个赋值会让它永远等同电池温度,修正就白做了。

九、最终结果对比

项目 修之前 v3(错误位置) v5(最终)
BATTERY INVALID: -22 ❌ 阻断启动 ✅ 消失 ✅ 消失
out of thermistor range ❌ 75℃ ❌ 仍有 ✅ 消失
Unknown waveform mode → MODE_07 — ❌ 有 ✅ 消失
Failed to load fw! (err -2) — ❌ 有 ✅ 消失
FAT-fs (loop1): bogus reserved sectors — ❌ 出现 2 次 ✅ 消失
显示就绪时间 — 27.4 秒 ✅ 12.5 秒
系统启动完成 永不 80.6 秒 ✅ 60.9 秒
ADC timeout 日志 每 60 秒 每 60 秒 ×6 ⚠️ 仅 1 次(无害)

一个意外的连带修复

「未知波形模式」确实是温度引起的 —— 这个推断被证实了。

温度输入从 75℃ 修正到约 28℃ 后,波形加载、模式识别、FAT 挂载全部自愈。这说明错误的温度值会级联影响整条波形处理链路。


十、这一路学到的东西

1. 错误码不是错误原因

-22 是 EINVAL,但真正的原因是温差校验失败。看到错误码就去搜「EINVAL 怎么修」会走偏。

2. 万用表能力有边界

「反向压降正常」只证明保护结构和对地通路没问题,不能证明信号到达了芯片内部。这两件事在万用表层面无法区分。

3. 工具的读数可能是假的

pmic rd 返回「回读残留」——五个不同寄存器读出同一个值(最后写入的值)。

识别方法:读一个内容必然不同的寄存器做对照。 如果它也返回同值,说明读取不可信。

4. 「整字节写」和「读-改-写」是两种完全不同的操作

一个在坏读取下正常工作,另一个会把整字节写坏。在 I²C 不可靠的环境里,任何 read-modify-write 都是定时炸弹。

5. 压缩参数必须精确匹配

Python 的 gzip 和 GNU gzip -9 不是同一种压缩。前者 3,567,221,后者 3,579,192,差 11,971 字节。

在需要精确重建的场合(如内核镜像),必须用原始工具和原始参数。

6. 官方源码包可能故意不完整

Amazon 的 GPL 包只给代码,不给二进制。而它自带的 initramfs.list 也是不完整的(漏了 mxc_epdc_eink.ko)。

最可靠的做法:从自己设备的原厂镜像里提取完整 initramfs,整个嵌回去。

7. 补丁要打在数据源头,不是消费者

wario_check_battery() 是消费者,adc_disp_gettemp_work() 是生产者。

改消费者只能骗过一次校验;改生产者才能让整个系统都拿到正确值。

8. 上下文决定结论

我一开始基于论坛帖子估出「PMIC 概率 10~15%」,结果实测把屏侧和电池侧全部排除,概率反转成 85%。

论坛数据是别人的机器,自己的实测才是证据。


附:最终交付物

文件 说明
uImage_v5 最终内核(3.41 MB),含完整原厂 initramfs + 温度源头补丁
uImage.orig 原厂内核,回滚用
编译环境 Ubuntu 18.04 + gcc-arm-linux-gnueabi 7.5.0 + 官方 GPL 5.15.1 源码

刷入

fastboot flash kernel uImage_v5

验证要点

日志里应当看到:

  • ❌ 没有 BATTERY INVALID
  • ❌ 没有 out of thermistor range
  • ❌ 没有 Unknown waveform mode
  • ✅ display:started 在 15 秒内
  • ✅ framework:started 在 70 秒内

后记

这台机器的 ADC 硬件问题没有修——max77696-adc 那一路仍然超时,日志里偶尔还会出现 adc conversion timed out。

但它的影响被完全隔离了:屏幕温度不再从 ADC 读取,改由电池温度近似。

代价是:波形温度补偿用的是「电池温度」而非「真实屏幕温度」。充电时电池可能比屏幕高 10℃,在 TRT 温度分档的粒度内通常可接受,但不是零误差。

要完全正确,只能换 PMIC。 而那是 BGA 封装,DIY 性价比为零。

对一个已经报废边缘的 2015 年设备来说,「能读、显示正常、不报错」已经是好结局了。

标签: 暂无
最后更新:2026年10月28日

yly

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

归档

  • 2026 年 10 月
  • 2026 年 7 月
  • 2024 年 11 月
  • 2023 年 9 月
  • 2023 年 7 月

分类

  • 未分类

COPYRIGHT © 2023 一一. ALL RIGHTS RESERVED.

Theme Kratos Made By Seaton Jiang