feat(svc_power): 升级写保护(卡根r3proii.upt存在+非空+可读+size>0, 失败不写mtd5/不重启) + dac status读板载audio.volume真实0-100(弃amixer dummy) (agent-163)

This commit is contained in:
MeowOS committed 2026-08-31 00:18:50 +08:00
1 parent 07e621e03b
commit b12404a986
3 files changed
+99 -58

No files matched your search

Binary file not shown.
+99 -58
View File
@@ -54,16 +54,22 @@
#define BATT_CAP "/sys/class/power_supply/battery/capacity"
#define BATT_STATUS "/sys/class/power_supply/battery/status"
#define BATT_VOLT "/sys/class/power_supply/battery/voltage_now"
#define DAC_NUMID "amixer -c 0 cget numid=%d 2>/dev/null"
#define UPGRADE_FW "/usr/data/mnt/sd_0/r3proii.upt" /* 卡根升级固件(写 mtd5 前完整性校验) */
/* 音量语义(与 launcher MEOW_VOL_DEFAULT/MEOW_VOL_MAX_DEFAULT、SDK MEOW_UI_VOL_* 一致):
* audio.volume 默认 60(写 DAC 映射值 0-100);audio.volume_max 默认 100(软上限 clamp)。 */
#ifndef MEOW_VOL_DEFAULT
#define MEOW_VOL_DEFAULT 60
#endif
#ifndef MEOW_VOL_MAX_DEFAULT
#define MEOW_VOL_MAX_DEFAULT 100
#endif
#define LINUX_REBOOT_MAGIC1 0xfee1dead
#define LINUX_REBOOT_MAGIC2 672274793 /* 0x28121969 */
#define LINUX_REBOOT_CMD_RESTART 0x01234567
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
#define SV_PIPE_MAX 4096 /* popen_read_tmo 上限 */
#define SV_TIMEOUT_MS 1500 /* popen 子命令读超时 */
static const char *g_sock = "/usr/data/meow_power.sock";
/* ---------------- 极简日志(stderr;svcd supervisor 捕获) ---------------- */
@@ -179,39 +185,68 @@ static int settings_set_int(const char *key, int val)
return 0;
}
/* ---------------- popen 限时读(kill 子进程防挂) ---------------- */
static char *popen_read_tmo(int tmo_ms, const char *cmd)
/* 读 settings.conf 某 int 键:兼容落盘 "key = value"(带空格/多空格),'=' 切分、key 去首尾空白精确匹配
* (避免 audio.volume 误配 audio.volume_max)。打开失败/键缺失/解析失败 → def。
* 与 launcher 读循环、SDK meow_ui_vol.c meow_ui_vol_read 同款解析。 */
static int settings_get_int_trim(const char *key, int def)
{
int p[2];
if (pipe(p) < 0) return NULL;
pid_t pid = fork();
if (pid < 0) { close(p[0]); close(p[1]); return NULL; }
if (pid == 0) {
dup2(p[1], 1);
close(p[0]); close(p[1]);
execl("/bin/sh", "sh", "-c", cmd, (char *)0);
_exit(127);
FILE *f = fopen(SETTINGS_FILE, "r");
if (!f) return def;
size_t kl = strlen(key);
char line[160];
char *found = NULL;
while (fgets(line, sizeof line, f)) {
char *eq = strchr(line, '=');
if (!eq) continue; /* 非 key=value 行(注释/空行)跳过 */
char *k = line;
while (*k == ' ' || *k == '\t') k++; /* key 左去空白 */
long n = (long)(eq - k);
while (n > 0 && (k[n - 1] == ' ' || k[n - 1] == '\t')) n--; /* key 右去空白 */
if ((size_t)n != kl || strncmp(k, key, kl) != 0) continue; /* key 不精确匹配 */
found = eq + 1; /* 命中所求键 */
break;
}
close(p[1]);
fcntl(p[0], F_SETFL, fcntl(p[0], F_GETFL, 0) | O_NONBLOCK);
char *buf = malloc(SV_PIPE_MAX);
if (!buf) { close(p[0]); waitpid(pid, NULL, 0); return NULL; }
size_t off = 0;
int remain = tmo_ms;
while (remain > 0 && off < SV_PIPE_MAX - 1) {
struct pollfd pf = { p[0], POLLIN, 0 };
int r = poll(&pf, 1, remain);
if (r < 0) { if (errno == EINTR) continue; break; }
if (r == 0) break; /* 超时 */
ssize_t rd = read(p[0], buf + off, SV_PIPE_MAX - 1 - off);
if (rd == 0) break; /* EOF(子进程退出/关写端) */
if (rd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; break; }
off += (size_t)rd;
fclose(f);
if (!found) return def;
while (*found == ' ' || *found == '\t') found++; /* value 左去空白;atoi 天然停于非数字 */
return atoi(found);
}
/* ---------------- 升级写保护(MeowOS 侧;固件只完整性校验,不签名) ----------------
* upgrade 信号(CLI 与 IPC POWER_UPGRADE 同路径)触发写 mtd5 前先校验卡根升级固件
* r3proii.upt(TF 卡挂载点 /usr/data/mnt/sd_0):
* 1. 存在(access F_OK)——无文件不写 mtd5;
* 2. 可读(access R_OK);
* 3. 常规文件 + 非空 + size>0(stat)——防 0 字节/损坏。
* 校验失败 → 返回非 MEOW_OK + why 提示;调用方绝不写 mtd5、不 reboot。
* 待补(二期):期望 md5/hash 校验——经 IPC/配置传期望值,或读卡上 MeowOS/config/ 固件 fingerprint;
* 本批只完整性(防"无文件/0 字节/损坏")。**固件不签名**(海贝官方 r3proii.upt 无签名,签名会挡自刷)。 */
static int upgrade_fw_check(char *why, int cap)
{
const char *path = UPGRADE_FW;
if (access(path, F_OK) < 0) {
svc_log("upgrade fw missing: %s (%s)", path, strerror(errno));
snprintf(why, cap, "卡上无升级文件 %s", path);
return MEOW_ERR_NOENT;
}
close(p[0]);
waitpid(pid, NULL, 0);
buf[off] = 0;
return buf;
if (access(path, R_OK) < 0) {
svc_log("upgrade fw unreadable: %s (%s)", path, strerror(errno));
snprintf(why, cap, "升级文件不可读 %s", path);
return MEOW_ERR_IO;
}
struct stat st;
if (stat(path, &st) < 0) {
svc_log("upgrade fw stat fail: %s (%s)", path, strerror(errno));
snprintf(why, cap, "升级文件状态读取失败 %s", path);
return MEOW_ERR_IO;
}
if (!S_ISREG(st.st_mode) || st.st_size <= 0) {
svc_log("upgrade fw invalid: %s size=%lld", path, (long long)st.st_size);
snprintf(why, cap, "升级文件为空或损坏 %s", path);
return MEOW_ERR_IO;
}
svc_log("upgrade fw ok: %s size=%lld", path, (long long)st.st_size);
return MEOW_OK;
}
/* 前置声明:CLI 用法串(cli_run 用到)。 */
@@ -349,28 +384,20 @@ static int screen_off(void)
/* ---------------- DAC(CS43198) ---------------- */
/* 原机 cs43198 驱动 pwr_gpio=-1:无上电/下电控制点(sysfs/amixer),on/off 不支持。
* status 仅报 amixer numid=1/2(L/R)当前音量上报值。 */
* status 报**真实音量**:读板载 /usr/data/meow/settings.conf 的 audio.volume(meow_dac_vol_write
* 写入映射值 0-100),按 audio.volume_max clamp(与 launcher vol_clamp / SDK meow_ui_vol_clamp 同口径)。
* 原 amixer -c 0 cget numid=1/2 为驱动 dummy 恒 0(不可靠),弃用——不再走 amixer 虚拟上报。 */
static int dac_status(char *out, int cap)
{
char l[48] = "?", r[48] = "?";
char *o1 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=1 2>/dev/null");
if (o1) {
char *p = strstr(o1, ": values=");
if (p) snprintf(l, sizeof l, "%.40s", p + 9);
free(o1);
}
char *o2 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=2 2>/dev/null");
if (o2) {
char *p = strstr(o2, ": values=");
if (p) snprintf(r, sizeof r, "%.40s", p + 9);
free(o2);
}
out[0] = 0;
cat_b(out, cap, "dac=cs43198 L=");
cat_b(out, cap, l);
cat_b(out, cap, " R=");
cat_b(out, cap, r);
cat_b(out, cap, " powerctl=unsupported(no_gpio)");
int vol = settings_get_int_trim("audio.volume", MEOW_VOL_DEFAULT);
int vmax = settings_get_int_trim("audio.volume_max", MEOW_VOL_MAX_DEFAULT);
if (vol < 0) vol = 0; /* 硬下限 0 */
if (vol > 100) vol = 100; /* 硬上限 100(0-100 口径) */
if (vmax < 0) vmax = 0; /* 异常上限兜底:不进负值 */
if (vol > vmax) vol = vmax; /* 尊重 audio.volume_max 软上限 */
/* 左右同值(单个 DAC 声道容量;L=R=vol%);settings 读不到 → 默认 MEOW_VOL_DEFAULT(60) 即真实默认。 */
snprintf(out, cap, "dac=cs43198 vol=%d%% L=R", vol);
svc_log("dac status: audio.volume=%d (volume_max=%d)", vol, vmax);
return 0;
}
@@ -405,10 +432,18 @@ static int execute_action(const m_power_action_t *a, m_power_status_t *st)
snprintf(st->msg, sizeof st->msg, "reboot accepted (boot=meow)");
return 1;
case POWER_UPGRADE:
sync();
st->code = MEOW_OK;
snprintf(st->msg, sizeof st->msg, "upgrade accepted");
return 1;
{ /* 写 mtd5 前先校验卡上升级固件(升级写保护);校验失败→非 OK、绝不写 mtd5/不 reboot。 */
char why[64];
int rc = upgrade_fw_check(why, sizeof why);
if (rc != MEOW_OK) {
st->code = rc;
snprintf(st->msg, sizeof st->msg, "upgrade rejected: %s", why);
return 0; /* 已填 st;调用方直接应答非 OK(不触发 run_system_action) */
}
sync();
st->code = MEOW_OK;
snprintf(st->msg, sizeof st->msg, "upgrade accepted");
return 1; }
case POWER_BACK_HIBY:
write_boot_default(1);
sync();
@@ -659,6 +694,12 @@ static int cli_run(int n, char **v)
return 0;
}
if (!strcmp(cmd, "upgrade")) {
char why[64];
int rc = upgrade_fw_check(why, sizeof why);
if (rc != MEOW_OK) {
fprintf(stderr, "upgrade aborted: %s (firmware NOT written to mtd5)\n", why);
return 1;
}
enter_upgrade();
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
return 0;
Binary file not shown.