feat(svc_power): 升级写保护(卡根r3proii.upt存在+非空+可读+size>0, 失败不写mtd5/不重启) + dac status读板载audio.volume真实0-100(弃amixer dummy) (agent-163)
This commit is contained in:
1 parent
07e621e03b
commit
b12404a986
3 files changed
+99
-58
No files matched your search
Binary file not shown.
@@ -54,16 +54,22 @@
|
|||||||
#define BATT_CAP "/sys/class/power_supply/battery/capacity"
|
#define BATT_CAP "/sys/class/power_supply/battery/capacity"
|
||||||
#define BATT_STATUS "/sys/class/power_supply/battery/status"
|
#define BATT_STATUS "/sys/class/power_supply/battery/status"
|
||||||
#define BATT_VOLT "/sys/class/power_supply/battery/voltage_now"
|
#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_MAGIC1 0xfee1dead
|
||||||
#define LINUX_REBOOT_MAGIC2 672274793 /* 0x28121969 */
|
#define LINUX_REBOOT_MAGIC2 672274793 /* 0x28121969 */
|
||||||
#define LINUX_REBOOT_CMD_RESTART 0x01234567
|
#define LINUX_REBOOT_CMD_RESTART 0x01234567
|
||||||
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
|
#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";
|
static const char *g_sock = "/usr/data/meow_power.sock";
|
||||||
|
|
||||||
/* ---------------- 极简日志(stderr;svcd supervisor 捕获) ---------------- */
|
/* ---------------- 极简日志(stderr;svcd supervisor 捕获) ---------------- */
|
||||||
@@ -179,39 +185,68 @@ static int settings_set_int(const char *key, int val)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------- popen 限时读(kill 子进程防挂) ---------------- */
|
/* 读 settings.conf 某 int 键:兼容落盘 "key = value"(带空格/多空格),'=' 切分、key 去首尾空白精确匹配
|
||||||
static char *popen_read_tmo(int tmo_ms, const char *cmd)
|
* (避免 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];
|
FILE *f = fopen(SETTINGS_FILE, "r");
|
||||||
if (pipe(p) < 0) return NULL;
|
if (!f) return def;
|
||||||
pid_t pid = fork();
|
size_t kl = strlen(key);
|
||||||
if (pid < 0) { close(p[0]); close(p[1]); return NULL; }
|
char line[160];
|
||||||
if (pid == 0) {
|
char *found = NULL;
|
||||||
dup2(p[1], 1);
|
while (fgets(line, sizeof line, f)) {
|
||||||
close(p[0]); close(p[1]);
|
char *eq = strchr(line, '=');
|
||||||
execl("/bin/sh", "sh", "-c", cmd, (char *)0);
|
if (!eq) continue; /* 非 key=value 行(注释/空行)跳过 */
|
||||||
_exit(127);
|
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]);
|
fclose(f);
|
||||||
fcntl(p[0], F_SETFL, fcntl(p[0], F_GETFL, 0) | O_NONBLOCK);
|
if (!found) return def;
|
||||||
char *buf = malloc(SV_PIPE_MAX);
|
while (*found == ' ' || *found == '\t') found++; /* value 左去空白;atoi 天然停于非数字 */
|
||||||
if (!buf) { close(p[0]); waitpid(pid, NULL, 0); return NULL; }
|
return atoi(found);
|
||||||
size_t off = 0;
|
}
|
||||||
int remain = tmo_ms;
|
|
||||||
while (remain > 0 && off < SV_PIPE_MAX - 1) {
|
/* ---------------- 升级写保护(MeowOS 侧;固件只完整性校验,不签名) ----------------
|
||||||
struct pollfd pf = { p[0], POLLIN, 0 };
|
* upgrade 信号(CLI 与 IPC POWER_UPGRADE 同路径)触发写 mtd5 前先校验卡根升级固件
|
||||||
int r = poll(&pf, 1, remain);
|
* r3proii.upt(TF 卡挂载点 /usr/data/mnt/sd_0):
|
||||||
if (r < 0) { if (errno == EINTR) continue; break; }
|
* 1. 存在(access F_OK)——无文件不写 mtd5;
|
||||||
if (r == 0) break; /* 超时 */
|
* 2. 可读(access R_OK);
|
||||||
ssize_t rd = read(p[0], buf + off, SV_PIPE_MAX - 1 - off);
|
* 3. 常规文件 + 非空 + size>0(stat)——防 0 字节/损坏。
|
||||||
if (rd == 0) break; /* EOF(子进程退出/关写端) */
|
* 校验失败 → 返回非 MEOW_OK + why 提示;调用方绝不写 mtd5、不 reboot。
|
||||||
if (rd < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) continue; break; }
|
* 待补(二期):期望 md5/hash 校验——经 IPC/配置传期望值,或读卡上 MeowOS/config/ 固件 fingerprint;
|
||||||
off += (size_t)rd;
|
* 本批只完整性(防"无文件/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]);
|
if (access(path, R_OK) < 0) {
|
||||||
waitpid(pid, NULL, 0);
|
svc_log("upgrade fw unreadable: %s (%s)", path, strerror(errno));
|
||||||
buf[off] = 0;
|
snprintf(why, cap, "升级文件不可读 %s", path);
|
||||||
return buf;
|
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 用到)。 */
|
/* 前置声明:CLI 用法串(cli_run 用到)。 */
|
||||||
@@ -349,28 +384,20 @@ static int screen_off(void)
|
|||||||
|
|
||||||
/* ---------------- DAC(CS43198) ---------------- */
|
/* ---------------- DAC(CS43198) ---------------- */
|
||||||
/* 原机 cs43198 驱动 pwr_gpio=-1:无上电/下电控制点(sysfs/amixer),on/off 不支持。
|
/* 原机 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)
|
static int dac_status(char *out, int cap)
|
||||||
{
|
{
|
||||||
char l[48] = "?", r[48] = "?";
|
int vol = settings_get_int_trim("audio.volume", MEOW_VOL_DEFAULT);
|
||||||
char *o1 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=1 2>/dev/null");
|
int vmax = settings_get_int_trim("audio.volume_max", MEOW_VOL_MAX_DEFAULT);
|
||||||
if (o1) {
|
if (vol < 0) vol = 0; /* 硬下限 0 */
|
||||||
char *p = strstr(o1, ": values=");
|
if (vol > 100) vol = 100; /* 硬上限 100(0-100 口径) */
|
||||||
if (p) snprintf(l, sizeof l, "%.40s", p + 9);
|
if (vmax < 0) vmax = 0; /* 异常上限兜底:不进负值 */
|
||||||
free(o1);
|
if (vol > vmax) vol = vmax; /* 尊重 audio.volume_max 软上限 */
|
||||||
}
|
/* 左右同值(单个 DAC 声道容量;L=R=vol%);settings 读不到 → 默认 MEOW_VOL_DEFAULT(60) 即真实默认。 */
|
||||||
char *o2 = popen_read_tmo(SV_TIMEOUT_MS, "PATH=/bin:/sbin:/usr/bin:/usr/sbin amixer -c 0 cget numid=2 2>/dev/null");
|
snprintf(out, cap, "dac=cs43198 vol=%d%% L=R", vol);
|
||||||
if (o2) {
|
svc_log("dac status: audio.volume=%d (volume_max=%d)", vol, vmax);
|
||||||
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)");
|
|
||||||
return 0;
|
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)");
|
snprintf(st->msg, sizeof st->msg, "reboot accepted (boot=meow)");
|
||||||
return 1;
|
return 1;
|
||||||
case POWER_UPGRADE:
|
case POWER_UPGRADE:
|
||||||
sync();
|
{ /* 写 mtd5 前先校验卡上升级固件(升级写保护);校验失败→非 OK、绝不写 mtd5/不 reboot。 */
|
||||||
st->code = MEOW_OK;
|
char why[64];
|
||||||
snprintf(st->msg, sizeof st->msg, "upgrade accepted");
|
int rc = upgrade_fw_check(why, sizeof why);
|
||||||
return 1;
|
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:
|
case POWER_BACK_HIBY:
|
||||||
write_boot_default(1);
|
write_boot_default(1);
|
||||||
sync();
|
sync();
|
||||||
@@ -659,6 +694,12 @@ static int cli_run(int n, char **v)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!strcmp(cmd, "upgrade")) {
|
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();
|
enter_upgrade();
|
||||||
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
sys_reboot_do(LINUX_REBOOT_CMD_RESTART);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Binary file not shown.
Reference in new issue
Block a user